package avro
import (
"errors"
"io"
"sync"
"github.com/modern-go/reflect2"
)
const (
defaultMaxByteSliceSize = 1_048_576
)
var DefaultConfig = Config {}.Freeze ()
type Config struct {
TagKey string
BlockLength int
DisableBlockSizeHeader bool
UnionResolutionError bool
PartialUnionTypeResolution bool
DisableCaching bool
MaxByteSliceSize int
MaxSliceAllocSize int
}
func (c Config ) Freeze () API {
api := &frozenConfig {
config : c ,
resolver : NewTypeResolver (),
typeConverters : NewTypeConverters (),
}
api .readerPool = &sync .Pool {
New : func () any {
return &Reader {
cfg : api ,
reader : nil ,
buf : nil ,
head : 0 ,
tail : 0 ,
}
},
}
api .writerPool = &sync .Pool {
New : func () any {
return &Writer {
cfg : api ,
out : nil ,
buf : make ([]byte , 0 , 512 ),
Error : nil ,
}
},
}
return api
}
type API interface {
Marshal (schema Schema , v any ) ([]byte , error )
Unmarshal (schema Schema , data []byte , v any ) error
NewEncoder (schema Schema , w io .Writer ) *Encoder
NewDecoder (schema Schema , r io .Reader ) *Decoder
DecoderOf (schema Schema , typ reflect2 .Type ) ValDecoder
EncoderOf (schema Schema , typ reflect2 .Type ) ValEncoder
Register (name string , obj any )
RegisterTypeConverters (conv ...TypeConverter )
}
type frozenConfig struct {
config Config
decoderCache sync .Map
encoderCache sync .Map
readerPool *sync .Pool
writerPool *sync .Pool
resolver *TypeResolver
typeConverters *TypeConverters
}
func (c *frozenConfig ) Marshal (schema Schema , v any ) ([]byte , error ) {
writer := c .borrowWriter ()
defer c .returnWriter (writer )
writer .WriteVal (schema , v )
if err := writer .Error ; err != nil {
return nil , err
}
result := writer .Buffer ()
copied := make ([]byte , len (result ))
copy (copied , result )
return copied , nil
}
func (c *frozenConfig ) borrowWriter () *Writer {
writer := c .writerPool .Get ().(*Writer )
writer .Reset (nil )
return writer
}
func (c *frozenConfig ) returnWriter (writer *Writer ) {
writer .out = nil
writer .Error = nil
c .writerPool .Put (writer )
}
func (c *frozenConfig ) Unmarshal (schema Schema , data []byte , v any ) error {
reader := c .borrowReader (data )
defer c .returnReader (reader )
reader .ReadVal (schema , v )
err := reader .Error
if errors .Is (err , io .EOF ) {
return nil
}
return err
}
func (c *frozenConfig ) borrowReader (data []byte ) *Reader {
reader := c .readerPool .Get ().(*Reader )
reader .Reset (data )
return reader
}
func (c *frozenConfig ) returnReader (reader *Reader ) {
reader .Error = nil
c .readerPool .Put (reader )
}
func (c *frozenConfig ) NewEncoder (schema Schema , w io .Writer ) *Encoder {
writer , ok := w .(*Writer )
if !ok {
writer = NewWriter (w , 512 , WithWriterConfig (c ))
}
return &Encoder {
s : schema ,
w : writer ,
}
}
func (c *frozenConfig ) NewDecoder (schema Schema , r io .Reader ) *Decoder {
reader := NewReader (r , 512 , WithReaderConfig (c ))
return &Decoder {
s : schema ,
r : reader ,
}
}
func (c *frozenConfig ) Register (name string , obj any ) {
c .resolver .Register (name , obj )
}
func (c *frozenConfig ) RegisterTypeConverters (convs ...TypeConverter ) {
c .typeConverters .RegisterTypeConverters (convs ...)
}
type cacheKey struct {
fingerprint [32 ]byte
rtype uintptr
}
func (c *frozenConfig ) addDecoderToCache (fingerprint [32 ]byte , rtype uintptr , dec ValDecoder ) {
if c .config .DisableCaching {
return
}
key := cacheKey {fingerprint : fingerprint , rtype : rtype }
c .decoderCache .Store (key , dec )
}
func (c *frozenConfig ) getDecoderFromCache (fingerprint [32 ]byte , rtype uintptr ) ValDecoder {
if c .config .DisableCaching {
return nil
}
key := cacheKey {fingerprint : fingerprint , rtype : rtype }
if dec , ok := c .decoderCache .Load (key ); ok {
return dec .(ValDecoder )
}
return nil
}
func (c *frozenConfig ) addEncoderToCache (fingerprint [32 ]byte , rtype uintptr , enc ValEncoder ) {
if c .config .DisableCaching {
return
}
key := cacheKey {fingerprint : fingerprint , rtype : rtype }
c .encoderCache .Store (key , enc )
}
func (c *frozenConfig ) getEncoderFromCache (fingerprint [32 ]byte , rtype uintptr ) ValEncoder {
if c .config .DisableCaching {
return nil
}
key := cacheKey {fingerprint : fingerprint , rtype : rtype }
if enc , ok := c .encoderCache .Load (key ); ok {
return enc .(ValEncoder )
}
return nil
}
func (c *frozenConfig ) getTagKey () string {
tagKey := c .config .TagKey
if tagKey == "" {
return "avro"
}
return tagKey
}
func (c *frozenConfig ) getBlockLength () int {
blockSize := c .config .BlockLength
if blockSize <= 0 {
return 100
}
return blockSize
}
func (c *frozenConfig ) getMaxByteSliceSize () int {
size := c .config .MaxByteSliceSize
if size == 0 {
return defaultMaxByteSliceSize
}
return size
}
func (c *frozenConfig ) getMaxSliceAllocSize () int {
size := c .config .MaxSliceAllocSize
if size > maxAllocSize || size <= 0 {
return maxAllocSize
}
return size
}
The pages are generated with Golds v0.8.2 . (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu .
PR and bug reports are welcome and can be submitted to the issue list .
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds .