1 /* 2 Copyright The containerd Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package typeurl 18 19 // Package typeurl assists with managing the registration, marshaling, and 20 // unmarshaling of types encoded as protobuf.Any. 21 // 22 // A protobuf.Any is a proto message that can contain any arbitrary data. It 23 // consists of two components, a TypeUrl and a Value, and its proto definition 24 // looks like this: 25 // 26 // message Any { 27 // string type_url = 1; 28 // bytes value = 2; 29 // } 30 // 31 // The TypeUrl is used to distinguish the contents from other proto.Any 32 // messages. This typeurl library manages these URLs to enable automagic 33 // marshaling and unmarshaling of the contents. 34 // 35 // For example, consider this go struct: 36 // 37 // type Foo struct { 38 // Field1 string 39 // Field2 string 40 // } 41 // 42 // To use typeurl, types must first be registered. This is typically done in 43 // the init function 44 // 45 // func init() { 46 // typeurl.Register(&Foo{}, "Foo") 47 // } 48 // 49 // This will register the type Foo with the url path "Foo". The arguments to 50 // Register are variadic, and are used to construct a url path. Consider this 51 // example, from the github.com/containerd/containerd/client package: 52 // 53 // func init() { 54 // const prefix = "types.containerd.io" 55 // // register TypeUrls for commonly marshaled external types 56 // major := strconv.Itoa(specs.VersionMajor) 57 // typeurl.Register(&specs.Spec{}, prefix, "opencontainers/runtime-spec", major, "Spec") 58 // // this function has more Register calls, which are elided. 59 // } 60 // 61 // This registers several types under a more complex url, which ends up mapping 62 // to `types.containerd.io/opencontainers/runtime-spec/1/Spec` (or some other 63 // value for major). 64 // 65 // Once a type is registered, it can be marshaled to a proto.Any message simply 66 // by calling `MarshalAny`, like this: 67 // 68 // foo := &Foo{Field1: "value1", Field2: "value2"} 69 // anyFoo, err := typeurl.MarshalAny(foo) 70 // 71 // MarshalAny will resolve the correct URL for the type. If the type in 72 // question implements the proto.Message interface, then it will be marshaled 73 // as a proto message. Otherwise, it will be marshaled as json. This means that 74 // typeurl will work on any arbitrary data, whether or not it has a proto 75 // definition, as long as it can be serialized to json. 76 // 77 // To unmarshal, the process is simply inverse: 78 // 79 // iface, err := typeurl.UnmarshalAny(anyFoo) 80 // foo := iface.(*Foo) 81 // 82 // The correct type is automatically chosen from the type registry, and the 83 // returned interface can be cast straight to that type. 84