-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathordered.go
165 lines (147 loc) · 3.86 KB
/
ordered.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
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
package constraints
import (
"fmt"
typecons "golang.org/x/exp/constraints"
)
// Min creates a Constraint which will declare an instance is valid
// if its value is greater than or equal to refValue.
func Min[
ValueT typecons.Ordered,
](refValue ValueT) OrderedConstraint[ValueT] {
return Func(
fmt.Sprintf("min %v", refValue),
GreaterThanOrEqualTo(refValue).IsValid)
}
// Max creates a Constraint which will declare an instance is valid
// if its value is less than or equal to refValue.
func Max[
ValueT typecons.Ordered,
](refValue ValueT) OrderedConstraint[ValueT] {
return Func(
fmt.Sprintf("max %v", refValue),
LessThanOrEqualTo(refValue).IsValid)
}
// LessThan creates an Constraint which an instance will be
// declared as valid if its value is less than refValue.
func LessThan[
ValueT typecons.Ordered,
](refValue ValueT) OrderedConstraint[ValueT] {
return &relOpConstraint[ValueT]{ref: refValue, op: relOpLess}
}
// LessThanOrEqualTo creates an Constraint which an instance will be
// declared as valid if its value is less than or equal to refValue.
func LessThanOrEqualTo[
ValueT typecons.Ordered,
](refValue ValueT) OrderedConstraint[ValueT] {
return &relOpConstraint[ValueT]{ref: refValue, op: relOpLessOrEqual}
}
// GreaterThan creates an Constraint which an instance will be declared
// as valid if its value is greater than refValue.
func GreaterThan[
ValueT typecons.Ordered,
](refValue ValueT) OrderedConstraint[ValueT] {
return &relOpConstraint[ValueT]{ref: refValue, op: relOpGreater}
}
// GreaterThanOrEqualTo creates an Constraint which an instance will be
// declared as valid if its value is greater than or equal to refValue.
func GreaterThanOrEqualTo[
ValueT typecons.Ordered,
](refValue ValueT) OrderedConstraint[ValueT] {
return &relOpConstraint[ValueT]{ref: refValue, op: relOpGreaterOrEqual}
}
type OrderedConstraint[ValueT typecons.Ordered] interface {
Constraint[ValueT]
}
var (
_ OrderedConstraint[int] = &relOpConstraint[int]{}
_ OrderedConstraint[int] = relOpConstraint[int]{}
)
type relOpConstraint[ValueT typecons.Ordered] struct {
op relOp
ref ValueT
}
func (c relOpConstraint[ValueT]) ConstraintDescription() string {
return fmt.Sprintf(c.op.StringFormat(), c.ref)
}
func (c relOpConstraint[ValueT]) IsValid(v ValueT) bool {
switch c.op {
case relOpEqual:
return v == c.ref
case relOpNotEqual:
return v != c.ref
case relOpLess:
return v < c.ref
case relOpLessOrEqual:
return v <= c.ref
case relOpGreater:
return v > c.ref
case relOpGreaterOrEqual:
return v >= c.ref
}
return false
}
// An relOp specifies relational operator.
type relOp int
// Supported relational operators.
const (
relOpEqual relOp = iota
relOpNotEqual
relOpLess
relOpLessOrEqual
relOpGreater
relOpGreaterOrEqual
)
func (op relOp) String() string {
switch op {
case relOpEqual:
return "equal"
case relOpNotEqual:
return "not equal"
case relOpLess:
return "less"
case relOpLessOrEqual:
return "less or equal"
case relOpGreater:
return "greater"
case relOpGreaterOrEqual:
return "greater or equal"
}
return ""
}
// Symbol returns representative symbol of the operator.
func (op relOp) Symbol() string {
switch op {
case relOpEqual:
return "="
case relOpNotEqual:
return "≠"
case relOpLess:
return "<"
case relOpLessOrEqual:
return "≤"
case relOpGreater:
return ">"
case relOpGreaterOrEqual:
return "≥"
}
return "?"
}
// StringFormat returns a string which could be used to in *printf functions.
// The string format expects a value to be passed.
func (op relOp) StringFormat() string {
switch op {
case relOpEqual:
return "equals %v"
case relOpNotEqual:
return "not equal to %v"
case relOpLess:
return "less than %v"
case relOpLessOrEqual:
return "less than or equal to %v"
case relOpGreater:
return "greater than %v"
case relOpGreaterOrEqual:
return "greater than or equal to %v"
}
return "(%v)"
}