-
-
Notifications
You must be signed in to change notification settings - Fork 8
/
Copy pathlist.go
99 lines (77 loc) · 1.81 KB
/
list.go
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
package httpsfv
import (
"errors"
"strings"
)
// ErrInvalidListFormat is returned when the format of a list is invalid.
var ErrInvalidListFormat = errors.New("invalid list format")
// List contains items an inner lists.
//
// See https://httpwg.org/specs/rfc8941.html#list
type List []Member
// marshalSFV serializes as defined in
// https://httpwg.org/specs/rfc8941.html#ser-list.
func (l List) marshalSFV(b *strings.Builder) error {
s := len(l)
for i := 0; i < s; i++ {
if err := l[i].marshalSFV(b); err != nil {
return err
}
if i != s-1 {
if _, err := b.WriteString(", "); err != nil {
return err
}
}
}
return nil
}
// UnmarshalList parses a list as defined in
// https://httpwg.org/specs/rfc8941.html#parse-list.
func UnmarshalList(v []string) (List, error) {
s := &scanner{
data: strings.Join(v, ","),
}
s.scanWhileSp()
sfv, err := parseList(s)
if err != nil {
return List{}, err
}
return sfv, nil
}
// parseList parses as defined in
// https://httpwg.org/specs/rfc8941.html#parse-list.
func parseList(s *scanner) (List, error) {
var l List
for !s.eof() {
m, err := parseItemOrInnerList(s)
if err != nil {
return nil, err
}
l = append(l, m)
s.scanWhileOWS()
if s.eof() {
return l, nil
}
if s.data[s.off] != ',' {
return nil, &UnmarshalError{s.off, ErrInvalidListFormat}
}
s.off++
s.scanWhileOWS()
if s.eof() {
// there is a trailing comma
return nil, &UnmarshalError{s.off, ErrInvalidListFormat}
}
}
return l, nil
}
// parseItemOrInnerList parses as defined in
// https://httpwg.org/specs/rfc8941.html#parse-item-or-list.
func parseItemOrInnerList(s *scanner) (Member, error) {
if s.eof() {
return nil, &UnmarshalError{s.off, ErrInvalidInnerListFormat}
}
if s.data[s.off] == '(' {
return parseInnerList(s)
}
return parseItem(s)
}