diff --git a/typeurl/marshal_test.go b/typeurl/marshal_test.go deleted file mode 100644 index 9ca5adca6..000000000 --- a/typeurl/marshal_test.go +++ /dev/null @@ -1,62 +0,0 @@ -package typeurl_test - -import ( - "fmt" - "reflect" - "testing" - - eventsapi "github.com/containerd/containerd/api/services/events/v1" - "github.com/containerd/containerd/typeurl" -) - -func TestMarshalEvent(t *testing.T) { - for _, testcase := range []struct { - event interface{} - url string - }{ - { - event: &eventsapi.TaskStart{}, - url: "types.containerd.io/containerd.services.events.v1.TaskStart", - }, - - { - event: &eventsapi.NamespaceUpdate{}, - url: "types.containerd.io/containerd.services.events.v1.NamespaceUpdate", - }, - } { - t.Run(fmt.Sprintf("%T", testcase.event), func(t *testing.T) { - a, err := typeurl.MarshalAny(testcase.event) - if err != nil { - t.Fatal(err) - } - if a.TypeUrl != testcase.url { - t.Fatalf("unexpected url: %v != %v", a.TypeUrl, testcase.url) - } - - v, err := typeurl.UnmarshalAny(a) - if err != nil { - t.Fatal(err) - } - if !reflect.DeepEqual(v, testcase.event) { - t.Fatalf("round trip failed %v != %v", v, testcase.event) - } - }) - } -} - -func BenchmarkMarshalEvent(b *testing.B) { - ev := &eventsapi.TaskStart{} - expected, err := typeurl.MarshalAny(ev) - if err != nil { - b.Fatal(err) - } - for i := 0; i < b.N; i++ { - a, err := typeurl.MarshalAny(ev) - if err != nil { - b.Fatal(err) - } - if a.TypeUrl != expected.TypeUrl { - b.Fatalf("incorrect type url: %v != %v", a, expected) - } - } -} diff --git a/typeurl/types.go b/typeurl/types.go deleted file mode 100644 index 63b214b5e..000000000 --- a/typeurl/types.go +++ /dev/null @@ -1,144 +0,0 @@ -package typeurl - -import ( - "encoding/json" - "path" - "reflect" - "strings" - "sync" - - "github.com/containerd/containerd/errdefs" - "github.com/gogo/protobuf/proto" - "github.com/gogo/protobuf/types" - "github.com/pkg/errors" -) - -const Prefix = "types.containerd.io" - -var ( - mu sync.Mutex - registry = make(map[reflect.Type]string) -) - -// Register a type with the base url of the type -func Register(v interface{}, args ...string) { - var ( - t = tryDereference(v) - p = path.Join(append([]string{Prefix}, args...)...) - ) - mu.Lock() - defer mu.Unlock() - if et, ok := registry[t]; ok { - if et != p { - panic(errors.Errorf("type registred with alternate path %q != %q", et, p)) - } - return - } - registry[t] = p -} - -// TypeURL returns the type url for a registred type -func TypeURL(v interface{}) (string, error) { - mu.Lock() - u, ok := registry[tryDereference(v)] - mu.Unlock() - if !ok { - // fallback to the proto registry if it is a proto message - pb, ok := v.(proto.Message) - if !ok { - return "", errors.Wrapf(errdefs.ErrNotFound, "type %s", reflect.TypeOf(v)) - } - return path.Join(Prefix, proto.MessageName(pb)), nil - } - return u, nil -} - -// Is returns true if the type of the Any is the same as v -func Is(any *types.Any, v interface{}) bool { - // call to check that v is a pointer - tryDereference(v) - url, err := TypeURL(v) - if err != nil { - return false - } - return any.TypeUrl == url -} - -// MarshalAny marshals the value v into an any with the correct TypeUrl -func MarshalAny(v interface{}) (*types.Any, error) { - var marshal func(v interface{}) ([]byte, error) - switch t := v.(type) { - case *types.Any: - // avoid reserializing the type if we have an any. - return t, nil - case proto.Message: - marshal = func(v interface{}) ([]byte, error) { - return proto.Marshal(t) - } - default: - marshal = json.Marshal - } - - url, err := TypeURL(v) - if err != nil { - return nil, err - } - - data, err := marshal(v) - if err != nil { - return nil, err - } - return &types.Any{ - TypeUrl: url, - Value: data, - }, nil -} - -// UnmarshalAny unmarshals the any type into a concrete type -func UnmarshalAny(any *types.Any) (interface{}, error) { - t, err := getTypeByUrl(any.TypeUrl) - if err != nil { - return nil, err - } - v := reflect.New(t.t).Interface() - if t.isProto { - err = proto.Unmarshal(any.Value, v.(proto.Message)) - } else { - err = json.Unmarshal(any.Value, v) - } - return v, err -} - -type urlType struct { - t reflect.Type - isProto bool -} - -func getTypeByUrl(url string) (urlType, error) { - for t, u := range registry { - if u == url { - return urlType{ - t: t, - }, nil - } - } - // fallback to proto registry - t := proto.MessageType(strings.TrimPrefix(url, Prefix+"/")) - if t != nil { - return urlType{ - // get the underlying Elem because proto returns a pointer to the type - t: t.Elem(), - isProto: true, - }, nil - } - return urlType{}, errors.Wrapf(errdefs.ErrNotFound, "type with url %s", url) -} - -func tryDereference(v interface{}) reflect.Type { - t := reflect.TypeOf(v) - if t.Kind() == reflect.Ptr { - // require check of pointer but dereference to register - return t.Elem() - } - panic("v is not a pointer to a type") -} diff --git a/typeurl/types_test.go b/typeurl/types_test.go deleted file mode 100644 index c4bc89592..000000000 --- a/typeurl/types_test.go +++ /dev/null @@ -1,115 +0,0 @@ -package typeurl - -import ( - "path/filepath" - "reflect" - "testing" -) - -type test struct { - Name string - Age int -} - -func clear() { - registry = make(map[reflect.Type]string) -} - -func TestRegisterPointerGetPointer(t *testing.T) { - clear() - expected := filepath.Join(Prefix, "test") - Register(&test{}, "test") - - url, err := TypeURL(&test{}) - if err != nil { - t.Fatal(err) - } - if url != expected { - t.Fatalf("expected %q but received %q", expected, url) - } -} - -func TestMarshal(t *testing.T) { - clear() - expected := filepath.Join(Prefix, "test") - Register(&test{}, "test") - - v := &test{ - Name: "koye", - Age: 6, - } - any, err := MarshalAny(v) - if err != nil { - t.Fatal(err) - } - if any.TypeUrl != expected { - t.Fatalf("expected %q but received %q", expected, any.TypeUrl) - } - - // marshal it again and make sure we get the same thing back. - newany, err := MarshalAny(any) - if err != nil { - t.Fatal(err) - } - - if newany != any { // you that right: we want the same *pointer*! - t.Fatalf("expected to get back same object: %v != %v", newany, any) - } - -} - -func TestMarshalUnmarshal(t *testing.T) { - clear() - Register(&test{}, "test") - - v := &test{ - Name: "koye", - Age: 6, - } - any, err := MarshalAny(v) - if err != nil { - t.Fatal(err) - } - nv, err := UnmarshalAny(any) - if err != nil { - t.Fatal(err) - } - td, ok := nv.(*test) - if !ok { - t.Fatal("expected value to cast to *test") - } - if td.Name != "koye" { - t.Fatal("invalid name") - } - if td.Age != 6 { - t.Fatal("invalid age") - } -} - -func TestIs(t *testing.T) { - clear() - Register(&test{}, "test") - - v := &test{ - Name: "koye", - Age: 6, - } - any, err := MarshalAny(v) - if err != nil { - t.Fatal(err) - } - if !Is(any, &test{}) { - t.Fatal("Is(any, test{}) should be true") - } -} - -func TestRegisterDiffUrls(t *testing.T) { - clear() - defer func() { - if err := recover(); err == nil { - t.Error("registering the same type with different urls should panic") - } - }() - Register(&test{}, "test") - Register(&test{}, "test", "two") -}