2009-07-09 15:33:43 -06:00
|
|
|
// Copyright 2009 The Go Authors. All rights reserved.
|
|
|
|
// Use of this source code is governed by a BSD-style
|
|
|
|
// license that can be found in the LICENSE file.
|
|
|
|
|
|
|
|
package gob
|
|
|
|
|
|
|
|
import (
|
2009-07-15 17:10:17 -06:00
|
|
|
"bytes";
|
2009-07-09 15:33:43 -06:00
|
|
|
"gob";
|
|
|
|
"io";
|
|
|
|
"os";
|
|
|
|
"reflect";
|
|
|
|
"sync";
|
|
|
|
)
|
|
|
|
|
|
|
|
type Encoder struct {
|
|
|
|
sync.Mutex; // each item must be sent atomically
|
2009-07-15 17:10:17 -06:00
|
|
|
w io.Writer; // where to send the data
|
2009-07-10 14:44:37 -06:00
|
|
|
sent map[reflect.Type] TypeId; // which types we've already sent
|
2009-07-15 17:10:17 -06:00
|
|
|
state *encoderState; // so we can encode integers, strings directly
|
|
|
|
countState *encoderState; // stage for writing counts
|
|
|
|
buf []byte; // for collecting the output.
|
2009-07-09 15:33:43 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
func NewEncoder(w io.Writer) *Encoder {
|
|
|
|
enc := new(Encoder);
|
2009-07-15 17:10:17 -06:00
|
|
|
enc.w = w;
|
2009-07-10 14:44:37 -06:00
|
|
|
enc.sent = make(map[reflect.Type] TypeId);
|
2009-07-15 17:10:17 -06:00
|
|
|
enc.state = new(encoderState);
|
|
|
|
enc.state.b = new(bytes.Buffer); // the rest isn't important; all we need is buffer and writer
|
|
|
|
enc.countState = new(encoderState);
|
|
|
|
enc.countState.b = new(bytes.Buffer); // the rest isn't important; all we need is buffer and writer
|
2009-07-09 15:33:43 -06:00
|
|
|
return enc;
|
|
|
|
}
|
|
|
|
|
|
|
|
func (enc *Encoder) badType(rt reflect.Type) {
|
2009-07-15 17:10:17 -06:00
|
|
|
enc.state.err = os.ErrorString("gob: can't encode type " + rt.String());
|
|
|
|
}
|
|
|
|
|
|
|
|
// Send the data item preceded by a unsigned count of its length.
|
|
|
|
func (enc *Encoder) send() {
|
|
|
|
// Encode the length.
|
|
|
|
encodeUint(enc.countState, uint64(enc.state.b.Len()));
|
|
|
|
// Build the buffer.
|
|
|
|
countLen := enc.countState.b.Len();
|
|
|
|
total := countLen + enc.state.b.Len();
|
|
|
|
if total > len(enc.buf) {
|
|
|
|
enc.buf = make([]byte, total+1000); // extra for growth
|
|
|
|
}
|
|
|
|
// Place the length before the data.
|
|
|
|
// TODO(r): avoid the extra copy here.
|
|
|
|
enc.countState.b.Read(enc.buf[0:countLen]);
|
|
|
|
// Now the data.
|
|
|
|
enc.state.b.Read(enc.buf[countLen:total]);
|
|
|
|
// Write the data.
|
|
|
|
enc.w.Write(enc.buf[0:total]);
|
2009-07-09 15:33:43 -06:00
|
|
|
}
|
|
|
|
|
2009-07-10 14:44:37 -06:00
|
|
|
func (enc *Encoder) sendType(origt reflect.Type) {
|
2009-07-09 15:33:43 -06:00
|
|
|
// Drill down to the base type.
|
2009-07-10 14:44:37 -06:00
|
|
|
rt, indir_ := indirect(origt);
|
2009-07-09 15:33:43 -06:00
|
|
|
|
|
|
|
// We only send structs - everything else is basic or an error
|
|
|
|
switch t := rt.(type) {
|
|
|
|
case *reflect.StructType:
|
|
|
|
break; // we handle these
|
|
|
|
case *reflect.ChanType:
|
|
|
|
enc.badType(rt);
|
|
|
|
return;
|
|
|
|
case *reflect.MapType:
|
|
|
|
enc.badType(rt);
|
|
|
|
return;
|
|
|
|
case *reflect.FuncType:
|
|
|
|
enc.badType(rt);
|
|
|
|
return;
|
|
|
|
case *reflect.InterfaceType:
|
|
|
|
enc.badType(rt);
|
|
|
|
return;
|
|
|
|
default:
|
|
|
|
return; // basic, array, etc; not a type to be sent.
|
|
|
|
}
|
|
|
|
|
2009-07-10 14:44:37 -06:00
|
|
|
// Have we already sent this type? This time we ask about the base type.
|
|
|
|
if id_, alreadySent := enc.sent[rt]; alreadySent {
|
2009-07-09 15:33:43 -06:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// Need to send it.
|
2009-07-16 18:55:16 -06:00
|
|
|
typeLock.Lock();
|
2009-07-09 15:33:43 -06:00
|
|
|
info := getTypeInfo(rt);
|
2009-07-16 18:55:16 -06:00
|
|
|
typeLock.Unlock();
|
2009-07-09 15:33:43 -06:00
|
|
|
// Send the pair (-id, type)
|
|
|
|
// Id:
|
2009-07-15 17:10:17 -06:00
|
|
|
encodeInt(enc.state, -int64(info.typeId));
|
2009-07-09 15:33:43 -06:00
|
|
|
// Type:
|
2009-07-15 17:10:17 -06:00
|
|
|
encode(enc.state.b, info.wire);
|
|
|
|
enc.send();
|
|
|
|
|
2009-07-09 15:33:43 -06:00
|
|
|
// Remember we've sent this type.
|
2009-07-10 14:44:37 -06:00
|
|
|
enc.sent[rt] = info.typeId;
|
|
|
|
// Remember we've sent the top-level, possibly indirect type too.
|
|
|
|
enc.sent[origt] = info.typeId;
|
2009-07-09 15:33:43 -06:00
|
|
|
// Now send the inner types
|
|
|
|
st := rt.(*reflect.StructType);
|
|
|
|
for i := 0; i < st.NumField(); i++ {
|
|
|
|
enc.sendType(st.Field(i).Type);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (enc *Encoder) Encode(e interface{}) os.Error {
|
2009-07-15 17:10:17 -06:00
|
|
|
if enc.state.b.Len() > 0 || enc.countState.b.Len() > 0 {
|
|
|
|
panicln("Encoder: buffer not empty")
|
|
|
|
}
|
2009-07-09 15:33:43 -06:00
|
|
|
rt, indir := indirect(reflect.Typeof(e));
|
|
|
|
|
|
|
|
// Make sure we're single-threaded through here.
|
|
|
|
enc.Lock();
|
|
|
|
defer enc.Unlock();
|
|
|
|
|
|
|
|
// Make sure the type is known to the other side.
|
2009-07-10 14:44:37 -06:00
|
|
|
// First, have we already sent this type?
|
|
|
|
if id_, alreadySent := enc.sent[rt]; !alreadySent {
|
|
|
|
// No, so send it.
|
|
|
|
enc.sendType(rt);
|
|
|
|
if enc.state.err != nil {
|
2009-07-15 17:10:17 -06:00
|
|
|
enc.state.b.Reset();
|
|
|
|
enc.countState.b.Reset();
|
2009-07-10 14:44:37 -06:00
|
|
|
return enc.state.err
|
|
|
|
}
|
2009-07-09 15:33:43 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
// Identify the type of this top-level value.
|
2009-07-15 17:10:17 -06:00
|
|
|
encodeInt(enc.state, int64(enc.sent[rt]));
|
2009-07-09 15:33:43 -06:00
|
|
|
|
2009-07-15 17:10:17 -06:00
|
|
|
// Encode the object.
|
|
|
|
encode(enc.state.b, e);
|
|
|
|
enc.send();
|
2009-07-09 15:33:43 -06:00
|
|
|
|
|
|
|
return enc.state.err
|
|
|
|
}
|