package rpc import ( "bytes" "errors" "fmt" ) type Vars map[string]string func NewVars() Vars { return make(Vars) } func (vs Vars) MarshalBinary() ([]byte, error) { var buf bytes.Buffer for k, v := range vs { buf.WriteString(k) buf.WriteByte(byte(0)) buf.Write(encodeLength(len(v))) buf.WriteString(v) buf.WriteByte(byte(0)) } return buf.Bytes(), nil } func (vs *Vars) UnmarshalBinary(data []byte) error { buf := bytes.NewBuffer(data) l := buf.Len() i := 0 //Read in the buffer var key bytes.Buffer for { key.Reset() if i == l { break // We've reached the end } for { n := buf.Next(1) i++ if n[0] != 0 { key.Write(n) } else { break } } length := buf.Next(4) i += 4 l := decodeLength(length) value := buf.Next(l) (*vs)[key.String()] = string(value) i += l end := buf.Next(1) if int(end[0]) != 0 { return errors.New(fmt.Sprintf("Expected null got %+v", end)) } i++ } return nil } func encodeLength(sl int) []byte { /* Using a slice instead of [4]byte the wasted 2 bytes are better than the more difficult to read read/write calls, and the extra copy operations that would be needed anyway, which waste 6 bytes at a time */ l := make([]byte, 4) l[0] = byte((sl / 0x1) % 0x100) l[1] = byte((sl / 0x100) % 0x100) l[2] = byte((sl / 0x10000) % 0x100) l[3] = byte((sl / 0x1000000) % 0x100) return l } func decodeLength(l []byte) int { length := int(l[0])*0x1 + int(l[1])*0x100 + int(l[2])*0x10000 + int(l[3])*0x1000000 return length }