-
-
Notifications
You must be signed in to change notification settings - Fork 8
/
integer.go
120 lines (90 loc) · 2.25 KB
/
integer.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
package httpsfv
import (
"errors"
"io"
"strconv"
)
const maxDigit = 12
// ErrNotDigit is returned when a character should be a digit but isn't.
var ErrNotDigit = errors.New("character is not a digit")
// ErrNumberOutOfRange is returned when the number is too large according to the specification.
var ErrNumberOutOfRange = errors.New("integer or decimal out of range")
// ErrInvalidDecimalFormat is returned when the decimal format is invalid.
var ErrInvalidDecimalFormat = errors.New("invalid decimal format")
const (
typeInteger = iota
typeDecimal
)
// marshalInteger serialized as defined in
// https://httpwg.org/specs/rfc8941.html#integer.
func marshalInteger(b io.StringWriter, i int64) error {
if i < -999999999999999 || i > 999999999999999 {
return ErrNumberOutOfRange
}
_, err := b.WriteString(strconv.FormatInt(i, 10))
return err
}
// parseNumber parses as defined in
// https://httpwg.org/specs/rfc8941.html#parse-number.
func parseNumber(s *scanner) (interface{}, error) {
neg := isNeg(s)
if neg && s.eof() {
return 0, &UnmarshalError{s.off, ErrUnexpectedEndOfString}
}
if !isDigit(s.data[s.off]) {
return 0, &UnmarshalError{s.off, ErrNotDigit}
}
start := s.off
s.off++
var (
decSepOff int
t int = typeInteger
)
for s.off < len(s.data) {
size := s.off - start
if (t == typeInteger && (size >= 15)) || size >= 16 {
return 0, &UnmarshalError{s.off, ErrNumberOutOfRange}
}
c := s.data[s.off]
if isDigit(c) {
s.off++
continue
}
if t == typeInteger && c == '.' {
if size > maxDigit {
return 0, &UnmarshalError{s.off, ErrNumberOutOfRange}
}
t = typeDecimal
decSepOff = s.off
s.off++
continue
}
break
}
str := s.data[start:s.off]
if t == typeInteger {
return parseInteger(str, neg, s.off)
}
return parseDecimal(s, decSepOff, str, neg)
}
func isNeg(s *scanner) bool {
if s.data[s.off] == '-' {
s.off++
return true
}
return false
}
func parseInteger(str string, neg bool, off int) (int64, error) {
i, err := strconv.ParseInt(str, 10, 64)
if err != nil {
// Should never happen
return 0, &UnmarshalError{off, err}
}
if neg {
i = -i
}
if i < -999999999999999 || i > 999999999999999 {
return 0, &UnmarshalError{off, ErrNumberOutOfRange}
}
return i, err
}