Răsfoiți Sursa

wire: support marshal/unmarshal arrays

Mike 1 an în urmă
părinte
comite
6c3f28b42e
4 a modificat fișierele cu 117 adăugiri și 2 ștergeri
  1. 17 0
      wire/decode.go
  2. 35 0
      wire/decode_test.go
  3. 17 0
      wire/encode.go
  4. 48 2
      wire/encode_test.go

+ 17 - 0
wire/decode.go

@@ -51,6 +51,8 @@ func unmarshal(t reflect.Type, v reflect.Value, tag reflect.StructTag, r io.Read
 	}
 
 	switch v.Kind() {
+	case reflect.Array:
+		return unmarshalArray(v, r, order)
 	case reflect.Slice:
 		return unmarshalSlice(v, oscTag, r, order)
 	case reflect.String:
@@ -90,6 +92,21 @@ func unmarshal(t reflect.Type, v reflect.Value, tag reflect.StructTag, r io.Read
 	}
 }
 
+func unmarshalArray(v reflect.Value, r io.Reader, order binary.ByteOrder) error {
+	arrLen := v.Len()
+	arrType := v.Type().Elem()
+
+	for i := 0; i < arrLen; i++ {
+		elem := reflect.New(arrType).Elem()
+		if err := unmarshal(arrType, elem, "", r, order); err != nil {
+			return err
+		}
+		v.Index(i).Set(elem)
+	}
+
+	return nil
+}
+
 func unmarshalSlice(v reflect.Value, oscTag oscarTag, r io.Reader, order binary.ByteOrder) error {
 	slice := reflect.New(v.Type()).Elem()
 	elemType := v.Type().Elem()

+ 35 - 0
wire/decode_test.go

@@ -641,6 +641,41 @@ func TestUnmarshal(t *testing.T) {
 			},
 			wantErr: errNonOptionalPointer,
 		},
+		{
+			name: "byte array",
+			prototype: &struct {
+				Val [5]byte
+			}{},
+			want: &struct {
+				Val [5]byte
+			}{
+				Val: [5]byte{'h', 'e', 'l', 'l', 'o'},
+			},
+			given: []byte{0x68, 0x65, 0x6c, 0x6c, 0x6f},
+		},
+		{
+			name: "array of invalid type",
+			prototype: &struct {
+				Val [5]int
+			}{},
+			wantErr: ErrUnmarshalFailure,
+			given:   []byte{1, 2, 3, 4, 5},
+		},
+		{
+			name: "struct array",
+			prototype: &struct {
+				Val [2]TLV
+			}{},
+			want: &struct {
+				Val [2]TLV
+			}{
+				Val: [2]TLV{
+					NewTLVBE(10, uint16(1234)),
+					NewTLVBE(20, uint16(1234)),
+				},
+			},
+			given: []byte{0x0, 0xa, 0x0, 0x2, 0x4, 0xd2, 0x0, 0x14, 0x0, 0x2, 0x4, 0xd2},
+		},
 	}
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {

+ 17 - 0
wire/encode.go

@@ -58,6 +58,8 @@ func marshal(t reflect.Type, v reflect.Value, tag reflect.StructTag, w io.Writer
 	}
 
 	switch t.Kind() {
+	case reflect.Array:
+		return marshalArray(t, v, w, order)
 	case reflect.Slice:
 		return marshalSlice(t, v, oscTag, w, order)
 	case reflect.String:
@@ -82,6 +84,21 @@ func marshalInterface(v reflect.Value, w io.Writer, tag oscarTag, order binary.B
 	return marshalStruct(elem.Type(), elem, tag, w, order)
 }
 
+func marshalArray(t reflect.Type, v reflect.Value, w io.Writer, order binary.ByteOrder) error {
+	if t.Elem().Kind() == reflect.Struct {
+		for j := 0; j < v.Len(); j++ {
+			if err := marshalStruct(t.Elem(), v.Index(j), oscarTag{}, w, order); err != nil {
+				return fmt.Errorf("error marshalling %s: %w", t.Elem().Kind(), err)
+			}
+		}
+	} else {
+		if err := binary.Write(w, order, v.Interface()); err != nil {
+			return fmt.Errorf("error marshalling %s: %w", t.Elem().Kind(), err)
+		}
+	}
+	return nil
+}
+
 func marshalSlice(t reflect.Type, v reflect.Value, oscTag oscarTag, w io.Writer, order binary.ByteOrder) error {
 	// todo: only write to temporary buffer if len_prefix is set
 	buf := &bytes.Buffer{}

+ 48 - 2
wire/encode_test.go

@@ -198,7 +198,7 @@ func TestMarshal(t *testing.T) {
 				Val: []byte(`hello`),
 			},
 			want: append(
-				[]byte{0x05},                             /* len prefix */
+				[]byte{0x05}, /* len prefix */
 				[]byte{0x68, 0x65, 0x6c, 0x6c, 0x6f}...), /* slice val */
 		},
 		{
@@ -220,7 +220,7 @@ func TestMarshal(t *testing.T) {
 				Val: []byte(`hello`),
 			},
 			want: append(
-				[]byte{0x00, 0x05},                       /* len prefix */
+				[]byte{0x00, 0x05}, /* len prefix */
 				[]byte{0x68, 0x65, 0x6c, 0x6c, 0x6f}...), /* slice val */
 		},
 		{
@@ -687,6 +687,52 @@ func TestMarshal(t *testing.T) {
 				0x34, 0x12, // Val2.Message.Val3
 			},
 		},
+		{
+			name: "byte array",
+			w:    &bytes.Buffer{},
+			given: struct {
+				Val [5]byte
+			}{
+				Val: [5]byte{'h', 'e', 'l', 'l', 'o'},
+			},
+			want: []byte{0x68, 0x65, 0x6c, 0x6c, 0x6f},
+		},
+		{
+			name: "byte array with error",
+			w:    errWriter{},
+			given: struct {
+				Val [5]byte
+			}{
+				Val: [5]byte{'h', 'e', 'l', 'l', 'o'},
+			},
+			wantErr: io.EOF,
+		},
+		{
+			name: "struct array",
+			w:    &bytes.Buffer{},
+			given: struct {
+				Val [2]TLV
+			}{
+				Val: [2]TLV{
+					NewTLVBE(10, uint16(1234)),
+					NewTLVBE(20, uint16(1234)),
+				},
+			},
+			want: []byte{0x0, 0xa, 0x0, 0x2, 0x4, 0xd2, 0x0, 0x14, 0x0, 0x2, 0x4, 0xd2},
+		},
+		{
+			name: "struct array with error",
+			w:    errWriter{},
+			given: struct {
+				Val [2]TLV
+			}{
+				Val: [2]TLV{
+					NewTLVBE(10, uint16(1234)),
+					NewTLVBE(20, uint16(1234)),
+				},
+			},
+			wantErr: io.EOF,
+		},
 	}
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {