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 }