github.com/hasnat/dolt/go@v0.0.0-20210628190320-9eb5d843fbb7/store/marshal/encode.go (about)

     1  // Copyright 2019 Dolthub, Inc.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  //
    15  // This file incorporates work covered by the following copyright and
    16  // permission notice:
    17  //
    18  // Copyright 2016 Attic Labs, Inc. All rights reserved.
    19  // Licensed under the Apache License, version 2.0:
    20  // http://www.apache.org/licenses/LICENSE-2.0
    21  
    22  // Package marshal implements encoding and decoding of Noms values. The mapping
    23  // between Noms objects and Go values is described  in the documentation for the
    24  // Marshal and Unmarshal functions.
    25  package marshal
    26  
    27  import (
    28  	"context"
    29  	"fmt"
    30  	"reflect"
    31  	"sort"
    32  	"strings"
    33  	"sync"
    34  
    35  	"github.com/dolthub/dolt/go/store/types"
    36  )
    37  
    38  // Marshal converts a Go value to a Noms value.
    39  //
    40  // Marshal traverses the value v recursively. Marshal uses the following
    41  // type-dependent encodings:
    42  //
    43  // Boolean values are encoded as Noms types.Bool.
    44  //
    45  // Floating point and integer values are encoded as Noms types.Float. At the
    46  // moment this might lead to some loss in precision because types.Float
    47  // currently takes a float64.
    48  //
    49  // String values are encoded as Noms types.String.
    50  //
    51  // Slices and arrays are encoded as Noms types.List by default. If a
    52  // field is tagged with `noms:"set", it will be encoded as Noms types.Set
    53  // instead.
    54  //
    55  // Maps are encoded as Noms types.Map, or a types.Set if the value type is
    56  // struct{} and the field is tagged with `noms:"set"`.
    57  //
    58  // Struct values are encoded as Noms structs (types.Struct). Each exported Go
    59  // struct field becomes a member of the Noms struct unless
    60  //   - The field's tag is "-"
    61  //   - The field is empty and its tag specifies the "omitempty" option.
    62  //   - The field has the "original" tag, in which case the field is used as an
    63  //     initial value onto which the fields of the Go type are added. When
    64  //     combined with the corresponding support for "original" in Unmarshal(),
    65  //     this allows one to find and modify any values of a known subtype.
    66  //
    67  // Additionally, user-defined types can implement the Marshaler interface to
    68  // provide a custom encoding.
    69  //
    70  // The empty values are false, 0, any nil pointer or interface value, and any
    71  // array, slice, map, or string of length zero.
    72  //
    73  // The Noms struct default field name is the Go struct field name where the
    74  // first character is lower cased, but can be specified in the Go struct field's
    75  // tag value. The "noms" key in the Go struct field's tag value is the field
    76  // name. Examples:
    77  //
    78  //   // Field is ignored.
    79  //   Field int `noms:"-"`
    80  //
    81  //   // Field appears in a Noms struct as field "myName".
    82  //   MyName int
    83  //
    84  //   // Field appears in a Noms struct as key "myName".
    85  //   Field int `noms:"myName"`
    86  //
    87  //   // Field appears in a Noms struct as key "myName" and the field is
    88  //   //  omitted from the object if its value is empty, as defined above.
    89  //   Field int `noms:"myName,omitempty"
    90  //
    91  //   // Field appears in a Noms struct as key "field" and the field is
    92  //   //  omitted from the object if its value is empty, as defined above.
    93  //   Field int `noms:",omitempty"
    94  //
    95  // The name of the Noms struct is the name of the Go struct where the first
    96  // character is changed to upper case. You can also implement the
    97  // StructNameMarshaler interface to get more control over the actual struct
    98  // name.
    99  //
   100  // Anonymous struct fields are usually marshaled as if their inner exported
   101  // fields were fields in the outer struct, subject to the usual Go visibility.
   102  // An anonymous struct field with a name given in its Noms tag is treated as
   103  // having that name, rather than being anonymous.
   104  //
   105  // Noms values (values implementing types.Value) are copied over without any
   106  // change.
   107  //
   108  // When marshalling interface{} the dynamic type is used.
   109  //
   110  // Go pointers, complex, function are not supported. Attempting to encode such a
   111  // value causes Marshal to return an UnsupportedTypeError.
   112  func Marshal(ctx context.Context, vrw types.ValueReadWriter, v interface{}) (types.Value, error) {
   113  	return MarshalOpt(ctx, vrw, v, Opt{})
   114  }
   115  
   116  // MarshalOpt is like Marshal but provides additional options.
   117  func MarshalOpt(ctx context.Context, vrw types.ValueReadWriter, v interface{}, opt Opt) (nomsValue types.Value, err error) {
   118  	nomsValue, err = marshalOpt(ctx, vrw, v, opt)
   119  	return nomsValue, err
   120  }
   121  
   122  // MustMarshalOpt is like MustMarshal, but with additional options.
   123  func marshalOpt(ctx context.Context, vrw types.ValueReadWriter, v interface{}, opt Opt) (types.Value, error) {
   124  	rv := reflect.ValueOf(v)
   125  	nt := nomsTags{
   126  		set: opt.Set,
   127  	}
   128  	encoder, err := typeEncoder(vrw.Format(), rv.Type(), map[string]reflect.Type{}, nt)
   129  
   130  	if err != nil {
   131  		return nil, err
   132  	}
   133  
   134  	return encoder(ctx, rv, vrw)
   135  }
   136  
   137  // Marshaler is an interface types can implement to provide their own encoding.
   138  type Marshaler interface {
   139  	// MarshalNoms returns the Noms Value encoding of a type, or an error.
   140  	// nil is not a valid return val - if both val and err are nil, Marshal will
   141  	// panic.
   142  	MarshalNoms(vrw types.ValueReadWriter) (val types.Value, err error)
   143  }
   144  
   145  // StructNameMarshaler is an interface that can be implemented to define the
   146  // name of a Noms struct.
   147  type StructNameMarshaler interface {
   148  	MarshalNomsStructName() string
   149  }
   150  
   151  // UnsupportedTypeError is returned by encode when attempting to encode a type
   152  // that isn't supported.
   153  type UnsupportedTypeError struct {
   154  	Type    reflect.Type
   155  	Message string
   156  }
   157  
   158  func (e *UnsupportedTypeError) Error() string {
   159  	msg := e.Message
   160  	if msg == "" {
   161  		msg = "Type is not supported"
   162  	}
   163  	return msg + ", type: " + e.Type.String()
   164  }
   165  
   166  // InvalidTagError is returned by encode and decode when the struct field tag is
   167  // invalid. For example if the field name is not a valid Noms struct field name.
   168  type InvalidTagError struct {
   169  	message string
   170  }
   171  
   172  func (e *InvalidTagError) Error() string {
   173  	return e.message
   174  }
   175  
   176  // marshalNomsError wraps errors from Marshaler.MarshalNoms. These should be
   177  // unwrapped and never leak to the caller of Marshal.
   178  type marshalNomsError struct {
   179  	err error
   180  }
   181  
   182  func (e *marshalNomsError) Error() string {
   183  	return e.err.Error()
   184  }
   185  
   186  type Opt struct {
   187  	// Marshal []T or map[T]struct{} to Set<T>, or Unmarhsal Set<T> to map[T]struct{}.
   188  	Set bool
   189  }
   190  
   191  type nomsTags struct {
   192  	name      string
   193  	omitEmpty bool
   194  	original  bool
   195  	set       bool
   196  	skip      bool
   197  	hasName   bool
   198  }
   199  
   200  var nomsValueInterface = reflect.TypeOf((*types.Value)(nil)).Elem()
   201  var emptyInterface = reflect.TypeOf((*interface{})(nil)).Elem()
   202  var marshalerInterface = reflect.TypeOf((*Marshaler)(nil)).Elem()
   203  var structNameMarshalerInterface = reflect.TypeOf((*StructNameMarshaler)(nil)).Elem()
   204  
   205  type encoderFunc func(ctx context.Context, v reflect.Value, vrw types.ValueReadWriter) (types.Value, error)
   206  
   207  func boolEncoder(ctx context.Context, v reflect.Value, vrw types.ValueReadWriter) (types.Value, error) {
   208  	return types.Bool(v.Bool()), nil
   209  }
   210  
   211  func float64Encoder(ctx context.Context, v reflect.Value, vrw types.ValueReadWriter) (types.Value, error) {
   212  	return types.Float(v.Float()), nil
   213  }
   214  
   215  func intEncoder(ctx context.Context, v reflect.Value, vrw types.ValueReadWriter) (types.Value, error) {
   216  	// TODO: encoding types.Int as types.Float is lossy, but will recquire a migration to change
   217  	return types.Float(float64(v.Int())), nil
   218  }
   219  
   220  func uintEncoder(ctx context.Context, v reflect.Value, vrw types.ValueReadWriter) (types.Value, error) {
   221  	// TODO: encoding types.Int as types.Uint is lossy, but will recquire a migration to change
   222  	return types.Float(float64(v.Uint())), nil
   223  }
   224  
   225  func stringEncoder(ctx context.Context, v reflect.Value, vrw types.ValueReadWriter) (types.Value, error) {
   226  	return types.String(v.String()), nil
   227  }
   228  
   229  func nomsValueEncoder(ctx context.Context, v reflect.Value, vrw types.ValueReadWriter) (types.Value, error) {
   230  	return v.Interface().(types.Value), nil
   231  }
   232  
   233  func marshalerEncoder(t reflect.Type) encoderFunc {
   234  	return func(ctx context.Context, v reflect.Value, vrw types.ValueReadWriter) (types.Value, error) {
   235  		val, err := v.Interface().(Marshaler).MarshalNoms(vrw)
   236  		if err != nil {
   237  			return nil, &marshalNomsError{err}
   238  		}
   239  		if val == nil {
   240  			return nil, fmt.Errorf("nil result from %s.MarshalNoms", t.String())
   241  		}
   242  		return val, nil
   243  	}
   244  }
   245  
   246  func typeEncoder(nbf *types.NomsBinFormat, t reflect.Type, seenStructs map[string]reflect.Type, tags nomsTags) (encoderFunc, error) {
   247  	if t.Implements(marshalerInterface) {
   248  		return marshalerEncoder(t), nil
   249  	}
   250  
   251  	switch t.Kind() {
   252  	case reflect.Bool:
   253  		return boolEncoder, nil
   254  	case reflect.Float64, reflect.Float32:
   255  		return float64Encoder, nil
   256  	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
   257  		return intEncoder, nil
   258  	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
   259  		return uintEncoder, nil
   260  	case reflect.String:
   261  		return stringEncoder, nil
   262  	case reflect.Struct:
   263  		return structEncoder(nbf, t, seenStructs)
   264  	case reflect.Slice, reflect.Array:
   265  		if shouldEncodeAsSet(t, tags) {
   266  			return setFromListEncoder(nbf, t, seenStructs)
   267  		}
   268  		return listEncoder(nbf, t, seenStructs)
   269  	case reflect.Map:
   270  		if shouldEncodeAsSet(t, tags) {
   271  			return setEncoder(nbf, t, seenStructs)
   272  		}
   273  		return mapEncoder(nbf, t, seenStructs)
   274  	case reflect.Interface:
   275  		return func(ctx context.Context, v reflect.Value, vrw types.ValueReadWriter) (types.Value, error) {
   276  			// Get the dynamic type.
   277  			v2 := reflect.ValueOf(v.Interface())
   278  			encFunc, err := typeEncoder(nbf, v2.Type(), seenStructs, tags)
   279  
   280  			if err != nil {
   281  				return nil, err
   282  			}
   283  
   284  			return encFunc(ctx, v2, vrw)
   285  		}, nil
   286  	case reflect.Ptr:
   287  		// Allow implementations of types.Value (like *types.Type)
   288  		if t.Implements(nomsValueInterface) {
   289  			return nomsValueEncoder, nil
   290  		}
   291  		fallthrough
   292  	default:
   293  		return nil, &UnsupportedTypeError{Type: t}
   294  	}
   295  }
   296  
   297  func getStructName(t reflect.Type) string {
   298  	if t.Implements(structNameMarshalerInterface) {
   299  		v := reflect.Zero(t)
   300  		return v.Interface().(StructNameMarshaler).MarshalNomsStructName()
   301  	}
   302  	return strings.Title(t.Name())
   303  }
   304  
   305  func structEncoder(nbf *types.NomsBinFormat, t reflect.Type, seenStructs map[string]reflect.Type) (encoderFunc, error) {
   306  	if t.Implements(nomsValueInterface) {
   307  		return nomsValueEncoder, nil
   308  	}
   309  
   310  	e := encoderCache.get(t)
   311  	if e != nil {
   312  		return e, nil
   313  	}
   314  
   315  	structName := getStructName(t)
   316  
   317  	seenStructs[t.Name()] = t
   318  	fields, knownShape, originalFieldIndex, err := typeFields(nbf, t, seenStructs, false, false)
   319  
   320  	if err != nil {
   321  		return nil, err
   322  	}
   323  
   324  	if knownShape {
   325  		fieldNames := make([]string, len(fields))
   326  		for i, f := range fields {
   327  			fieldNames[i] = f.name
   328  		}
   329  
   330  		structTemplate := types.MakeStructTemplate(structName, fieldNames)
   331  		e = func(ctx context.Context, v reflect.Value, vrw types.ValueReadWriter) (types.Value, error) {
   332  			values := make(types.ValueSlice, len(fields))
   333  			for i, f := range fields {
   334  				var err error
   335  				values[i], err = f.encoder(ctx, v.FieldByIndex(f.index), vrw)
   336  
   337  				if err != nil {
   338  					return nil, err
   339  				}
   340  			}
   341  			return structTemplate.NewStruct(nbf, values)
   342  		}
   343  	} else if originalFieldIndex == nil {
   344  		// Slower path: cannot precompute the Noms type since there are Noms collections,
   345  		// but at least there are a set number of fields.
   346  		e = func(ctx context.Context, v reflect.Value, vrw types.ValueReadWriter) (types.Value, error) {
   347  			data := make(types.StructData, len(fields))
   348  			for _, f := range fields {
   349  				fv := v.FieldByIndex(f.index)
   350  				if !fv.IsValid() || f.omitEmpty && isEmptyValue(fv) {
   351  					continue
   352  				}
   353  				var err error
   354  				data[f.name], err = f.encoder(ctx, fv, vrw)
   355  
   356  				if err != nil {
   357  					return nil, err
   358  				}
   359  			}
   360  			return types.NewStruct(nbf, structName, data)
   361  		}
   362  	} else {
   363  		// Slowest path - we are extending some other struct. We need to start with the
   364  		// type of that struct and extend.
   365  		e = func(ctx context.Context, v reflect.Value, vrw types.ValueReadWriter) (types.Value, error) {
   366  			fv := v.FieldByIndex(originalFieldIndex)
   367  			ret := fv.Interface().(types.Struct)
   368  			if ret.IsZeroValue() {
   369  				var err error
   370  				ret, err = types.NewStruct(nbf, structName, nil)
   371  				if err != nil {
   372  					return nil, err
   373  				}
   374  			}
   375  			for _, f := range fields {
   376  				fv := v.FieldByIndex(f.index)
   377  				if !fv.IsValid() || f.omitEmpty && isEmptyValue(fv) {
   378  					continue
   379  				}
   380  
   381  				encVal, err := f.encoder(ctx, fv, vrw)
   382  				if err != nil {
   383  					return nil, err
   384  				}
   385  
   386  				ret, err = ret.Set(f.name, encVal)
   387  				if err != nil {
   388  					return nil, err
   389  				}
   390  			}
   391  			return ret, nil
   392  		}
   393  	}
   394  
   395  	encoderCache.set(t, e)
   396  	return e, nil
   397  }
   398  
   399  func isEmptyValue(v reflect.Value) bool {
   400  	switch v.Kind() {
   401  	case reflect.Array, reflect.Map, reflect.Slice, reflect.String:
   402  		return v.Len() == 0
   403  	case reflect.Bool:
   404  		return !v.Bool()
   405  	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
   406  		return v.Int() == 0
   407  	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
   408  		return v.Uint() == 0
   409  	case reflect.Float32, reflect.Float64:
   410  		return v.Float() == 0
   411  	case reflect.Struct:
   412  		z := reflect.Zero(v.Type())
   413  		return reflect.DeepEqual(z.Interface(), v.Interface())
   414  	case reflect.Interface:
   415  		return v.IsNil()
   416  	}
   417  	return false
   418  }
   419  
   420  type field struct {
   421  	name      string
   422  	encoder   encoderFunc
   423  	index     []int
   424  	nomsType  *types.Type
   425  	omitEmpty bool
   426  }
   427  
   428  type fieldSlice []field
   429  
   430  func (fs fieldSlice) Len() int           { return len(fs) }
   431  func (fs fieldSlice) Swap(i, j int)      { fs[i], fs[j] = fs[j], fs[i] }
   432  func (fs fieldSlice) Less(i, j int) bool { return fs[i].name < fs[j].name }
   433  
   434  type encoderCacheT struct {
   435  	sync.RWMutex
   436  	m map[reflect.Type]encoderFunc
   437  }
   438  
   439  var encoderCache = &encoderCacheT{}
   440  
   441  // Separate Set encoder cache because the same type with and without the
   442  // `noms:",set"` tag encode differently (Set vs Map).
   443  var setEncoderCache = &encoderCacheT{}
   444  
   445  func (c *encoderCacheT) get(t reflect.Type) encoderFunc {
   446  	c.RLock()
   447  	defer c.RUnlock()
   448  	return c.m[t]
   449  }
   450  
   451  func (c *encoderCacheT) set(t reflect.Type, e encoderFunc) {
   452  	c.Lock()
   453  	defer c.Unlock()
   454  	if c.m == nil {
   455  		c.m = map[reflect.Type]encoderFunc{}
   456  	}
   457  	c.m[t] = e
   458  }
   459  
   460  func getTags(f reflect.StructField) (tags nomsTags, err error) {
   461  	reflectTags := f.Tag.Get("noms")
   462  	if reflectTags == "-" {
   463  		tags.skip = true
   464  		return
   465  	}
   466  
   467  	tagsSlice := strings.Split(reflectTags, ",")
   468  
   469  	// The first tag is always the name, or empty to use the field as the name.
   470  	if len(tagsSlice) == 0 || tagsSlice[0] == "" {
   471  		tags.name = strings.ToLower(f.Name[:1]) + f.Name[1:]
   472  	} else {
   473  		tags.name = tagsSlice[0]
   474  		tags.hasName = true
   475  	}
   476  
   477  	if !types.IsValidStructFieldName(tags.name) {
   478  		return nomsTags{}, &InvalidTagError{"Invalid struct field name: " + tags.name}
   479  	}
   480  
   481  	for i := 1; i < len(tagsSlice); i++ {
   482  		switch tag := tagsSlice[i]; tag {
   483  		case "omitempty":
   484  			tags.omitEmpty = true
   485  		case "original":
   486  			tags.original = true
   487  		case "set":
   488  			tags.set = true
   489  		default:
   490  			return nomsTags{}, &InvalidTagError{"Unrecognized tag: " + tag}
   491  		}
   492  	}
   493  	return
   494  }
   495  
   496  func validateField(f reflect.StructField, t reflect.Type) error {
   497  	// PkgPath is the package path that qualifies a lower case (unexported)
   498  	// field name. It is empty for upper case (exported) field names.
   499  	// See https://golang.org/ref/spec#Uniqueness_of_identifiers
   500  	if f.PkgPath != "" && !f.Anonymous { // unexported
   501  		return &UnsupportedTypeError{t, "Non exported fields are not supported"}
   502  	}
   503  
   504  	return nil
   505  }
   506  
   507  func typeFields(nbf *types.NomsBinFormat, t reflect.Type, seenStructs map[string]reflect.Type, computeType, embedded bool) (fields fieldSlice, knownShape bool, originalFieldIndex []int, err error) {
   508  	knownShape = true
   509  	for i := 0; i < t.NumField(); i++ {
   510  		index := make([]int, 1)
   511  		index[0] = i
   512  		f := t.Field(i)
   513  		tags, err := getTags(f)
   514  
   515  		if err != nil {
   516  			return nil, false, nil, err
   517  		}
   518  
   519  		if tags.skip {
   520  			continue
   521  		}
   522  
   523  		if tags.original {
   524  			originalFieldIndex = f.Index
   525  			continue
   526  		}
   527  
   528  		if f.Anonymous && f.PkgPath == "" && !tags.hasName {
   529  			embeddedFields, embeddedKnownShape, embeddedOriginalFieldIndex, err := typeFields(nbf, f.Type, seenStructs, computeType, true)
   530  
   531  			if err != nil {
   532  				return nil, false, nil, err
   533  			}
   534  
   535  			if embeddedOriginalFieldIndex != nil {
   536  				originalFieldIndex = append(index, embeddedOriginalFieldIndex...)
   537  			}
   538  			knownShape = knownShape && embeddedKnownShape
   539  
   540  			for _, ef := range embeddedFields {
   541  				ef.index = append(index, ef.index...)
   542  				fields = append(fields, ef)
   543  			}
   544  
   545  			continue
   546  		}
   547  
   548  		var nt *types.Type
   549  		err = validateField(f, t)
   550  
   551  		if err != nil {
   552  			return nil, false, nil, err
   553  		}
   554  
   555  		if computeType {
   556  			var err error
   557  			nt, err = encodeType(nbf, f.Type, seenStructs, tags)
   558  
   559  			if err != nil {
   560  				return nil, false, nil, err
   561  			}
   562  
   563  			if nt == nil {
   564  				knownShape = false
   565  			}
   566  		}
   567  
   568  		if tags.omitEmpty && !computeType {
   569  			knownShape = false
   570  		}
   571  
   572  		encFunc, err := typeEncoder(nbf, f.Type, seenStructs, tags)
   573  
   574  		if err != nil {
   575  			return nil, false, nil, err
   576  		}
   577  
   578  		fields = append(fields, field{
   579  			name:      tags.name,
   580  			encoder:   encFunc,
   581  			index:     index,
   582  			nomsType:  nt,
   583  			omitEmpty: tags.omitEmpty,
   584  		})
   585  	}
   586  
   587  	if !embedded {
   588  		sort.Sort(fields)
   589  	}
   590  
   591  	return fields, knownShape, originalFieldIndex, err
   592  }
   593  
   594  func listEncoder(nbf *types.NomsBinFormat, t reflect.Type, seenStructs map[string]reflect.Type) (encoderFunc, error) {
   595  	e := encoderCache.get(t)
   596  	if e != nil {
   597  		return e, nil
   598  	}
   599  
   600  	var elemEncoder encoderFunc
   601  	// lock e until encoder(s) are initialized
   602  	var init sync.RWMutex
   603  	init.Lock()
   604  	defer init.Unlock()
   605  	e = func(ctx context.Context, v reflect.Value, vrw types.ValueReadWriter) (types.Value, error) {
   606  		init.RLock()
   607  		defer init.RUnlock()
   608  		values := make([]types.Value, v.Len())
   609  		for i := 0; i < v.Len(); i++ {
   610  			var err error
   611  			values[i], err = elemEncoder(ctx, v.Index(i), vrw)
   612  
   613  			if err != nil {
   614  				return nil, err
   615  			}
   616  		}
   617  		return types.NewList(ctx, vrw, values...)
   618  	}
   619  
   620  	encoderCache.set(t, e)
   621  	var err error
   622  	elemEncoder, err = typeEncoder(nbf, t.Elem(), seenStructs, nomsTags{})
   623  
   624  	if err != nil {
   625  		return nil, err
   626  	}
   627  
   628  	return e, nil
   629  }
   630  
   631  // Encode set from array or slice
   632  func setFromListEncoder(nbf *types.NomsBinFormat, t reflect.Type, seenStructs map[string]reflect.Type) (encoderFunc, error) {
   633  	e := setEncoderCache.get(t)
   634  	if e != nil {
   635  		return e, nil
   636  	}
   637  
   638  	var elemEncoder encoderFunc
   639  	// lock e until encoder(s) are initialized
   640  	var init sync.RWMutex
   641  	init.Lock()
   642  	defer init.Unlock()
   643  	e = func(ctx context.Context, v reflect.Value, vrw types.ValueReadWriter) (types.Value, error) {
   644  		init.RLock()
   645  		defer init.RUnlock()
   646  		values := make([]types.Value, v.Len())
   647  		for i := 0; i < v.Len(); i++ {
   648  			var err error
   649  			values[i], err = elemEncoder(ctx, v.Index(i), vrw)
   650  
   651  			if err != nil {
   652  				return nil, err
   653  			}
   654  		}
   655  		return types.NewSet(ctx, vrw, values...)
   656  	}
   657  
   658  	setEncoderCache.set(t, e)
   659  
   660  	var err error
   661  	elemEncoder, err = typeEncoder(nbf, t.Elem(), seenStructs, nomsTags{})
   662  
   663  	if err != nil {
   664  		return nil, err
   665  	}
   666  
   667  	return e, err
   668  }
   669  
   670  func setEncoder(nbf *types.NomsBinFormat, t reflect.Type, seenStructs map[string]reflect.Type) (encoderFunc, error) {
   671  	e := setEncoderCache.get(t)
   672  	if e != nil {
   673  		return e, nil
   674  	}
   675  
   676  	var encoder encoderFunc
   677  	// lock e until encoder(s) are initialized
   678  	var init sync.RWMutex
   679  	init.Lock()
   680  	defer init.Unlock()
   681  	e = func(ctx context.Context, v reflect.Value, vrw types.ValueReadWriter) (types.Value, error) {
   682  		init.RLock()
   683  		defer init.RUnlock()
   684  		values := make([]types.Value, v.Len())
   685  		for i, k := range v.MapKeys() {
   686  			var err error
   687  			values[i], err = encoder(ctx, k, vrw)
   688  
   689  			if err != nil {
   690  				return nil, err
   691  			}
   692  		}
   693  		return types.NewSet(ctx, vrw, values...)
   694  	}
   695  
   696  	setEncoderCache.set(t, e)
   697  
   698  	var err error
   699  	encoder, err = typeEncoder(nbf, t.Key(), seenStructs, nomsTags{})
   700  
   701  	if err != nil {
   702  		return nil, err
   703  	}
   704  
   705  	return e, nil
   706  }
   707  
   708  func mapEncoder(nbf *types.NomsBinFormat, t reflect.Type, seenStructs map[string]reflect.Type) (encoderFunc, error) {
   709  	e := encoderCache.get(t)
   710  	if e != nil {
   711  		return e, nil
   712  	}
   713  
   714  	var keyEncoder encoderFunc
   715  	var valueEncoder encoderFunc
   716  	// lock e until encoder(s) are initialized
   717  	var init sync.RWMutex
   718  	init.Lock()
   719  	defer init.Unlock()
   720  	e = func(ctx context.Context, v reflect.Value, vrw types.ValueReadWriter) (types.Value, error) {
   721  		init.RLock()
   722  		defer init.RUnlock()
   723  		keys := v.MapKeys()
   724  		kvs := make([]types.Value, 2*len(keys))
   725  		for i, k := range keys {
   726  			var err error
   727  			kvs[2*i], err = keyEncoder(ctx, k, vrw)
   728  
   729  			if err != nil {
   730  				return nil, err
   731  			}
   732  
   733  			kvs[2*i+1], err = valueEncoder(ctx, v.MapIndex(k), vrw)
   734  
   735  			if err != nil {
   736  				return nil, err
   737  			}
   738  		}
   739  		return types.NewMap(ctx, vrw, kvs...)
   740  	}
   741  
   742  	encoderCache.set(t, e)
   743  
   744  	var err error
   745  	keyEncoder, err = typeEncoder(nbf, t.Key(), seenStructs, nomsTags{})
   746  
   747  	if err != nil {
   748  		return nil, err
   749  	}
   750  
   751  	valueEncoder, err = typeEncoder(nbf, t.Elem(), seenStructs, nomsTags{})
   752  
   753  	if err != nil {
   754  		return nil, err
   755  	}
   756  
   757  	return e, nil
   758  }
   759  
   760  func shouldEncodeAsSet(t reflect.Type, tags nomsTags) bool {
   761  	switch t.Kind() {
   762  	case reflect.Slice, reflect.Array:
   763  		return tags.set
   764  	case reflect.Map:
   765  		// map[T]struct{} `noms:,"set"`
   766  		return tags.set &&
   767  			t.Elem().Kind() == reflect.Struct &&
   768  			t.Elem().NumField() == 0
   769  	default:
   770  		panic(fmt.Errorf("called with unexpected kind %v", t.Kind()))
   771  	}
   772  }