mirror of
https://gitea.com/Lydanne/buildx.git
synced 2025-07-09 21:17:09 +08:00
vendor: update github.com/hashicorp/hcl/v2 to v2.19.1
Signed-off-by: CrazyMax <crazy-max@users.noreply.github.com>
This commit is contained in:
747
vendor/github.com/zclconf/go-cty/cty/unknown_refinement.go
generated
vendored
Normal file
747
vendor/github.com/zclconf/go-cty/cty/unknown_refinement.go
generated
vendored
Normal file
@ -0,0 +1,747 @@
|
||||
package cty
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"strings"
|
||||
|
||||
"github.com/zclconf/go-cty/cty/ctystrings"
|
||||
)
|
||||
|
||||
// Refine creates a [RefinementBuilder] with which to annotate the reciever
|
||||
// with zero or more additional refinements that constrain the range of
|
||||
// the value.
|
||||
//
|
||||
// Calling methods on a RefinementBuilder for a known value essentially just
|
||||
// serves as assertions about the range of that value, leading to panics if
|
||||
// those assertions don't hold in practice. This is mainly supported just to
|
||||
// make programs that rely on refinements automatically self-check by using
|
||||
// the refinement codepath unconditionally on both placeholders and final
|
||||
// values for those placeholders. It's always a bug to refine the range of
|
||||
// an unknown value and then later substitute an exact value outside of the
|
||||
// refined range.
|
||||
//
|
||||
// Calling methods on a RefinementBuilder for an unknown value is perhaps
|
||||
// more useful because the newly-refined value will then be a placeholder for
|
||||
// a smaller range of values and so it may be possible for other operations
|
||||
// on the unknown value to return a known result despite the exact value not
|
||||
// yet being known.
|
||||
//
|
||||
// It is never valid to refine [DynamicVal], because that value is a
|
||||
// placeholder for a value about which we knkow absolutely nothing. A value
|
||||
// must at least have a known root type before it can support further
|
||||
// refinement.
|
||||
func (v Value) Refine() *RefinementBuilder {
|
||||
v, marks := v.Unmark()
|
||||
if unk, isUnk := v.v.(*unknownType); isUnk && unk.refinement != nil {
|
||||
// We're refining a value that's already been refined before, so
|
||||
// we'll start from a copy of its existing refinements.
|
||||
wip := unk.refinement.copy()
|
||||
return &RefinementBuilder{v, marks, wip}
|
||||
}
|
||||
|
||||
ty := v.Type()
|
||||
var wip unknownValRefinement
|
||||
switch {
|
||||
case ty == DynamicPseudoType && !v.IsKnown():
|
||||
panic("cannot refine an unknown value of an unknown type")
|
||||
case ty == String:
|
||||
wip = &refinementString{}
|
||||
case ty == Number:
|
||||
wip = &refinementNumber{}
|
||||
case ty.IsCollectionType():
|
||||
wip = &refinementCollection{
|
||||
// A collection can never have a negative length, so we'll
|
||||
// start with that already constrained.
|
||||
minLen: 0,
|
||||
maxLen: math.MaxInt,
|
||||
}
|
||||
case ty == Bool || ty.IsObjectType() || ty.IsTupleType() || ty.IsCapsuleType():
|
||||
// For other known types we'll just track nullability
|
||||
wip = &refinementNullable{}
|
||||
case ty == DynamicPseudoType && v.IsNull():
|
||||
// It's okay in principle to refine a null value of unknown type,
|
||||
// although all we can refine about it is that it's definitely null and
|
||||
// so this is pretty pointless and only supported to avoid callers
|
||||
// always needing to treat this situation as a special case to avoid
|
||||
// panic.
|
||||
wip = &refinementNullable{
|
||||
isNull: tristateTrue,
|
||||
}
|
||||
default:
|
||||
// we leave "wip" as nil for all other types, representing that
|
||||
// they don't support refinements at all and so any call on the
|
||||
// RefinementBuilder should fail.
|
||||
|
||||
// NOTE: We intentionally don't allow any refinements for
|
||||
// cty.DynamicVal here, even though it could be nice in principle
|
||||
// to at least track non-nullness for those, because it's historically
|
||||
// been valid to directly compare values with cty.DynamicVal using
|
||||
// the Go "==" operator and recording a refinement for an untyped
|
||||
// unknown value would break existing code relying on that.
|
||||
}
|
||||
|
||||
return &RefinementBuilder{v, marks, wip}
|
||||
}
|
||||
|
||||
// RefineWith is a variant of Refine which uses callback functions instead of
|
||||
// the builder pattern.
|
||||
//
|
||||
// The result is equivalent to passing the return value of [Value.Refine] to the
|
||||
// first callback, and then continue passing the builder through any other
|
||||
// callbacks in turn, and then calling [RefinementBuilder.NewValue] on the
|
||||
// final result.
|
||||
//
|
||||
// The builder pattern approach of [Value.Refine] is more convenient for inline
|
||||
// annotation of refinements when constructing a value, but this alternative
|
||||
// approach may be more convenient when applying pre-defined collections of
|
||||
// refinements, or when refinements are defined separately from the values
|
||||
// they will apply to.
|
||||
//
|
||||
// Each refiner callback should return the same pointer that it was given,
|
||||
// typically after having mutated it using the [RefinementBuilder] methods.
|
||||
// It's invalid to return a different builder.
|
||||
func (v Value) RefineWith(refiners ...func(*RefinementBuilder) *RefinementBuilder) Value {
|
||||
if len(refiners) == 0 {
|
||||
return v
|
||||
}
|
||||
origBuilder := v.Refine()
|
||||
builder := origBuilder
|
||||
for _, refiner := range refiners {
|
||||
builder = refiner(builder)
|
||||
if builder != origBuilder {
|
||||
panic("refiner callback returned a different builder")
|
||||
}
|
||||
}
|
||||
return builder.NewValue()
|
||||
}
|
||||
|
||||
// RefineNotNull is a shorthand for Value.Refine().NotNull().NewValue(), because
|
||||
// declaring that a unknown value isn't null is by far the most common use of
|
||||
// refinements.
|
||||
func (v Value) RefineNotNull() Value {
|
||||
return v.Refine().NotNull().NewValue()
|
||||
}
|
||||
|
||||
// RefinementBuilder is a supporting type for the [Value.Refine] method,
|
||||
// using the builder pattern to apply zero or more constraints before
|
||||
// constructing a new value with all of those constraints applied.
|
||||
//
|
||||
// Most of the methods of this type return the same reciever to allow
|
||||
// for method call chaining. End call chains with a call to
|
||||
// [RefinementBuilder.NewValue] to obtain the newly-refined value.
|
||||
type RefinementBuilder struct {
|
||||
orig Value
|
||||
marks ValueMarks
|
||||
wip unknownValRefinement
|
||||
}
|
||||
|
||||
func (b *RefinementBuilder) assertRefineable() {
|
||||
if b.wip == nil {
|
||||
panic(fmt.Sprintf("cannot refine a %#v value", b.orig.Type()))
|
||||
}
|
||||
}
|
||||
|
||||
// NotNull constrains the value as definitely not being null.
|
||||
//
|
||||
// NotNull is valid when refining values of the following types:
|
||||
// - number, boolean, and string values
|
||||
// - list, set, or map types of any element type
|
||||
// - values of object types
|
||||
// - values of collection types
|
||||
// - values of capsule types
|
||||
//
|
||||
// When refining any other type this function will panic.
|
||||
//
|
||||
// In particular note that it is not valid to constrain an untyped value
|
||||
// -- a value whose type is `cty.DynamicPseudoType` -- as being non-null.
|
||||
// An unknown value of an unknown type is always completely unconstrained.
|
||||
func (b *RefinementBuilder) NotNull() *RefinementBuilder {
|
||||
b.assertRefineable()
|
||||
|
||||
if b.orig.IsKnown() && b.orig.IsNull() {
|
||||
panic("refining null value as non-null")
|
||||
}
|
||||
if b.wip.null() == tristateTrue {
|
||||
panic("refining null value as non-null")
|
||||
}
|
||||
|
||||
b.wip.setNull(tristateFalse)
|
||||
|
||||
return b
|
||||
}
|
||||
|
||||
// Null constrains the value as definitely null.
|
||||
//
|
||||
// Null is valid for the same types as [RefinementBuilder.NotNull].
|
||||
// When refining any other type this function will panic.
|
||||
//
|
||||
// Explicitly cnstraining a value to be null is strange because that suggests
|
||||
// that the caller does actually know the value -- there is only one null
|
||||
// value for each type constraint -- but this is here for symmetry with the
|
||||
// fact that a [ValueRange] can also represent that a value is definitely null.
|
||||
func (b *RefinementBuilder) Null() *RefinementBuilder {
|
||||
b.assertRefineable()
|
||||
|
||||
if b.orig.IsKnown() && !b.orig.IsNull() {
|
||||
panic("refining non-null value as null")
|
||||
}
|
||||
if b.wip.null() == tristateFalse {
|
||||
panic("refining non-null value as null")
|
||||
}
|
||||
|
||||
b.wip.setNull(tristateTrue)
|
||||
|
||||
return b
|
||||
}
|
||||
|
||||
// NumericRange constrains the upper and/or lower bounds of a number value,
|
||||
// or panics if this builder is not refining a number value.
|
||||
//
|
||||
// The two given values are interpreted as inclusive bounds and either one
|
||||
// may be an unknown number if only one of the two bounds is currently known.
|
||||
// If either of the given values is not a non-null number value then this
|
||||
// function will panic.
|
||||
func (b *RefinementBuilder) NumberRangeInclusive(min, max Value) *RefinementBuilder {
|
||||
return b.NumberRangeLowerBound(min, true).NumberRangeUpperBound(max, true)
|
||||
}
|
||||
|
||||
// NumberRangeLowerBound constraints the lower bound of a number value, or
|
||||
// panics if this builder is not refining a number value.
|
||||
func (b *RefinementBuilder) NumberRangeLowerBound(min Value, inclusive bool) *RefinementBuilder {
|
||||
b.assertRefineable()
|
||||
|
||||
wip, ok := b.wip.(*refinementNumber)
|
||||
if !ok {
|
||||
panic(fmt.Sprintf("cannot refine numeric bounds for a %#v value", b.orig.Type()))
|
||||
}
|
||||
|
||||
if !min.IsKnown() {
|
||||
// Nothing to do if the lower bound is unknown.
|
||||
return b
|
||||
}
|
||||
if min.IsNull() {
|
||||
panic("number range lower bound must not be null")
|
||||
}
|
||||
|
||||
if inclusive {
|
||||
if gt := min.GreaterThan(b.orig); gt.IsKnown() && gt.True() {
|
||||
panic(fmt.Sprintf("refining %#v to be >= %#v", b.orig, min))
|
||||
}
|
||||
} else {
|
||||
if gt := min.GreaterThanOrEqualTo(b.orig); gt.IsKnown() && gt.True() {
|
||||
panic(fmt.Sprintf("refining %#v to be > %#v", b.orig, min))
|
||||
}
|
||||
}
|
||||
|
||||
if wip.min != NilVal {
|
||||
var ok Value
|
||||
if inclusive && !wip.minInc {
|
||||
ok = min.GreaterThan(wip.min)
|
||||
} else {
|
||||
ok = min.GreaterThanOrEqualTo(wip.min)
|
||||
}
|
||||
if ok.IsKnown() && ok.False() {
|
||||
return b // Our existing refinement is more constrained
|
||||
}
|
||||
}
|
||||
|
||||
if min != NegativeInfinity {
|
||||
wip.min = min
|
||||
wip.minInc = inclusive
|
||||
}
|
||||
|
||||
wip.assertConsistentBounds()
|
||||
return b
|
||||
}
|
||||
|
||||
// NumberRangeUpperBound constraints the upper bound of a number value, or
|
||||
// panics if this builder is not refining a number value.
|
||||
func (b *RefinementBuilder) NumberRangeUpperBound(max Value, inclusive bool) *RefinementBuilder {
|
||||
b.assertRefineable()
|
||||
|
||||
wip, ok := b.wip.(*refinementNumber)
|
||||
if !ok {
|
||||
panic(fmt.Sprintf("cannot refine numeric bounds for a %#v value", b.orig.Type()))
|
||||
}
|
||||
|
||||
if !max.IsKnown() {
|
||||
// Nothing to do if the upper bound is unknown.
|
||||
return b
|
||||
}
|
||||
if max.IsNull() {
|
||||
panic("number range upper bound must not be null")
|
||||
}
|
||||
|
||||
if inclusive {
|
||||
if lt := max.LessThan(b.orig); lt.IsKnown() && lt.True() {
|
||||
panic(fmt.Sprintf("refining %#v to be <= %#v", b.orig, max))
|
||||
}
|
||||
} else {
|
||||
if lt := max.LessThanOrEqualTo(b.orig); lt.IsKnown() && lt.True() {
|
||||
panic(fmt.Sprintf("refining %#v to be < %#v", b.orig, max))
|
||||
}
|
||||
}
|
||||
|
||||
if wip.max != NilVal {
|
||||
var ok Value
|
||||
if inclusive && !wip.maxInc {
|
||||
ok = max.LessThan(wip.max)
|
||||
} else {
|
||||
ok = max.LessThanOrEqualTo(wip.max)
|
||||
}
|
||||
if ok.IsKnown() && ok.False() {
|
||||
return b // Our existing refinement is more constrained
|
||||
}
|
||||
}
|
||||
|
||||
if max != PositiveInfinity {
|
||||
wip.max = max
|
||||
wip.maxInc = inclusive
|
||||
}
|
||||
|
||||
wip.assertConsistentBounds()
|
||||
return b
|
||||
}
|
||||
|
||||
// CollectionLengthLowerBound constrains the lower bound of the length of a
|
||||
// collection value, or panics if this builder is not refining a collection
|
||||
// value.
|
||||
func (b *RefinementBuilder) CollectionLengthLowerBound(min int) *RefinementBuilder {
|
||||
b.assertRefineable()
|
||||
|
||||
wip, ok := b.wip.(*refinementCollection)
|
||||
if !ok {
|
||||
panic(fmt.Sprintf("cannot refine collection length bounds for a %#v value", b.orig.Type()))
|
||||
}
|
||||
|
||||
minVal := NumberIntVal(int64(min))
|
||||
if b.orig.IsKnown() {
|
||||
realLen := b.orig.Length()
|
||||
if gt := minVal.GreaterThan(realLen); gt.IsKnown() && gt.True() {
|
||||
panic(fmt.Sprintf("refining collection of length %#v with lower bound %#v", realLen, min))
|
||||
}
|
||||
}
|
||||
|
||||
if wip.minLen > min {
|
||||
return b // Our existing refinement is more constrained
|
||||
}
|
||||
|
||||
wip.minLen = min
|
||||
wip.assertConsistentLengthBounds()
|
||||
|
||||
return b
|
||||
}
|
||||
|
||||
// CollectionLengthUpperBound constrains the upper bound of the length of a
|
||||
// collection value, or panics if this builder is not refining a collection
|
||||
// value.
|
||||
//
|
||||
// The upper bound must be a known, non-null number or this function will
|
||||
// panic.
|
||||
func (b *RefinementBuilder) CollectionLengthUpperBound(max int) *RefinementBuilder {
|
||||
b.assertRefineable()
|
||||
|
||||
wip, ok := b.wip.(*refinementCollection)
|
||||
if !ok {
|
||||
panic(fmt.Sprintf("cannot refine collection length bounds for a %#v value", b.orig.Type()))
|
||||
}
|
||||
|
||||
if b.orig.IsKnown() {
|
||||
maxVal := NumberIntVal(int64(max))
|
||||
realLen := b.orig.Length()
|
||||
if lt := maxVal.LessThan(realLen); lt.IsKnown() && lt.True() {
|
||||
panic(fmt.Sprintf("refining collection of length %#v with upper bound %#v", realLen, max))
|
||||
}
|
||||
}
|
||||
|
||||
if wip.maxLen < max {
|
||||
return b // Our existing refinement is more constrained
|
||||
}
|
||||
|
||||
wip.maxLen = max
|
||||
wip.assertConsistentLengthBounds()
|
||||
|
||||
return b
|
||||
}
|
||||
|
||||
// CollectionLength is a shorthand for passing the same length to both
|
||||
// [CollectionLengthLowerBound] and [CollectionLengthUpperBound].
|
||||
//
|
||||
// A collection with a refined length with equal bounds can sometimes collapse
|
||||
// to a known value. Refining to length zero always produces a known value.
|
||||
// The behavior for other lengths varies by collection type kind.
|
||||
//
|
||||
// If the unknown value is of a set type, it's only valid to use this method
|
||||
// if the caller knows that there will be the given number of _unique_ values
|
||||
// in the set. If any values might potentially coalesce together once known,
|
||||
// use [CollectionLengthUpperBound] instead.
|
||||
func (b *RefinementBuilder) CollectionLength(length int) *RefinementBuilder {
|
||||
return b.CollectionLengthLowerBound(length).CollectionLengthUpperBound(length)
|
||||
}
|
||||
|
||||
// StringPrefix constrains the prefix of a string value, or panics if this
|
||||
// builder is not refining a string value.
|
||||
//
|
||||
// The given prefix will be Unicode normalized in the same way that a
|
||||
// cty.StringVal would be.
|
||||
//
|
||||
// Due to Unicode normalization and grapheme cluster rules, appending new
|
||||
// characters to a string can change the meaning of earlier characters.
|
||||
// StringPrefix may discard one or more characters from the end of the given
|
||||
// prefix to avoid that problem.
|
||||
//
|
||||
// Although cty cannot check this automatically, applications should avoid
|
||||
// relying on the discarding of the suffix for correctness. For example, if the
|
||||
// prefix ends with an emoji base character then StringPrefix will discard it
|
||||
// in case subsequent characters include emoji modifiers, but it's still
|
||||
// incorrect for the final string to use an entirely different base character.
|
||||
//
|
||||
// Applications which fully control the final result and can guarantee the
|
||||
// subsequent characters will not combine with the prefix may be able to use
|
||||
// [RefinementBuilder.StringPrefixFull] instead, after carefully reviewing
|
||||
// the constraints described in its documentation.
|
||||
func (b *RefinementBuilder) StringPrefix(prefix string) *RefinementBuilder {
|
||||
return b.StringPrefixFull(ctystrings.SafeKnownPrefix(prefix))
|
||||
}
|
||||
|
||||
// StringPrefixFull is a variant of StringPrefix that will never shorten the
|
||||
// given prefix to take into account the possibility of the next character
|
||||
// combining with the end of the prefix.
|
||||
//
|
||||
// Applications which fully control the subsequent characters can use this
|
||||
// as long as they guarantee that the characters added later cannot possibly
|
||||
// combine with characters at the end of the prefix to form a single grapheme
|
||||
// cluster. For example, it would be unsafe to use the full prefix "hello" if
|
||||
// there is any chance that the final string will add a combining diacritic
|
||||
// character after the "o", because that would then change the final character.
|
||||
//
|
||||
// Use [RefinementBuilder.StringPrefix] instead if an application cannot fully
|
||||
// control the final result to avoid violating this rule.
|
||||
func (b *RefinementBuilder) StringPrefixFull(prefix string) *RefinementBuilder {
|
||||
b.assertRefineable()
|
||||
|
||||
wip, ok := b.wip.(*refinementString)
|
||||
if !ok {
|
||||
panic(fmt.Sprintf("cannot refine string prefix for a %#v value", b.orig.Type()))
|
||||
}
|
||||
|
||||
// We must apply the same Unicode processing we'd normally use for a
|
||||
// cty string so that the prefix will be comparable.
|
||||
prefix = NormalizeString(prefix)
|
||||
|
||||
// If we have a known string value then the given prefix must actually
|
||||
// match it.
|
||||
if b.orig.IsKnown() && !b.orig.IsNull() {
|
||||
have := b.orig.AsString()
|
||||
matchLen := len(have)
|
||||
if l := len(prefix); l < matchLen {
|
||||
matchLen = l
|
||||
}
|
||||
have = have[:matchLen]
|
||||
new := prefix[:matchLen]
|
||||
if have != new {
|
||||
panic("refined prefix is inconsistent with known value")
|
||||
}
|
||||
}
|
||||
|
||||
// If we already have a refined prefix then the overlapping parts of that
|
||||
// and the new prefix must match.
|
||||
{
|
||||
matchLen := len(wip.prefix)
|
||||
if l := len(prefix); l < matchLen {
|
||||
matchLen = l
|
||||
}
|
||||
|
||||
have := wip.prefix[:matchLen]
|
||||
new := prefix[:matchLen]
|
||||
if have != new {
|
||||
panic("refined prefix is inconsistent with previous refined prefix")
|
||||
}
|
||||
}
|
||||
|
||||
// We'll only save the new prefix if it's longer than the one we already
|
||||
// had.
|
||||
if len(prefix) > len(wip.prefix) {
|
||||
wip.prefix = prefix
|
||||
}
|
||||
|
||||
return b
|
||||
}
|
||||
|
||||
// NewValue completes the refinement process by constructing a new value
|
||||
// that is guaranteed to meet all of the previously-specified refinements.
|
||||
//
|
||||
// If the original value being refined was known then the result is exactly
|
||||
// that value, because otherwise the previous refinement calls would have
|
||||
// panicked reporting the refinements as invalid for the value.
|
||||
//
|
||||
// If the original value was unknown then the result is typically also unknown
|
||||
// but may have additional refinements compared to the original. If the applied
|
||||
// refinements have reduced the range to a single exact value then the result
|
||||
// might be that known value.
|
||||
func (b *RefinementBuilder) NewValue() (ret Value) {
|
||||
defer func() {
|
||||
// Regardless of how we return, the new value should have the same
|
||||
// marks as our original value.
|
||||
ret = ret.WithMarks(b.marks)
|
||||
}()
|
||||
|
||||
if b.orig.IsKnown() {
|
||||
return b.orig
|
||||
}
|
||||
|
||||
// We have a few cases where the value has been refined enough that we now
|
||||
// know exactly what the value is, or at least we can produce a more
|
||||
// detailed approximation of it.
|
||||
switch b.wip.null() {
|
||||
case tristateTrue:
|
||||
// There is only one null value of each type so this is now known.
|
||||
return NullVal(b.orig.Type())
|
||||
case tristateFalse:
|
||||
// If we know it's definitely not null then we might have enough
|
||||
// information to construct a known, non-null value.
|
||||
if rfn, ok := b.wip.(*refinementNumber); ok {
|
||||
// If both bounds are inclusive and equal then our value can
|
||||
// only be the same number as the bounds.
|
||||
if rfn.maxInc && rfn.minInc {
|
||||
if rfn.min != NilVal && rfn.max != NilVal {
|
||||
eq := rfn.min.Equals(rfn.max)
|
||||
if eq.IsKnown() && eq.True() {
|
||||
return rfn.min
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if rfn, ok := b.wip.(*refinementCollection); ok {
|
||||
// If both of the bounds are equal then we know the length is
|
||||
// the same number as the bounds.
|
||||
if rfn.minLen == rfn.maxLen {
|
||||
knownLen := rfn.minLen
|
||||
ty := b.orig.Type()
|
||||
if knownLen == 0 {
|
||||
// If we know the length is zero then we can construct
|
||||
// a known value of any collection kind.
|
||||
switch {
|
||||
case ty.IsListType():
|
||||
return ListValEmpty(ty.ElementType())
|
||||
case ty.IsSetType():
|
||||
return SetValEmpty(ty.ElementType())
|
||||
case ty.IsMapType():
|
||||
return MapValEmpty(ty.ElementType())
|
||||
}
|
||||
} else if ty.IsListType() {
|
||||
// If we know the length of the list then we can
|
||||
// create a known list with unknown elements instead
|
||||
// of a wholly-unknown list.
|
||||
elems := make([]Value, knownLen)
|
||||
unk := UnknownVal(ty.ElementType())
|
||||
for i := range elems {
|
||||
elems[i] = unk
|
||||
}
|
||||
return ListVal(elems)
|
||||
} else if ty.IsSetType() && knownLen == 1 {
|
||||
// If we know we have a one-element set then we
|
||||
// know the one element can't possibly coalesce with
|
||||
// anything else and so we can create a known set with
|
||||
// an unknown element.
|
||||
return SetVal([]Value{UnknownVal(ty.ElementType())})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Value{
|
||||
ty: b.orig.ty,
|
||||
v: &unknownType{refinement: b.wip},
|
||||
}
|
||||
}
|
||||
|
||||
// unknownValRefinment is an interface pretending to be a sum type representing
|
||||
// the different kinds of unknown value refinements we support for different
|
||||
// types of value.
|
||||
type unknownValRefinement interface {
|
||||
unknownValRefinementSigil()
|
||||
copy() unknownValRefinement
|
||||
null() tristateBool
|
||||
setNull(tristateBool)
|
||||
rawEqual(other unknownValRefinement) bool
|
||||
GoString() string
|
||||
}
|
||||
|
||||
type refinementString struct {
|
||||
refinementNullable
|
||||
prefix string
|
||||
}
|
||||
|
||||
func (r *refinementString) unknownValRefinementSigil() {}
|
||||
|
||||
func (r *refinementString) copy() unknownValRefinement {
|
||||
ret := *r
|
||||
// Everything in refinementString is immutable, so a shallow copy is sufficient.
|
||||
return &ret
|
||||
}
|
||||
|
||||
func (r *refinementString) rawEqual(other unknownValRefinement) bool {
|
||||
{
|
||||
other, ok := other.(*refinementString)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
return (r.refinementNullable.rawEqual(&other.refinementNullable) &&
|
||||
r.prefix == other.prefix)
|
||||
}
|
||||
}
|
||||
|
||||
func (r *refinementString) GoString() string {
|
||||
var b strings.Builder
|
||||
b.WriteString(r.refinementNullable.GoString())
|
||||
if r.prefix != "" {
|
||||
fmt.Fprintf(&b, ".StringPrefixFull(%q)", r.prefix)
|
||||
}
|
||||
return b.String()
|
||||
}
|
||||
|
||||
type refinementNumber struct {
|
||||
refinementNullable
|
||||
min, max Value
|
||||
minInc, maxInc bool
|
||||
}
|
||||
|
||||
func (r *refinementNumber) unknownValRefinementSigil() {}
|
||||
|
||||
func (r *refinementNumber) copy() unknownValRefinement {
|
||||
ret := *r
|
||||
// Everything in refinementNumber is immutable, so a shallow copy is sufficient.
|
||||
return &ret
|
||||
}
|
||||
|
||||
func (r *refinementNumber) rawEqual(other unknownValRefinement) bool {
|
||||
{
|
||||
other, ok := other.(*refinementNumber)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
return (r.refinementNullable.rawEqual(&other.refinementNullable) &&
|
||||
r.min.RawEquals(other.min) &&
|
||||
r.max.RawEquals(other.max) &&
|
||||
r.minInc == other.minInc &&
|
||||
r.maxInc == other.maxInc)
|
||||
}
|
||||
}
|
||||
|
||||
func (r *refinementNumber) GoString() string {
|
||||
var b strings.Builder
|
||||
b.WriteString(r.refinementNullable.GoString())
|
||||
if r.min != NilVal && r.min != NegativeInfinity {
|
||||
fmt.Fprintf(&b, ".NumberLowerBound(%#v, %t)", r.min, r.minInc)
|
||||
}
|
||||
if r.max != NilVal && r.max != PositiveInfinity {
|
||||
fmt.Fprintf(&b, ".NumberUpperBound(%#v, %t)", r.max, r.maxInc)
|
||||
}
|
||||
return b.String()
|
||||
}
|
||||
|
||||
func (r *refinementNumber) assertConsistentBounds() {
|
||||
if r.min == NilVal || r.max == NilVal {
|
||||
return // If only one bound is constrained then there's nothing to be inconsistent with
|
||||
}
|
||||
var ok Value
|
||||
if r.minInc != r.maxInc {
|
||||
ok = r.min.LessThan(r.max)
|
||||
} else {
|
||||
ok = r.min.LessThanOrEqualTo(r.max)
|
||||
}
|
||||
if ok.IsKnown() && ok.False() {
|
||||
panic(fmt.Sprintf("number lower bound %#v is greater than upper bound %#v", r.min, r.max))
|
||||
}
|
||||
}
|
||||
|
||||
type refinementCollection struct {
|
||||
refinementNullable
|
||||
minLen, maxLen int
|
||||
}
|
||||
|
||||
func (r *refinementCollection) unknownValRefinementSigil() {}
|
||||
|
||||
func (r *refinementCollection) copy() unknownValRefinement {
|
||||
ret := *r
|
||||
// Everything in refinementCollection is immutable, so a shallow copy is sufficient.
|
||||
return &ret
|
||||
}
|
||||
|
||||
func (r *refinementCollection) rawEqual(other unknownValRefinement) bool {
|
||||
{
|
||||
other, ok := other.(*refinementCollection)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
return (r.refinementNullable.rawEqual(&other.refinementNullable) &&
|
||||
r.minLen == other.minLen &&
|
||||
r.maxLen == other.maxLen)
|
||||
}
|
||||
}
|
||||
|
||||
func (r *refinementCollection) GoString() string {
|
||||
var b strings.Builder
|
||||
b.WriteString(r.refinementNullable.GoString())
|
||||
if r.minLen != 0 {
|
||||
fmt.Fprintf(&b, ".CollectionLengthLowerBound(%d)", r.minLen)
|
||||
}
|
||||
if r.maxLen != math.MaxInt {
|
||||
fmt.Fprintf(&b, ".CollectionLengthUpperBound(%d)", r.maxLen)
|
||||
}
|
||||
return b.String()
|
||||
}
|
||||
|
||||
func (r *refinementCollection) assertConsistentLengthBounds() {
|
||||
if r.maxLen < r.minLen {
|
||||
panic(fmt.Sprintf("collection length upper bound %d is less than lower bound %d", r.maxLen, r.minLen))
|
||||
}
|
||||
}
|
||||
|
||||
type refinementNullable struct {
|
||||
isNull tristateBool
|
||||
}
|
||||
|
||||
func (r *refinementNullable) unknownValRefinementSigil() {}
|
||||
|
||||
func (r *refinementNullable) copy() unknownValRefinement {
|
||||
ret := *r
|
||||
// Everything in refinementJustNull is immutable, so a shallow copy is sufficient.
|
||||
return &ret
|
||||
}
|
||||
|
||||
func (r *refinementNullable) null() tristateBool {
|
||||
return r.isNull
|
||||
}
|
||||
|
||||
func (r *refinementNullable) setNull(v tristateBool) {
|
||||
r.isNull = v
|
||||
}
|
||||
|
||||
func (r *refinementNullable) rawEqual(other unknownValRefinement) bool {
|
||||
{
|
||||
other, ok := other.(*refinementNullable)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
return r.isNull == other.isNull
|
||||
}
|
||||
}
|
||||
|
||||
func (r *refinementNullable) GoString() string {
|
||||
switch r.isNull {
|
||||
case tristateFalse:
|
||||
return ".NotNull()"
|
||||
case tristateTrue:
|
||||
return ".Null()"
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
type tristateBool rune
|
||||
|
||||
const tristateTrue tristateBool = 'T'
|
||||
const tristateFalse tristateBool = 'F'
|
||||
const tristateUnknown tristateBool = 0
|
Reference in New Issue
Block a user