encodeStruct encodes a composite object.
(obj reflect.Value, dest *wire.Object)
| 479 | |
| 480 | // encodeStruct encodes a composite object. |
| 481 | func (es *encodeState) encodeStruct(obj reflect.Value, dest *wire.Object) { |
| 482 | if s, ok := es.encodedStructs[obj]; ok { |
| 483 | *dest = s |
| 484 | return |
| 485 | } |
| 486 | s := &wire.Struct{} |
| 487 | *dest = s |
| 488 | es.encodedStructs[obj] = s |
| 489 | |
| 490 | // Ensure that the obj is addressable. There are two cases when it is |
| 491 | // not. First, is when this is dispatched via SaveValue. Second, when |
| 492 | // this is a map key as a struct. Either way, we need to make a copy to |
| 493 | // obtain an addressable value. |
| 494 | if !obj.CanAddr() { |
| 495 | localObj := reflect.New(obj.Type()) |
| 496 | localObj.Elem().Set(obj) |
| 497 | obj = localObj.Elem() |
| 498 | } |
| 499 | |
| 500 | // Look the type up in the database. |
| 501 | te, ok := es.types.Lookup(obj.Type()) |
| 502 | if te == nil { |
| 503 | if obj.NumField() == 0 { |
| 504 | // Allow unregistered anonymous, empty structs. This |
| 505 | // will just return success without ever invoking the |
| 506 | // passed function. This uses the immutable EmptyStruct |
| 507 | // variable to prevent an allocation in this case. |
| 508 | // |
| 509 | // Note that this mechanism does *not* work for |
| 510 | // interfaces in general. So you can't dispatch |
| 511 | // non-registered empty structs via interfaces because |
| 512 | // then they can't be restored. |
| 513 | s.Alloc(0) |
| 514 | return |
| 515 | } |
| 516 | // We need a SaverLoader for struct types. |
| 517 | Failf("struct %T does not implement SaverLoader", obj.Interface()) |
| 518 | } |
| 519 | if !ok { |
| 520 | // Queue the type to be serialized. |
| 521 | es.pendingTypes = append(es.pendingTypes, te.Type) |
| 522 | } |
| 523 | |
| 524 | // Invoke the provided saver. |
| 525 | s.TypeID = wire.TypeID(te.ID) |
| 526 | s.Alloc(len(te.Fields)) |
| 527 | oe := objectEncoder{ |
| 528 | es: es, |
| 529 | encoded: s, |
| 530 | } |
| 531 | es.stats.start(te.ID) |
| 532 | defer es.stats.done() |
| 533 | if sl, ok := obj.Addr().Interface().(SaverLoader); ok { |
| 534 | // Note: may be a registered empty struct which does not |
| 535 | // implement the saver/loader interfaces. |
| 536 | sl.StateSave(Sink{internal: oe}) |
| 537 | } |
| 538 | } |