diff options
author | ian <ian@138bc75d-0d04-0410-961f-82ee72b054a4> | 2012-03-02 20:01:37 +0000 |
---|---|---|
committer | ian <ian@138bc75d-0d04-0410-961f-82ee72b054a4> | 2012-03-02 20:01:37 +0000 |
commit | ef10b1dda693467283a3645a5da610e810149764 (patch) | |
tree | 3eeb8918d39d675108073c8b76d6dd10586a608c /libgo/go/encoding | |
parent | ea6ad4ae9afbd45b5c19aadab39ddbf1db0d50f8 (diff) | |
download | gcc-ef10b1dda693467283a3645a5da610e810149764.tar.gz |
libgo: Update to weekly.2012-02-22 release.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@184819 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'libgo/go/encoding')
-rw-r--r-- | libgo/go/encoding/gob/decode.go | 14 | ||||
-rw-r--r-- | libgo/go/encoding/gob/encoder_test.go | 51 | ||||
-rw-r--r-- | libgo/go/encoding/gob/type.go | 16 | ||||
-rw-r--r-- | libgo/go/encoding/json/decode.go | 14 | ||||
-rw-r--r-- | libgo/go/encoding/json/decode_test.go | 29 | ||||
-rw-r--r-- | libgo/go/encoding/json/encode.go | 5 | ||||
-rw-r--r-- | libgo/go/encoding/xml/marshal.go | 89 | ||||
-rw-r--r-- | libgo/go/encoding/xml/read.go | 55 |
8 files changed, 184 insertions, 89 deletions
diff --git a/libgo/go/encoding/gob/decode.go b/libgo/go/encoding/gob/decode.go index 750d623cde2..a0bb985300f 100644 --- a/libgo/go/encoding/gob/decode.go +++ b/libgo/go/encoding/gob/decode.go @@ -464,7 +464,7 @@ func allocate(rtyp reflect.Type, p uintptr, indir int) uintptr { // decodeSingle decodes a top-level value that is not a struct and stores it through p. // Such values are preceded by a zero, making them have the memory layout of a // struct field (although with an illegal field number). -func (dec *Decoder) decodeSingle(engine *decEngine, ut *userTypeInfo, basep uintptr) (err error) { +func (dec *Decoder) decodeSingle(engine *decEngine, ut *userTypeInfo, basep uintptr) { state := dec.newDecoderState(&dec.buf) state.fieldnum = singletonField delta := int(state.decodeUint()) @@ -473,7 +473,7 @@ func (dec *Decoder) decodeSingle(engine *decEngine, ut *userTypeInfo, basep uint } instr := &engine.instr[singletonField] if instr.indir != ut.indir { - return errors.New("gob: internal error: inconsistent indirection") + errorf("internal error: inconsistent indirection instr %d ut %d", instr.indir, ut.indir) } ptr := unsafe.Pointer(basep) // offset will be zero if instr.indir > 1 { @@ -481,10 +481,9 @@ func (dec *Decoder) decodeSingle(engine *decEngine, ut *userTypeInfo, basep uint } instr.op(instr, state, ptr) dec.freeDecoderState(state) - return nil } -// decodeSingle decodes a top-level struct and stores it through p. +// decodeStruct decodes a top-level struct and stores it through p. // Indir is for the value, not the type. At the time of the call it may // differ from ut.indir, which was computed when the engine was built. // This state cannot arise for decodeSingle, which is called directly @@ -839,11 +838,10 @@ func (dec *Decoder) decOpFor(wireId typeId, rt reflect.Type, name string, inProg } case reflect.Map: - name = "element of " + name keyId := dec.wireType[wireId].MapT.Key elemId := dec.wireType[wireId].MapT.Elem - keyOp, keyIndir := dec.decOpFor(keyId, t.Key(), name, inProgress) - elemOp, elemIndir := dec.decOpFor(elemId, t.Elem(), name, inProgress) + keyOp, keyIndir := dec.decOpFor(keyId, t.Key(), "key of "+name, inProgress) + elemOp, elemIndir := dec.decOpFor(elemId, t.Elem(), "element of "+name, inProgress) ovfl := overflow(name) op = func(i *decInstr, state *decoderState, p unsafe.Pointer) { up := unsafe.Pointer(p) @@ -1151,7 +1149,7 @@ func (dec *Decoder) compileDec(remoteId typeId, ut *userTypeInfo) (engine *decEn // getDecEnginePtr returns the engine for the specified type. func (dec *Decoder) getDecEnginePtr(remoteId typeId, ut *userTypeInfo) (enginePtr **decEngine, err error) { - rt := ut.base + rt := ut.user decoderMap, ok := dec.decoderCache[rt] if !ok { decoderMap = make(map[typeId]**decEngine) diff --git a/libgo/go/encoding/gob/encoder_test.go b/libgo/go/encoding/gob/encoder_test.go index 9a62cf9c2ad..3bfae30f39a 100644 --- a/libgo/go/encoding/gob/encoder_test.go +++ b/libgo/go/encoding/gob/encoder_test.go @@ -685,3 +685,54 @@ func TestSliceIncompatibility(t *testing.T) { t.Error("expected compatibility error") } } + +// Mutually recursive slices of structs caused problems. +type Bug3 struct { + Num int + Children []*Bug3 +} + +func TestGobPtrSlices(t *testing.T) { + in := []*Bug3{ + &Bug3{1, nil}, + &Bug3{2, nil}, + } + b := new(bytes.Buffer) + err := NewEncoder(b).Encode(&in) + if err != nil { + t.Fatal("encode:", err) + } + + var out []*Bug3 + err = NewDecoder(b).Decode(&out) + if err != nil { + t.Fatal("decode:", err) + } + if !reflect.DeepEqual(in, out) { + t.Fatal("got %v; wanted %v", out, in) + } +} + +// getDecEnginePtr cached engine for ut.base instead of ut.user so we passed +// a *map and then tried to reuse its engine to decode the inner map. +func TestPtrToMapOfMap(t *testing.T) { + Register(make(map[string]interface{})) + subdata := make(map[string]interface{}) + subdata["bar"] = "baz" + data := make(map[string]interface{}) + data["foo"] = subdata + + b := new(bytes.Buffer) + err := NewEncoder(b).Encode(data) + if err != nil { + t.Fatal("encode:", err) + } + var newData map[string]interface{} + err = NewDecoder(b).Decode(&newData) + if err != nil { + t.Fatal("decode:", err) + } + if !reflect.DeepEqual(data, newData) { + t.Fatalf("expected %v got %v", data, newData) + } +} diff --git a/libgo/go/encoding/gob/type.go b/libgo/go/encoding/gob/type.go index 39006efdb2d..0dd7a0a770e 100644 --- a/libgo/go/encoding/gob/type.go +++ b/libgo/go/encoding/gob/type.go @@ -152,6 +152,10 @@ var idToType = make(map[typeId]gobType) var builtinIdToType map[typeId]gobType // set in init() after builtins are established func setTypeId(typ gobType) { + // When building recursive types, someone may get there before us. + if typ.id() != 0 { + return + } nextId++ typ.setId(nextId) idToType[nextId] = typ @@ -346,6 +350,11 @@ func newSliceType(name string) *sliceType { func (s *sliceType) init(elem gobType) { // Set our type id before evaluating the element's, in case it's our own. setTypeId(s) + // See the comments about ids in newTypeObject. Only slices and + // structs have mutual recursion. + if elem.id() == 0 { + setTypeId(elem) + } s.Elem = elem.id() } @@ -503,6 +512,13 @@ func newTypeObject(name string, ut *userTypeInfo, rt reflect.Type) (gobType, err if err != nil { return nil, err } + // Some mutually recursive types can cause us to be here while + // still defining the element. Fix the element type id here. + // We could do this more neatly by setting the id at the start of + // building every type, but that would break binary compatibility. + if gt.id() == 0 { + setTypeId(gt) + } st.Field = append(st.Field, &fieldType{f.Name, gt.id()}) } return st, nil diff --git a/libgo/go/encoding/json/decode.go b/libgo/go/encoding/json/decode.go index 87076b53dc0..110c6fd6238 100644 --- a/libgo/go/encoding/json/decode.go +++ b/libgo/go/encoding/json/decode.go @@ -496,6 +496,12 @@ func (d *decodeState) object(v reflect.Value) { // Pretend this field doesn't exist. continue } + if sf.Anonymous { + // Pretend this field doesn't exist, + // so that we can do a good job with + // these in a later version. + continue + } // First, tag match tagName, _ := parseTag(tag) if tagName == key { @@ -963,3 +969,11 @@ func unquoteBytes(s []byte) (t []byte, ok bool) { } return b[0:w], true } + +// The following is issue 3069. + +// BUG(rsc): This package ignores anonymous (embedded) struct fields +// during encoding and decoding. A future version may assign meaning +// to them. To force an anonymous field to be ignored in all future +// versions of this package, use an explicit `json:"-"` tag in the struct +// definition. diff --git a/libgo/go/encoding/json/decode_test.go b/libgo/go/encoding/json/decode_test.go index 775becfa7c9..0eec586a9bb 100644 --- a/libgo/go/encoding/json/decode_test.go +++ b/libgo/go/encoding/json/decode_test.go @@ -619,3 +619,32 @@ func TestRefUnmarshal(t *testing.T) { t.Errorf("got %+v, want %+v", got, want) } } + +// Test that anonymous fields are ignored. +// We may assign meaning to them later. +func TestAnonymous(t *testing.T) { + type S struct { + T + N int + } + + data, err := Marshal(new(S)) + if err != nil { + t.Fatalf("Marshal: %v", err) + } + want := `{"N":0}` + if string(data) != want { + t.Fatalf("Marshal = %#q, want %#q", string(data), want) + } + + var s S + if err := Unmarshal([]byte(`{"T": 1, "T": {"Y": 1}, "N": 2}`), &s); err != nil { + t.Fatalf("Unmarshal: %v", err) + } + if s.N != 2 { + t.Fatal("Unmarshal: did not set N") + } + if s.T.Y != 0 { + t.Fatal("Unmarshal: did set T.Y") + } +} diff --git a/libgo/go/encoding/json/encode.go b/libgo/go/encoding/json/encode.go index 83e73c09cb4..8a794b79bd5 100644 --- a/libgo/go/encoding/json/encode.go +++ b/libgo/go/encoding/json/encode.go @@ -538,6 +538,11 @@ func encodeFields(t reflect.Type) []encodeField { if f.PkgPath != "" { continue } + if f.Anonymous { + // We want to do a better job with these later, + // so for now pretend they don't exist. + continue + } var ef encodeField ef.i = i ef.tag = f.Name diff --git a/libgo/go/encoding/xml/marshal.go b/libgo/go/encoding/xml/marshal.go index a96c523d553..6c3170bdda3 100644 --- a/libgo/go/encoding/xml/marshal.go +++ b/libgo/go/encoding/xml/marshal.go @@ -57,35 +57,14 @@ const ( // if the field value is empty. The empty values are false, 0, any // nil pointer or interface value, and any array, slice, map, or // string of length zero. +// - a non-pointer anonymous struct field is handled as if the +// fields of its value were part of the outer struct. // // If a field uses a tag "a>b>c", then the element c will be nested inside // parent elements a and b. Fields that appear next to each other that name -// the same parent will be enclosed in one XML element. For example: +// the same parent will be enclosed in one XML element. // -// type Result struct { -// XMLName xml.Name `xml:"result"` -// Id int `xml:"id,attr"` -// FirstName string `xml:"person>name>first"` -// LastName string `xml:"person>name>last"` -// Age int `xml:"person>age"` -// Height float `xml:"person>height,omitempty"` -// Married bool `xml:"person>married"` -// } -// -// xml.Marshal(&Result{Id: 13, FirstName: "John", LastName: "Doe", Age: 42}) -// -// would be marshalled as: -// -// <result> -// <person id="13"> -// <name> -// <first>John</first> -// <last>Doe</last> -// </name> -// <age>42</age> -// <married>false</married> -// </person> -// </result> +// See MarshalIndent for an example. // // Marshal will return an error if asked to marshal a channel, function, or map. func Marshal(v interface{}) ([]byte, error) { @@ -96,6 +75,22 @@ func Marshal(v interface{}) ([]byte, error) { return b.Bytes(), nil } +// MarshalIndent works like Marshal, but each XML element begins on a new +// indented line that starts with prefix and is followed by one or more +// copies of indent according to the nesting depth. +func MarshalIndent(v interface{}, prefix, indent string) ([]byte, error) { + var b bytes.Buffer + enc := NewEncoder(&b) + enc.prefix = prefix + enc.indent = indent + err := enc.marshalValue(reflect.ValueOf(v), nil) + enc.Flush() + if err != nil { + return nil, err + } + return b.Bytes(), nil +} + // An Encoder writes XML data to an output stream. type Encoder struct { printer @@ -103,7 +98,7 @@ type Encoder struct { // NewEncoder returns a new encoder that writes to w. func NewEncoder(w io.Writer) *Encoder { - return &Encoder{printer{bufio.NewWriter(w)}} + return &Encoder{printer{Writer: bufio.NewWriter(w)}} } // Encode writes the XML encoding of v to the stream. @@ -118,8 +113,14 @@ func (enc *Encoder) Encode(v interface{}) error { type printer struct { *bufio.Writer + indent string + prefix string + depth int + indentedIn bool } +// marshalValue writes one or more XML elements representing val. +// If val was obtained from a struct field, finfo must have its details. func (p *printer) marshalValue(val reflect.Value, finfo *fieldInfo) error { if !val.IsValid() { return nil @@ -177,6 +178,7 @@ func (p *printer) marshalValue(val reflect.Value, finfo *fieldInfo) error { } } + p.writeIndent(1) p.WriteByte('<') p.WriteString(name) @@ -216,6 +218,7 @@ func (p *printer) marshalValue(val reflect.Value, finfo *fieldInfo) error { return err } + p.writeIndent(-1) p.WriteByte('<') p.WriteByte('/') p.WriteString(name) @@ -294,6 +297,7 @@ func (p *printer) marshalStruct(tinfo *typeInfo, val reflect.Value) error { if vf.Len() == 0 { continue } + p.writeIndent(0) p.WriteString("<!--") dashDash := false dashLast := false @@ -352,6 +356,33 @@ func (p *printer) marshalStruct(tinfo *typeInfo, val reflect.Value) error { return nil } +func (p *printer) writeIndent(depthDelta int) { + if len(p.prefix) == 0 && len(p.indent) == 0 { + return + } + if depthDelta < 0 { + p.depth-- + if p.indentedIn { + p.indentedIn = false + return + } + p.indentedIn = false + } + p.WriteByte('\n') + if len(p.prefix) > 0 { + p.WriteString(p.prefix) + } + if len(p.indent) > 0 { + for i := 0; i < p.depth; i++ { + p.WriteString(p.indent) + } + } + if depthDelta > 0 { + p.depth++ + p.indentedIn = true + } +} + type parentStack struct { *printer stack []string @@ -367,20 +398,20 @@ func (s *parentStack) trim(parents []string) { break } } - for i := len(s.stack) - 1; i >= split; i-- { + s.writeIndent(-1) s.WriteString("</") s.WriteString(s.stack[i]) s.WriteByte('>') } - s.stack = parents[:split] } // push adds parent elements to the stack and writes open tags. func (s *parentStack) push(parents []string) { for i := 0; i < len(parents); i++ { - s.WriteString("<") + s.writeIndent(1) + s.WriteByte('<') s.WriteString(parents[i]) s.WriteByte('>') } diff --git a/libgo/go/encoding/xml/read.go b/libgo/go/encoding/xml/read.go index b5a3426a328..c2168242091 100644 --- a/libgo/go/encoding/xml/read.go +++ b/libgo/go/encoding/xml/read.go @@ -25,58 +25,6 @@ import ( // slice, or string. Well-formed data that does not fit into v is // discarded. // -// For example, given these definitions: -// -// type Email struct { -// Where string `xml:",attr"` -// Addr string -// } -// -// type Result struct { -// XMLName xml.Name `xml:"result"` -// Name string -// Phone string -// Email []Email -// Groups []string `xml:"group>value"` -// } -// -// result := Result{Name: "name", Phone: "phone", Email: nil} -// -// unmarshalling the XML input -// -// <result> -// <email where="home"> -// <addr>gre@example.com</addr> -// </email> -// <email where='work'> -// <addr>gre@work.com</addr> -// </email> -// <name>Grace R. Emlin</name> -// <group> -// <value>Friends</value> -// <value>Squash</value> -// </group> -// <address>123 Main Street</address> -// </result> -// -// via Unmarshal(data, &result) is equivalent to assigning -// -// r = Result{ -// xml.Name{Local: "result"}, -// "Grace R. Emlin", // name -// "phone", // no phone given -// []Email{ -// Email{"home", "gre@example.com"}, -// Email{"work", "gre@work.com"}, -// }, -// []string{"Friends", "Squash"}, -// } -// -// Note that the field r.Phone has not been modified and -// that the XML <address> element was discarded. Also, the field -// Groups was assigned considering the element path provided in the -// field tag. -// // Because Unmarshal uses the reflect package, it can only assign // to exported (upper case) fields. Unmarshal uses a case-sensitive // comparison to match XML element names to tag values and struct @@ -133,6 +81,9 @@ import ( // of the above rules and the struct has a field with tag ",any", // unmarshal maps the sub-element to that struct field. // +// * A non-pointer anonymous struct field is handled as if the +// fields of its value were part of the outer struct. +// // * A struct field with tag "-" is never unmarshalled into. // // Unmarshal maps an XML element to a string or []byte by saving the |