Skip to content

Commit

Permalink
Merge pull request #76 from dekarrin/ghi069-reflect-value
Browse files Browse the repository at this point in the history
Ghi069 reflect value
  • Loading branch information
dekarrin committed Dec 15, 2023
2 parents 736720b + 45b25cd commit 655aa8d
Show file tree
Hide file tree
Showing 9 changed files with 2,883 additions and 618 deletions.
64 changes: 31 additions & 33 deletions maps.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,27 +72,25 @@ func (smk sortableMapKeys) Less(i, j int) bool {
}

// encCheckedMap encodes a compatible map as a REZI map.
func encCheckedMap(v interface{}, ti typeInfo) ([]byte, error) {
if ti.Main != mtMap {
func encCheckedMap(value analyzed[any]) ([]byte, error) {
if value.ti.Main != mtMap {
panic("not a map type")
}

return encWithNilCheck(v, ti, func(val interface{}) ([]byte, error) {
return encMap(val, *ti.KeyType)
}, reflect.Value.Interface)
return encWithNilCheck(value, encMap, reflect.Value.Interface)
}

func encMap(v interface{}, keyType typeInfo) ([]byte, error) {
refVal := reflect.ValueOf(v)

if v == nil || refVal.IsNil() {
// requires keyType type info to be avail under *mapVal.ti.KeyType and ref to be
// set.
func encMap(val analyzed[any]) ([]byte, error) {
if val.native == nil || val.ref.IsNil() {
return encNilHeader(0), nil
}

mapKeys := refVal.MapKeys()
mapKeys := val.ref.MapKeys()
keysToSort := sortableMapKeys{
keys: mapKeys,
ti: keyType,
ti: *val.ti.KeyType,
}
sort.Sort(keysToSort)
mapKeys = keysToSort.keys
Expand All @@ -101,7 +99,7 @@ func encMap(v interface{}, keyType typeInfo) ([]byte, error) {

for i := range mapKeys {
k := mapKeys[i]
v := refVal.MapIndex(k)
v := val.ref.MapIndex(k)

keyData, err := Enc(k.Interface())
if err != nil {
Expand All @@ -116,46 +114,44 @@ func encMap(v interface{}, keyType typeInfo) ([]byte, error) {
enc = append(enc, valData...)
}

enc = append(encInt(tLen(len(enc))), enc...)
enc = append(encCount(len(enc), nil), enc...)
return enc, nil
}

// decCheckedMap decodes a REZI map as a compatible map type.
func decCheckedMap(data []byte, v interface{}, ti typeInfo) (int, error) {
if ti.Main != mtMap {
func decCheckedMap(data []byte, v analyzed[any]) (int, error) {
if v.ti.Main != mtMap {
panic("not a map type")
}

m, n, err := decWithNilCheck(data, v, ti, fn_DecToWrappedReceiver(v, ti,
_, di, n, err := decWithNilCheck(data, v, fn_DecToWrappedReceiver(v,
func(t reflect.Type) bool {
return t.Kind() == reflect.Pointer && t.Elem().Kind() == reflect.Map
},
func(b []byte, i interface{}) (interface{}, int, error) {
decN, err := decMap(b, i)
return nil, decN, err
},
decMap,
))
if err != nil {
return n, err
}
if ti.Indir == 0 {
refReceiver := reflect.ValueOf(v)
refReceiver.Elem().Set(reflect.ValueOf(m))
if v.ti.Indir == 0 {
refReceiver := v.ref
refReceiver.Elem().Set(di.Ref)
}
return n, err
}

func decMap(data []byte, v interface{}) (int, error) {
func decMap(data []byte, v analyzed[any]) (decInfo, int, error) {
var di decInfo
var totalConsumed int

toConsume, _, n, err := decInt[tLen](data)
if err != nil {
return 0, errorDecf(0, "decode byte count: %s", err)
return di, 0, errorDecf(0, "decode byte count: %s", err)
}
data = data[n:]
totalConsumed += n

refVal := reflect.ValueOf(v)
refVal := v.ref
refMapType := refVal.Type().Elem()

if toConsume == 0 {
Expand All @@ -164,14 +160,16 @@ func decMap(data []byte, v interface{}) (int, error) {

// set it to the value
refVal.Elem().Set(emptyMap)
return totalConsumed, nil
di.Ref = emptyMap
return di, totalConsumed, nil
} else if toConsume == -1 {
// initialize to the nil map
nilMap := reflect.Zero(refMapType)

// set it to the value
refVal.Elem().Set(nilMap)
return totalConsumed, nil
di.Ref = nilMap
return di, totalConsumed, nil
}

if len(data) < toConsume {
Expand All @@ -183,7 +181,7 @@ func decMap(data []byte, v interface{}) (int, error) {
}
const errFmt = "decoded map byte count is %d but only %d byte%s remain%s in data at offset"
err := errorDecf(totalConsumed, errFmt, toConsume, len(data), s, verbS).wrap(io.ErrUnexpectedEOF, ErrMalformedData)
return totalConsumed, err
return di, totalConsumed, err
}

// clamp values we are allowed to read so we don't try to read other data
Expand All @@ -200,7 +198,7 @@ func decMap(data []byte, v interface{}) (int, error) {
refKey := reflect.New(refKType)
n, err := Dec(data, refKey.Interface())
if err != nil {
return totalConsumed, errorDecf(totalConsumed, "map key: %v", err)
return di, totalConsumed, errorDecf(totalConsumed, "map key: %v", err)
}
totalConsumed += n
i += n
Expand All @@ -209,7 +207,7 @@ func decMap(data []byte, v interface{}) (int, error) {
refValue := reflect.New(refVType)
n, err = Dec(data, refValue.Interface())
if err != nil {
return totalConsumed, errorDecf(totalConsumed, "map value[%v]: %v", refKey.Elem().Interface(), err)
return di, totalConsumed, errorDecf(totalConsumed, "map value[%v]: %v", refKey.Elem().Interface(), err)
}
totalConsumed += n
i += n
Expand All @@ -219,6 +217,6 @@ func decMap(data []byte, v interface{}) (int, error) {
}

refVal.Elem().Set(m)

return totalConsumed, nil
di.Ref = m
return di, totalConsumed, nil
}

0 comments on commit 655aa8d

Please sign in to comment.