package gob
import (
"bytes"
"io"
"os"
"reflect"
"sync"
)
type Encoder struct {
mutex sync.Mutex
w io.Writer
sent map[reflect.Type]typeId
state *encoderState
countState *encoderState
buf []byte
}
func NewEncoder(w io.Writer) *Encoder {
enc := new(Encoder)
enc.w = w
enc.sent = make(map[reflect.Type]typeId)
enc.state = new(encoderState)
enc.state.b = new(bytes.Buffer)
enc.countState = new(encoderState)
enc.countState.b = new(bytes.Buffer)
return enc
}
func (enc *Encoder) badType(rt reflect.Type) {
enc.setError(os.ErrorString("gob: can't encode type " + rt.String()))
}
func (enc *Encoder) setError(err os.Error) {
if enc.state.err == nil {
enc.state.err = err
}
enc.state.b.Reset()
}
func (enc *Encoder) send() {
encodeUint(enc.countState, uint64(enc.state.b.Len()))
countLen := enc.countState.b.Len()
total := countLen + enc.state.b.Len()
if total > len(enc.buf) {
enc.buf = make([]byte, total+1000)
}
enc.countState.b.Read(enc.buf[0:countLen])
enc.state.b.Read(enc.buf[countLen:total])
_, err := enc.w.Write(enc.buf[0:total])
if err != nil {
enc.setError(err)
}
}
func (enc *Encoder) sendType(origt reflect.Type) (sent bool) {
rt, _ := indirect(origt)
switch rt := rt.(type) {
default:
return
case *reflect.SliceType:
if rt.Elem().Kind() == reflect.Uint8 {
return
}
break
case *reflect.ArrayType:
break
case *reflect.MapType:
break
case *reflect.StructType:
break
case *reflect.ChanType, *reflect.FuncType, *reflect.InterfaceType:
enc.badType(rt)
return
}
if _, alreadySent := enc.sent[rt]; alreadySent {
return
}
typeLock.Lock()
info, err := getTypeInfo(rt)
typeLock.Unlock()
if err != nil {
enc.setError(err)
return
}
encodeInt(enc.state, -int64(info.id))
encode(enc.state.b, reflect.NewValue(info.wire))
enc.send()
if enc.state.err != nil {
return
}
enc.sent[rt] = info.id
enc.sent[origt] = info.id
switch st := rt.(type) {
case *reflect.StructType:
for i := 0; i < st.NumField(); i++ {
enc.sendType(st.Field(i).Type)
}
case reflect.ArrayOrSliceType:
enc.sendType(st.Elem())
}
return
}
func (enc *Encoder) Encode(e interface{}) os.Error {
return enc.EncodeValue(reflect.NewValue(e))
}
func (enc *Encoder) EncodeValue(value reflect.Value) os.Error {
enc.mutex.Lock()
defer enc.mutex.Unlock()
enc.state.err = nil
rt, _ := indirect(value.Type())
if enc.state.b.Len() > 0 || enc.countState.b.Len() > 0 {
enc.state.err = os.ErrorString("encoder: buffer not empty")
return enc.state.err
}
if _, alreadySent := enc.sent[rt]; !alreadySent {
sent := enc.sendType(rt)
if enc.state.err != nil {
return enc.state.err
}
if !sent {
typeLock.Lock()
info, err := getTypeInfo(rt)
typeLock.Unlock()
if err != nil {
enc.setError(err)
return err
}
enc.sent[rt] = info.id
}
}
encodeInt(enc.state, int64(enc.sent[rt]))
err := encode(enc.state.b, value)
if err != nil {
enc.setError(err)
} else {
enc.send()
}
return enc.state.err
}