Skip to content

Commit

Permalink
add encoder
Browse files Browse the repository at this point in the history
  • Loading branch information
zerosnake0 committed Jan 8, 2020
1 parent 05cd7bd commit 772abb6
Show file tree
Hide file tree
Showing 134 changed files with 8,601 additions and 2,673 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,4 @@ jobs:
fi
- name: Test
run: go test -v ./...
run: go test ./...
7 changes: 6 additions & 1 deletion TODO.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
# Feature

- [x] Skip object
- [ ] Support other tag than `json`
- [x] Support other tag than `json`
- [x] Decoder option `UseNumber`
- [x] Decoder option `DisallowUnknownFields`
- [x] tag option `quoted`
- [ ] json/text marshaler (pointer receiver) for values
- [ ] tag option `omitempty`

# Improvement

Expand Down
7 changes: 6 additions & 1 deletion convert.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,12 @@ import (
)

func localStringToBytes(s string) []byte {
return *(*[]byte)(unsafe.Pointer((*reflect.SliceHeader)(unsafe.Pointer(&s))))
sh := (*reflect.StringHeader)(unsafe.Pointer(&s))
return *(*[]byte)(unsafe.Pointer(&reflect.SliceHeader{
Data: sh.Data,
Len: sh.Len,
Cap: sh.Len,
}))
}

func localByteToString(buf []byte) string {
Expand Down
80 changes: 44 additions & 36 deletions decoder.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ type DecoderOption struct {
Tag string

OnlyTaggedField bool

UseNumber bool

DisallowUnknownFields bool
}

type decoderCache = map[rtype]ValDecoder
Expand All @@ -32,9 +36,11 @@ type Decoder struct {
cacheMu sync.Mutex
decoderCache atomic.Value

caseSensitive bool
tag string
onlyTaggedField bool
caseSensitive bool
tag string
onlyTaggedField bool
useNumber bool
disallowUnknownFields bool
}

func NewDecoder(opt *DecoderOption) *Decoder {
Expand All @@ -52,6 +58,8 @@ func NewDecoder(opt *DecoderOption) *Decoder {
dec.tag = opt.Tag
}
dec.onlyTaggedField = opt.OnlyTaggedField
dec.useNumber = opt.UseNumber
dec.disallowUnknownFields = opt.DisallowUnknownFields
}
dec.decoderCache.Store(cache)
return &dec
Expand All @@ -64,6 +72,10 @@ func (dec *Decoder) Unmarshal(data []byte, obj interface{}) error {
return err
}

func (dec *Decoder) UnmarshalFromString(s string, obj interface{}) error {
return dec.Unmarshal(localStringToBytes(s), obj)
}

func (dec *Decoder) getDecoderFromCache(rType rtype) ValDecoder {
return dec.decoderCache.Load().(decoderCache)[rType]
}
Expand All @@ -82,23 +94,18 @@ func (dec *Decoder) createDecoder(rType rtype, ptrType reflect.Type) ValDecoder
for k, v := range cache {
newCache[k] = v
}
typesToCreate := []reflect.Type{ptrType}
dec.createDecoderInternal(newCache, typesToCreate)
var q typeQueue
q.push(ptrType)
dec.createDecoderInternal(newCache, q)
dec.decoderCache.Store(newCache)
return newCache[rType]
}

