Browse Source

codec: honor SelfExt during naked decoding

Include some minor clean up for lint warnings, etc

Updates #274
Ugorji Nwoke 6 years ago
parent
commit
7a66d0f64d
5 changed files with 48 additions and 47 deletions
  1. 1 4
      README.md
  2. 27 15
      codec/decode.go
  3. 1 3
      codec/doc.go
  4. 19 20
      codec/helper.go
  5. 0 5
      codec/values_flex_test.go

+ 1 - 4
README.md

@@ -31,10 +31,7 @@ Supported Serialization formats are:
 
 
 This package will carefully use 'package unsafe' for performance reasons in
 This package will carefully use 'package unsafe' for performance reasons in
 specific places. You can build without unsafe use by passing the safe or
 specific places. You can build without unsafe use by passing the safe or
-appengine tag i.e. 'go install -tags=safe ...'. Note that unsafe is only
-supported for the last 4 go releases e.g. current go release is go 1.12, so
-we support unsafe use only from go 1.9+ . This is because supporting unsafe
-requires knowledge of implementation details.
+appengine tag i.e. 'go install -tags=safe ...'.
 
 
 For detailed usage information, read the primer at
 For detailed usage information, read the primer at
 http://ugorji.net/blog/go-codec-primer .
 http://ugorji.net/blog/go-codec-primer .

+ 27 - 15
codec/decode.go

@@ -1292,26 +1292,38 @@ func (d *Decoder) kInterfaceNaked(f *codecFnInfo) (rvn reflect.Value) {
 			}
 			}
 		}
 		}
 	case valueTypeExt:
 	case valueTypeExt:
-		var v interface{}
 		tag, bytes := n.u, n.l // calling decode below might taint the values
 		tag, bytes := n.u, n.l // calling decode below might taint the values
-		if bytes == nil {
-			d.decode(&v)
-		}
 		bfn := d.h.getExtForTag(tag)
 		bfn := d.h.getExtForTag(tag)
-		if bfn == nil {
-			var re RawExt
-			re.Tag = tag
-			re.Data = detachZeroCopyBytes(d.bytes, nil, bytes)
-			re.Value = v
-			rvn = reflect.ValueOf(&re).Elem()
+		var re = RawExt{Tag: tag}
+		if bytes == nil {
+			// it is one of the InterfaceExt ones: json and cbor
+			// almost definitely cbor, as json naked decoding never reveals valueTypeExt (no tagging support).
+			if bfn == nil {
+				d.decode(&re.Value)
+				rvn = reflect.ValueOf(&re).Elem()
+			} else {
+				rvn = reflect.New(bfn.rt)
+				if bfn.ext == SelfExt {
+					d.decodeValue(rvn, d.h.fnNoExt(rvn.Type().Elem()))
+				} else {
+					d.interfaceExtConvertAndDecode(rv2i(rvn), bfn.ext)
+				}
+				rvn = rvn.Elem()
+			}
 		} else {
 		} else {
-			rvnA := reflect.New(bfn.rt)
-			if bytes != nil {
-				bfn.ext.ReadExt(rv2i(rvnA), bytes)
+			// one of the BytesExt ones: binc, msgpack, simple
+			if bfn == nil {
+				re.Data = detachZeroCopyBytes(d.bytes, nil, bytes)
+				rvn = reflect.ValueOf(&re).Elem()
 			} else {
 			} else {
-				bfn.ext.UpdateExt(rv2i(rvnA), v)
+				rvn = reflect.New(bfn.rt)
+				if bfn.ext == SelfExt {
+					d.sideDecode(rv2i(rvn), bytes)
+				} else {
+					bfn.ext.ReadExt(rv2i(rvn), bytes)
+				}
+				rvn = rvn.Elem()
 			}
 			}
-			rvn = rvnA.Elem()
 		}
 		}
 	case valueTypeNil:
 	case valueTypeNil:
 		// no-op
 		// no-op

+ 1 - 3
codec/doc.go

@@ -16,9 +16,7 @@ Supported Serialization formats are:
 
 
 This package will carefully use 'package unsafe' for performance reasons in specific places.
 This package will carefully use 'package unsafe' for performance reasons in specific places.
 You can build without unsafe use by passing the safe or appengine tag
 You can build without unsafe use by passing the safe or appengine tag
-i.e. 'go install -tags=safe ...'. Note that unsafe is only supported for the last 4
-go releases e.g. current go release is go 1.12, so we support unsafe use only from
-go 1.9+ . This is because supporting unsafe requires knowledge of implementation details.
+i.e. 'go install -tags=safe ...'.
 
 
 For detailed usage information, read the primer at http://ugorji.net/blog/go-codec-primer .
 For detailed usage information, read the primer at http://ugorji.net/blog/go-codec-primer .
 
 

