@@ -85,9 +85,11 @@ func Duration(v time.Duration) Any {
85
85
// Primitive values (booleans, integers, floats, strings, bytes, timestamps,
86
86
// durations) are supported, along with values that implement either
87
87
// proto.Message, json.Marshaler, encoding.TextMarshaler or
88
- // encoding.BinaryMarshaler.
88
+ // encoding.BinaryMarshaler. Slices and maps are also supported, as long
89
+ // as they are JSON-like in shape.
89
90
func Marshal (v any ) (Any , error ) {
90
- if rv := reflect .ValueOf (v ); rv .Kind () == reflect .Pointer && rv .IsNil () {
91
+ rv := reflect .ValueOf (v )
92
+ if rv .Kind () == reflect .Pointer && rv .IsNil () {
91
93
return Nil (), nil
92
94
}
93
95
var m proto.Message
@@ -160,7 +162,10 @@ func Marshal(v any) (Any, error) {
160
162
case []byte :
161
163
m = wrapperspb .Bytes (vv )
162
164
default :
163
- return Any {}, fmt .Errorf ("cannot serialize %v (%T)" , v , v )
165
+ var err error
166
+ if m , err = newStructpbValue (rv ); err != nil {
167
+ return Any {}, fmt .Errorf ("cannot serialize %v: %w" , v , err )
168
+ }
164
169
}
165
170
166
171
proto , err := anypb .New (m )
@@ -386,6 +391,10 @@ func (a Any) Unmarshal(v any) error {
386
391
}
387
392
}
388
393
394
+ if s , ok := m .(* structpb.Value ); ok {
395
+ return fromStructpbValue (elem , s )
396
+ }
397
+
389
398
return fmt .Errorf ("cannot deserialize %T into %v (%v kind)" , m , elem .Type (), elem .Kind ())
390
399
}
391
400
@@ -404,3 +413,144 @@ func (a Any) String() string {
404
413
func (a Any ) Equal (other Any ) bool {
405
414
return proto .Equal (a .proto , other .proto )
406
415
}
416
+
417
+ func newStructpbValue (rv reflect.Value ) (* structpb.Value , error ) {
418
+ switch rv .Kind () {
419
+ case reflect .Bool :
420
+ return structpb .NewBoolValue (rv .Bool ()), nil
421
+ case reflect .Int , reflect .Int8 , reflect .Int16 , reflect .Int32 , reflect .Int64 :
422
+ n := rv .Int ()
423
+ f := float64 (n )
424
+ if int64 (f ) != n {
425
+ return nil , fmt .Errorf ("cannot serialize %d as number structpb.Value (%v) without losing information" , n , f )
426
+ }
427
+ return structpb .NewNumberValue (f ), nil
428
+ case reflect .Uint , reflect .Uint8 , reflect .Uint16 , reflect .Uint32 , reflect .Uint64 :
429
+ n := rv .Uint ()
430
+ f := float64 (n )
431
+ if uint64 (f ) != n {
432
+ return nil , fmt .Errorf ("cannot serialize %d as number structpb.Value (%v) without losing information" , n , f )
433
+ }
434
+ return structpb .NewNumberValue (f ), nil
435
+ case reflect .Float32 , reflect .Float64 :
436
+ return structpb .NewNumberValue (rv .Float ()), nil
437
+ case reflect .String :
438
+ return structpb .NewStringValue (rv .String ()), nil
439
+ case reflect .Interface :
440
+ if rv .NumMethod () == 0 { // interface{} aka. any
441
+ v := rv .Interface ()
442
+ if v == nil {
443
+ return structpb .NewNullValue (), nil
444
+ }
445
+ return newStructpbValue (reflect .ValueOf (v ))
446
+ }
447
+ case reflect .Slice :
448
+ list := & structpb.ListValue {Values : make ([]* structpb.Value , rv .Len ())}
449
+ for i := range list .Values {
450
+ elem := rv .Index (i )
451
+ var err error
452
+ list .Values [i ], err = newStructpbValue (elem )
453
+ if err != nil {
454
+ return nil , err
455
+ }
456
+ }
457
+ return structpb .NewListValue (list ), nil
458
+ case reflect .Map :
459
+ strct := & structpb.Struct {Fields : make (map [string ]* structpb.Value , rv .Len ())}
460
+ iter := rv .MapRange ()
461
+ for iter .Next () {
462
+ k := iter .Key ()
463
+
464
+ var strKey string
465
+ var hasStrKey bool
466
+ switch k .Kind () {
467
+ case reflect .String :
468
+ strKey = k .String ()
469
+ hasStrKey = true
470
+ case reflect .Interface :
471
+ if s , ok := k .Interface ().(string ); ok {
472
+ strKey = s
473
+ hasStrKey = true
474
+ }
475
+ }
476
+ if ! hasStrKey {
477
+ return nil , fmt .Errorf ("cannot serialize map with %s (%s) key" , k .Type (), k .Kind ())
478
+ }
479
+
480
+ v , err := newStructpbValue (iter .Value ())
481
+ if err != nil {
482
+ return nil , err
483
+ }
484
+ strct .Fields [strKey ] = v
485
+ }
486
+ return structpb .NewStructValue (strct ), nil
487
+ }
488
+ return nil , fmt .Errorf ("not implemented: %s" , rv .Type ())
489
+ }
490
+
491
+ func fromStructpbValue (rv reflect.Value , s * structpb.Value ) error {
492
+ switch rv .Kind () {
493
+ case reflect .Bool :
494
+ if b , ok := s .Kind .(* structpb.Value_BoolValue ); ok {
495
+ rv .SetBool (b .BoolValue )
496
+ return nil
497
+ }
498
+ case reflect .Int , reflect .Int8 , reflect .Int16 , reflect .Int32 , reflect .Int64 :
499
+ if n , ok := s .Kind .(* structpb.Value_NumberValue ); ok {
500
+ rv .SetInt (int64 (n .NumberValue ))
501
+ return nil
502
+ }
503
+ case reflect .Uint , reflect .Uint8 , reflect .Uint16 , reflect .Uint32 , reflect .Uint64 :
504
+ if n , ok := s .Kind .(* structpb.Value_NumberValue ); ok {
505
+ rv .SetUint (uint64 (n .NumberValue ))
506
+ return nil
507
+ }
508
+ case reflect .Float32 , reflect .Float64 :
509
+ if n , ok := s .Kind .(* structpb.Value_NumberValue ); ok {
510
+ rv .SetFloat (n .NumberValue )
511
+ return nil
512
+ }
513
+ case reflect .String :
514
+ if str , ok := s .Kind .(* structpb.Value_StringValue ); ok {
515
+ rv .SetString (str .StringValue )
516
+ return nil
517
+ }
518
+ case reflect .Slice :
519
+ if l , ok := s .Kind .(* structpb.Value_ListValue ); ok {
520
+ values := l .ListValue .GetValues ()
521
+ rv .Grow (len (values ))
522
+ rv .SetLen (len (values ))
523
+ for i , value := range values {
524
+ if err := fromStructpbValue (rv .Index (i ), value ); err != nil {
525
+ return err
526
+ }
527
+ }
528
+ return nil
529
+ }
530
+ case reflect .Map :
531
+ if strct , ok := s .Kind .(* structpb.Value_StructValue ); ok {
532
+ fields := strct .StructValue .Fields
533
+ rv .Set (reflect .MakeMapWithSize (rv .Type (), len (fields )))
534
+ valueType := rv .Type ().Elem ()
535
+ for key , value := range fields {
536
+ mv := reflect .New (valueType ).Elem ()
537
+ if err := fromStructpbValue (mv , value ); err != nil {
538
+ return err
539
+ }
540
+ rv .SetMapIndex (reflect .ValueOf (key ), mv )
541
+ }
542
+ return nil
543
+ }
544
+ case reflect .Interface :
545
+ if rv .NumMethod () == 0 { // interface{} aka. any
546
+ v := s .AsInterface ()
547
+ if v == nil {
548
+ rv .SetZero ()
549
+ } else {
550
+ rv .Set (reflect .ValueOf (s .AsInterface ()))
551
+ }
552
+ return nil
553
+ }
554
+ }
555
+ return fmt .Errorf ("cannot deserialize %T into %v (%v kind)" , s , rv .Type (), rv .Kind ())
556
+ }
0 commit comments