func (dec *Decoder) createDecoderInternal(cache decoderCache, typesToCreate []reflect.Type) {
func (dec *Decoder) createDecoderInternal(cache decoderCache, typesToCreate typeQueue) {
rebuildMap := map[rtype]interface{}{}
idx := len(typesToCreate) - 1
for idx >= 0 {
// pop one
ptrType := typesToCreate[idx]
typesToCreate = typesToCreate[:idx]
idx -= 1

for ptrType := typesToCreate.pop(); ptrType != nil; ptrType = typesToCreate.pop() {
rType := rtypeOfType(ptrType)
if _, ok := cache[rType]; ok { // double check
if _, ok := cache[rType]; ok { // check if visited
continue
}
// check global decoders
Expand All @@ -117,7 +124,7 @@ func (dec *Decoder) createDecoderInternal(cache decoderCache, typesToCreate []re
}
elem := ptrType.Elem()
elemKind := elem.Kind()
if elemNativeRType := kindMap[elemKind]; elemNativeRType != 0 {
if elemNativeRType := decoderKindMap[elemKind]; elemNativeRType != 0 {
// TODO: shall we make this an option?
// TODO: so that only the native type is affected?
// check if the native type has a custom decoder
Expand All @@ -139,36 +146,36 @@ func (dec *Decoder) createDecoderInternal(cache decoderCache, typesToCreate []re
cache[rType] = (*ifaceDecoder)(nil)
}
case reflect.Struct:
vd := dec.newStructDecoder(elem)
if vd == nil {
w := dec.newStructDecoder(elem)
if w == nil {
// no field to unmarshal
cache[rType] = (*skipDecoder)(nil)
if dec.disallowUnknownFields {
cache[rType] = (*emptyObjectDecoder)(nil)
} else {
cache[rType] = (*skipDecoder)(nil)
}
} else {
for i := range vd.fields.list {
fi := &vd.fields.list[i]
typesToCreate = append(typesToCreate, fi.ptrType)
idx += 1
for i := range w.fields.list {
fi := &w.fields.list[i]
typesToCreate.push(fi.ptrType)
}
cache[rType] = vd
rebuildMap[rType] = vd
cache[rType] = w.decoder
rebuildMap[rType] = w
}
case reflect.Ptr:
typesToCreate = append(typesToCreate, elem)
idx += 1
typesToCreate.push(elem)
w := newPointerDecoder(elem)
cache[rType] = w.decoder
rebuildMap[rType] = w
case reflect.Array:
elemPtrType := reflect.PtrTo(elem.Elem())
typesToCreate = append(typesToCreate, elemPtrType)
idx += 1
typesToCreate.push(elemPtrType)
w := newArrayDecoder(elem)
cache[rType] = w.decoder
rebuildMap[rType] = w
case reflect.Slice:
elemPtrType := reflect.PtrTo(elem.Elem())
typesToCreate = append(typesToCreate, elemPtrType)
idx += 1
typesToCreate.push(elemPtrType)
w := newSliceDecoder(elem)
cache[rType] = w.decoder
rebuildMap[rType] = w
Expand All @@ -178,8 +185,7 @@ func (dec *Decoder) createDecoderInternal(cache decoderCache, typesToCreate []re
cache[rType] = notSupportedDecoder(ptrType.String())
} else {
valuePtrType := reflect.PtrTo(elem.Elem())
typesToCreate = append(typesToCreate, valuePtrType)
idx += 1
typesToCreate.push(valuePtrType)
cache[rType] = w.decoder
rebuildMap[rType] = w
}
Expand All @@ -188,14 +194,16 @@ func (dec *Decoder) createDecoderInternal(cache decoderCache, typesToCreate []re
}
}
// rebuild some decoders
for _, vd := range rebuildMap {
switch x := vd.(type) {
for _, builder := range rebuildMap {
switch x := builder.(type) {
case *pointerDecoderBuilder:
x.decoder.elemDec = cache[x.ptrRType]
case *structDecoder:
case *structDecoderBuilder:
x.decoder.fields.init(len(x.fields.list))
for i := range x.fields.list {
fi := &x.fields.list[i]
fi.decoder = cache[fi.rtype]
fiPtrRType := rtypeOfType(fi.ptrType)
x.decoder.fields.add(fi, cache[fiPtrRType])
}
case *arrayDecoderBuilder:
x.decoder.elemDec = cache[x.elemPtrRType]
Expand Down
Loading

0 comments on commit 772abb6

Please sign in to comment.