-
Notifications
You must be signed in to change notification settings - Fork 99
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: optimise generic decodes (#349)
- Loading branch information
Showing
9 changed files
with
233 additions
and
340 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,140 +1,138 @@ | ||
package avro | ||
|
||
import ( | ||
"fmt" | ||
"errors" | ||
"math/big" | ||
"time" | ||
"unsafe" | ||
|
||
"github.com/modern-go/reflect2" | ||
) | ||
|
||
func genericDecode(schema Schema, r *Reader) any { | ||
rPtr, rTyp, err := genericReceiver(schema) | ||
if err != nil { | ||
r.ReportError("Read", err.Error()) | ||
return nil | ||
} | ||
decoderOfType(r.cfg, schema, rTyp).Decode(rPtr, r) | ||
func genericDecode(typ reflect2.Type, dec ValDecoder, r *Reader) any { | ||
ptr := typ.UnsafeNew() | ||
dec.Decode(ptr, r) | ||
if r.Error != nil { | ||
return nil | ||
} | ||
obj := rTyp.UnsafeIndirect(rPtr) | ||
|
||
obj := typ.UnsafeIndirect(ptr) | ||
if reflect2.IsNil(obj) { | ||
return nil | ||
} | ||
|
||
// Generic reader returns a different result from the | ||
// codec in the case of a big.Rat. Handle this. | ||
if rTyp.Type1() == ratType { | ||
if typ.Type1() == ratType { | ||
dec := obj.(big.Rat) | ||
return &dec | ||
} | ||
|
||
return obj | ||
} | ||
|
||
func genericReceiver(schema Schema) (unsafe.Pointer, reflect2.Type, error) { | ||
func genericReceiver(schema Schema) (reflect2.Type, error) { | ||
if schema.Type() == Ref { | ||
schema = schema.(*RefSchema).Schema() | ||
} | ||
|
||
var ls LogicalSchema | ||
lts, ok := schema.(LogicalTypeSchema) | ||
if ok { | ||
ls = lts.Logical() | ||
} | ||
|
||
name := string(schema.Type()) | ||
schemaName := string(schema.Type()) | ||
if ls != nil { | ||
name += "." + string(ls.Type()) | ||
schemaName += "." + string(ls.Type()) | ||
} | ||
|
||
switch schema.Type() { | ||
case Boolean: | ||
var v bool | ||
return unsafe.Pointer(&v), reflect2.TypeOf(v), nil | ||
return reflect2.TypeOf(v), nil | ||
case Int: | ||
if ls != nil { | ||
switch ls.Type() { | ||
case Date: | ||
var v time.Time | ||
return unsafe.Pointer(&v), reflect2.TypeOf(v), nil | ||
return reflect2.TypeOf(v), nil | ||
|
||
case TimeMillis: | ||
var v time.Duration | ||
return unsafe.Pointer(&v), reflect2.TypeOf(v), nil | ||
return reflect2.TypeOf(v), nil | ||
} | ||
} | ||
var v int | ||
return unsafe.Pointer(&v), reflect2.TypeOf(v), nil | ||
return reflect2.TypeOf(v), nil | ||
case Long: | ||
if ls != nil { | ||
switch ls.Type() { | ||
case TimeMicros: | ||
var v time.Duration | ||
return unsafe.Pointer(&v), reflect2.TypeOf(v), nil | ||
return reflect2.TypeOf(v), nil | ||
case TimestampMillis: | ||
var v time.Time | ||
return unsafe.Pointer(&v), reflect2.TypeOf(v), nil | ||
return reflect2.TypeOf(v), nil | ||
case TimestampMicros: | ||
var v time.Time | ||
return unsafe.Pointer(&v), reflect2.TypeOf(v), nil | ||
return reflect2.TypeOf(v), nil | ||
case LocalTimestampMillis: | ||
var v time.Time | ||
return unsafe.Pointer(&v), reflect2.TypeOf(v), nil | ||
return reflect2.TypeOf(v), nil | ||
case LocalTimestampMicros: | ||
var v time.Time | ||
return unsafe.Pointer(&v), reflect2.TypeOf(v), nil | ||
return reflect2.TypeOf(v), nil | ||
} | ||
} | ||
var v int64 | ||
return unsafe.Pointer(&v), reflect2.TypeOf(v), nil | ||
return reflect2.TypeOf(v), nil | ||
case Float: | ||
var v float32 | ||
return unsafe.Pointer(&v), reflect2.TypeOf(v), nil | ||
return reflect2.TypeOf(v), nil | ||
case Double: | ||
var v float64 | ||
return unsafe.Pointer(&v), reflect2.TypeOf(v), nil | ||
return reflect2.TypeOf(v), nil | ||
case String: | ||
var v string | ||
return unsafe.Pointer(&v), reflect2.TypeOf(v), nil | ||
return reflect2.TypeOf(v), nil | ||
case Bytes: | ||
if ls != nil && ls.Type() == Decimal { | ||
var v *big.Rat | ||
return unsafe.Pointer(&v), reflect2.TypeOf(v), nil | ||
return reflect2.TypeOf(v), nil | ||
} | ||
var v []byte | ||
return unsafe.Pointer(&v), reflect2.TypeOf(v), nil | ||
return reflect2.TypeOf(v), nil | ||
case Record: | ||
var v map[string]any | ||
return unsafe.Pointer(&v), reflect2.TypeOf(v), nil | ||
case Ref: | ||
return genericReceiver(schema.(*RefSchema).Schema()) | ||
return reflect2.TypeOf(v), nil | ||
case Enum: | ||
var v string | ||
return unsafe.Pointer(&v), reflect2.TypeOf(v), nil | ||
return reflect2.TypeOf(v), nil | ||
case Array: | ||
v := make([]any, 0) | ||
return unsafe.Pointer(&v), reflect2.TypeOf(v), nil | ||
return reflect2.TypeOf(v), nil | ||
case Map: | ||
var v map[string]any | ||
return unsafe.Pointer(&v), reflect2.TypeOf(v), nil | ||
return reflect2.TypeOf(v), nil | ||
case Union: | ||
var v map[string]any | ||
return unsafe.Pointer(&v), reflect2.TypeOf(v), nil | ||
return reflect2.TypeOf(v), nil | ||
case Fixed: | ||
fixed := schema.(*FixedSchema) | ||
ls := fixed.Logical() | ||
if ls != nil { | ||
switch ls.Type() { | ||
case Duration: | ||
var v LogicalDuration | ||
return unsafe.Pointer(&v), reflect2.TypeOf(v), nil | ||
return reflect2.TypeOf(v), nil | ||
case Decimal: | ||
var v big.Rat | ||
return unsafe.Pointer(&v), reflect2.TypeOf(v), nil | ||
return reflect2.TypeOf(v), nil | ||
} | ||
} | ||
v := byteSliceToArray(make([]byte, fixed.Size()), fixed.Size()) | ||
return unsafe.Pointer(&v), reflect2.TypeOf(v), nil | ||
return reflect2.TypeOf(v), nil | ||
default: | ||
return nil, nil, fmt.Errorf("dynamic receiver not found for schema: %v", name) | ||
// This should not be possible. | ||
return nil, errors.New("dynamic receiver not found for schema " + schemaName) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.