package rpc import ( "bytes" "io" "log" "sync" ) type Encoder struct { mutex sync.Mutex w io.Writer buf bytes.Buffer } func NewEncoder(w io.Writer) *Encoder { enc := &Encoder{ w: w, } return enc } func (enc *Encoder) Encode(vs []*Var) error { //So our messages don't get garbled with multiple goroutines using an encoder enc.mutex.Lock() defer enc.mutex.Unlock() enc.buf.Reset() //Reset the buffer for a new message for _, v := range vs { d, err := v.MarshalBinary() if err != nil { return err } enc.buf.Write(d) } l := enc.buf.Len() if l >= 0x1fffffff { log.Panicf("Buffer %s is too long to be sent in a single msg", enc.buf.String()) } enc.w.Write(*enc.header(l)) enc.w.Write(enc.buf.Bytes()) return nil } func (enc *Encoder) header(l int) *[]byte { /* Using a slice instead of [5]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 7 bytes at a time */ h := make([]byte, 5) // Not entirely convinced this will act the same as c++ but heres to hoping h[1] = byte((l / 0x1) % 0x100) h[2] = byte((l / 0x100) % 0x100) h[3] = byte((l / 0x10000) % 0x100) h[4] = byte((l / 0x1000000) % 0x100) h[0] = h[1] ^ h[2] ^ h[3] ^ h[4] return &h }