github.com/hamba/avro@v1.8.0/config.go (about) 1 package avro 2 3 import ( 4 "errors" 5 "io" 6 "sync" 7 8 "github.com/modern-go/concurrent" 9 "github.com/modern-go/reflect2" 10 ) 11 12 // DefaultConfig is the default API. 13 var DefaultConfig = Config{}.Freeze() 14 15 // Config customises how the codec should behave. 16 type Config struct { 17 // TagKey is the struct tag key used when en/decoding structs. 18 // This defaults to "avro". 19 TagKey string 20 21 // BlockLength is the length of blocks for maps and arrays. 22 // This defaults to 100. 23 BlockLength int 24 25 // UnionResolutionError determines if an error will be returned 26 // when a type cannot be resolved while decoding a union. 27 UnionResolutionError bool 28 } 29 30 // Freeze makes the configuration immutable. 31 func (c Config) Freeze() API { 32 api := &frozenConfig{ 33 config: c, 34 decoderCache: concurrent.NewMap(), 35 encoderCache: concurrent.NewMap(), 36 resolver: NewTypeResolver(), 37 } 38 39 api.readerPool = &sync.Pool{ 40 New: func() interface{} { 41 return &Reader{ 42 cfg: api, 43 reader: nil, 44 buf: nil, 45 head: 0, 46 tail: 0, 47 } 48 }, 49 } 50 api.writerPool = &sync.Pool{ 51 New: func() interface{} { 52 return &Writer{ 53 cfg: api, 54 out: nil, 55 buf: make([]byte, 0, 512), 56 Error: nil, 57 } 58 }, 59 } 60 61 return api 62 } 63 64 // API represents a frozen Config. 65 type API interface { 66 // Marshal returns the Avro encoding of v. 67 Marshal(schema Schema, v interface{}) ([]byte, error) 68 69 // Unmarshal parses the Avro encoded data and stores the result in the value pointed to by v. 70 // If v is nil or not a pointer, Unmarshal returns an error. 71 Unmarshal(schema Schema, data []byte, v interface{}) error 72 73 // NewEncoder returns a new encoder that writes to w using schema. 74 NewEncoder(schema Schema, w io.Writer) *Encoder 75 76 // NewDecoder returns a new decoder that reads from reader r using schema. 77 NewDecoder(schema Schema, r io.Reader) *Decoder 78 79 // DecoderOf returns the value decoder for a given schema and type. 80 DecoderOf(schema Schema, typ reflect2.Type) ValDecoder 81 82 // EncoderOf returns the value encoder for a given schema and type. 83 EncoderOf(schema Schema, tpy reflect2.Type) ValEncoder 84 85 // Register registers names to their types for resolution. All primitive types are pre-registered. 86 Register(name string, obj interface{}) 87 } 88 89 type frozenConfig struct { 90 config Config 91 92 decoderCache *concurrent.Map // map[cacheKey]ValDecoder 93 encoderCache *concurrent.Map // map[cacheKey]ValEncoder 94 95 readerPool *sync.Pool 96 writerPool *sync.Pool 97 98 resolver *TypeResolver 99 } 100 101 func (c *frozenConfig) Marshal(schema Schema, v interface{}) ([]byte, error) { 102 writer := c.borrowWriter() 103 104 writer.WriteVal(schema, v) 105 if err := writer.Error; err != nil { 106 c.returnWriter(writer) 107 return nil, err 108 } 109 110 result := writer.Buffer() 111 copied := make([]byte, len(result)) 112 copy(copied, result) 113 114 c.returnWriter(writer) 115 return copied, nil 116 } 117 118 func (c *frozenConfig) borrowWriter() *Writer { 119 writer := c.writerPool.Get().(*Writer) 120 writer.Reset(nil) 121 return writer 122 } 123 124 func (c *frozenConfig) returnWriter(writer *Writer) { 125 writer.out = nil 126 writer.Error = nil 127 128 c.writerPool.Put(writer) 129 } 130 131 func (c *frozenConfig) Unmarshal(schema Schema, data []byte, v interface{}) error { 132 reader := c.borrowReader(data) 133 134 reader.ReadVal(schema, v) 135 err := reader.Error 136 c.returnReader(reader) 137 138 if errors.Is(err, io.EOF) { 139 return nil 140 } 141 142 return err 143 } 144 145 func (c *frozenConfig) borrowReader(data []byte) *Reader { 146 reader := c.readerPool.Get().(*Reader) 147 reader.Reset(data) 148 return reader 149 } 150 151 func (c *frozenConfig) returnReader(reader *Reader) { 152 reader.Error = nil 153 c.readerPool.Put(reader) 154 } 155 156 func (c *frozenConfig) NewEncoder(schema Schema, w io.Writer) *Encoder { 157 writer := NewWriter(w, 512, WithWriterConfig(c)) 158 return &Encoder{ 159 s: schema, 160 w: writer, 161 } 162 } 163 164 func (c *frozenConfig) NewDecoder(schema Schema, r io.Reader) *Decoder { 165 reader := NewReader(r, 512, WithReaderConfig(c)) 166 return &Decoder{ 167 s: schema, 168 r: reader, 169 } 170 } 171 172 func (c *frozenConfig) Register(name string, obj interface{}) { 173 c.resolver.Register(name, obj) 174 } 175 176 type cacheKey struct { 177 fingerprint [32]byte 178 rtype uintptr 179 } 180 181 func (c *frozenConfig) addDecoderToCache(fingerprint [32]byte, rtype uintptr, dec ValDecoder) { 182 key := cacheKey{fingerprint: fingerprint, rtype: rtype} 183 c.decoderCache.Store(key, dec) 184 } 185 186 func (c *frozenConfig) getDecoderFromCache(fingerprint [32]byte, rtype uintptr) ValDecoder { 187 key := cacheKey{fingerprint: fingerprint, rtype: rtype} 188 if dec, ok := c.decoderCache.Load(key); ok { 189 return dec.(ValDecoder) 190 } 191 192 return nil 193 } 194 195 func (c *frozenConfig) addEncoderToCache(fingerprint [32]byte, rtype uintptr, enc ValEncoder) { 196 key := cacheKey{fingerprint: fingerprint, rtype: rtype} 197 c.encoderCache.Store(key, enc) 198 } 199 200 func (c *frozenConfig) getEncoderFromCache(fingerprint [32]byte, rtype uintptr) ValEncoder { 201 key := cacheKey{fingerprint: fingerprint, rtype: rtype} 202 if enc, ok := c.encoderCache.Load(key); ok { 203 return enc.(ValEncoder) 204 } 205 206 return nil 207 } 208 209 func (c *frozenConfig) getTagKey() string { 210 tagKey := c.config.TagKey 211 if tagKey == "" { 212 return "avro" 213 } 214 return tagKey 215 } 216 217 func (c *frozenConfig) getBlockLength() int { 218 blockSize := c.config.BlockLength 219 if blockSize <= 0 { 220 return 100 221 } 222 return blockSize 223 }