+ 19 - 20
codec/helper.go

@@ -683,26 +683,26 @@ LOOP:
 	return
 	return
 }
 }
 
 
-func (c *BasicHandle) fn(rt reflect.Type) (fn *codecFn) {
-	return c.fnVia(rt, &c.rtidFns, true)
+func (x *BasicHandle) fn(rt reflect.Type) (fn *codecFn) {
+	return x.fnVia(rt, &x.rtidFns, true)
 }
 }
 
 
-func (c *BasicHandle) fnNoExt(rt reflect.Type) (fn *codecFn) {
-	return c.fnVia(rt, &c.rtidFnsNoExt, false)
+func (x *BasicHandle) fnNoExt(rt reflect.Type) (fn *codecFn) {
+	return x.fnVia(rt, &x.rtidFnsNoExt, false)
 }
 }
 
 
-func (c *BasicHandle) fnVia(rt reflect.Type, fs *atomicRtidFnSlice, checkExt bool) (fn *codecFn) {
+func (x *BasicHandle) fnVia(rt reflect.Type, fs *atomicRtidFnSlice, checkExt bool) (fn *codecFn) {
 	// xdebug2f("fnVia: rt: %v, checkExt: %v", rt, checkExt)
 	// xdebug2f("fnVia: rt: %v, checkExt: %v", rt, checkExt)
 	rtid := rt2id(rt)
 	rtid := rt2id(rt)
 	sp := fs.load()
 	sp := fs.load()
 	if sp != nil {
 	if sp != nil {
 		if _, fn = findFn(sp, rtid); fn != nil {
 		if _, fn = findFn(sp, rtid); fn != nil {
-			// xdebugf("<<<< %c: found fn for %v in rtidfns of size: %v", c.n, rt, len(sp))
+			// xdebugf("<<<< %c: found fn for %v in rtidfns of size: %v", x.n, rt, len(sp))
 			return
 			return
 		}
 		}
 	}
 	}
-	fn = c.fnLoad(rt, rtid, checkExt)
-	c.mu.Lock()
+	fn = x.fnLoad(rt, rtid, checkExt)
+	x.mu.Lock()
 	var sp2 []codecRtidFn
 	var sp2 []codecRtidFn
 	sp = fs.load()
 	sp = fs.load()
 	if sp == nil {
 	if sp == nil {
@@ -717,27 +717,27 @@ func (c *BasicHandle) fnVia(rt reflect.Type, fs *atomicRtidFnSlice, checkExt boo
 			copy(sp2, sp[:idx])
 			copy(sp2, sp[:idx])
 			copy(sp2[idx+1:], sp[idx:])
 			copy(sp2[idx+1:], sp[idx:])
 			sp2[idx] = codecRtidFn{rtid, fn}
 			sp2[idx] = codecRtidFn{rtid, fn}
-			c.rtidFns.store(sp2)
+			x.rtidFns.store(sp2)
 			// xdebugf(">>>> adding rt: %v to rtidfns of size: %v", rt, len(sp2))
 			// xdebugf(">>>> adding rt: %v to rtidfns of size: %v", rt, len(sp2))
 
 
 		}
 		}
 	}
 	}
-	c.mu.Unlock()
+	x.mu.Unlock()
 	return
 	return
 }
 }
 
 
-func (c *BasicHandle) fnLoad(rt reflect.Type, rtid uintptr, checkExt bool) (fn *codecFn) {
-	// xdebugf("#### for %c: load fn for %v in rtidfns of size: %v", c.n, rt, len(sp))
+func (x *BasicHandle) fnLoad(rt reflect.Type, rtid uintptr, checkExt bool) (fn *codecFn) {
+	// xdebugf("#### for %c: load fn for %v in rtidfns of size: %v", x.n, rt, len(sp))
 	fn = new(codecFn)
 	fn = new(codecFn)
 	fi := &(fn.i)
 	fi := &(fn.i)
-	ti := c.getTypeInfo(rtid, rt)
+	ti := x.getTypeInfo(rtid, rt)
 	fi.ti = ti
 	fi.ti = ti
 
 
 	rk := reflect.Kind(ti.kind)
 	rk := reflect.Kind(ti.kind)
 
 
 	// anything can be an extension except the built-in ones: time, raw and rawext
 	// anything can be an extension except the built-in ones: time, raw and rawext
 
 
-	if rtid == timeTypId && !c.TimeNotBuiltin {
+	if rtid == timeTypId && !x.TimeNotBuiltin {
 		fn.fe = (*Encoder).kTime
 		fn.fe = (*Encoder).kTime
 		fn.fd = (*Decoder).kTime
 		fn.fd = (*Decoder).kTime
 	} else if rtid == rawTypId {
 	} else if rtid == rawTypId {
@@ -749,7 +749,7 @@ func (c *BasicHandle) fnLoad(rt reflect.Type, rtid uintptr, checkExt bool) (fn *
 		fi.addrF = true
 		fi.addrF = true
 		fi.addrD = true
 		fi.addrD = true
 		fi.addrE = true
 		fi.addrE = true
-	} else if xfFn := c.getExt(rtid, checkExt); xfFn != nil {
+	} else if xfFn := x.getExt(rtid, checkExt); xfFn != nil {
 		fi.xfTag, fi.xfFn = xfFn.tag, xfFn.ext
 		fi.xfTag, fi.xfFn = xfFn.tag, xfFn.ext
 		fn.fe = (*Encoder).ext
 		fn.fe = (*Encoder).ext
 		fn.fd = (*Decoder).ext
 		fn.fd = (*Decoder).ext
@@ -764,13 +764,13 @@ func (c *BasicHandle) fnLoad(rt reflect.Type, rtid uintptr, checkExt bool) (fn *
 		fi.addrF = true
 		fi.addrF = true
 		fi.addrD = ti.csp
 		fi.addrD = ti.csp
 		fi.addrE = ti.csp
 		fi.addrE = ti.csp
-	} else if supportMarshalInterfaces && c.isBe() && (ti.bm || ti.bmp) && (ti.bu || ti.bup) {
+	} else if supportMarshalInterfaces && x.isBe() && (ti.bm || ti.bmp) && (ti.bu || ti.bup) {
 		fn.fe = (*Encoder).binaryMarshal
 		fn.fe = (*Encoder).binaryMarshal
 		fn.fd = (*Decoder).binaryUnmarshal
 		fn.fd = (*Decoder).binaryUnmarshal
 		fi.addrF = true
 		fi.addrF = true
 		fi.addrD = ti.bup
 		fi.addrD = ti.bup
 		fi.addrE = ti.bmp
 		fi.addrE = ti.bmp
-	} else if supportMarshalInterfaces && !c.isBe() && c.isJs() &&
+	} else if supportMarshalInterfaces && !x.isBe() && x.isJs() &&
 		(ti.jm || ti.jmp) && (ti.ju || ti.jup) {
 		(ti.jm || ti.jmp) && (ti.ju || ti.jup) {
 		//If JSON, we should check JSONMarshal before textMarshal
 		//If JSON, we should check JSONMarshal before textMarshal
 		fn.fe = (*Encoder).jsonMarshal
 		fn.fe = (*Encoder).jsonMarshal
@@ -778,7 +778,7 @@ func (c *BasicHandle) fnLoad(rt reflect.Type, rtid uintptr, checkExt bool) (fn *
 		fi.addrF = true
 		fi.addrF = true
 		fi.addrD = ti.jup
 		fi.addrD = ti.jup
 		fi.addrE = ti.jmp
 		fi.addrE = ti.jmp
-	} else if supportMarshalInterfaces && !c.isBe() && (ti.tm || ti.tmp) && (ti.tu || ti.tup) {
+	} else if supportMarshalInterfaces && !x.isBe() && (ti.tm || ti.tmp) && (ti.tu || ti.tup) {
 		fn.fe = (*Encoder).textMarshal
 		fn.fe = (*Encoder).textMarshal
 		fn.fd = (*Decoder).textUnmarshal
 		fn.fd = (*Decoder).textUnmarshal
 		fi.addrF = true
 		fi.addrF = true
@@ -2091,9 +2091,8 @@ func usableByteSlice(bs []byte, slen int) []byte {
 	if cap(bs) >= slen {
 	if cap(bs) >= slen {
 		if bs == nil {
 		if bs == nil {
 			return []byte{}
 			return []byte{}
-		} else {
-			return bs[:slen]
 		}
 		}
+		return bs[:slen]
 	}
 	}
 	return make([]byte, slen)
 	return make([]byte, slen)
 }
 }

+ 0 - 5
codec/values_flex_test.go

@@ -145,11 +145,6 @@ type TestSelfExtImpl struct {
 	testSelfExtHelper
 	testSelfExtHelper
 }
 }
 
 
-func (t *TestSelfExtImpl) CodecConvertExt() interface{} {
-	return &t.testSelfExtHelper
-}
-func (t *TestSelfExtImpl) CodecUpdateExt(v interface{}) {}
-
 var testWRepeated512 wrapBytes
 var testWRepeated512 wrapBytes
 var testStrucTime = time.Date(2012, 2, 2, 2, 2, 2, 2000, time.UTC).UTC()
 var testStrucTime = time.Date(2012, 2, 2, 2, 2, 2, 2000, time.UTC).UTC()