-
Notifications
You must be signed in to change notification settings - Fork 6
Expand file tree
/
Copy pathlist.go
More file actions
137 lines (120 loc) · 3.06 KB
/
Copy pathlist.go
File metadata and controls
137 lines (120 loc) · 3.06 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
package pack
import (
"encoding/json"
"fmt"
"math/rand"
"reflect"
"github.com/renproject/surge"
)
type List struct {
T Type
Elems []Value
}
func EmptyList(t Type) List {
return List{
T: t,
Elems: []Value{},
}
}
func NewList(vs ...Value) (List, error) {
if len(vs) == 0 {
return List{}, fmt.Errorf("cannot construct list with no elements")
}
elems := make([]Value, len(vs))
var t Type
for i := range vs {
// Verify the list elements have a consistent type.
if t == nil {
t = vs[i].Type()
} else if !vs[i].Type().Equals(t) {
return List{}, fmt.Errorf("inconsistent list type: expected %v, got %v", t, vs[i].Type())
}
elems[i] = vs[i]
}
return List{
T: t,
Elems: elems,
}, nil
}
// Type returns the list type.
func (v List) Type() Type {
return typeList{
Type: v.T,
}
}
// SizeHint returns the number of bytes required to represent the list in
// binary.
func (v List) SizeHint() int {
return surge.SizeHint(v.Elems)
}
// Marshal the list into binary.
func (v List) Marshal(buf []byte, rem int) ([]byte, int, error) {
buf, rem, err := surge.MarshalLen(uint32(len(v.Elems)), buf, rem)
if err != nil {
return buf, rem, err
}
for i := range v.Elems {
buf, rem, err = v.Elems[i].Marshal(buf, rem)
if err != nil {
return buf, rem, err
}
}
return buf, rem, nil
}
// Unmarshal the list from binary.
func (v *List) Unmarshal(buf []byte, rem int) ([]byte, int, error) {
if v.T == nil {
return buf, rem, fmt.Errorf("cannot unmarshal into list with unknown type")
}
var numElems uint32
buf, rem, err := surge.UnmarshalLen(&numElems, 0, buf, rem)
if err != nil {
return buf, rem, err
}
v.Elems = make([]Value, numElems)
for i := range v.Elems {
v.Elems[i], buf, rem, err = v.T.UnmarshalValue(buf, rem)
if err != nil {
return buf, rem, err
}
// Ensure all elements are of the same type.
if v.Elems[i].Type() != v.T {
return buf, rem, fmt.Errorf("unexpected type: expected %v, got %v", v.T, v.Elems[i].Type())
}
}
return buf, rem, nil
}
// MarshalJSON marshals the list to JSON.
func (v List) MarshalJSON() ([]byte, error) {
raw := []interface{}{}
for _, elem := range v.Elems {
rawField, err := elem.MarshalJSON()
if err != nil {
return nil, fmt.Errorf("marshaling list element: %v", err)
}
raw = append(raw, json.RawMessage(rawField))
}
return json.Marshal(raw)
}
// String returns the list in its JSON representation.
func (v List) String() string {
data, err := v.MarshalJSON()
if err != nil {
return err.Error()
}
return string(data)
}
// Generate a random list. This method is implemented for use in quick tests.
// See https://golang.org/pkg/testing/quick/#Generator for more information.
// Generated lists will never contain embedded lists.
func (List) Generate(r *rand.Rand, size int) reflect.Value {
l := List{
T: Generate(r, size, false, false).Interface().(Value).Type(),
Elems: make([]Value, 0, size),
}
for i := 0; i < size; i++ {
v := GenerateFromKind(r, size, l.T.Kind(), false, false).Interface().(Value)
l.Elems = append(l.Elems, v)
}
return reflect.ValueOf(l)
}