diff --git a/decode.go b/decode.go index 6abb85f..86cacbb 100644 --- a/decode.go +++ b/decode.go @@ -20,8 +20,7 @@ type decoder interface { } type Decoder struct { - s *stream - structTypeToDecoder map[uintptr]decoder + s *stream } var ( @@ -33,6 +32,51 @@ const ( nul = '\000' ) +func unmarshal(data []byte, v interface{}) error { + src := make([]byte, len(data)+1) // append nul byte to the end + copy(src, data) + + header := (*interfaceHeader)(unsafe.Pointer(&v)) + header.typ.escape() + return decode(src, header) +} + +func unmarshalNoEscape(data []byte, v interface{}) error { + src := make([]byte, len(data)+1) // append nul byte to the end + copy(src, data) + + header := (*interfaceHeader)(unsafe.Pointer(&v)) + return decode(src, header) +} + +func decode(src []byte, header *interfaceHeader) error { + typ := header.typ + typeptr := uintptr(unsafe.Pointer(typ)) + + // noescape trick for header.typ ( *reflect.rtype ) + copiedType := *(**rtype)(unsafe.Pointer(&typeptr)) + ptr := uintptr(header.ptr) + + if err := validateType(copiedType, ptr); err != nil { + return err + } + dec, err := decodeCompileToGetDecoder(typeptr, typ) + if err != nil { + return err + } + if _, err := dec.decode(src, 0, header.ptr); err != nil { + return err + } + return nil +} + +func validateType(typ *rtype, p uintptr) error { + if typ.Kind() != reflect.Ptr || p == 0 { + return &InvalidUnmarshalError{Type: rtype2type(typ)} + } + return nil +} + // NewDecoder returns a new decoder that reads from r. // // The decoder introduces its own buffering and may @@ -50,45 +94,6 @@ func (d *Decoder) Buffered() io.Reader { return d.s.buffered() } -func (d *Decoder) validateType(typ *rtype, p uintptr) error { - if typ.Kind() != reflect.Ptr || p == 0 { - return &InvalidUnmarshalError{Type: rtype2type(typ)} - } - return nil -} - -func (d *Decoder) decode(src []byte, header *interfaceHeader) error { - typ := header.typ - typeptr := uintptr(unsafe.Pointer(typ)) - - // noescape trick for header.typ ( reflect.*rtype ) - copiedType := *(**rtype)(unsafe.Pointer(&typeptr)) - ptr := uintptr(header.ptr) - - if err := d.validateType(copiedType, ptr); err != nil { - return err - } - dec, err := decodeCompileToGetDecoder(typeptr, typ) - if err != nil { - return err - } - if _, err := dec.decode(src, 0, header.ptr); err != nil { - return err - } - return nil -} - -func (d *Decoder) decodeForUnmarshal(src []byte, v interface{}) error { - header := (*interfaceHeader)(unsafe.Pointer(&v)) - header.typ.escape() - return d.decode(src, header) -} - -func (d *Decoder) decodeForUnmarshalNoEscape(src []byte, v interface{}) error { - header := (*interfaceHeader)(unsafe.Pointer(&v)) - return d.decode(src, header) -} - func (d *Decoder) prepareForDecode() error { s := d.s for { @@ -123,7 +128,7 @@ func (d *Decoder) Decode(v interface{}) error { // noescape trick for header.typ ( reflect.*rtype ) copiedType := *(**rtype)(unsafe.Pointer(&typeptr)) - if err := d.validateType(copiedType, ptr); err != nil { + if err := validateType(copiedType, ptr); err != nil { return err } diff --git a/json.go b/json.go index ee21941..b3f7ae6 100644 --- a/json.go +++ b/json.go @@ -262,17 +262,11 @@ func MarshalIndentWithOption(v interface{}, prefix, indent string, optFuncs ...E // character U+FFFD. // func Unmarshal(data []byte, v interface{}) error { - src := make([]byte, len(data)+1) // append nul byte to end - copy(src, data) - var dec Decoder - return dec.decodeForUnmarshal(src, v) + return unmarshal(data, v) } func UnmarshalNoEscape(data []byte, v interface{}) error { - src := make([]byte, len(data)+1) // append nul byte to end - copy(src, data) - var dec Decoder - return dec.decodeForUnmarshalNoEscape(src, v) + return unmarshalNoEscape(data, v) } // A Token holds a value of one of these types: