encode.go 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
  1. package oscar
  2. import (
  3. "bytes"
  4. "encoding/binary"
  5. "errors"
  6. "io"
  7. "reflect"
  8. )
  9. func Marshal(v any, w io.Writer) error {
  10. return marshal(reflect.TypeOf(v), reflect.ValueOf(v), "", w)
  11. }
  12. func marshal(t reflect.Type, v reflect.Value, tag reflect.StructTag, w io.Writer) error {
  13. switch t.Kind() {
  14. case reflect.Struct:
  15. for i := 0; i < t.NumField(); i++ {
  16. if err := marshal(t.Field(i).Type, v.Field(i), t.Field(i).Tag, w); err != nil {
  17. return err
  18. }
  19. }
  20. case reflect.String:
  21. if l, ok := tag.Lookup("len_prefix"); ok {
  22. switch l {
  23. case "uint8":
  24. if err := binary.Write(w, binary.BigEndian, uint8(len(v.String()))); err != nil {
  25. return err
  26. }
  27. case "uint16":
  28. if err := binary.Write(w, binary.BigEndian, uint16(len(v.String()))); err != nil {
  29. return err
  30. }
  31. default:
  32. panic("length not set")
  33. }
  34. }
  35. if err := binary.Write(w, binary.BigEndian, []byte(v.String())); err != nil {
  36. return err
  37. }
  38. case reflect.Slice:
  39. // todo: only write to temporary buffer if len_prefix is set
  40. buf := &bytes.Buffer{}
  41. if t.Elem().Kind() == reflect.Struct {
  42. for j := 0; j < v.Len(); j++ {
  43. element := v.Index(j)
  44. if err := Marshal(element.Interface(), buf); err != nil {
  45. return err
  46. }
  47. }
  48. } else {
  49. if err := binary.Write(buf, binary.BigEndian, v.Interface()); err != nil {
  50. return err
  51. }
  52. }
  53. //todo what if both len_prefix and count_prefix are set?
  54. if l, ok := tag.Lookup("len_prefix"); ok {
  55. switch l {
  56. case "uint8":
  57. if err := binary.Write(w, binary.BigEndian, uint8(buf.Len())); err != nil {
  58. return err
  59. }
  60. case "uint16":
  61. if err := binary.Write(w, binary.BigEndian, uint16(buf.Len())); err != nil {
  62. return err
  63. }
  64. }
  65. }
  66. if l, ok := tag.Lookup("count_prefix"); ok {
  67. switch l {
  68. case "uint8":
  69. if err := binary.Write(w, binary.BigEndian, uint8(v.Len())); err != nil {
  70. return err
  71. }
  72. case "uint16":
  73. if err := binary.Write(w, binary.BigEndian, uint16(v.Len())); err != nil {
  74. return err
  75. }
  76. }
  77. }
  78. if _, err := w.Write(buf.Bytes()); err != nil {
  79. return err
  80. }
  81. case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Array:
  82. if err := binary.Write(w, binary.BigEndian, v.Interface()); err != nil {
  83. return err
  84. }
  85. default:
  86. return errors.New("unsupported type for marshalling")
  87. }
  88. return nil
  89. }