Skip to content

Commit 54bed95

Browse files
committed
update the common methods in Value
1 parent f1e26f4 commit 54bed95

File tree

10 files changed

+475
-109
lines changed

10 files changed

+475
-109
lines changed

tftypes/refinement/collection_length_lower_bound.go

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,19 +3,24 @@
33

44
package refinement
55

6+
import "fmt"
7+
68
// TODO: doc
79
type CollectionLengthLowerBound struct {
810
value int64
911
}
1012

11-
func (n CollectionLengthLowerBound) Equal(Refinement) bool {
12-
// TODO: implement
13-
return false
13+
func (n CollectionLengthLowerBound) Equal(other Refinement) bool {
14+
otherVal, ok := other.(CollectionLengthLowerBound)
15+
if !ok {
16+
return false
17+
}
18+
19+
return n.LowerBound() == otherVal.LowerBound()
1420
}
1521

1622
func (n CollectionLengthLowerBound) String() string {
17-
// TODO: implement
18-
return "todo - CollectionLengthLowerBound"
23+
return fmt.Sprintf("length lower bound = %d", n.LowerBound())
1924
}
2025

2126
// TODO: doc

tftypes/refinement/collection_length_upper_bound.go

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,19 +3,24 @@
33

44
package refinement
55

6+
import "fmt"
7+
68
// TODO: doc
79
type CollectionLengthUpperBound struct {
810
value int64
911
}
1012

11-
func (n CollectionLengthUpperBound) Equal(Refinement) bool {
12-
// TODO: implement
13-
return false
13+
func (n CollectionLengthUpperBound) Equal(other Refinement) bool {
14+
otherVal, ok := other.(CollectionLengthUpperBound)
15+
if !ok {
16+
return false
17+
}
18+
19+
return n.UpperBound() == otherVal.UpperBound()
1420
}
1521

1622
func (n CollectionLengthUpperBound) String() string {
17-
// TODO: implement
18-
return "todo - CollectionLengthUpperBound"
23+
return fmt.Sprintf("length upper bound = %d", n.UpperBound())
1924
}
2025

2126
// TODO: doc

tftypes/refinement/nullness.go

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,23 @@ type Nullness struct {
88
value bool
99
}
1010

11-
func (n Nullness) Equal(Refinement) bool {
12-
// TODO: implement
13-
return false
11+
func (n Nullness) Equal(other Refinement) bool {
12+
otherVal, ok := other.(Nullness)
13+
if !ok {
14+
return false
15+
}
16+
17+
return n.Nullness() == otherVal.Nullness()
1418
}
1519

1620
func (n Nullness) String() string {
17-
// TODO: implement
18-
return "todo - Nullness"
21+
if n.value {
22+
// This case should never happen, as an unknown value that is definitely null should be
23+
// represented as a known null value.
24+
return "null"
25+
}
26+
27+
return "not null"
1928
}
2029

2130
// TODO: doc

tftypes/refinement/number_lower_bound.go

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
package refinement
55

66
import (
7+
"fmt"
78
"math/big"
89
)
910

@@ -13,14 +14,22 @@ type NumberLowerBound struct {
1314
value *big.Float
1415
}
1516

16-
func (n NumberLowerBound) Equal(Refinement) bool {
17-
// TODO: implement
18-
return false
17+
func (n NumberLowerBound) Equal(other Refinement) bool {
18+
otherVal, ok := other.(NumberLowerBound)
19+
if !ok {
20+
return false
21+
}
22+
23+
return n.IsInclusive() == otherVal.IsInclusive() && n.LowerBound().Cmp(otherVal.LowerBound()) == 0
1924
}
2025

2126
func (n NumberLowerBound) String() string {
22-
// TODO: implement
23-
return "todo - NumberLowerBound"
27+
rangeDescription := "inclusive"
28+
if !n.IsInclusive() {
29+
rangeDescription = "exclusive"
30+
}
31+
32+
return fmt.Sprintf("lower bound = %s (%s)", n.LowerBound().String(), rangeDescription)
2433
}
2534

2635
// TODO: doc

tftypes/refinement/number_upper_bound.go

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
package refinement
55

66
import (
7+
"fmt"
78
"math/big"
89
)
910

@@ -13,14 +14,22 @@ type NumberUpperBound struct {
1314
value *big.Float
1415
}
1516

16-
func (n NumberUpperBound) Equal(Refinement) bool {
17-
// TODO: implement
18-
return false
17+
func (n NumberUpperBound) Equal(other Refinement) bool {
18+
otherVal, ok := other.(NumberUpperBound)
19+
if !ok {
20+
return false
21+
}
22+
23+
return n.IsInclusive() == otherVal.IsInclusive() && n.UpperBound().Cmp(otherVal.UpperBound()) == 0
1924
}
2025

2126
func (n NumberUpperBound) String() string {
22-
// TODO: implement
23-
return "todo - NumberUpperBound"
27+
rangeDescription := "inclusive"
28+
if !n.IsInclusive() {
29+
rangeDescription = "exclusive"
30+
}
31+
32+
return fmt.Sprintf("upper bound = %s (%s)", n.UpperBound().String(), rangeDescription)
2433
}
2534

2635
// TODO: doc

tftypes/refinement/refinement.go

Lines changed: 37 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ package refinement
55

66
import (
77
"fmt"
8+
"sort"
9+
"strings"
810
)
911

1012
type Key int64
@@ -78,10 +80,41 @@ type Refinement interface {
7880
// TODO: docs
7981
type Refinements map[Key]Refinement
8082

81-
func (r Refinements) Equal(o Refinements) bool {
82-
return false
83+
func (r Refinements) Equal(other Refinements) bool {
84+
if len(r) != len(other) {
85+
return false
86+
}
87+
88+
for key, refnVal := range r {
89+
otherRefnVal, ok := other[key]
90+
if !ok {
91+
// Didn't find a refinement at the same key
92+
return false
93+
}
94+
95+
if !refnVal.Equal(otherRefnVal) {
96+
// Refinement data is not equal
97+
return false
98+
}
99+
}
100+
101+
return true
83102
}
84103
func (r Refinements) String() string {
85-
// TODO: Not sure when this is used, should just aggregate and call all underlying refinements.String() method
86-
return "todo"
104+
var res strings.Builder
105+
106+
keys := make([]Key, 0, len(r))
107+
for k := range r {
108+
keys = append(keys, k)
109+
}
110+
111+
sort.Slice(keys, func(a, b int) bool { return keys[a] < keys[b] })
112+
for pos, key := range keys {
113+
if pos != 0 {
114+
res.WriteString(", ")
115+
}
116+
res.WriteString(r[key].String())
117+
}
118+
119+
return res.String()
87120
}

tftypes/refinement/string_prefix.go

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,19 +3,24 @@
33

44
package refinement
55

6+
import "fmt"
7+
68
// TODO: doc
79
type StringPrefix struct {
810
value string
911
}
1012

11-
func (s StringPrefix) Equal(Refinement) bool {
12-
// TODO: implement
13-
return false
13+
func (s StringPrefix) Equal(other Refinement) bool {
14+
otherVal, ok := other.(StringPrefix)
15+
if !ok {
16+
return false
17+
}
18+
19+
return s.PrefixValue() == otherVal.PrefixValue()
1420
}
1521

1622
func (s StringPrefix) String() string {
17-
// TODO: implement
18-
return "todo - stringPrefix"
23+
return fmt.Sprintf("prefix = %q", s.PrefixValue())
1924
}
2025

2126
// TODO: doc

tftypes/value.go

Lines changed: 37 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -63,10 +63,16 @@ func (val Value) String() string {
6363
return typ.String() + "<null>"
6464
}
6565

66-
// TODO: print refinements
67-
6866
if !val.IsKnown() {
69-
return typ.String() + "<unknown>"
67+
var res strings.Builder
68+
res.WriteString(typ.String())
69+
res.WriteString("<unknown")
70+
if len(val.refinements) > 0 {
71+
res.WriteString(", " + val.Refinements().String())
72+
}
73+
res.WriteString(">")
74+
75+
return res.String()
7076
}
7177

7278
// everything else is built up
@@ -230,7 +236,13 @@ func (val Value) Equal(o Value) bool {
230236
return false
231237
}
232238

233-
// TODO: compare refinements
239+
if len(val.refinements) != len(o.refinements) {
240+
return false
241+
}
242+
243+
if len(val.refinements) > 0 && !val.refinements.Equal(o.refinements) {
244+
return false
245+
}
234246

235247
deepEqual, err := val.deepEqual(o)
236248
if err != nil {
@@ -242,9 +254,6 @@ func (val Value) Equal(o Value) bool {
242254
// Copy returns a defensively-copied clone of Value that shares no underlying
243255
// data structures with the original Value and can be mutated without
244256
// accidentally mutating the original.
245-
//
246-
// TODO: Make sure this actually works for refinements. Consuming packages should not be able to mutate refinements of val
247-
// TODO: Add docs referencing refinements
248257
func (val Value) Copy() Value {
249258
newVal := val.value
250259
switch v := val.value.(type) {
@@ -263,7 +272,15 @@ func (val Value) Copy() Value {
263272
}
264273

265274
newTfValue := NewValue(val.Type(), newVal)
266-
newTfValue.refinements = val.refinements
275+
276+
if len(val.refinements) > 0 {
277+
newRefinements := make(refinement.Refinements, len(val.refinements))
278+
for key, refnVal := range val.refinements {
279+
newRefinements[key] = refnVal
280+
}
281+
282+
newTfValue.refinements = newRefinements
283+
}
267284

268285
return newTfValue
269286
}
@@ -611,19 +628,28 @@ func unexpectedValueTypeError(p *AttributePath, expected, got interface{}, typ T
611628
return p.NewErrorf("unexpected value type %T, %s values must be of type %T", got, typ, expected)
612629
}
613630

614-
// TODO: do we need to return an error? Like if you attempt to refine a value improperly (like string prefix on a number)?
631+
// TODO: doc, mention returning value if not unknown
615632
func (val Value) Refine(refinements refinement.Refinements) Value {
616633
newVal := val.Copy()
617634

635+
// Refinements are only relevant for unknown values
636+
if val.IsKnown() {
637+
return newVal
638+
}
639+
618640
if len(refinements) >= 0 {
619-
newVal.refinements = refinements
641+
newRefinements := make(refinement.Refinements, len(refinements))
642+
for key, refnVal := range refinements {
643+
newRefinements[key] = refnVal
644+
}
645+
newVal.refinements = newRefinements
620646
}
621647

622648
return newVal
623649
}
624650

651+
// TODO: doc, mention copy
625652
func (val Value) Refinements() refinement.Refinements {
626-
// TODO: is this copy really needed?
627653
valCopy := val.Copy()
628654

629655
return valCopy.refinements

0 commit comments

Comments
 (0)