Copyright 2014 Google Inc. All Rights Reserved. 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.
This file is a simple protocol buffer encoder and decoder. The format is described at https://developers.google.com/protocol-buffers/docs/encoding A protocol message must implement the message interface: decoder() []decoder encode(*buffer) The decode method returns a slice indexed by field number that gives the function to decode that field. The encode method encodes its receiver into the given buffer. The two methods are simple enough to be implemented by hand rather than by using a protocol compiler. See profile.go for examples of messages implementing this interface. There is no support for groups, message sets, or "has" bits.

package profile

import (
	
	
)

type buffer struct {
	field int // field tag
	typ   int // proto wire type code for field
	u64   uint64
	data  []byte
	tmp   [16]byte
}

type decoder func(*buffer, message) error

type message interface {
	decoder() []decoder
	encode(*buffer)
}

func ( message) []byte {
	var  buffer
	.encode(&)
	return .data
}

func ( *buffer,  uint64) {
	for  >= 128 {
		.data = append(.data, byte()|0x80)
		 >>= 7
	}
	.data = append(.data, byte())
}

func ( *buffer,  int,  int) {
	encodeVarint(, uint64()<<3|2)
	encodeVarint(, uint64())
}

append varint to b.data
	encodeVarint(, uint64()<<3)
	encodeVarint(, )
}

func ( *buffer,  int,  []uint64) {
Use packed encoding
		 := len(.data)
		for ,  := range  {
			encodeVarint(, )
		}
		 := len(.data)
		encodeLength(, , -)
		 := len(.data)
		copy(.tmp[:], .data[:])
		copy(.data[+(-):], .data[:])
		copy(.data[:], .tmp[:-])
		return
	}
	for ,  := range  {
		encodeUint64(, , )
	}
}

func ( *buffer,  int,  uint64) {
	if  == 0 {
		return
	}
	encodeUint64(, , )
}

func ( *buffer,  int,  int64) {
	 := uint64()
	encodeUint64(, , )
}

func ( *buffer,  int,  []int64) {
Use packed encoding
		 := len(.data)
		for ,  := range  {
			encodeVarint(, uint64())
		}
		 := len(.data)
		encodeLength(, , -)
		 := len(.data)
		copy(.tmp[:], .data[:])
		copy(.data[+(-):], .data[:])
		copy(.data[:], .tmp[:-])
		return
	}
	for ,  := range  {
		encodeInt64(, , )
	}
}

func ( *buffer,  int,  int64) {
	if  == 0 {
		return
	}
	encodeInt64(, , )
}

func ( *buffer,  int,  string) {
	encodeLength(, , len())
	.data = append(.data, ...)
}

func ( *buffer,  int,  []string) {
	for ,  := range  {
		encodeString(, , )
	}
}

func ( *buffer,  int,  bool) {
	if  {
		encodeUint64(, , 1)
	} else {
		encodeUint64(, , 0)
	}
}

func ( *buffer,  int,  bool) {
	if  {
		encodeBool(, , )
	}
}

func ( *buffer,  int,  message) {
	 := len(.data)
	.encode()
	 := len(.data)
	encodeLength(, , -)
	 := len(.data)
	copy(.tmp[:], .data[:])
	copy(.data[+(-):], .data[:])
	copy(.data[:], .tmp[:-])
}

func ( []byte,  message) ( error) {
	 := buffer{data: , typ: 2}
	return decodeMessage(&, )
}

func ( []byte) uint64 {
	return uint64([0]) | uint64([1])<<8 | uint64([2])<<16 | uint64([3])<<24 | uint64([4])<<32 | uint64([5])<<40 | uint64([6])<<48 | uint64([7])<<56
}

func ( []byte) uint32 {
	return uint32([0]) | uint32([1])<<8 | uint32([2])<<16 | uint32([3])<<24
}

func ( []byte) (uint64, []byte, error) {
	var  uint64
	for  := 0; ; ++ {
		if  >= 10 ||  >= len() {
			return 0, nil, errors.New("bad varint")
		}
		 |= uint64([]&0x7F) << uint(7*)
		if []&0x80 == 0 {
			return , [+1:], nil
		}
	}
}

func ( *buffer,  []byte) ([]byte, error) {
	, ,  := decodeVarint()
	if  != nil {
		return nil, 
	}
	.field = int( >> 3)
	.typ = int( & 7)
	.data = nil
	.u64 = 0
	switch .typ {
	case 0:
		.u64, ,  = decodeVarint()
		if  != nil {
			return nil, 
		}
	case 1:
		if len() < 8 {
			return nil, errors.New("not enough data")
		}
		.u64 = le64([:8])
		 = [8:]
	case 2:
		var  uint64
		, ,  = decodeVarint()
		if  != nil {
			return nil, 
		}
		if  > uint64(len()) {
			return nil, errors.New("too much data")
		}
		.data = [:]
		 = [:]
	case 5:
		if len() < 4 {
			return nil, errors.New("not enough data")
		}
		.u64 = uint64(le32([:4]))
		 = [4:]
	default:
		return nil, fmt.Errorf("unknown wire type: %d", .typ)
	}

	return , nil
}

func ( *buffer,  int) error {
	if .typ !=  {
		return errors.New("type mismatch")
	}
	return nil
}

func ( *buffer,  message) error {
	if  := checkType(, 2);  != nil {
		return 
	}
	 := .decoder()
	 := .data
pull varint field# + type
		var  error
		,  = decodeField(, )
		if  != nil {
			return 
		}
		if .field >= len() || [.field] == nil {
			continue
		}
		if  := [.field](, );  != nil {
			return 
		}
	}
	return nil
}

func ( *buffer,  *int64) error {
	if  := checkType(, 0);  != nil {
		return 
	}
	* = int64(.u64)
	return nil
}

func ( *buffer,  *[]int64) error {
Packed encoding
		 := .data
		 := make([]int64, 0, len()) // Maximally sized
		for len() > 0 {
			var  uint64
			var  error

			if , ,  = decodeVarint();  != nil {
				return 
			}
			 = append(, int64())
		}
		* = append(*, ...)
		return nil
	}
	var  int64
	if  := decodeInt64(, &);  != nil {
		return 
	}
	* = append(*, )
	return nil
}

func ( *buffer,  *uint64) error {
	if  := checkType(, 0);  != nil {
		return 
	}
	* = .u64
	return nil
}

func ( *buffer,  *[]uint64) error {
	if .typ == 2 {
Packed encoding
		 := make([]uint64, 0, len()) // Maximally sized
		for len() > 0 {
			var  uint64
			var  error

			if , ,  = decodeVarint();  != nil {
				return 
			}
			 = append(, )
		}
		* = append(*, ...)
		return nil
	}
	var  uint64
	if  := decodeUint64(, &);  != nil {
		return 
	}
	* = append(*, )
	return nil
}

func ( *buffer,  *string) error {
	if  := checkType(, 2);  != nil {
		return 
	}
	* = string(.data)
	return nil
}

func ( *buffer,  *[]string) error {
	var  string
	if  := decodeString(, &);  != nil {
		return 
	}
	* = append(*, )
	return nil
}

func ( *buffer,  *bool) error {
	if  := checkType(, 0);  != nil {
		return 
	}
	if int64(.u64) == 0 {
		* = false
	} else {
		* = true
	}
	return nil