github.com/cosmos/cosmos-proto@v1.0.0-beta.3/anyutil/any.go (about) 1 // Protocol Buffers - Google's data interchange format 2 // Copyright 2008 Google Inc. All rights reserved. 3 // https://developers.google.com/protocol-buffers/ 4 // 5 // Redistribution and use in source and binary forms, with or without 6 // modification, are permitted provided that the following conditions are 7 // met: 8 // 9 // * Redistributions of source code must retain the above copyright 10 // notice, this list of conditions and the following disclaimer. 11 // * Redistributions in binary form must reproduce the above 12 // copyright notice, this list of conditions and the following disclaimer 13 // in the documentation and/or other materials provided with the 14 // distribution. 15 // * Neither the name of Google Inc. nor the names of its 16 // contributors may be used to endorse or promote products derived from 17 // this software without specific prior written permission. 18 // 19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 31 package anyutil 32 33 import ( 34 "fmt" 35 "strings" 36 37 "google.golang.org/protobuf/proto" 38 "google.golang.org/protobuf/reflect/protodesc" 39 "google.golang.org/protobuf/reflect/protoreflect" 40 "google.golang.org/protobuf/reflect/protoregistry" 41 protoimpl "google.golang.org/protobuf/runtime/protoimpl" 42 "google.golang.org/protobuf/types/dynamicpb" 43 "google.golang.org/protobuf/types/known/anypb" 44 ) 45 46 // New marshals src into a new Any instance. 47 func New(src proto.Message) (*anypb.Any, error) { 48 dst := new(anypb.Any) 49 if err := MarshalFrom(dst, src, proto.MarshalOptions{}); err != nil { 50 return nil, err 51 } 52 return dst, nil 53 } 54 55 // MarshalFrom marshals src into dst as the underlying message 56 // using the provided marshal options. 57 // 58 // If no options are specified, call dst.MarshalFrom instead. 59 func MarshalFrom(dst *anypb.Any, src proto.Message, opts proto.MarshalOptions) error { 60 if src == nil { 61 return protoimpl.X.NewError("invalid nil source message") 62 } 63 b, err := opts.Marshal(src) 64 if err != nil { 65 return err 66 } 67 dst.TypeUrl = "/" + string(src.ProtoReflect().Descriptor().FullName()) 68 dst.Value = b 69 return nil 70 } 71 72 // Unpack unpacks the message inside an any, first using the provided 73 // typeResolver (defaults to protoregistry.GlobalTypes), and if that fails, 74 // then using the provided fileResolver (defaults to protoregistry.GlobalFiles) 75 // with dynamicpb. 76 func Unpack(any *anypb.Any, fileResolver protodesc.Resolver, typeResolver protoregistry.MessageTypeResolver) (proto.Message, error) { 77 if typeResolver == nil { 78 typeResolver = protoregistry.GlobalTypes 79 } 80 81 url := any.TypeUrl 82 typ, err := typeResolver.FindMessageByURL(url) 83 if err == protoregistry.NotFound { 84 if fileResolver == nil { 85 fileResolver = protoregistry.GlobalFiles 86 } 87 88 // If the proto v2 registry doesn't have this message, then we use 89 // protoFiles (which can e.g. be initialized to gogo's MergedRegistry) 90 // to retrieve the message descriptor, and then use dynamicpb on that 91 // message descriptor to create a proto.Message 92 typeURL := strings.TrimPrefix(any.TypeUrl, "/") 93 94 msgDesc, err := fileResolver.FindDescriptorByName(protoreflect.FullName(typeURL)) 95 if err != nil { 96 return nil, fmt.Errorf("protoFiles does not have descriptor %s: %w", any.TypeUrl, err) 97 } 98 99 typ = dynamicpb.NewMessageType(msgDesc.(protoreflect.MessageDescriptor)) 100 101 } else if err != nil { 102 return nil, err 103 } 104 105 packedMsg := typ.New().Interface() 106 err = any.UnmarshalTo(packedMsg) 107 if err != nil { 108 return nil, fmt.Errorf("cannot unmarshal msg %s: %w", any.TypeUrl, err) 109 } 110 111 return packedMsg, nil 112 }