-
Notifications
You must be signed in to change notification settings - Fork 0
/
sfv.go
143 lines (122 loc) · 3.68 KB
/
sfv.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
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
138
139
140
141
142
143
// Package sfv provides a parser and a serializer for Structured Field Values (SFV).
package sfv
const (
// The range of Integers
MaxInteger = 999_999_999_999_999
MinInteger = -999_999_999_999_999
// Decimals must be smaller than 1e12, after it is rounded
// with more than three digits of precision in the fractional component.
//
// 0x1.d1a94a1fffffcp+39 = 999999999999.99951171875 =~ 1000000000000.000 = 1e12
// ^ rounded here
// 0x1.d1a94a1fffffbp+39 = 999999999999.9993896484375 =~ 999999999999.999 < 1e12
// ^ rounded here
// The range of Decimals
MaxDecimal = 0x1.d1a94a1fffffbp+39 // = 999999999999.9993896484375
MinDecimal = -0x1.d1a94a1fffffbp+39 // = -999999999999.9993896484375
)
// Token is a token defined in RFC 9651 Section 3.3.4. Tokens.
// The token must match the following regular expression:
//
// [a-zA-Z*][a-zA-Z0-9:/!#$%&'*+_.^_`|~-]*
type Token string
// Valid returns whether the t has valid form.
func (t Token) Valid() bool {
if t == "" {
return false
}
ch := t[0]
if ch != '*' && (ch < 'a' || ch > 'z') && (ch < 'A' || ch > 'Z') {
return false
}
for _, ch := range []byte(t[1:]) {
if !validTokenChars[ch] {
return false
}
}
return true
}
// IsValidString returns whether the s has valid form.
func IsValidString(s string) bool {
for _, ch := range []byte(s) {
if ch < 0x20 || ch >= 0x7f {
return false
}
}
return true
}
// DisplayString is a unicode string.
type DisplayString string
// Value is a bare item.
// It might be Integers, Decimals, Strings, Tokens, Byte Sequences, Booleans or Inner Lists.
// It's type is one of these:
//
// int64 for Integers
// float64 for Decimals
// string for Strings
// Token for Tokens
// []byte for Byte Sequences
// bool for Booleans
// time.Time for Date
// DisplayString for Display Strings
// InnerList for Inner Lists
type Value interface{}
// Parameter is a key-value pair of Parameters.
type Parameter struct {
// Key must match the following regular expression:
//
// [a-z*][a-z0-9_.*-]
Key string
// Value is a bare item.
Value Value
}
// Parameters are an ordered map of key-value pairs defined in RFC 9651 Section 3.1.2. Parameters.
type Parameters []Parameter
// Get returns the last value associated with the given key.
// If there are no values associated with the key, Get returns Value(nil).
func (param Parameters) Get(key string) Value {
// In many cases, there are a few parameters.
// So Linear searching is enough to handle them.
for _, kv := range param {
if kv.Key == key {
return kv.Value
}
}
return nil
}
// Len returns the number of items in the param.
func (param Parameters) Len() int {
return len(param)
}
// Item is an item defined RFC 9651 Section 3.3. Items.
type Item struct {
Value Value
Parameters Parameters
}
// InnerList is an array defined in RFC 9651 Section 3.1.1. Inner Lists.
type InnerList []Item
// List is an array defined in RFC 9651 Section 3.1. Lists.
type List []Item
// DictMember is a key-value pair of Dictionary.
type DictMember struct {
Key string
Item Item
}
// Dictionary is an ordered map of key-value pairs defined in RFC 9651 Section 3.2. Dictionaries.
type Dictionary []DictMember
// Get returns the last item associated with the given key.
// If there are no items associated with the key, Get returns the zero value of Item.
func (dict Dictionary) Get(key string) Item {
// In many cases, there are a few items.
// So Linear searching is enough to handle them.
for _, kv := range dict {
if kv.Key == key {
return kv.Item
}
}
return Item{}
}
// Len returns the number of items in the dict.
func (dict Dictionary) Len() int {
return len(dict)
}