Repository navigation
Expand file tree
/
Copy pathlenstring.go
More file actions
164 lines (149 loc) · 4.55 KB
/
Copy pathlenstring.go
File metadata and controls
164 lines (149 loc) · 4.55 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
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
package types
import (
"bytes"
"encoding/json"
"errors"
"fmt"
)
// LenString holds a string together with a minimum and maximum length constraints.
// It implements validation to ensure the string length falls within the specified bounds.
// The length is counted in bytes, not runes.
// All methods have pointer receivers, so a LenString value that is not
// addressable, like a field of a struct marshalled by value, is encoded
// by encoding/json as an empty object.
// LenString implements the encoding.TextUnmarshaler, json.Unmarshaler,
// and strfmt.Scannable interfaces that will perform length validation.
type LenString struct {
str string
min int
max int
}
// NewLenString returns a new LenString without validating it.
// Use this when you want to create a LenString and validate it separately.
func NewLenString(str string, min, max int) *LenString {
return &LenString{
str: str,
min: min,
max: max,
}
}
// MustLenString returns a LenString or panics on errors from Validate.
// Use this when you're certain the string meets the length constraints.
func MustLenString(str string, min, max int) LenString {
s := LenString{
str: str,
min: min,
max: max,
}
err := s.Validate()
if err != nil {
panic(err)
}
return s
}
// Validate implements the Validatable interface.
// It checks that the minimum and maximum lengths are valid and that the string
// length falls within the specified bounds.
func (s *LenString) Validate() error {
if s == nil {
return errors.New("nil LenString")
}
if s.min < 0 {
return fmt.Errorf("negative minimum length %d of LenString %q", s.min, s.str)
}
if s.max < 0 {
return fmt.Errorf("negative maximum length %d of LenString %q", s.max, s.str)
}
if s.min > s.max {
return fmt.Errorf("minimum length %d is greater than maximum length %d of LenString %q", s.min, s.max, s.str)
}
return s.validateLen(s.str)
}
// validateLen checks if the string length is within the min/max bounds.
func (s *LenString) validateLen(str string) error {
l := len(str)
if l < s.min {
return fmt.Errorf("length %d of LenString %q is shorter than minimum of %d", l, str, s.min)
}
if l > s.max {
return fmt.Errorf("length %d of LenString %q is longer than maximum of %d", l, str, s.max)
}
return nil
}
// String returns the string or "<nil>".
// String implements the fmt.Stringer interface.
func (s *LenString) String() string {
if s == nil {
return "<nil>"
}
return s.str
}
// SetString sets the string value after validating it against the length constraints.
// Returns an error if the string doesn't meet the length requirements.
func (s *LenString) SetString(str string) error {
if err := s.validateLen(str); err != nil {
return err
}
s.str = str
return nil
}
// MinLen returns the minimum allowed length for the string.
func (s *LenString) MinLen() int {
return s.min
}
// MaxLen returns the maximum allowed length for the string.
func (s *LenString) MaxLen() int {
return s.max
}
// MarshalText implements the encoding.TextMarshaler interface.
func (s *LenString) MarshalText() (text []byte, err error) {
if s == nil {
return nil, nil
}
return []byte(s.str), nil
}
// UnmarshalText implements the encoding.TextUnmarshaler interface.
// It validates the text length before setting the string value.
func (s *LenString) UnmarshalText(text []byte) error {
return s.SetString(string(text))
}
// MarshalJSON implements the json.Marshaler interface.
func (s *LenString) MarshalJSON() (text []byte, err error) {
if s == nil {
return []byte("null"), nil
}
return json.Marshal(s.str)
}
// UnmarshalJSON implements the json.Unmarshaler interface.
// It validates the string length after unmarshaling from JSON
// and leaves the value unchanged if the length is not valid.
// JSON null leaves the value unchanged too.
func (s *LenString) UnmarshalJSON(text []byte) error {
if bytes.Equal(text, []byte("null")) {
return nil // no-op
}
var str string
err := json.Unmarshal(text, &str)
if err != nil {
return fmt.Errorf("can't unmarshal JSON to LenString because of: %w", err)
}
return s.SetString(str)
}
// ScanString tries to parse and assign the passed
// source string as value of the implementing type.
//
// If validate is true, the source string is checked
// for validity before it is assigned to the type.
//
// If validate is false and the source string
// can still be assigned in some non-normalized way
// it will be assigned without returning an error.
func (s *LenString) ScanString(source string, validate bool) error {
if validate {
if err := s.validateLen(source); err != nil {
return err
}
}
s.str = source
return nil
}