|
@@ -0,0 +1,83 @@
|
|
|
+/*
|
|
|
+ Copyright The containerd Authors.
|
|
|
+
|
|
|
+ Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
+ you may not use this file except in compliance with the License.
|
|
|
+ You may obtain a copy of the License at
|
|
|
+
|
|
|
+ http://www.apache.org/licenses/LICENSE-2.0
|
|
|
+
|
|
|
+ Unless required by applicable law or agreed to in writing, software
|
|
|
+ distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
+ See the License for the specific language governing permissions and
|
|
|
+ limitations under the License.
|
|
|
+*/
|
|
|
+
|
|
|
+package typeurl
|
|
|
+
|
|
|
+// Package typeurl assists with managing the registration, marshaling, and
|
|
|
+// unmarshaling of types encoded as protobuf.Any.
|
|
|
+//
|
|
|
+// A protobuf.Any is a proto message that can contain any arbitrary data. It
|
|
|
+// consists of two components, a TypeUrl and a Value, and its proto definition
|
|
|
+// looks like this:
|
|
|
+//
|
|
|
+// message Any {
|
|
|
+// string type_url = 1;
|
|
|
+// bytes value = 2;
|
|
|
+// }
|
|
|
+//
|
|
|
+// The TypeUrl is used to distinguish the contents from other proto.Any
|
|
|
+// messages. This typeurl library manages these URLs to enable automagic
|
|
|
+// marshaling and unmarshaling of the contents.
|
|
|
+//
|
|
|
+// For example, consider this go struct:
|
|
|
+//
|
|
|
+// type Foo struct {
|
|
|
+// Field1 string
|
|
|
+// Field2 string
|
|
|
+// }
|
|
|
+//
|
|
|
+// To use typeurl, types must first be registered. This is typically done in
|
|
|
+// the init function
|
|
|
+//
|
|
|
+// func init() {
|
|
|
+// typeurl.Register(&Foo{}, "Foo")
|
|
|
+// }
|
|
|
+//
|
|
|
+// This will register the type Foo with the url path "Foo". The arguments to
|
|
|
+// Register are variadic, and are used to construct a url path. Consider this
|
|
|
+// example, from the github.com/containerd/containerd/client package:
|
|
|
+//
|
|
|
+// func init() {
|
|
|
+// const prefix = "types.containerd.io"
|
|
|
+// // register TypeUrls for commonly marshaled external types
|
|
|
+// major := strconv.Itoa(specs.VersionMajor)
|
|
|
+// typeurl.Register(&specs.Spec{}, prefix, "opencontainers/runtime-spec", major, "Spec")
|
|
|
+// // this function has more Register calls, which are elided.
|
|
|
+// }
|
|
|
+//
|
|
|
+// This registers several types under a more complex url, which ends up mapping
|
|
|
+// to `types.containerd.io/opencontainers/runtime-spec/1/Spec` (or some other
|
|
|
+// value for major).
|
|
|
+//
|
|
|
+// Once a type is registered, it can be marshaled to a proto.Any message simply
|
|
|
+// by calling `MarshalAny`, like this:
|
|
|
+//
|
|
|
+// foo := &Foo{Field1: "value1", Field2: "value2"}
|
|
|
+// anyFoo, err := typeurl.MarshalAny(foo)
|
|
|
+//
|
|
|
+// MarshalAny will resolve the correct URL for the type. If the type in
|
|
|
+// question implements the proto.Message interface, then it will be marshaled
|
|
|
+// as a proto message. Otherwise, it will be marshaled as json. This means that
|
|
|
+// typeurl will work on any arbitrary data, whether or not it has a proto
|
|
|
+// definition, as long as it can be serialized to json.
|
|
|
+//
|
|
|
+// To unmarshal, the process is simply inverse:
|
|
|
+//
|
|
|
+// iface, err := typeurl.UnmarshalAny(anyFoo)
|
|
|
+// foo := iface.(*Foo)
|
|
|
+//
|
|
|
+// The correct type is automatically chosen from the type registry, and the
|
|
|
+// returned interface can be cast straight to that type.
|