summaryrefslogtreecommitdiff
path: root/libgo/go/encoding
diff options
context:
space:
mode:
authorian <ian@138bc75d-0d04-0410-961f-82ee72b054a4>2012-03-02 20:01:37 +0000
committerian <ian@138bc75d-0d04-0410-961f-82ee72b054a4>2012-03-02 20:01:37 +0000
commitef10b1dda693467283a3645a5da610e810149764 (patch)
tree3eeb8918d39d675108073c8b76d6dd10586a608c /libgo/go/encoding
parentea6ad4ae9afbd45b5c19aadab39ddbf1db0d50f8 (diff)
downloadgcc-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.go14
-rw-r--r--libgo/go/encoding/gob/encoder_test.go51
-rw-r--r--libgo/go/encoding/gob/type.go16
-rw-r--r--libgo/go/encoding/json/decode.go14
-rw-r--r--libgo/go/encoding/json/decode_test.go29
-rw-r--r--libgo/go/encoding/json/encode.go5
-rw-r--r--libgo/go/encoding/xml/marshal.go89
-rw-r--r--libgo/go/encoding/xml/read.go55
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