github.com/matm/etcd@v0.3.1-0.20140328024009-5b4a473f1453/third_party/code.google.com/p/gogoprotobuf/proto/message_set.go (about)

     1  // Go support for Protocol Buffers - Google's data interchange format
     2  //
     3  // Copyright 2010 The Go Authors.  All rights reserved.
     4  // http://code.google.com/p/goprotobuf/
     5  //
     6  // Redistribution and use in source and binary forms, with or without
     7  // modification, are permitted provided that the following conditions are
     8  // met:
     9  //
    10  //     * Redistributions of source code must retain the above copyright
    11  // notice, this list of conditions and the following disclaimer.
    12  //     * Redistributions in binary form must reproduce the above
    13  // copyright notice, this list of conditions and the following disclaimer
    14  // in the documentation and/or other materials provided with the
    15  // distribution.
    16  //     * Neither the name of Google Inc. nor the names of its
    17  // contributors may be used to endorse or promote products derived from
    18  // this software without specific prior written permission.
    19  //
    20  // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
    21  // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
    22  // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
    23  // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
    24  // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
    25  // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
    26  // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
    27  // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
    28  // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    29  // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
    30  // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    31  
    32  package proto
    33  
    34  /*
    35   * Support for message sets.
    36   */
    37  
    38  import (
    39  	"errors"
    40  	"reflect"
    41  	"sort"
    42  )
    43  
    44  // ErrNoMessageTypeId occurs when a protocol buffer does not have a message type ID.
    45  // A message type ID is required for storing a protocol buffer in a message set.
    46  var ErrNoMessageTypeId = errors.New("proto does not have a message type ID")
    47  
    48  // The first two types (_MessageSet_Item and MessageSet)
    49  // model what the protocol compiler produces for the following protocol message:
    50  //   message MessageSet {
    51  //     repeated group Item = 1 {
    52  //       required int32 type_id = 2;
    53  //       required string message = 3;
    54  //     };
    55  //   }
    56  // That is the MessageSet wire format. We can't use a proto to generate these
    57  // because that would introduce a circular dependency between it and this package.
    58  //
    59  // When a proto1 proto has a field that looks like:
    60  //   optional message<MessageSet> info = 3;
    61  // the protocol compiler produces a field in the generated struct that looks like:
    62  //   Info *_proto_.MessageSet  `protobuf:"bytes,3,opt,name=info"`
    63  // The package is automatically inserted so there is no need for that proto file to
    64  // import this package.
    65  
    66  type _MessageSet_Item struct {
    67  	TypeId  *int32 `protobuf:"varint,2,req,name=type_id"`
    68  	Message []byte `protobuf:"bytes,3,req,name=message"`
    69  }
    70  
    71  type MessageSet struct {
    72  	Item             []*_MessageSet_Item `protobuf:"group,1,rep"`
    73  	XXX_unrecognized []byte
    74  	// TODO: caching?
    75  }
    76  
    77  // Make sure MessageSet is a Message.
    78  var _ Message = (*MessageSet)(nil)
    79  
    80  // messageTypeIder is an interface satisfied by a protocol buffer type
    81  // that may be stored in a MessageSet.
    82  type messageTypeIder interface {
    83  	MessageTypeId() int32
    84  }
    85  
    86  func (ms *MessageSet) find(pb Message) *_MessageSet_Item {
    87  	mti, ok := pb.(messageTypeIder)
    88  	if !ok {
    89  		return nil
    90  	}
    91  	id := mti.MessageTypeId()
    92  	for _, item := range ms.Item {
    93  		if *item.TypeId == id {
    94  			return item
    95  		}
    96  	}
    97  	return nil
    98  }
    99  
   100  func (ms *MessageSet) Has(pb Message) bool {
   101  	if ms.find(pb) != nil {
   102  		return true
   103  	}
   104  	return false
   105  }
   106  
   107  func (ms *MessageSet) Unmarshal(pb Message) error {
   108  	if item := ms.find(pb); item != nil {
   109  		return Unmarshal(item.Message, pb)
   110  	}
   111  	if _, ok := pb.(messageTypeIder); !ok {
   112  		return ErrNoMessageTypeId
   113  	}
   114  	return nil // TODO: return error instead?
   115  }
   116  
   117  func (ms *MessageSet) Marshal(pb Message) error {
   118  	msg, err := Marshal(pb)
   119  	if err != nil {
   120  		return err
   121  	}
   122  	if item := ms.find(pb); item != nil {
   123  		// reuse existing item
   124  		item.Message = msg
   125  		return nil
   126  	}
   127  
   128  	mti, ok := pb.(messageTypeIder)
   129  	if !ok {
   130  		return ErrWrongType // TODO: custom error?
   131  	}
   132  
   133  	mtid := mti.MessageTypeId()
   134  	ms.Item = append(ms.Item, &_MessageSet_Item{
   135  		TypeId:  &mtid,
   136  		Message: msg,
   137  	})
   138  	return nil
   139  }
   140  
   141  func (ms *MessageSet) Reset()         { *ms = MessageSet{} }
   142  func (ms *MessageSet) String() string { return CompactTextString(ms) }
   143  func (*MessageSet) ProtoMessage()     {}
   144  
   145  // Support for the message_set_wire_format message option.
   146  
   147  func skipVarint(buf []byte) []byte {
   148  	i := 0
   149  	for ; buf[i]&0x80 != 0; i++ {
   150  	}
   151  	return buf[i+1:]
   152  }
   153  
   154  // MarshalMessageSet encodes the extension map represented by m in the message set wire format.
   155  // It is called by generated Marshal methods on protocol buffer messages with the message_set_wire_format option.
   156  func MarshalMessageSet(m map[int32]Extension) ([]byte, error) {
   157  	if err := encodeExtensionMap(m); err != nil {
   158  		return nil, err
   159  	}
   160  
   161  	// Sort extension IDs to provide a deterministic encoding.
   162  	// See also enc_map in encode.go.
   163  	ids := make([]int, 0, len(m))
   164  	for id := range m {
   165  		ids = append(ids, int(id))
   166  	}
   167  	sort.Ints(ids)
   168  
   169  	ms := &MessageSet{Item: make([]*_MessageSet_Item, 0, len(m))}
   170  	for _, id := range ids {
   171  		e := m[int32(id)]
   172  		// Remove the wire type and field number varint, as well as the length varint.
   173  		msg := skipVarint(skipVarint(e.enc))
   174  
   175  		ms.Item = append(ms.Item, &_MessageSet_Item{
   176  			TypeId:  Int32(int32(id)),
   177  			Message: msg,
   178  		})
   179  	}
   180  	return Marshal(ms)
   181  }
   182  
   183  // UnmarshalMessageSet decodes the extension map encoded in buf in the message set wire format.
   184  // It is called by generated Unmarshal methods on protocol buffer messages with the message_set_wire_format option.
   185  func UnmarshalMessageSet(buf []byte, m map[int32]Extension) error {
   186  	ms := new(MessageSet)
   187  	if err := Unmarshal(buf, ms); err != nil {
   188  		return err
   189  	}
   190  	for _, item := range ms.Item {
   191  		// restore wire type and field number varint, plus length varint.
   192  		b := EncodeVarint(uint64(*item.TypeId)<<3 | WireBytes)
   193  		b = append(b, EncodeVarint(uint64(len(item.Message)))...)
   194  		b = append(b, item.Message...)
   195  
   196  		m[*item.TypeId] = Extension{enc: b}
   197  	}
   198  	return nil
   199  }
   200  
   201  // A global registry of types that can be used in a MessageSet.
   202  
   203  var messageSetMap = make(map[int32]messageSetDesc)
   204  
   205  type messageSetDesc struct {
   206  	t    reflect.Type // pointer to struct
   207  	name string
   208  }
   209  
   210  // RegisterMessageSetType is called from the generated code.
   211  func RegisterMessageSetType(i messageTypeIder, name string) {
   212  	messageSetMap[i.MessageTypeId()] = messageSetDesc{
   213  		t:    reflect.TypeOf(i),
   214  		name: name,
   215  	}
   216  }