Skip to content
Snippets Groups Projects
encode.go 6.08 KiB
Newer Older
  • Learn to ignore specific revisions
  • ale's avatar
    ale committed
    // Go support for Protocol Buffers - Google's data interchange format
    //
    // Copyright 2010 The Go Authors.  All rights reserved.
    // https://github.com/golang/protobuf
    //
    // Redistribution and use in source and binary forms, with or without
    // modification, are permitted provided that the following conditions are
    // met:
    //
    //     * Redistributions of source code must retain the above copyright
    // notice, this list of conditions and the following disclaimer.
    //     * Redistributions in binary form must reproduce the above
    // copyright notice, this list of conditions and the following disclaimer
    // in the documentation and/or other materials provided with the
    // distribution.
    //     * Neither the name of Google Inc. nor the names of its
    // contributors may be used to endorse or promote products derived from
    // this software without specific prior written permission.
    //
    // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
    // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
    // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
    // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
    // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
    // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
    // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
    // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
    // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
    // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    
    package proto
    
    /*
     * Routines for encoding data into the wire format for protocol buffers.
     */
    
    import (
    	"errors"
    	"reflect"
    )
    
    var (
    	// errRepeatedHasNil is the error returned if Marshal is called with
    	// a struct with a repeated field containing a nil element.
    	errRepeatedHasNil = errors.New("proto: repeated field has nil element")
    
    	// errOneofHasNil is the error returned if Marshal is called with
    	// a struct with a oneof field containing a nil element.
    	errOneofHasNil = errors.New("proto: oneof field has nil value")
    
    	// ErrNil is the error returned if Marshal is called with nil.
    	ErrNil = errors.New("proto: Marshal called with nil")
    
    	// ErrTooLarge is the error returned if Marshal is called with a
    	// message that encodes to >2GB.
    	ErrTooLarge = errors.New("proto: message encodes to over 2 GB")
    )
    
    // The fundamental encoders that put bytes on the wire.
    // Those that take integer types all accept uint64 and are
    // therefore of type valueEncoder.
    
    const maxVarintBytes = 10 // maximum length of a varint
    
    // EncodeVarint returns the varint encoding of x.
    // This is the format for the
    // int32, int64, uint32, uint64, bool, and enum
    // protocol buffer types.
    // Not used by the package itself, but helpful to clients
    // wishing to use the same encoding.
    func EncodeVarint(x uint64) []byte {
    	var buf [maxVarintBytes]byte
    	var n int
    	for n = 0; x > 127; n++ {
    		buf[n] = 0x80 | uint8(x&0x7F)
    		x >>= 7
    	}
    	buf[n] = uint8(x)
    	n++
    	return buf[0:n]
    }
    
    // EncodeVarint writes a varint-encoded integer to the Buffer.
    // This is the format for the
    // int32, int64, uint32, uint64, bool, and enum
    // protocol buffer types.
    func (p *Buffer) EncodeVarint(x uint64) error {
    	for x >= 1<<7 {
    		p.buf = append(p.buf, uint8(x&0x7f|0x80))
    		x >>= 7
    	}
    	p.buf = append(p.buf, uint8(x))
    	return nil
    }
    
    // SizeVarint returns the varint encoding size of an integer.
    func SizeVarint(x uint64) int {
    
    ale's avatar
    ale committed
    	switch {
    	case x < 1<<7:
    		return 1
    	case x < 1<<14:
    		return 2
    	case x < 1<<21:
    		return 3
    	case x < 1<<28:
    		return 4
    	case x < 1<<35:
    		return 5
    	case x < 1<<42:
    		return 6
    	case x < 1<<49:
    		return 7
    	case x < 1<<56:
    		return 8
    	case x < 1<<63:
    		return 9
    	}
    	return 10
    
    ale's avatar
    ale committed
    }
    
    // EncodeFixed64 writes a 64-bit integer to the Buffer.
    // This is the format for the
    // fixed64, sfixed64, and double protocol buffer types.
    func (p *Buffer) EncodeFixed64(x uint64) error {
    	p.buf = append(p.buf,
    		uint8(x),
    		uint8(x>>8),
    		uint8(x>>16),
    		uint8(x>>24),
    		uint8(x>>32),
    		uint8(x>>40),
    		uint8(x>>48),
    		uint8(x>>56))
    	return nil
    }
    
    // EncodeFixed32 writes a 32-bit integer to the Buffer.
    // This is the format for the
    // fixed32, sfixed32, and float protocol buffer types.
    func (p *Buffer) EncodeFixed32(x uint64) error {
    	p.buf = append(p.buf,
    		uint8(x),
    		uint8(x>>8),
    		uint8(x>>16),
    		uint8(x>>24))
    	return nil
    }
    
    // EncodeZigzag64 writes a zigzag-encoded 64-bit integer
    // to the Buffer.
    // This is the format used for the sint64 protocol buffer type.
    func (p *Buffer) EncodeZigzag64(x uint64) error {
    	// use signed number to get arithmetic right shift.
    
    ale's avatar
    ale committed
    	return p.EncodeVarint(uint64((x << 1) ^ uint64((int64(x) >> 63))))
    
    ale's avatar
    ale committed
    }
    
    // EncodeZigzag32 writes a zigzag-encoded 32-bit integer
    // to the Buffer.
    // This is the format used for the sint32 protocol buffer type.
    func (p *Buffer) EncodeZigzag32(x uint64) error {
    	// use signed number to get arithmetic right shift.
    	return p.EncodeVarint(uint64((uint32(x) << 1) ^ uint32((int32(x) >> 31))))
    }
    
    // EncodeRawBytes writes a count-delimited byte buffer to the Buffer.
    // This is the format used for the bytes protocol buffer
    // type and for embedded messages.
    func (p *Buffer) EncodeRawBytes(b []byte) error {
    	p.EncodeVarint(uint64(len(b)))
    	p.buf = append(p.buf, b...)
    	return nil
    }
    
    // EncodeStringBytes writes an encoded string to the Buffer.
    // This is the format used for the proto2 string type.
    func (p *Buffer) EncodeStringBytes(s string) error {
    	p.EncodeVarint(uint64(len(s)))
    	p.buf = append(p.buf, s...)
    	return nil
    }
    
    // Marshaler is the interface representing objects that can marshal themselves.
    type Marshaler interface {
    	Marshal() ([]byte, error)
    }
    
    // EncodeMessage writes the protocol buffer to the Buffer,
    // prefixed by a varint-encoded length.
    func (p *Buffer) EncodeMessage(pb Message) error {
    
    ale's avatar
    ale committed
    	siz := Size(pb)
    	p.EncodeVarint(uint64(siz))
    	return p.Marshal(pb)
    
    ale's avatar
    ale committed
    }
    
    // All protocol buffer fields are nillable, but be careful.
    func isNil(v reflect.Value) bool {
    	switch v.Kind() {
    	case reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice:
    		return v.IsNil()
    	}
    	return false
    }