@@ -18,6 +18,7 @@ import (
18
18
"bytes"
19
19
"fmt"
20
20
"reflect"
21
+ "sync"
21
22
22
23
_cbor "github.com/fxamacker/cbor/v2"
23
24
"github.com/jinzhu/copier"
@@ -109,27 +110,43 @@ func DecodeById(
109
110
return ret , nil
110
111
}
111
112
113
+ var decodeGenericTypeCache = map [reflect.Type ]reflect.Type {}
114
+ var decodeGenericTypeCacheMutex sync.RWMutex
115
+
112
116
// DecodeGeneric decodes the specified CBOR into the destination object without using the
113
117
// destination object's UnmarshalCBOR() function
114
118
func DecodeGeneric (cborData []byte , dest interface {}) error {
115
- // Create a duplicate(-ish) struct from the destination
116
- // We do this so that we can bypass any custom UnmarshalCBOR() function on the
117
- // destination object
119
+ // Get destination type
118
120
valueDest := reflect .ValueOf (dest )
119
- if valueDest .Kind () != reflect .Pointer ||
120
- valueDest .Elem ().Kind () != reflect .Struct {
121
- return fmt .Errorf ("destination must be a pointer to a struct" )
122
- }
123
- typeDestElem := valueDest .Elem ().Type ()
124
- destTypeFields := []reflect.StructField {}
125
- for i := 0 ; i < typeDestElem .NumField (); i ++ {
126
- tmpField := typeDestElem .Field (i )
127
- if tmpField .IsExported () && tmpField .Name != "DecodeStoreCbor" {
128
- destTypeFields = append (destTypeFields , tmpField )
121
+ typeDest := valueDest .Elem ().Type ()
122
+ // Check type cache
123
+ decodeGenericTypeCacheMutex .RLock ()
124
+ tmpTypeDest , ok := decodeGenericTypeCache [typeDest ]
125
+ decodeGenericTypeCacheMutex .RUnlock ()
126
+ if ! ok {
127
+ // Create a duplicate(-ish) struct from the destination
128
+ // We do this so that we can bypass any custom UnmarshalCBOR() function on the
129
+ // destination object
130
+ if valueDest .Kind () != reflect .Pointer ||
131
+ valueDest .Elem ().Kind () != reflect .Struct {
132
+ decodeGenericTypeCacheMutex .Unlock ()
133
+ return fmt .Errorf ("destination must be a pointer to a struct" )
134
+ }
135
+ destTypeFields := []reflect.StructField {}
136
+ for i := 0 ; i < typeDest .NumField (); i ++ {
137
+ tmpField := typeDest .Field (i )
138
+ if tmpField .IsExported () && tmpField .Name != "DecodeStoreCbor" {
139
+ destTypeFields = append (destTypeFields , tmpField )
140
+ }
129
141
}
142
+ tmpTypeDest = reflect .StructOf (destTypeFields )
143
+ // Populate cache
144
+ decodeGenericTypeCacheMutex .Lock ()
145
+ decodeGenericTypeCache [typeDest ] = tmpTypeDest
146
+ decodeGenericTypeCacheMutex .Unlock ()
130
147
}
131
148
// Create temporary object with the type created above
132
- tmpDest := reflect .New (reflect . StructOf ( destTypeFields ) )
149
+ tmpDest := reflect .New (tmpTypeDest )
133
150
// Decode CBOR into temporary object
134
151
if _ , err := Decode (cborData , tmpDest .Interface ()); err != nil {
135
152
return err
0 commit comments