github.com/hamba/avro/v2@v2.22.1-0.20240518180522-aff3955acf7d/schema.go (about)

     1  package avro
     2  
     3  import (
     4  	"bytes"
     5  	"crypto/md5"
     6  	"crypto/sha256"
     7  	"errors"
     8  	"fmt"
     9  	"sort"
    10  	"strconv"
    11  	"strings"
    12  	"sync"
    13  	"sync/atomic"
    14  
    15  	"github.com/hamba/avro/v2/pkg/crc64"
    16  	jsoniter "github.com/json-iterator/go"
    17  )
    18  
    19  var nullDefault = struct{}{}
    20  
    21  var (
    22  	schemaReserved = []string{
    23  		"doc", "fields", "items", "name", "namespace", "size", "symbols",
    24  		"values", "type", "aliases", "logicalType", "precision", "scale",
    25  	}
    26  	fieldReserved = []string{"default", "doc", "name", "order", "type", "aliases"}
    27  )
    28  
    29  // Type is a schema type.
    30  type Type string
    31  
    32  // Schema type constants.
    33  const (
    34  	Record  Type = "record"
    35  	Error   Type = "error"
    36  	Ref     Type = "<ref>"
    37  	Enum    Type = "enum"
    38  	Array   Type = "array"
    39  	Map     Type = "map"
    40  	Union   Type = "union"
    41  	Fixed   Type = "fixed"
    42  	String  Type = "string"
    43  	Bytes   Type = "bytes"
    44  	Int     Type = "int"
    45  	Long    Type = "long"
    46  	Float   Type = "float"
    47  	Double  Type = "double"
    48  	Boolean Type = "boolean"
    49  	Null    Type = "null"
    50  )
    51  
    52  // Order is a field order.
    53  type Order string
    54  
    55  // Field orders.
    56  const (
    57  	Asc    Order = "ascending"
    58  	Desc   Order = "descending"
    59  	Ignore Order = "ignore"
    60  )
    61  
    62  // LogicalType is a schema logical type.
    63  type LogicalType string
    64  
    65  // Schema logical type constants.
    66  const (
    67  	Decimal              LogicalType = "decimal"
    68  	UUID                 LogicalType = "uuid"
    69  	Date                 LogicalType = "date"
    70  	TimeMillis           LogicalType = "time-millis"
    71  	TimeMicros           LogicalType = "time-micros"
    72  	TimestampMillis      LogicalType = "timestamp-millis"
    73  	TimestampMicros      LogicalType = "timestamp-micros"
    74  	LocalTimestampMillis LogicalType = "local-timestamp-millis"
    75  	LocalTimestampMicros LogicalType = "local-timestamp-micros"
    76  	Duration             LogicalType = "duration"
    77  )
    78  
    79  // Action is a field action used during decoding process.
    80  type Action string
    81  
    82  // Action type constants.
    83  const (
    84  	FieldIgnore     Action = "ignore"
    85  	FieldSetDefault Action = "set_default"
    86  )
    87  
    88  // FingerprintType is a fingerprinting algorithm.
    89  type FingerprintType string
    90  
    91  // Fingerprint type constants.
    92  const (
    93  	CRC64Avro FingerprintType = "CRC64-AVRO"
    94  	MD5       FingerprintType = "MD5"
    95  	SHA256    FingerprintType = "SHA256"
    96  )
    97  
    98  // SchemaCache is a cache of schemas.
    99  type SchemaCache struct {
   100  	cache sync.Map // map[string]Schema
   101  }
   102  
   103  // Add adds a schema to the cache with the given name.
   104  func (c *SchemaCache) Add(name string, schema Schema) {
   105  	c.cache.Store(name, schema)
   106  }
   107  
   108  // Get returns the Schema if it exists.
   109  func (c *SchemaCache) Get(name string) Schema {
   110  	if v, ok := c.cache.Load(name); ok {
   111  		return v.(Schema)
   112  	}
   113  
   114  	return nil
   115  }
   116  
   117  // Schemas is a slice of Schemas.
   118  type Schemas []Schema
   119  
   120  // Get gets a schema and position by type or name if it is a named schema.
   121  func (s Schemas) Get(name string) (Schema, int) {
   122  	for i, schema := range s {
   123  		if schemaTypeName(schema) == name {
   124  			return schema, i
   125  		}
   126  	}
   127  
   128  	return nil, -1
   129  }
   130  
   131  // Schema represents an Avro schema.
   132  type Schema interface {
   133  	// Type returns the type of the schema.
   134  	Type() Type
   135  
   136  	// String returns the canonical form of the schema.
   137  	String() string
   138  
   139  	// Fingerprint returns the SHA256 fingerprint of the schema.
   140  	Fingerprint() [32]byte
   141  
   142  	// FingerprintUsing returns the fingerprint of the schema using the given algorithm or an error.
   143  	FingerprintUsing(FingerprintType) ([]byte, error)
   144  
   145  	// CacheFingerprint returns the unique identity of the schema.
   146  	// This returns a unique identity for schemas resolved from a writer schema, otherwise it returns
   147  	// the schemas Fingerprint.
   148  	CacheFingerprint() [32]byte
   149  }
   150  
   151  // LogicalSchema represents an Avro schema with a logical type.
   152  type LogicalSchema interface {
   153  	// Type returns the type of the logical schema.
   154  	Type() LogicalType
   155  
   156  	// String returns the canonical form of the logical schema.
   157  	String() string
   158  }
   159  
   160  // PropertySchema represents a schema with properties.
   161  type PropertySchema interface {
   162  	// Prop gets a property from the schema.
   163  	Prop(string) any
   164  }
   165  
   166  // NamedSchema represents a schema with a name.
   167  type NamedSchema interface {
   168  	Schema
   169  	PropertySchema
   170  
   171  	// Name returns the name of the schema.
   172  	Name() string
   173  
   174  	// Namespace returns the namespace of a schema.
   175  	Namespace() string
   176  
   177  	// FullName returns the full qualified name of a schema.
   178  	FullName() string
   179  
   180  	// Aliases returns the full qualified aliases of a schema.
   181  	Aliases() []string
   182  }
   183  
   184  // LogicalTypeSchema represents a schema that can contain a logical type.
   185  type LogicalTypeSchema interface {
   186  	// Logical returns the logical schema or nil.
   187  	Logical() LogicalSchema
   188  }
   189  
   190  type name struct {
   191  	name      string
   192  	namespace string
   193  	full      string
   194  	aliases   []string
   195  }
   196  
   197  func newName(n, ns string, aliases []string) (name, error) {
   198  	if idx := strings.LastIndexByte(n, '.'); idx > -1 {
   199  		ns = n[:idx]
   200  		n = n[idx+1:]
   201  	}
   202  
   203  	full := n
   204  	if ns != "" {
   205  		full = ns + "." + n
   206  	}
   207  
   208  	for _, part := range strings.Split(full, ".") {
   209  		if err := validateName(part); err != nil {
   210  			return name{}, fmt.Errorf("avro: invalid name part %q in name %q: %w", full, part, err)
   211  		}
   212  	}
   213  
   214  	a := make([]string, 0, len(aliases))
   215  	for _, alias := range aliases {
   216  		if !strings.Contains(alias, ".") {
   217  			if err := validateName(alias); err != nil {
   218  				return name{}, fmt.Errorf("avro: invalid name %q: %w", alias, err)
   219  			}
   220  			if ns == "" {
   221  				a = append(a, alias)
   222  				continue
   223  			}
   224  			a = append(a, ns+"."+alias)
   225  			continue
   226  		}
   227  
   228  		for _, part := range strings.Split(alias, ".") {
   229  			if err := validateName(part); err != nil {
   230  				return name{}, fmt.Errorf("avro: invalid name part %q in name %q: %w", full, part, err)
   231  			}
   232  		}
   233  		a = append(a, alias)
   234  	}
   235  
   236  	return name{
   237  		name:      n,
   238  		namespace: ns,
   239  		full:      full,
   240  		aliases:   a,
   241  	}, nil
   242  }
   243  
   244  // Name returns the name of a schema.
   245  func (n name) Name() string {
   246  	return n.name
   247  }
   248  
   249  // Namespace returns the namespace of a schema.
   250  func (n name) Namespace() string {
   251  	return n.namespace
   252  }
   253  
   254  // FullName returns the fully qualified name of a schema.
   255  func (n name) FullName() string {
   256  	return n.full
   257  }
   258  
   259  // Aliases returns the fully qualified aliases of a schema.
   260  func (n name) Aliases() []string {
   261  	return n.aliases
   262  }
   263  
   264  type fingerprinter struct {
   265  	fingerprint atomic.Value // [32]byte
   266  	cache       sync.Map     // map[FingerprintType][]byte
   267  }
   268  
   269  // Fingerprint returns the SHA256 fingerprint of the schema.
   270  func (f *fingerprinter) Fingerprint(stringer fmt.Stringer) [32]byte {
   271  	if v := f.fingerprint.Load(); v != nil {
   272  		return v.([32]byte)
   273  	}
   274  
   275  	fingerprint := sha256.Sum256([]byte(stringer.String()))
   276  	f.fingerprint.Store(fingerprint)
   277  	return fingerprint
   278  }
   279  
   280  // FingerprintUsing returns the fingerprint of the schema using the given algorithm or an error.
   281  func (f *fingerprinter) FingerprintUsing(typ FingerprintType, stringer fmt.Stringer) ([]byte, error) {
   282  	if v, ok := f.cache.Load(typ); ok {
   283  		return v.([]byte), nil
   284  	}
   285  
   286  	data := []byte(stringer.String())
   287  
   288  	var fingerprint []byte
   289  	switch typ {
   290  	case CRC64Avro:
   291  		h := crc64.Sum(data)
   292  		fingerprint = h[:]
   293  	case MD5:
   294  		h := md5.Sum(data)
   295  		fingerprint = h[:]
   296  	case SHA256:
   297  		h := sha256.Sum256(data)
   298  		fingerprint = h[:]
   299  	default:
   300  		return nil, fmt.Errorf("avro: unknown fingerprint algorithm %s", typ)
   301  	}
   302  
   303  	f.cache.Store(typ, fingerprint)
   304  	return fingerprint, nil
   305  }
   306  
   307  type cacheFingerprinter struct {
   308  	writerFingerprint *[32]byte
   309  
   310  	cache atomic.Value // [32]byte
   311  }
   312  
   313  // CacheFingerprint returns the SHA256 identity of the schema.
   314  func (i *cacheFingerprinter) CacheFingerprint(schema Schema, fn func() []byte) [32]byte {
   315  	if v := i.cache.Load(); v != nil {
   316  		return v.([32]byte)
   317  	}
   318  
   319  	if i.writerFingerprint == nil {
   320  		fp := schema.Fingerprint()
   321  		i.cache.Store(fp)
   322  		return fp
   323  	}
   324  
   325  	fp := schema.Fingerprint()
   326  	d := append([]byte{}, fp[:]...)
   327  	d = append(d, (*i.writerFingerprint)[:]...)
   328  	if fn != nil {
   329  		d = append(d, fn()...)
   330  	}
   331  	ident := sha256.Sum256(d)
   332  	i.cache.Store(ident)
   333  	return ident
   334  }
   335  
   336  type properties struct {
   337  	props map[string]any
   338  }
   339  
   340  func newProperties(props map[string]any, res []string) properties {
   341  	p := properties{props: map[string]any{}}
   342  	for k, v := range props {
   343  		if isReserved(res, k) {
   344  			continue
   345  		}
   346  		p.props[k] = v
   347  	}
   348  	return p
   349  }
   350  
   351  func isReserved(res []string, k string) bool {
   352  	for _, r := range res {
   353  		if k == r {
   354  			return true
   355  		}
   356  	}
   357  	return false
   358  }
   359  
   360  // Prop gets a property from the schema.
   361  func (p properties) Prop(name string) any {
   362  	if p.props == nil {
   363  		return nil
   364  	}
   365  
   366  	return p.props[name]
   367  }
   368  
   369  func (p properties) marshalPropertiesToJSON(buf *bytes.Buffer) error {
   370  	sortedPropertyKeys := make([]string, 0, len(p.props))
   371  	for k := range p.props {
   372  		sortedPropertyKeys = append(sortedPropertyKeys, k)
   373  	}
   374  	sort.Strings(sortedPropertyKeys)
   375  	for _, k := range sortedPropertyKeys {
   376  		vv, err := jsoniter.Marshal(p.props[k])
   377  		if err != nil {
   378  			return err
   379  		}
   380  		buf.WriteString(`,"` + k + `":`)
   381  		buf.Write(vv)
   382  	}
   383  	return nil
   384  }
   385  
   386  type schemaConfig struct {
   387  	aliases []string
   388  	doc     string
   389  	def     any
   390  	order   Order
   391  	props   map[string]any
   392  	wfp     *[32]byte
   393  }
   394  
   395  // SchemaOption is a function that sets a schema option.
   396  type SchemaOption func(*schemaConfig)
   397  
   398  // WithAliases sets the aliases on a schema.
   399  func WithAliases(aliases []string) SchemaOption {
   400  	return func(opts *schemaConfig) {
   401  		opts.aliases = aliases
   402  	}
   403  }
   404  
   405  // WithDoc sets the doc on a schema.
   406  func WithDoc(doc string) SchemaOption {
   407  	return func(opts *schemaConfig) {
   408  		opts.doc = doc
   409  	}
   410  }
   411  
   412  // WithDefault sets the default on a schema.
   413  func WithDefault(def any) SchemaOption {
   414  	return func(opts *schemaConfig) {
   415  		opts.def = def
   416  	}
   417  }
   418  
   419  // WithOrder sets the order on a schema.
   420  func WithOrder(order Order) SchemaOption {
   421  	return func(opts *schemaConfig) {
   422  		opts.order = order
   423  	}
   424  }
   425  
   426  // WithProps sets the properties on a schema.
   427  func WithProps(props map[string]any) SchemaOption {
   428  	return func(opts *schemaConfig) {
   429  		opts.props = props
   430  	}
   431  }
   432  
   433  func withWriterFingerprint(fp [32]byte) SchemaOption {
   434  	return func(opts *schemaConfig) {
   435  		opts.wfp = &fp
   436  	}
   437  }
   438  
   439  func withWriterFingerprintIfResolved(fp [32]byte, resolved bool) SchemaOption {
   440  	return func(opts *schemaConfig) {
   441  		if resolved {
   442  			opts.wfp = &fp
   443  		}
   444  	}
   445  }
   446  
   447  // PrimitiveSchema is an Avro primitive type schema.
   448  type PrimitiveSchema struct {
   449  	properties
   450  	fingerprinter
   451  	cacheFingerprinter
   452  
   453  	typ     Type
   454  	logical LogicalSchema
   455  
   456  	// encodedType is the type of the encoded value, if it is different from the typ.
   457  	// It's only used in the context of write-read schema resolution.
   458  	encodedType Type
   459  }
   460  
   461  // NewPrimitiveSchema creates a new PrimitiveSchema.
   462  func NewPrimitiveSchema(t Type, l LogicalSchema, opts ...SchemaOption) *PrimitiveSchema {
   463  	var cfg schemaConfig
   464  	for _, opt := range opts {
   465  		opt(&cfg)
   466  	}
   467  
   468  	return &PrimitiveSchema{
   469  		properties:         newProperties(cfg.props, schemaReserved),
   470  		cacheFingerprinter: cacheFingerprinter{writerFingerprint: cfg.wfp},
   471  		typ:                t,
   472  		logical:            l,
   473  	}
   474  }
   475  
   476  // Type returns the type of the schema.
   477  func (s *PrimitiveSchema) Type() Type {
   478  	return s.typ
   479  }
   480  
   481  // Logical returns the logical schema or nil.
   482  func (s *PrimitiveSchema) Logical() LogicalSchema {
   483  	return s.logical
   484  }
   485  
   486  // String returns the canonical form of the schema.
   487  func (s *PrimitiveSchema) String() string {
   488  	if s.logical == nil {
   489  		return `"` + string(s.typ) + `"`
   490  	}
   491  
   492  	return `{"type":"` + string(s.typ) + `",` + s.logical.String() + `}`
   493  }
   494  
   495  // MarshalJSON marshals the schema to json.
   496  func (s *PrimitiveSchema) MarshalJSON() ([]byte, error) {
   497  	if s.logical == nil && len(s.props) == 0 {
   498  		return jsoniter.Marshal(s.typ)
   499  	}
   500  
   501  	buf := new(bytes.Buffer)
   502  	buf.WriteString(`{"type":"` + string(s.typ) + `"`)
   503  	if s.logical != nil {
   504  		buf.WriteString(`,"logicalType":"` + string(s.logical.Type()) + `"`)
   505  		if d, ok := s.logical.(*DecimalLogicalSchema); ok {
   506  			buf.WriteString(`,"precision":` + strconv.Itoa(d.prec))
   507  			if d.scale > 0 {
   508  				buf.WriteString(`,"scale":` + strconv.Itoa(d.scale))
   509  			}
   510  		}
   511  	}
   512  	if err := s.marshalPropertiesToJSON(buf); err != nil {
   513  		return nil, err
   514  	}
   515  	buf.WriteString("}")
   516  	return buf.Bytes(), nil
   517  }
   518  
   519  // Fingerprint returns the SHA256 fingerprint of the schema.
   520  func (s *PrimitiveSchema) Fingerprint() [32]byte {
   521  	return s.fingerprinter.Fingerprint(s)
   522  }
   523  
   524  // FingerprintUsing returns the fingerprint of the schema using the given algorithm or an error.
   525  func (s *PrimitiveSchema) FingerprintUsing(typ FingerprintType) ([]byte, error) {
   526  	return s.fingerprinter.FingerprintUsing(typ, s)
   527  }
   528  
   529  // CacheFingerprint returns unique identity of the schema.
   530  func (s *PrimitiveSchema) CacheFingerprint() [32]byte {
   531  	return s.cacheFingerprinter.CacheFingerprint(s, nil)
   532  }
   533  
   534  // RecordSchema is an Avro record type schema.
   535  type RecordSchema struct {
   536  	name
   537  	properties
   538  	fingerprinter
   539  	cacheFingerprinter
   540  	isError bool
   541  	fields  []*Field
   542  	doc     string
   543  }
   544  
   545  // NewRecordSchema creates a new record schema instance.
   546  func NewRecordSchema(name, namespace string, fields []*Field, opts ...SchemaOption) (*RecordSchema, error) {
   547  	var cfg schemaConfig
   548  	for _, opt := range opts {
   549  		opt(&cfg)
   550  	}
   551  
   552  	n, err := newName(name, namespace, cfg.aliases)
   553  	if err != nil {
   554  		return nil, err
   555  	}
   556  
   557  	return &RecordSchema{
   558  		name:               n,
   559  		properties:         newProperties(cfg.props, schemaReserved),
   560  		cacheFingerprinter: cacheFingerprinter{writerFingerprint: cfg.wfp},
   561  		fields:             fields,
   562  		doc:                cfg.doc,
   563  	}, nil
   564  }
   565  
   566  // NewErrorRecordSchema creates a new error record schema instance.
   567  func NewErrorRecordSchema(name, namespace string, fields []*Field, opts ...SchemaOption) (*RecordSchema, error) {
   568  	rec, err := NewRecordSchema(name, namespace, fields, opts...)
   569  	if err != nil {
   570  		return nil, err
   571  	}
   572  
   573  	rec.isError = true
   574  
   575  	return rec, nil
   576  }
   577  
   578  // Type returns the type of the schema.
   579  func (s *RecordSchema) Type() Type {
   580  	return Record
   581  }
   582  
   583  // Doc returns the documentation of a record.
   584  func (s *RecordSchema) Doc() string {
   585  	return s.doc
   586  }
   587  
   588  // IsError determines is this is an error record.
   589  func (s *RecordSchema) IsError() bool {
   590  	return s.isError
   591  }
   592  
   593  // Fields returns the fields of a record.
   594  func (s *RecordSchema) Fields() []*Field {
   595  	return s.fields
   596  }
   597  
   598  // String returns the canonical form of the schema.
   599  func (s *RecordSchema) String() string {
   600  	typ := "record"
   601  	if s.isError {
   602  		typ = "error"
   603  	}
   604  
   605  	fields := ""
   606  	for _, f := range s.fields {
   607  		fields += f.String() + ","
   608  	}
   609  	if len(fields) > 0 {
   610  		fields = fields[:len(fields)-1]
   611  	}
   612  
   613  	return `{"name":"` + s.FullName() + `","type":"` + typ + `","fields":[` + fields + `]}`
   614  }
   615  
   616  // MarshalJSON marshals the schema to json.
   617  func (s *RecordSchema) MarshalJSON() ([]byte, error) {
   618  	buf := new(bytes.Buffer)
   619  	buf.WriteString(`{"name":"` + s.full + `"`)
   620  	if len(s.aliases) > 0 {
   621  		aliasesJSON, err := jsoniter.Marshal(s.aliases)
   622  		if err != nil {
   623  			return nil, err
   624  		}
   625  		buf.WriteString(`,"aliases":`)
   626  		buf.Write(aliasesJSON)
   627  	}
   628  	if s.doc != "" {
   629  		buf.WriteString(`,"doc":"` + s.doc + `"`)
   630  	}
   631  	if s.isError {
   632  		buf.WriteString(`,"type":"error"`)
   633  	} else {
   634  		buf.WriteString(`,"type":"record"`)
   635  	}
   636  	fieldsJSON, err := jsoniter.Marshal(s.fields)
   637  	if err != nil {
   638  		return nil, err
   639  	}
   640  	buf.WriteString(`,"fields":`)
   641  	buf.Write(fieldsJSON)
   642  	if err := s.marshalPropertiesToJSON(buf); err != nil {
   643  		return nil, err
   644  	}
   645  	buf.WriteString("}")
   646  	return buf.Bytes(), nil
   647  }
   648  
   649  // Fingerprint returns the SHA256 fingerprint of the schema.
   650  func (s *RecordSchema) Fingerprint() [32]byte {
   651  	return s.fingerprinter.Fingerprint(s)
   652  }
   653  
   654  // FingerprintUsing returns the fingerprint of the schema using the given algorithm or an error.
   655  func (s *RecordSchema) FingerprintUsing(typ FingerprintType) ([]byte, error) {
   656  	return s.fingerprinter.FingerprintUsing(typ, s)
   657  }
   658  
   659  // CacheFingerprint returns unique identity of the schema.
   660  func (s *RecordSchema) CacheFingerprint() [32]byte {
   661  	return s.cacheFingerprinter.CacheFingerprint(s, func() []byte {
   662  		var defs []any
   663  		for _, field := range s.fields {
   664  			if !field.HasDefault() {
   665  				continue
   666  			}
   667  			defs = append(defs, field.Default())
   668  		}
   669  		b, _ := jsoniter.Marshal(defs)
   670  		return b
   671  	})
   672  }
   673  
   674  // Field is an Avro record type field.
   675  type Field struct {
   676  	properties
   677  
   678  	name    string
   679  	aliases []string
   680  	doc     string
   681  	typ     Schema
   682  	hasDef  bool
   683  	def     any
   684  	order   Order
   685  
   686  	// action mainly used when decoding data that lack the field for schema evolution purposes.
   687  	action Action
   688  	// encodedDef mainly used when decoding data that lack the field for schema evolution purposes.
   689  	// Its value remains empty unless the field's encodeDefault function is called.
   690  	encodedDef atomic.Value
   691  }
   692  
   693  type noDef struct{}
   694  
   695  // NoDefault is used when no default exists for a field.
   696  var NoDefault = noDef{}
   697  
   698  // NewField creates a new field instance.
   699  func NewField(name string, typ Schema, opts ...SchemaOption) (*Field, error) {
   700  	cfg := schemaConfig{def: NoDefault}
   701  	for _, opt := range opts {
   702  		opt(&cfg)
   703  	}
   704  
   705  	if err := validateName(name); err != nil {
   706  		return nil, err
   707  	}
   708  	for _, a := range cfg.aliases {
   709  		if err := validateName(a); err != nil {
   710  			return nil, err
   711  		}
   712  	}
   713  
   714  	switch cfg.order {
   715  	case "":
   716  		cfg.order = Asc
   717  	case Asc, Desc, Ignore:
   718  	default:
   719  		return nil, fmt.Errorf("avro: field %q order %q is invalid", name, cfg.order)
   720  	}
   721  
   722  	f := &Field{
   723  		properties: newProperties(cfg.props, fieldReserved),
   724  		name:       name,
   725  		aliases:    cfg.aliases,
   726  		doc:        cfg.doc,
   727  		typ:        typ,
   728  		order:      cfg.order,
   729  	}
   730  
   731  	if cfg.def != NoDefault {
   732  		def, err := validateDefault(name, typ, cfg.def)
   733  		if err != nil {
   734  			return nil, err
   735  		}
   736  		f.def = def
   737  		f.hasDef = true
   738  	}
   739  
   740  	return f, nil
   741  }
   742  
   743  // Name returns the name of a field.
   744  func (f *Field) Name() string {
   745  	return f.name
   746  }
   747  
   748  // Aliases return the field aliases.
   749  func (f *Field) Aliases() []string {
   750  	return f.aliases
   751  }
   752  
   753  // Type returns the schema of a field.
   754  func (f *Field) Type() Schema {
   755  	return f.typ
   756  }
   757  
   758  // HasDefault determines if the field has a default value.
   759  func (f *Field) HasDefault() bool {
   760  	return f.hasDef
   761  }
   762  
   763  // Default returns the default of a field or nil.
   764  //
   765  // The only time a nil default is valid is for a Null Type.
   766  func (f *Field) Default() any {
   767  	if f.def == nullDefault {
   768  		return nil
   769  	}
   770  
   771  	return f.def
   772  }
   773  
   774  func (f *Field) encodeDefault(encode func(any) ([]byte, error)) ([]byte, error) {
   775  	if v := f.encodedDef.Load(); v != nil {
   776  		return v.([]byte), nil
   777  	}
   778  	if !f.hasDef {
   779  		return nil, fmt.Errorf("avro: '%s' field must have a non-empty default value", f.name)
   780  	}
   781  	if encode == nil {
   782  		return nil, fmt.Errorf("avro: failed to encode '%s' default value", f.name)
   783  	}
   784  	b, err := encode(f.Default())
   785  	if err != nil {
   786  		return nil, err
   787  	}
   788  	f.encodedDef.Store(b)
   789  
   790  	return b, nil
   791  }
   792  
   793  // Doc returns the documentation of a field.
   794  func (f *Field) Doc() string {
   795  	return f.doc
   796  }
   797  
   798  // Order returns the field order.
   799  func (f *Field) Order() Order {
   800  	return f.order
   801  }
   802  
   803  // String returns the canonical form of a field.
   804  func (f *Field) String() string {
   805  	return `{"name":"` + f.name + `","type":` + f.typ.String() + `}`
   806  }
   807  
   808  // MarshalJSON marshals the schema to json.
   809  func (f *Field) MarshalJSON() ([]byte, error) {
   810  	buf := new(bytes.Buffer)
   811  	buf.WriteString(`{"name":"` + f.name + `"`)
   812  	if len(f.aliases) > 0 {
   813  		aliasesJSON, err := jsoniter.Marshal(f.aliases)
   814  		if err != nil {
   815  			return nil, err
   816  		}
   817  		buf.WriteString(`,"aliases":`)
   818  		buf.Write(aliasesJSON)
   819  	}
   820  	if f.doc != "" {
   821  		buf.WriteString(`,"doc":"` + f.doc + `"`)
   822  	}
   823  	typeJSON, err := jsoniter.Marshal(f.typ)
   824  	if err != nil {
   825  		return nil, err
   826  	}
   827  	buf.WriteString(`,"type":`)
   828  	buf.Write(typeJSON)
   829  	if f.hasDef {
   830  		defaultValueJSON, err := jsoniter.Marshal(f.Default())
   831  		if err != nil {
   832  			return nil, err
   833  		}
   834  		buf.WriteString(`,"default":`)
   835  		buf.Write(defaultValueJSON)
   836  	}
   837  	if f.order != "" && f.order != Asc {
   838  		buf.WriteString(`,"order":"` + string(f.order) + `"`)
   839  	}
   840  	if err := f.marshalPropertiesToJSON(buf); err != nil {
   841  		return nil, err
   842  	}
   843  	buf.WriteString("}")
   844  	return buf.Bytes(), nil
   845  }
   846  
   847  // EnumSchema is an Avro enum type schema.
   848  type EnumSchema struct {
   849  	name
   850  	properties
   851  	fingerprinter
   852  	cacheFingerprinter
   853  
   854  	symbols []string
   855  	def     string
   856  	doc     string
   857  
   858  	// encodedSymbols is the symbols of the encoded value.
   859  	// It's only used in the context of write-read schema resolution.
   860  	encodedSymbols []string
   861  }
   862  
   863  // NewEnumSchema creates a new enum schema instance.
   864  func NewEnumSchema(name, namespace string, symbols []string, opts ...SchemaOption) (*EnumSchema, error) {
   865  	var cfg schemaConfig
   866  	for _, opt := range opts {
   867  		opt(&cfg)
   868  	}
   869  
   870  	n, err := newName(name, namespace, cfg.aliases)
   871  	if err != nil {
   872  		return nil, err
   873  	}
   874  
   875  	if len(symbols) == 0 {
   876  		return nil, errors.New("avro: enum must have a non-empty array of symbols")
   877  	}
   878  	for _, sym := range symbols {
   879  		if err = validateName(sym); err != nil {
   880  			return nil, fmt.Errorf("avro: invalid symbol %q", sym)
   881  		}
   882  	}
   883  
   884  	var def string
   885  	if d, ok := cfg.def.(string); ok && d != "" {
   886  		if !hasSymbol(symbols, d) {
   887  			return nil, fmt.Errorf("avro: symbol default %q must be a symbol", d)
   888  		}
   889  		def = d
   890  	}
   891  
   892  	return &EnumSchema{
   893  		name:               n,
   894  		properties:         newProperties(cfg.props, schemaReserved),
   895  		cacheFingerprinter: cacheFingerprinter{writerFingerprint: cfg.wfp},
   896  		symbols:            symbols,
   897  		def:                def,
   898  		doc:                cfg.doc,
   899  	}, nil
   900  }
   901  
   902  func hasSymbol(symbols []string, sym string) bool {
   903  	for _, s := range symbols {
   904  		if s == sym {
   905  			return true
   906  		}
   907  	}
   908  	return false
   909  }
   910  
   911  // Type returns the type of the schema.
   912  func (s *EnumSchema) Type() Type {
   913  	return Enum
   914  }
   915  
   916  // Doc returns the schema doc.
   917  func (s *EnumSchema) Doc() string {
   918  	return s.doc
   919  }
   920  
   921  // Symbols returns the symbols of an enum.
   922  func (s *EnumSchema) Symbols() []string {
   923  	return s.symbols
   924  }
   925  
   926  // Symbol returns the symbol for the given index.
   927  // It might return the default value in the context of write-read schema resolution.
   928  func (s *EnumSchema) Symbol(i int) (string, bool) {
   929  	resolv := len(s.encodedSymbols) > 0
   930  	symbols := s.symbols
   931  	if resolv {
   932  		// A different set of symbols is encoded.
   933  		symbols = s.encodedSymbols
   934  	}
   935  
   936  	if i < 0 || i >= len(symbols) {
   937  		return "", false
   938  	}
   939  
   940  	symbol := symbols[i]
   941  	if resolv && !hasSymbol(s.symbols, symbol) {
   942  		if !s.HasDefault() {
   943  			return "", false
   944  		}
   945  		return s.Default(), true
   946  	}
   947  	return symbol, true
   948  }
   949  
   950  // Default returns the default of an enum or an empty string.
   951  func (s *EnumSchema) Default() string {
   952  	return s.def
   953  }
   954  
   955  // HasDefault determines if the schema has a default value.
   956  func (s *EnumSchema) HasDefault() bool {
   957  	return s.def != ""
   958  }
   959  
   960  // String returns the canonical form of the schema.
   961  func (s *EnumSchema) String() string {
   962  	symbols := ""
   963  	for _, sym := range s.symbols {
   964  		symbols += `"` + sym + `",`
   965  	}
   966  	if len(symbols) > 0 {
   967  		symbols = symbols[:len(symbols)-1]
   968  	}
   969  
   970  	return `{"name":"` + s.FullName() + `","type":"enum","symbols":[` + symbols + `]}`
   971  }
   972  
   973  // MarshalJSON marshals the schema to json.
   974  func (s *EnumSchema) MarshalJSON() ([]byte, error) {
   975  	buf := new(bytes.Buffer)
   976  	buf.WriteString(`{"name":"` + s.full + `"`)
   977  	if len(s.aliases) > 0 {
   978  		aliasesJSON, err := jsoniter.Marshal(s.aliases)
   979  		if err != nil {
   980  			return nil, err
   981  		}
   982  		buf.WriteString(`,"aliases":`)
   983  		buf.Write(aliasesJSON)
   984  	}
   985  	if s.doc != "" {
   986  		buf.WriteString(`,"doc":"` + s.doc + `"`)
   987  	}
   988  	buf.WriteString(`,"type":"enum"`)
   989  	symbolsJSON, err := jsoniter.Marshal(s.symbols)
   990  	if err != nil {
   991  		return nil, err
   992  	}
   993  	buf.WriteString(`,"symbols":`)
   994  	buf.Write(symbolsJSON)
   995  	if s.def != "" {
   996  		buf.WriteString(`,"default":"` + s.def + `"`)
   997  	}
   998  	if err := s.marshalPropertiesToJSON(buf); err != nil {
   999  		return nil, err
  1000  	}
  1001  	buf.WriteString("}")
  1002  	return buf.Bytes(), nil
  1003  }
  1004  
  1005  // Fingerprint returns the SHA256 fingerprint of the schema.
  1006  func (s *EnumSchema) Fingerprint() [32]byte {
  1007  	return s.fingerprinter.Fingerprint(s)
  1008  }
  1009  
  1010  // FingerprintUsing returns the fingerprint of the schema using the given algorithm or an error.
  1011  func (s *EnumSchema) FingerprintUsing(typ FingerprintType) ([]byte, error) {
  1012  	return s.fingerprinter.FingerprintUsing(typ, s)
  1013  }
  1014  
  1015  // CacheFingerprint returns unique identity of the schema.
  1016  func (s *EnumSchema) CacheFingerprint() [32]byte {
  1017  	return s.cacheFingerprinter.CacheFingerprint(s, func() []byte {
  1018  		if !s.HasDefault() {
  1019  			return []byte{}
  1020  		}
  1021  		return []byte(s.Default())
  1022  	})
  1023  }
  1024  
  1025  // ArraySchema is an Avro array type schema.
  1026  type ArraySchema struct {
  1027  	properties
  1028  	fingerprinter
  1029  	cacheFingerprinter
  1030  
  1031  	items Schema
  1032  }
  1033  
  1034  // NewArraySchema creates an array schema instance.
  1035  func NewArraySchema(items Schema, opts ...SchemaOption) *ArraySchema {
  1036  	var cfg schemaConfig
  1037  	for _, opt := range opts {
  1038  		opt(&cfg)
  1039  	}
  1040  
  1041  	return &ArraySchema{
  1042  		properties:         newProperties(cfg.props, schemaReserved),
  1043  		cacheFingerprinter: cacheFingerprinter{writerFingerprint: cfg.wfp},
  1044  		items:              items,
  1045  	}
  1046  }
  1047  
  1048  // Type returns the type of the schema.
  1049  func (s *ArraySchema) Type() Type {
  1050  	return Array
  1051  }
  1052  
  1053  // Items returns the items schema of an array.
  1054  func (s *ArraySchema) Items() Schema {
  1055  	return s.items
  1056  }
  1057  
  1058  // String returns the canonical form of the schema.
  1059  func (s *ArraySchema) String() string {
  1060  	return `{"type":"array","items":` + s.items.String() + `}`
  1061  }
  1062  
  1063  // MarshalJSON marshals the schema to json.
  1064  func (s *ArraySchema) MarshalJSON() ([]byte, error) {
  1065  	buf := new(bytes.Buffer)
  1066  	buf.WriteString(`{"type":"array"`)
  1067  	itemsJSON, err := jsoniter.Marshal(s.items)
  1068  	if err != nil {
  1069  		return nil, err
  1070  	}
  1071  	buf.WriteString(`,"items":`)
  1072  	buf.Write(itemsJSON)
  1073  	if err = s.marshalPropertiesToJSON(buf); err != nil {
  1074  		return nil, err
  1075  	}
  1076  	buf.WriteString("}")
  1077  	return buf.Bytes(), nil
  1078  }
  1079  
  1080  // Fingerprint returns the SHA256 fingerprint of the schema.
  1081  func (s *ArraySchema) Fingerprint() [32]byte {
  1082  	return s.fingerprinter.Fingerprint(s)
  1083  }
  1084  
  1085  // FingerprintUsing returns the fingerprint of the schema using the given algorithm or an error.
  1086  func (s *ArraySchema) FingerprintUsing(typ FingerprintType) ([]byte, error) {
  1087  	return s.fingerprinter.FingerprintUsing(typ, s)
  1088  }
  1089  
  1090  // CacheFingerprint returns unique identity of the schema.
  1091  func (s *ArraySchema) CacheFingerprint() [32]byte {
  1092  	return s.cacheFingerprinter.CacheFingerprint(s, nil)
  1093  }
  1094  
  1095  // MapSchema is an Avro map type schema.
  1096  type MapSchema struct {
  1097  	properties
  1098  	fingerprinter
  1099  	cacheFingerprinter
  1100  
  1101  	values Schema
  1102  }
  1103  
  1104  // NewMapSchema creates a map schema instance.
  1105  func NewMapSchema(values Schema, opts ...SchemaOption) *MapSchema {
  1106  	var cfg schemaConfig
  1107  	for _, opt := range opts {
  1108  		opt(&cfg)
  1109  	}
  1110  
  1111  	return &MapSchema{
  1112  		properties:         newProperties(cfg.props, schemaReserved),
  1113  		cacheFingerprinter: cacheFingerprinter{writerFingerprint: cfg.wfp},
  1114  		values:             values,
  1115  	}
  1116  }
  1117  
  1118  // Type returns the type of the schema.
  1119  func (s *MapSchema) Type() Type {
  1120  	return Map
  1121  }
  1122  
  1123  // Values returns the values schema of a map.
  1124  func (s *MapSchema) Values() Schema {
  1125  	return s.values
  1126  }
  1127  
  1128  // String returns the canonical form of the schema.
  1129  func (s *MapSchema) String() string {
  1130  	return `{"type":"map","values":` + s.values.String() + `}`
  1131  }
  1132  
  1133  // MarshalJSON marshals the schema to json.
  1134  func (s *MapSchema) MarshalJSON() ([]byte, error) {
  1135  	buf := new(bytes.Buffer)
  1136  	buf.WriteString(`{"type":"map"`)
  1137  	valuesJSON, err := jsoniter.Marshal(s.values)
  1138  	if err != nil {
  1139  		return nil, err
  1140  	}
  1141  	buf.WriteString(`,"values":`)
  1142  	buf.Write(valuesJSON)
  1143  	if err := s.marshalPropertiesToJSON(buf); err != nil {
  1144  		return nil, err
  1145  	}
  1146  	buf.WriteString("}")
  1147  	return buf.Bytes(), nil
  1148  }
  1149  
  1150  // Fingerprint returns the SHA256 fingerprint of the schema.
  1151  func (s *MapSchema) Fingerprint() [32]byte {
  1152  	return s.fingerprinter.Fingerprint(s)
  1153  }
  1154  
  1155  // FingerprintUsing returns the fingerprint of the schema using the given algorithm or an error.
  1156  func (s *MapSchema) FingerprintUsing(typ FingerprintType) ([]byte, error) {
  1157  	return s.fingerprinter.FingerprintUsing(typ, s)
  1158  }
  1159  
  1160  // CacheFingerprint returns unique identity of the schema.
  1161  func (s *MapSchema) CacheFingerprint() [32]byte {
  1162  	return s.cacheFingerprinter.CacheFingerprint(s, nil)
  1163  }
  1164  
  1165  // UnionSchema is an Avro union type schema.
  1166  type UnionSchema struct {
  1167  	fingerprinter
  1168  	cacheFingerprinter
  1169  
  1170  	types Schemas
  1171  }
  1172  
  1173  // NewUnionSchema creates a union schema instance.
  1174  func NewUnionSchema(types []Schema, opts ...SchemaOption) (*UnionSchema, error) {
  1175  	var cfg schemaConfig
  1176  	for _, opt := range opts {
  1177  		opt(&cfg)
  1178  	}
  1179  
  1180  	seen := map[string]bool{}
  1181  	for _, schema := range types {
  1182  		if schema.Type() == Union {
  1183  			return nil, errors.New("avro: union type cannot be a union")
  1184  		}
  1185  
  1186  		strType := schemaTypeName(schema)
  1187  
  1188  		if seen[strType] {
  1189  			return nil, errors.New("avro: union type must be unique")
  1190  		}
  1191  		seen[strType] = true
  1192  	}
  1193  
  1194  	return &UnionSchema{
  1195  		cacheFingerprinter: cacheFingerprinter{writerFingerprint: cfg.wfp},
  1196  		types:              types,
  1197  	}, nil
  1198  }
  1199  
  1200  // Type returns the type of the schema.
  1201  func (s *UnionSchema) Type() Type {
  1202  	return Union
  1203  }
  1204  
  1205  // Types returns the types of a union.
  1206  func (s *UnionSchema) Types() Schemas {
  1207  	return s.types
  1208  }
  1209  
  1210  // Nullable returns the Schema if the union is nullable, otherwise nil.
  1211  func (s *UnionSchema) Nullable() bool {
  1212  	if len(s.types) != 2 || s.types[0].Type() != Null && s.types[1].Type() != Null {
  1213  		return false
  1214  	}
  1215  
  1216  	return true
  1217  }
  1218  
  1219  // Indices returns the index of the null and type schemas for a
  1220  // nullable schema. For non-nullable schemas 0 is returned for
  1221  // both.
  1222  func (s *UnionSchema) Indices() (null, typ int) {
  1223  	if !s.Nullable() {
  1224  		return 0, 0
  1225  	}
  1226  	if s.types[0].Type() == Null {
  1227  		return 0, 1
  1228  	}
  1229  	return 1, 0
  1230  }
  1231  
  1232  // String returns the canonical form of the schema.
  1233  func (s *UnionSchema) String() string {
  1234  	types := ""
  1235  	for _, typ := range s.types {
  1236  		types += typ.String() + ","
  1237  	}
  1238  	if len(types) > 0 {
  1239  		types = types[:len(types)-1]
  1240  	}
  1241  
  1242  	return `[` + types + `]`
  1243  }
  1244  
  1245  // MarshalJSON marshals the schema to json.
  1246  func (s *UnionSchema) MarshalJSON() ([]byte, error) {
  1247  	return jsoniter.Marshal(s.types)
  1248  }
  1249  
  1250  // Fingerprint returns the SHA256 fingerprint of the schema.
  1251  func (s *UnionSchema) Fingerprint() [32]byte {
  1252  	return s.fingerprinter.Fingerprint(s)
  1253  }
  1254  
  1255  // FingerprintUsing returns the fingerprint of the schema using the given algorithm or an error.
  1256  func (s *UnionSchema) FingerprintUsing(typ FingerprintType) ([]byte, error) {
  1257  	return s.fingerprinter.FingerprintUsing(typ, s)
  1258  }
  1259  
  1260  // CacheFingerprint returns unique identity of the schema.
  1261  func (s *UnionSchema) CacheFingerprint() [32]byte {
  1262  	return s.cacheFingerprinter.CacheFingerprint(s, nil)
  1263  }
  1264  
  1265  // FixedSchema is an Avro fixed type schema.
  1266  type FixedSchema struct {
  1267  	name
  1268  	properties
  1269  	fingerprinter
  1270  	cacheFingerprinter
  1271  
  1272  	size    int
  1273  	logical LogicalSchema
  1274  }
  1275  
  1276  // NewFixedSchema creates a new fixed schema instance.
  1277  func NewFixedSchema(
  1278  	name, namespace string,
  1279  	size int,
  1280  	logical LogicalSchema,
  1281  	opts ...SchemaOption,
  1282  ) (*FixedSchema, error) {
  1283  	var cfg schemaConfig
  1284  	for _, opt := range opts {
  1285  		opt(&cfg)
  1286  	}
  1287  
  1288  	n, err := newName(name, namespace, cfg.aliases)
  1289  	if err != nil {
  1290  		return nil, err
  1291  	}
  1292  
  1293  	return &FixedSchema{
  1294  		name:               n,
  1295  		properties:         newProperties(cfg.props, schemaReserved),
  1296  		cacheFingerprinter: cacheFingerprinter{writerFingerprint: cfg.wfp},
  1297  		size:               size,
  1298  		logical:            logical,
  1299  	}, nil
  1300  }
  1301  
  1302  // Type returns the type of the schema.
  1303  func (s *FixedSchema) Type() Type {
  1304  	return Fixed
  1305  }
  1306  
  1307  // Size returns the number of bytes of the fixed schema.
  1308  func (s *FixedSchema) Size() int {
  1309  	return s.size
  1310  }
  1311  
  1312  // Logical returns the logical schema or nil.
  1313  func (s *FixedSchema) Logical() LogicalSchema {
  1314  	return s.logical
  1315  }
  1316  
  1317  // String returns the canonical form of the schema.
  1318  func (s *FixedSchema) String() string {
  1319  	size := strconv.Itoa(s.size)
  1320  
  1321  	var logical string
  1322  	if s.logical != nil {
  1323  		logical = "," + s.logical.String()
  1324  	}
  1325  
  1326  	return `{"name":"` + s.FullName() + `","type":"fixed","size":` + size + logical + `}`
  1327  }
  1328  
  1329  // MarshalJSON marshals the schema to json.
  1330  func (s *FixedSchema) MarshalJSON() ([]byte, error) {
  1331  	buf := new(bytes.Buffer)
  1332  	buf.WriteString(`{"name":"` + s.full + `"`)
  1333  	if len(s.aliases) > 0 {
  1334  		aliasesJSON, err := jsoniter.Marshal(s.aliases)
  1335  		if err != nil {
  1336  			return nil, err
  1337  		}
  1338  		buf.WriteString(`,"aliases":`)
  1339  		buf.Write(aliasesJSON)
  1340  	}
  1341  	buf.WriteString(`,"type":"fixed"`)
  1342  	buf.WriteString(`,"size":` + strconv.Itoa(s.size))
  1343  	if s.logical != nil {
  1344  		buf.WriteString(`,"logicalType":"` + string(s.logical.Type()) + `"`)
  1345  		if d, ok := s.logical.(*DecimalLogicalSchema); ok {
  1346  			buf.WriteString(`,"precision":` + strconv.Itoa(d.prec))
  1347  			if d.scale > 0 {
  1348  				buf.WriteString(`,"scale":` + strconv.Itoa(d.scale))
  1349  			}
  1350  		}
  1351  	}
  1352  	if err := s.marshalPropertiesToJSON(buf); err != nil {
  1353  		return nil, err
  1354  	}
  1355  	buf.WriteString("}")
  1356  	return buf.Bytes(), nil
  1357  }
  1358  
  1359  // Fingerprint returns the SHA256 fingerprint of the schema.
  1360  func (s *FixedSchema) Fingerprint() [32]byte {
  1361  	return s.fingerprinter.Fingerprint(s)
  1362  }
  1363  
  1364  // FingerprintUsing returns the fingerprint of the schema using the given algorithm or an error.
  1365  func (s *FixedSchema) FingerprintUsing(typ FingerprintType) ([]byte, error) {
  1366  	return s.fingerprinter.FingerprintUsing(typ, s)
  1367  }
  1368  
  1369  // CacheFingerprint returns unique identity of the schema.
  1370  func (s *FixedSchema) CacheFingerprint() [32]byte {
  1371  	return s.cacheFingerprinter.CacheFingerprint(s, nil)
  1372  }
  1373  
  1374  // NullSchema is an Avro null type schema.
  1375  type NullSchema struct {
  1376  	fingerprinter
  1377  }
  1378  
  1379  // Type returns the type of the schema.
  1380  func (s *NullSchema) Type() Type {
  1381  	return Null
  1382  }
  1383  
  1384  // String returns the canonical form of the schema.
  1385  func (s *NullSchema) String() string {
  1386  	return `"null"`
  1387  }
  1388  
  1389  // MarshalJSON marshals the schema to json.
  1390  func (s *NullSchema) MarshalJSON() ([]byte, error) {
  1391  	return []byte(`"null"`), nil
  1392  }
  1393  
  1394  // Fingerprint returns the SHA256 fingerprint of the schema.
  1395  func (s *NullSchema) Fingerprint() [32]byte {
  1396  	return s.fingerprinter.Fingerprint(s)
  1397  }
  1398  
  1399  // FingerprintUsing returns the fingerprint of the schema using the given algorithm or an error.
  1400  func (s *NullSchema) FingerprintUsing(typ FingerprintType) ([]byte, error) {
  1401  	return s.fingerprinter.FingerprintUsing(typ, s)
  1402  }
  1403  
  1404  // CacheFingerprint returns unique identity of the schema.
  1405  func (s *NullSchema) CacheFingerprint() [32]byte {
  1406  	return s.Fingerprint()
  1407  }
  1408  
  1409  // RefSchema is a reference to a named Avro schema.
  1410  type RefSchema struct {
  1411  	actual NamedSchema
  1412  }
  1413  
  1414  // NewRefSchema creates a ref schema instance.
  1415  func NewRefSchema(schema NamedSchema) *RefSchema {
  1416  	return &RefSchema{
  1417  		actual: schema,
  1418  	}
  1419  }
  1420  
  1421  // Type returns the type of the schema.
  1422  func (s *RefSchema) Type() Type {
  1423  	return Ref
  1424  }
  1425  
  1426  // Schema returns the schema being referenced.
  1427  func (s *RefSchema) Schema() NamedSchema {
  1428  	return s.actual
  1429  }
  1430  
  1431  // String returns the canonical form of the schema.
  1432  func (s *RefSchema) String() string {
  1433  	return `"` + s.actual.FullName() + `"`
  1434  }
  1435  
  1436  // MarshalJSON marshals the schema to json.
  1437  func (s *RefSchema) MarshalJSON() ([]byte, error) {
  1438  	return []byte(`"` + s.actual.FullName() + `"`), nil
  1439  }
  1440  
  1441  // Fingerprint returns the SHA256 fingerprint of the schema.
  1442  func (s *RefSchema) Fingerprint() [32]byte {
  1443  	return s.actual.Fingerprint()
  1444  }
  1445  
  1446  // FingerprintUsing returns the fingerprint of the schema using the given algorithm or an error.
  1447  func (s *RefSchema) FingerprintUsing(typ FingerprintType) ([]byte, error) {
  1448  	return s.actual.FingerprintUsing(typ)
  1449  }
  1450  
  1451  // CacheFingerprint returns unique identity of the schema.
  1452  func (s *RefSchema) CacheFingerprint() [32]byte {
  1453  	return s.actual.CacheFingerprint()
  1454  }
  1455  
  1456  // PrimitiveLogicalSchema is a logical type with no properties.
  1457  type PrimitiveLogicalSchema struct {
  1458  	typ LogicalType
  1459  }
  1460  
  1461  // NewPrimitiveLogicalSchema creates a new primitive logical schema instance.
  1462  func NewPrimitiveLogicalSchema(typ LogicalType) *PrimitiveLogicalSchema {
  1463  	return &PrimitiveLogicalSchema{
  1464  		typ: typ,
  1465  	}
  1466  }
  1467  
  1468  // Type returns the type of the logical schema.
  1469  func (s *PrimitiveLogicalSchema) Type() LogicalType {
  1470  	return s.typ
  1471  }
  1472  
  1473  // String returns the canonical form of the logical schema.
  1474  func (s *PrimitiveLogicalSchema) String() string {
  1475  	return `"logicalType":"` + string(s.typ) + `"`
  1476  }
  1477  
  1478  // DecimalLogicalSchema is a decimal logical type.
  1479  type DecimalLogicalSchema struct {
  1480  	prec  int
  1481  	scale int
  1482  }
  1483  
  1484  // NewDecimalLogicalSchema creates a new decimal logical schema instance.
  1485  func NewDecimalLogicalSchema(prec, scale int) *DecimalLogicalSchema {
  1486  	return &DecimalLogicalSchema{
  1487  		prec:  prec,
  1488  		scale: scale,
  1489  	}
  1490  }
  1491  
  1492  // Type returns the type of the logical schema.
  1493  func (s *DecimalLogicalSchema) Type() LogicalType {
  1494  	return Decimal
  1495  }
  1496  
  1497  // Precision returns the precision of the decimal logical schema.
  1498  func (s *DecimalLogicalSchema) Precision() int {
  1499  	return s.prec
  1500  }
  1501  
  1502  // Scale returns the scale of the decimal logical schema.
  1503  func (s *DecimalLogicalSchema) Scale() int {
  1504  	return s.scale
  1505  }
  1506  
  1507  // String returns the canonical form of the logical schema.
  1508  func (s *DecimalLogicalSchema) String() string {
  1509  	var scale string
  1510  	if s.scale > 0 {
  1511  		scale = `,"scale":` + strconv.Itoa(s.scale)
  1512  	}
  1513  	precision := strconv.Itoa(s.prec)
  1514  
  1515  	return `"logicalType":"` + string(Decimal) + `","precision":` + precision + scale
  1516  }
  1517  
  1518  func invalidNameFirstChar(r rune) bool {
  1519  	return (r < 'A' || r > 'Z') && (r < 'a' || r > 'z') && r != '_'
  1520  }
  1521  
  1522  func invalidNameOtherChar(r rune) bool {
  1523  	return invalidNameFirstChar(r) && (r < '0' || r > '9')
  1524  }
  1525  
  1526  func validateName(name string) error {
  1527  	if name == "" {
  1528  		return errors.New("name must be a non-empty")
  1529  	}
  1530  
  1531  	if strings.IndexFunc(name[:1], invalidNameFirstChar) > -1 {
  1532  		return fmt.Errorf("invalid name %s", name)
  1533  	}
  1534  	if strings.IndexFunc(name[1:], invalidNameOtherChar) > -1 {
  1535  		return fmt.Errorf("invalid name %s", name)
  1536  	}
  1537  
  1538  	return nil
  1539  }
  1540  
  1541  func validateDefault(name string, schema Schema, def any) (any, error) {
  1542  	def, ok := isValidDefault(schema, def)
  1543  	if !ok {
  1544  		return nil, fmt.Errorf("avro: invalid default for field %s. %+v not a %s", name, def, schema.Type())
  1545  	}
  1546  	return def, nil
  1547  }
  1548  
  1549  func isValidDefault(schema Schema, def any) (any, bool) {
  1550  	switch schema.Type() {
  1551  	case Ref:
  1552  		ref := schema.(*RefSchema)
  1553  		return isValidDefault(ref.Schema(), def)
  1554  	case Null:
  1555  		return nullDefault, def == nil
  1556  	case Enum:
  1557  		v, ok := def.(string)
  1558  		if !ok || len(v) == 0 {
  1559  			return def, false
  1560  		}
  1561  
  1562  		var found bool
  1563  		for _, sym := range schema.(*EnumSchema).symbols {
  1564  			if def == sym {
  1565  				found = true
  1566  				break
  1567  			}
  1568  		}
  1569  		return def, found
  1570  	case String:
  1571  		if _, ok := def.(string); ok {
  1572  			return def, true
  1573  		}
  1574  	case Bytes, Fixed:
  1575  		// Spec: Default values for bytes and fixed fields are JSON strings,
  1576  		// where Unicode code points 0-255 are mapped to unsigned 8-bit byte values 0-255.
  1577  		if d, ok := def.(string); ok {
  1578  			if b, ok := isValidDefaultBytes(d); ok {
  1579  				if schema.Type() == Fixed {
  1580  					return byteSliceToArray(b, schema.(*FixedSchema).Size()), true
  1581  				}
  1582  				return b, true
  1583  			}
  1584  		}
  1585  	case Boolean:
  1586  		if _, ok := def.(bool); ok {
  1587  			return def, true
  1588  		}
  1589  	case Int:
  1590  		if i, ok := def.(int8); ok {
  1591  			return int(i), true
  1592  		}
  1593  		if i, ok := def.(int16); ok {
  1594  			return int(i), true
  1595  		}
  1596  		if i, ok := def.(int32); ok {
  1597  			return int(i), true
  1598  		}
  1599  		if _, ok := def.(int); ok {
  1600  			return def, true
  1601  		}
  1602  		if f, ok := def.(float64); ok {
  1603  			return int(f), true
  1604  		}
  1605  	case Long:
  1606  		if _, ok := def.(int64); ok {
  1607  			return def, true
  1608  		}
  1609  		if f, ok := def.(float64); ok {
  1610  			return int64(f), true
  1611  		}
  1612  	case Float:
  1613  		if _, ok := def.(float32); ok {
  1614  			return def, true
  1615  		}
  1616  		if f, ok := def.(float64); ok {
  1617  			return float32(f), true
  1618  		}
  1619  	case Double:
  1620  		if _, ok := def.(float64); ok {
  1621  			return def, true
  1622  		}
  1623  	case Array:
  1624  		arr, ok := def.([]any)
  1625  		if !ok {
  1626  			return nil, false
  1627  		}
  1628  
  1629  		as := schema.(*ArraySchema)
  1630  		for i, v := range arr {
  1631  			v, ok := isValidDefault(as.Items(), v)
  1632  			if !ok {
  1633  				return nil, false
  1634  			}
  1635  			arr[i] = v
  1636  		}
  1637  		return arr, true
  1638  	case Map:
  1639  		m, ok := def.(map[string]any)
  1640  		if !ok {
  1641  			return nil, false
  1642  		}
  1643  
  1644  		ms := schema.(*MapSchema)
  1645  		for k, v := range m {
  1646  			v, ok := isValidDefault(ms.Values(), v)
  1647  			if !ok {
  1648  				return nil, false
  1649  			}
  1650  
  1651  			m[k] = v
  1652  		}
  1653  		return m, true
  1654  	case Union:
  1655  		unionSchema := schema.(*UnionSchema)
  1656  		return isValidDefault(unionSchema.Types()[0], def)
  1657  	case Record:
  1658  		m, ok := def.(map[string]any)
  1659  		if !ok {
  1660  			return nil, false
  1661  		}
  1662  
  1663  		for _, field := range schema.(*RecordSchema).Fields() {
  1664  			fieldDef := field.Default()
  1665  			if newDef, ok := m[field.Name()]; ok {
  1666  				fieldDef = newDef
  1667  			}
  1668  
  1669  			v, ok := isValidDefault(field.Type(), fieldDef)
  1670  			if !ok {
  1671  				return nil, false
  1672  			}
  1673  
  1674  			m[field.Name()] = v
  1675  		}
  1676  		return m, true
  1677  	}
  1678  	return nil, false
  1679  }
  1680  
  1681  func schemaTypeName(schema Schema) string {
  1682  	if schema.Type() == Ref {
  1683  		schema = schema.(*RefSchema).Schema()
  1684  	}
  1685  
  1686  	if n, ok := schema.(NamedSchema); ok {
  1687  		return n.FullName()
  1688  	}
  1689  
  1690  	sname := string(schema.Type())
  1691  	if lt := getLogicalType(schema); lt != "" {
  1692  		sname += "." + string(lt)
  1693  	}
  1694  	return sname
  1695  }
  1696  
  1697  func isValidDefaultBytes(def string) ([]byte, bool) {
  1698  	runes := []rune(def)
  1699  	l := len(runes)
  1700  	b := make([]byte, l)
  1701  	for i := 0; i < l; i++ {
  1702  		if runes[i] < 0 || runes[i] > 255 {
  1703  			return nil, false
  1704  		}
  1705  		b[i] = byte(runes[i])
  1706  	}
  1707  	return b, true
  1708  }