Commit 77baac11 authored by Rob Pike's avatar Rob Pike

encode and decode for nested structures.

fix a bug in delta encoding: only update the delta-base if something is marshaled.

R=rsc
DELTA=154  (94 added, 56 deleted, 4 changed)
OCL=31069
CL=31071
parent 1ca1e1be
...@@ -569,10 +569,14 @@ func TestScalarDecInstructions(t *testing.T) { ...@@ -569,10 +569,14 @@ func TestScalarDecInstructions(t *testing.T) {
func TestEncode(t *testing.T) { func TestEncode(t *testing.T) {
type T2 struct {
t string
}
type T1 struct { type T1 struct {
a, b,c int; a, b,c int;
s string; s string;
y []byte; y []byte;
t *T2;
} }
t1 := &T1{ t1 := &T1{
a: 17, a: 17,
...@@ -580,6 +584,7 @@ func TestEncode(t *testing.T) { ...@@ -580,6 +584,7 @@ func TestEncode(t *testing.T) {
c: -5, c: -5,
s: "Now is the time", s: "Now is the time",
y: strings.Bytes("hello, sailor"), y: strings.Bytes("hello, sailor"),
t: &T2{"this is T2"},
}; };
b := new(bytes.Buffer); b := new(bytes.Buffer);
Encode(b, t1); Encode(b, t1);
......
...@@ -279,6 +279,31 @@ type decEngine struct { ...@@ -279,6 +279,31 @@ type decEngine struct {
instr []decInstr instr []decInstr
} }
func (engine *decEngine) decodeStruct(r io.Reader, p uintptr) os.Error {
state := new(DecState);
state.r = r;
state.base = p;
state.fieldnum = -1;
for state.err == nil {
delta := int(DecodeUint(state));
if state.err != nil || delta == 0 { // struct terminator is zero delta fieldnum
break
}
fieldnum := state.fieldnum + delta;
if fieldnum >= len(engine.instr) {
panicln("TODO(r): need to handle unknown data");
}
instr := &engine.instr[fieldnum];
p := unsafe.Pointer(state.base+instr.offset);
if instr.indir > 1 {
p = decIndirect(p, instr.indir);
}
instr.op(instr, state, p);
state.fieldnum = fieldnum;
}
return state.err
}
var decEngineMap = make(map[reflect.Type] *decEngine) var decEngineMap = make(map[reflect.Type] *decEngine)
var decOpMap = map[int] decOp { var decOpMap = map[int] decOp {
reflect.BoolKind: decBool, reflect.BoolKind: decBool,
...@@ -298,6 +323,8 @@ var decOpMap = map[int] decOp { ...@@ -298,6 +323,8 @@ var decOpMap = map[int] decOp {
reflect.StringKind: decString, reflect.StringKind: decString,
} }
func getDecEngine(rt reflect.Type) *decEngine
func decOpFor(typ reflect.Type) decOp { func decOpFor(typ reflect.Type) decOp {
op, ok := decOpMap[typ.Kind()]; op, ok := decOpMap[typ.Kind()];
if !ok { if !ok {
...@@ -309,6 +336,13 @@ func decOpFor(typ reflect.Type) decOp { ...@@ -309,6 +336,13 @@ func decOpFor(typ reflect.Type) decOp {
op = decUint8Array op = decUint8Array
} }
} }
if typ.Kind() == reflect.StructKind {
// Generate a closure that calls out to the engine for the nested type.
engine := getDecEngine(typ);
op = func(i *decInstr, state *DecState, p unsafe.Pointer) {
state.err = engine.decodeStruct(state.r, uintptr(p))
};
}
} }
if op == nil { if op == nil {
panicln("decode can't handle type", typ.String()); panicln("decode can't handle type", typ.String());
...@@ -355,35 +389,6 @@ func getDecEngine(rt reflect.Type) *decEngine { ...@@ -355,35 +389,6 @@ func getDecEngine(rt reflect.Type) *decEngine {
return engine; return engine;
} }
func (engine *decEngine) decode(r io.Reader, v reflect.Value) os.Error {
sv, ok := v.(reflect.StructValue);
if !ok {
panicln("decoder can't handle non-struct values yet");
}
state := new(DecState);
state.r = r;
state.base = uintptr(sv.Addr());
state.fieldnum = -1;
for state.err == nil {
delta := int(DecodeUint(state));
if state.err != nil || delta == 0 { // struct terminator is zero delta fieldnum
break
}
fieldnum := state.fieldnum + delta;
if fieldnum >= len(engine.instr) {
panicln("TODO(r): need to handle unknown data");
}
instr := &engine.instr[fieldnum];
p := unsafe.Pointer(state.base+instr.offset);
if instr.indir > 1 {
p = decIndirect(p, instr.indir);
}
instr.op(instr, state, p);
state.fieldnum = fieldnum;
}
return state.err
}
func Decode(r io.Reader, e interface{}) os.Error { func Decode(r io.Reader, e interface{}) os.Error {
// Dereference down to the underlying object. // Dereference down to the underlying object.
rt := reflect.Typeof(e); rt := reflect.Typeof(e);
...@@ -396,8 +401,11 @@ func Decode(r io.Reader, e interface{}) os.Error { ...@@ -396,8 +401,11 @@ func Decode(r io.Reader, e interface{}) os.Error {
rt = pt.Sub(); rt = pt.Sub();
v = reflect.Indirect(v); v = reflect.Indirect(v);
} }
if v.Kind() != reflect.StructKind {
return os.ErrorString("decode can't handle " + v.Type().String())
}
typeLock.Lock(); typeLock.Lock();
engine := getDecEngine(rt); engine := getDecEngine(rt);
typeLock.Unlock(); typeLock.Unlock();
return engine.decode(r, v); return engine.decodeStruct(r, uintptr(v.Addr()));
} }
...@@ -92,6 +92,7 @@ func encBool(i *encInstr, state *EncState, p unsafe.Pointer) { ...@@ -92,6 +92,7 @@ func encBool(i *encInstr, state *EncState, p unsafe.Pointer) {
if b { if b {
EncodeUint(state, uint64(i.field - state.fieldnum)); EncodeUint(state, uint64(i.field - state.fieldnum));
EncodeUint(state, 1); EncodeUint(state, 1);
state.fieldnum = i.field;
} }
} }
...@@ -100,6 +101,7 @@ func encInt(i *encInstr, state *EncState, p unsafe.Pointer) { ...@@ -100,6 +101,7 @@ func encInt(i *encInstr, state *EncState, p unsafe.Pointer) {
if v != 0 { if v != 0 {
EncodeUint(state, uint64(i.field - state.fieldnum)); EncodeUint(state, uint64(i.field - state.fieldnum));
EncodeInt(state, v); EncodeInt(state, v);
state.fieldnum = i.field;
} }
} }
...@@ -108,6 +110,7 @@ func encUint(i *encInstr, state *EncState, p unsafe.Pointer) { ...@@ -108,6 +110,7 @@ func encUint(i *encInstr, state *EncState, p unsafe.Pointer) {
if v != 0 { if v != 0 {
EncodeUint(state, uint64(i.field - state.fieldnum)); EncodeUint(state, uint64(i.field - state.fieldnum));
EncodeUint(state, v); EncodeUint(state, v);
state.fieldnum = i.field;
} }
} }
...@@ -116,6 +119,7 @@ func encInt8(i *encInstr, state *EncState, p unsafe.Pointer) { ...@@ -116,6 +119,7 @@ func encInt8(i *encInstr, state *EncState, p unsafe.Pointer) {
if v != 0 { if v != 0 {
EncodeUint(state, uint64(i.field - state.fieldnum)); EncodeUint(state, uint64(i.field - state.fieldnum));
EncodeInt(state, v); EncodeInt(state, v);
state.fieldnum = i.field;
} }
} }
...@@ -124,6 +128,7 @@ func encUint8(i *encInstr, state *EncState, p unsafe.Pointer) { ...@@ -124,6 +128,7 @@ func encUint8(i *encInstr, state *EncState, p unsafe.Pointer) {
if v != 0 { if v != 0 {
EncodeUint(state, uint64(i.field - state.fieldnum)); EncodeUint(state, uint64(i.field - state.fieldnum));
EncodeUint(state, v); EncodeUint(state, v);
state.fieldnum = i.field;
} }
} }
...@@ -132,6 +137,7 @@ func encInt16(i *encInstr, state *EncState, p unsafe.Pointer) { ...@@ -132,6 +137,7 @@ func encInt16(i *encInstr, state *EncState, p unsafe.Pointer) {
if v != 0 { if v != 0 {
EncodeUint(state, uint64(i.field - state.fieldnum)); EncodeUint(state, uint64(i.field - state.fieldnum));
EncodeInt(state, v); EncodeInt(state, v);
state.fieldnum = i.field;
} }
} }
...@@ -140,6 +146,7 @@ func encUint16(i *encInstr, state *EncState, p unsafe.Pointer) { ...@@ -140,6 +146,7 @@ func encUint16(i *encInstr, state *EncState, p unsafe.Pointer) {
if v != 0 { if v != 0 {
EncodeUint(state, uint64(i.field - state.fieldnum)); EncodeUint(state, uint64(i.field - state.fieldnum));
EncodeUint(state, v); EncodeUint(state, v);
state.fieldnum = i.field;
} }
} }
...@@ -148,6 +155,7 @@ func encInt32(i *encInstr, state *EncState, p unsafe.Pointer) { ...@@ -148,6 +155,7 @@ func encInt32(i *encInstr, state *EncState, p unsafe.Pointer) {
if v != 0 { if v != 0 {
EncodeUint(state, uint64(i.field - state.fieldnum)); EncodeUint(state, uint64(i.field - state.fieldnum));
EncodeInt(state, v); EncodeInt(state, v);
state.fieldnum = i.field;
} }
} }
...@@ -156,6 +164,7 @@ func encUint32(i *encInstr, state *EncState, p unsafe.Pointer) { ...@@ -156,6 +164,7 @@ func encUint32(i *encInstr, state *EncState, p unsafe.Pointer) {
if v != 0 { if v != 0 {
EncodeUint(state, uint64(i.field - state.fieldnum)); EncodeUint(state, uint64(i.field - state.fieldnum));
EncodeUint(state, v); EncodeUint(state, v);
state.fieldnum = i.field;
} }
} }
...@@ -164,6 +173,7 @@ func encInt64(i *encInstr, state *EncState, p unsafe.Pointer) { ...@@ -164,6 +173,7 @@ func encInt64(i *encInstr, state *EncState, p unsafe.Pointer) {
if v != 0 { if v != 0 {
EncodeUint(state, uint64(i.field - state.fieldnum)); EncodeUint(state, uint64(i.field - state.fieldnum));
EncodeInt(state, v); EncodeInt(state, v);
state.fieldnum = i.field;
} }
} }
...@@ -172,6 +182,7 @@ func encUint64(i *encInstr, state *EncState, p unsafe.Pointer) { ...@@ -172,6 +182,7 @@ func encUint64(i *encInstr, state *EncState, p unsafe.Pointer) {
if v != 0 { if v != 0 {
EncodeUint(state, uint64(i.field - state.fieldnum)); EncodeUint(state, uint64(i.field - state.fieldnum));
EncodeUint(state, v); EncodeUint(state, v);
state.fieldnum = i.field;
} }
} }
...@@ -197,6 +208,7 @@ func encFloat(i *encInstr, state *EncState, p unsafe.Pointer) { ...@@ -197,6 +208,7 @@ func encFloat(i *encInstr, state *EncState, p unsafe.Pointer) {
v := floatBits(float64(f)); v := floatBits(float64(f));
EncodeUint(state, uint64(i.field - state.fieldnum)); EncodeUint(state, uint64(i.field - state.fieldnum));
EncodeUint(state, v); EncodeUint(state, v);
state.fieldnum = i.field;
} }
} }
...@@ -206,6 +218,7 @@ func encFloat32(i *encInstr, state *EncState, p unsafe.Pointer) { ...@@ -206,6 +218,7 @@ func encFloat32(i *encInstr, state *EncState, p unsafe.Pointer) {
v := floatBits(float64(f)); v := floatBits(float64(f));
EncodeUint(state, uint64(i.field - state.fieldnum)); EncodeUint(state, uint64(i.field - state.fieldnum));
EncodeUint(state, v); EncodeUint(state, v);
state.fieldnum = i.field;
} }
} }
...@@ -215,6 +228,7 @@ func encFloat64(i *encInstr, state *EncState, p unsafe.Pointer) { ...@@ -215,6 +228,7 @@ func encFloat64(i *encInstr, state *EncState, p unsafe.Pointer) {
v := floatBits(f); v := floatBits(f);
EncodeUint(state, uint64(i.field - state.fieldnum)); EncodeUint(state, uint64(i.field - state.fieldnum));
EncodeUint(state, v); EncodeUint(state, v);
state.fieldnum = i.field;
} }
} }
...@@ -225,6 +239,7 @@ func encUint8Array(i *encInstr, state *EncState, p unsafe.Pointer) { ...@@ -225,6 +239,7 @@ func encUint8Array(i *encInstr, state *EncState, p unsafe.Pointer) {
EncodeUint(state, uint64(i.field - state.fieldnum)); EncodeUint(state, uint64(i.field - state.fieldnum));
EncodeUint(state, uint64(len(b))); EncodeUint(state, uint64(len(b)));
state.w.Write(b); state.w.Write(b);
state.fieldnum = i.field;
} }
} }
...@@ -235,6 +250,7 @@ func encString(i *encInstr, state *EncState, p unsafe.Pointer) { ...@@ -235,6 +250,7 @@ func encString(i *encInstr, state *EncState, p unsafe.Pointer) {
EncodeUint(state, uint64(i.field - state.fieldnum)); EncodeUint(state, uint64(i.field - state.fieldnum));
EncodeUint(state, uint64(len(s))); EncodeUint(state, uint64(len(s)));
io.WriteString(state.w, s); io.WriteString(state.w, s);
state.fieldnum = i.field;
} }
} }
...@@ -251,6 +267,28 @@ type encEngine struct { ...@@ -251,6 +267,28 @@ type encEngine struct {
instr []encInstr instr []encInstr
} }
func (engine *encEngine) encodeStruct(w io.Writer, p uintptr) os.Error {
state := new(EncState);
state.w = w;
state.base = p;
state.fieldnum = -1;
for i := 0; i < len(engine.instr); i++ {
instr := &engine.instr[i];
p := unsafe.Pointer(state.base+instr.offset);
if instr.indir > 0 {
if p = encIndirect(p, instr.indir); p == nil {
state.fieldnum = i;
continue
}
}
instr.op(instr, state, p);
if state.err != nil {
break
}
}
return state.err
}
var encEngineMap = make(map[reflect.Type] *encEngine) var encEngineMap = make(map[reflect.Type] *encEngine)
var encOpMap = map[int] encOp { var encOpMap = map[int] encOp {
reflect.BoolKind: encBool, reflect.BoolKind: encBool,
...@@ -270,6 +308,8 @@ var encOpMap = map[int] encOp { ...@@ -270,6 +308,8 @@ var encOpMap = map[int] encOp {
reflect.StringKind: encString, reflect.StringKind: encString,
} }
func getEncEngine(rt reflect.Type) *encEngine
func encOpFor(typ reflect.Type) encOp { func encOpFor(typ reflect.Type) encOp {
op, ok := encOpMap[typ.Kind()]; op, ok := encOpMap[typ.Kind()];
if !ok { if !ok {
...@@ -281,6 +321,15 @@ func encOpFor(typ reflect.Type) encOp { ...@@ -281,6 +321,15 @@ func encOpFor(typ reflect.Type) encOp {
op = encUint8Array op = encUint8Array
} }
} }
if typ.Kind() == reflect.StructKind {
// Generate a closure that calls out to the engine for the nested type.
engine := getEncEngine(typ);
op = func(i *encInstr, state *EncState, p unsafe.Pointer) {
EncodeUint(state, uint64(i.field - state.fieldnum));
state.err = engine.encodeStruct(state.w, uintptr(p));
state.fieldnum = i.field;
};
}
} }
if op == nil { if op == nil {
panicln("encode can't handle type", typ.String()); panicln("encode can't handle type", typ.String());
...@@ -327,33 +376,6 @@ func getEncEngine(rt reflect.Type) *encEngine { ...@@ -327,33 +376,6 @@ func getEncEngine(rt reflect.Type) *encEngine {
return engine return engine
} }
func (engine *encEngine) encode(w io.Writer, v reflect.Value) os.Error {
sv, ok := v.(reflect.StructValue);
if !ok {
panicln("encoder can't handle non-struct values yet");
}
state := new(EncState);
state.w = w;
state.base = uintptr(sv.Addr());
state.fieldnum = -1;
for i := 0; i < len(engine.instr); i++ {
instr := &engine.instr[i];
p := unsafe.Pointer(state.base+instr.offset);
if instr.indir > 0 {
if p = encIndirect(p, instr.indir); p == nil {
state.fieldnum = i;
continue
}
}
instr.op(instr, state, p);
if state.err != nil {
break
}
state.fieldnum = i;
}
return state.err
}
func Encode(w io.Writer, e interface{}) os.Error { func Encode(w io.Writer, e interface{}) os.Error {
// Dereference down to the underlying object. // Dereference down to the underlying object.
rt := reflect.Typeof(e); rt := reflect.Typeof(e);
...@@ -366,8 +388,11 @@ func Encode(w io.Writer, e interface{}) os.Error { ...@@ -366,8 +388,11 @@ func Encode(w io.Writer, e interface{}) os.Error {
rt = pt.Sub(); rt = pt.Sub();
v = reflect.Indirect(v); v = reflect.Indirect(v);
} }
if v.Kind() != reflect.StructKind {
return os.ErrorString("decode can't handle " + v.Type().String())
}
typeLock.Lock(); typeLock.Lock();
engine := getEncEngine(rt); engine := getEncEngine(rt);
typeLock.Unlock(); typeLock.Unlock();
return engine.encode(w, v); return engine.encodeStruct(w, uintptr(v.(reflect.StructValue).Addr()));
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment