| // Copyright 2015 The Vanadium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| package vdl |
| |
| import ( |
| "bytes" |
| "errors" |
| "fmt" |
| "sort" |
| "strconv" |
| ) |
| |
| var ( |
| errNilType = errors.New("vdl: nil *Type is invalid") |
| errNonNilZeroAny = errors.New("vdl: the any type doesn't have a non-nil zero value") |
| ) |
| |
| // Value is the generic representation of any value expressible in vanadium. All |
| // values are typed. |
| // |
| // Not all methods apply to all kinds of values. Restrictions are noted in the |
| // documentation for each method. Calling a method inappropriate to the kind of |
| // value causes a run-time panic. |
| // |
| // Cyclic values are not supported. The zero Value is invalid; use Zero or one |
| // of the *Value helper functions to create a valid Value. |
| type Value struct { |
| // Each value is represented by a non-nil Type, along with a different |
| // representation depending on the kind of Type. |
| t *Type |
| rep interface{} // see zeroRep for allowed types |
| } |
| |
| var zeroTypeObject = AnyType // the zero TypeObject returns the any type |
| |
| // enumIndex represents an enum value by the index of its label. |
| type enumIndex int |
| |
| // zeroRep returns the zero representation for each kind of type. |
| func zeroRep(t *Type) interface{} { |
| if t.IsBytes() { |
| // Represent []byte and [N]byte as repBytes. |
| // Represent repBytes.Index as *byte. |
| return make(repBytes, t.len) |
| } |
| switch t.kind { |
| case Bool: |
| return false |
| case Byte, Uint16, Uint32, Uint64: |
| return uint64(0) |
| case Int8, Int16, Int32, Int64: |
| return int64(0) |
| case Float32, Float64: |
| return float64(0) |
| case Complex64, Complex128: |
| return complex128(0) |
| case String: |
| return "" |
| case Enum: |
| return enumIndex(0) |
| case TypeObject: |
| return zeroTypeObject |
| case Array: |
| return make(repSequence, t.len) |
| case List: |
| return repSequence(nil) |
| case Set, Map: |
| return zeroRepMap(t.key) |
| case Struct: |
| return make(repSequence, len(t.fields)) |
| case Union: |
| return repUnion{0, ZeroValue(t.fields[0].Type)} |
| case Any, Optional: |
| return (*Value)(nil) // nil represents nonexistence |
| default: |
| panic(fmt.Errorf("vdl: unhandled kind: %v", t.kind)) |
| } |
| } |
| |
| func isZeroRep(t *Type, rep interface{}) bool { |
| switch trep := rep.(type) { |
| case bool: |
| return !trep |
| case uint64: |
| return trep == 0 |
| case int64: |
| return trep == 0 |
| case float64: |
| return trep == 0 |
| case complex128: |
| return trep == 0 |
| case string: |
| return trep == "" |
| case enumIndex: |
| return trep == 0 |
| case *Type: |
| return trep == zeroTypeObject |
| case repBytes: |
| return trep.IsZero(t) |
| case *byte: |
| return *trep == 0 |
| case repMap: |
| return trep.Len() == 0 |
| case repSequence: |
| switch t.Kind() { |
| case List: |
| return len(trep) == 0 |
| case Array, Struct: |
| return trep.AllValuesZero() |
| } |
| case repUnion: |
| return trep.IsZero() |
| case *Value: |
| return trep == nil |
| } |
| panic(fmt.Errorf("vdl: isZeroRep unhandled %v %T %v", t, rep, rep)) |
| } |
| |
| func copyRep(t *Type, rep interface{}) interface{} { |
| switch trep := rep.(type) { |
| case bool, uint64, int64, float64, complex128, string, enumIndex, *Type: |
| return trep |
| case repBytes: |
| return copyRepBytes(trep) |
| case *byte: |
| return uint64(*trep) // convert to standard uint64 representation |
| case repMap: |
| return copyRepMap(trep) |
| case repSequence: |
| return copyRepSequence(trep) |
| case repUnion: |
| return copyRepUnion(trep) |
| case *Value: |
| return CopyValue(trep) |
| default: |
| panic(fmt.Errorf("vdl: copyRep unhandled %v %T %v", t.kind, rep, rep)) |
| } |
| } |
| |
| func stringRep(t *Type, rep interface{}) string { |
| switch trep := rep.(type) { |
| case bool, uint64, int64, float64: |
| return fmt.Sprint(trep) |
| case complex128: |
| return fmt.Sprintf("%v+%vi", real(trep), imag(trep)) |
| case string: |
| return strconv.Quote(trep) |
| case enumIndex: |
| return t.labels[int(trep)] |
| case *Type: |
| return trep.String() |
| case repBytes: |
| return strconv.Quote(string(trep)) |
| case *byte: |
| return fmt.Sprint(*trep) |
| case repMap: |
| return trep.String() |
| case repSequence: |
| return trep.String(t) |
| case repUnion: |
| return trep.String(t) |
| case *Value: |
| switch { |
| case trep == nil: |
| return "nil" |
| case t.kind == Optional: |
| return stringRep(t.elem, trep.rep) // don't include the type |
| } |
| return trep.String() // include the type |
| default: |
| panic(fmt.Errorf("vdl: stringRep unhandled %v %T %v", t.kind, rep, rep)) |
| } |
| } |
| |
| // AnyValue is a convenience to create an Any value. |
| func AnyValue(x *Value) *Value { return ZeroValue(AnyType).Assign(x) } |
| |
| // OptionalValue returns an optional value with elem assigned to x. Panics if |
| // the type of x cannot be made optional. |
| func OptionalValue(x *Value) *Value { return &Value{OptionalType(x.t), x} } |
| |
| // BoolValue is a convenience to create a Bool value. |
| func BoolValue(x bool) *Value { return ZeroValue(BoolType).AssignBool(x) } |
| |
| // ByteValue is a convenience to create an Byte value. |
| func ByteValue(x byte) *Value { return ZeroValue(ByteType).AssignUint(uint64(x)) } |
| |
| // Uint16Value is a convenience to create an Uint16 value. |
| func Uint16Value(x uint16) *Value { return ZeroValue(Uint16Type).AssignUint(uint64(x)) } |
| |
| // Uint32Value is a convenience to create an Uint32 value. |
| func Uint32Value(x uint32) *Value { return ZeroValue(Uint32Type).AssignUint(uint64(x)) } |
| |
| // Uint64Value is a convenience to create an Uint64 value. |
| func Uint64Value(x uint64) *Value { return ZeroValue(Uint64Type).AssignUint(x) } |
| |
| // Int8Value is a convenience to create an Int8 value. |
| func Int8Value(x int8) *Value { return ZeroValue(Int8Type).AssignInt(int64(x)) } |
| |
| // Int16Value is a convenience to create an Int16 value. |
| func Int16Value(x int16) *Value { return ZeroValue(Int16Type).AssignInt(int64(x)) } |
| |
| // Int32Value is a convenience to create an Int32 value. |
| func Int32Value(x int32) *Value { return ZeroValue(Int32Type).AssignInt(int64(x)) } |
| |
| // Int64Value is a convenience to create an Int64 value. |
| func Int64Value(x int64) *Value { return ZeroValue(Int64Type).AssignInt(x) } |
| |
| // Float32Value is a convenience to create a Float32 value. |
| func Float32Value(x float32) *Value { return ZeroValue(Float32Type).AssignFloat(float64(x)) } |
| |
| // Float64Value is a convenience to create a Float64 value. |
| func Float64Value(x float64) *Value { return ZeroValue(Float64Type).AssignFloat(x) } |
| |
| // Complex64Value is a convenience to create a Complex64 value. |
| func Complex64Value(x complex64) *Value { return ZeroValue(Complex64Type).AssignComplex(complex128(x)) } |
| |
| // Complex128Value is a convenience to create a Complex128 value. |
| func Complex128Value(x complex128) *Value { return ZeroValue(Complex128Type).AssignComplex(x) } |
| |
| // StringValue is a convenience to create a String value. |
| func StringValue(x string) *Value { return ZeroValue(StringType).AssignString(x) } |
| |
| // BytesValue is a convenience to create a []byte value. The bytes are copied. |
| func BytesValue(x []byte) *Value { return ZeroValue(ListType(ByteType)).AssignBytes(x) } |
| |
| // TypeObjectValue is a convenience to create a TypeObject value. |
| func TypeObjectValue(x *Type) *Value { return ZeroValue(TypeObjectType).AssignTypeObject(x) } |
| |
| // ZeroValue returns a new Value of type t representing the zero value for t: |
| // o Bool: false |
| // o Numbers: 0 |
| // o String: "" |
| // o Enum: label at index 0 |
| // o TypeObject: AnyType |
| // o List: empty collection |
| // o Set: empty collection |
| // o Map: empty collection |
| // o Array: zero values for all elems |
| // o Struct: zero values for all fields |
| // o Union: zero value of the type at index 0 |
| // o Any: nil value, representing nonexistence |
| // o Optional: nil value, representing nonexistence |
| // |
| // Panics if t == nil. |
| func ZeroValue(t *Type) *Value { |
| if t == nil { |
| panic(errNilType) |
| } |
| return &Value{t, zeroRep(t)} |
| } |
| |
| // NonNilZeroValue returns a new Value of type t representing the non-nil zero |
| // value for t. It is is the same as ZeroValue, except if t is Optional, in |
| // which case it returns a Value representing the zero value of the elem type. |
| // |
| // Panics if t == nil or t is Any. |
| func NonNilZeroValue(t *Type) *Value { |
| if t == nil { |
| panic(errNilType) |
| } |
| switch t.kind { |
| case Any: |
| panic(errNonNilZeroAny) |
| case Optional: |
| return &Value{t, ZeroValue(t.elem)} |
| } |
| return ZeroValue(t) |
| } |
| |
| // CopyValue returns a copy of the Value v. |
| func CopyValue(v *Value) *Value { |
| if v == nil { |
| return nil |
| } |
| return &Value{v.t, copyRep(v.t, v.rep)} |
| } |
| |
| // EqualValue returns true iff a and b have the same type, and equal values. |
| func EqualValue(a, b *Value) bool { |
| if a == nil || b == nil { |
| return a == nil && b == nil |
| } |
| if a.t != b.t { |
| return false |
| } |
| if a.t == ByteType { |
| // ByteType has two representations, either uint64 or *byte. |
| return a.Uint() == b.Uint() |
| } |
| switch arep := a.rep.(type) { |
| case bool: |
| return arep == b.rep.(bool) |
| case uint64: |
| return arep == b.rep.(uint64) |
| case int64: |
| return arep == b.rep.(int64) |
| case float64: |
| return arep == b.rep.(float64) |
| case complex128: |
| return arep == b.rep.(complex128) |
| case string: |
| return arep == b.rep.(string) |
| case enumIndex: |
| return arep == b.rep.(enumIndex) |
| case *Type: |
| return arep == b.rep.(*Type) |
| case repBytes: |
| return bytes.Equal(arep, b.rep.(repBytes)) |
| case repMap: |
| return equalRepMap(arep, b.rep.(repMap)) |
| case repSequence: |
| return equalRepSequence(arep, b.rep.(repSequence)) |
| case repUnion: |
| return equalRepUnion(arep, b.rep.(repUnion)) |
| case *Value: |
| return EqualValue(arep, b.rep.(*Value)) |
| default: |
| panic(fmt.Errorf("vdl: EqualValue unhandled %v %T %v", a.t.kind, arep, arep)) |
| } |
| } |
| |
| // IsZero returns true iff v is the zero value for its type. |
| func (v *Value) IsZero() bool { |
| return isZeroRep(v.t, v.rep) |
| } |
| |
| // IsNil returns true iff v is Optional or Any and has the nil value. |
| func (v *Value) IsNil() bool { |
| vrep, ok := v.rep.(*Value) |
| return ok && vrep == nil |
| } |
| |
| // IsValid returns true iff v is valid. Nil and new(Value) are invalid; most |
| // other methods panic if called on an invalid Value. |
| func (v *Value) IsValid() bool { |
| return v != nil && v.t != nil |
| } |
| |
| // Kind returns the kind of type of v. |
| func (v *Value) Kind() Kind { return v.t.kind } |
| |
| // Type returns the type of v. All valid values have a non-nil type. |
| func (v *Value) Type() *Type { return v.t } |
| |
| // Bool returns the underlying value of a Bool. |
| func (v *Value) Bool() bool { |
| v.t.checkKind("Bool", Bool) |
| return v.rep.(bool) |
| } |
| |
| // Uint returns the underlying value of a Byte or Uint{16,32,64}. |
| func (v *Value) Uint() uint64 { |
| v.t.checkKind("Uint", Byte, Uint16, Uint32, Uint64) |
| switch trep := v.rep.(type) { |
| case uint64: |
| return trep |
| case *byte: |
| return uint64(*trep) |
| } |
| panic(fmt.Errorf("vdl: Uint mismatched rep %v %T %v", v.t, v.rep, v.rep)) |
| } |
| |
| // Int returns the underlying value of an Int{8,16,32,64}. |
| func (v *Value) Int() int64 { |
| v.t.checkKind("Int", Int8, Int16, Int32, Int64) |
| return v.rep.(int64) |
| } |
| |
| // Float returns the underlying value of a Float{32,64}. |
| func (v *Value) Float() float64 { |
| v.t.checkKind("Float", Float32, Float64) |
| return v.rep.(float64) |
| } |
| |
| // Complex returns the underlying value of a Complex{64,128}. |
| func (v *Value) Complex() complex128 { |
| v.t.checkKind("Complex", Complex64, Complex128) |
| return v.rep.(complex128) |
| } |
| |
| // RawString returns the underlying value of a String. |
| func (v *Value) RawString() string { |
| v.t.checkKind("RawString", String) |
| return v.rep.(string) |
| } |
| |
| // String returns a human-readable representation of the value. |
| // To retrieve the underlying value of a String, use RawString. |
| func (v *Value) String() string { |
| if !v.IsValid() { |
| // This occurs if the user calls new(Value).String(). |
| return "INVALID" |
| } |
| switch v.t { |
| case BoolType, StringType: |
| // Unnamed bool and string don't need the type to be printed. |
| return stringRep(v.t, v.rep) |
| } |
| switch v.t.Kind() { |
| case Array, List, Set, Map, Struct, Union: |
| // { } are used instead of ( ) for composites, except for []byte and [N]byte |
| if !v.t.IsBytes() { |
| return v.t.String() + stringRep(v.t, v.rep) |
| } |
| } |
| return v.t.String() + "(" + stringRep(v.t, v.rep) + ")" |
| } |
| |
| // Bytes returns the underlying value of a []byte or [N]byte. Mutations of the |
| // returned value are reflected in the underlying value. |
| func (v *Value) Bytes() []byte { |
| v.t.checkIsBytes("Bytes") |
| return v.rep.(repBytes) |
| } |
| |
| // EnumIndex returns the index of the underlying Enum. |
| func (v *Value) EnumIndex() int { |
| v.t.checkKind("EnumIndex", Enum) |
| return int(v.rep.(enumIndex)) |
| } |
| |
| // EnumLabel returns the label of the underlying Enum. |
| func (v *Value) EnumLabel() string { |
| v.t.checkKind("EnumLabel", Enum) |
| return v.t.labels[int(v.rep.(enumIndex))] |
| } |
| |
| // TypeObject returns the underlying value of a TypeObject. |
| func (v *Value) TypeObject() *Type { |
| v.t.checkKind("TypeObject", TypeObject) |
| return v.rep.(*Type) |
| } |
| |
| // Len returns the length of the underlying Array, List, Set or Map. |
| func (v *Value) Len() int { |
| switch trep := v.rep.(type) { |
| case repMap: |
| return trep.Len() |
| case repSequence: |
| if v.t.kind != Struct { // Len not allowed on Struct |
| return len(trep) |
| } |
| case repBytes: |
| return len(trep) |
| } |
| panic(v.t.errKind("Len", Array, List, Set, Map)) |
| } |
| |
| // Index returns the i'th element of the underlying Array or List. Panics if |
| // the index is out of range. |
| func (v *Value) Index(index int) *Value { |
| switch trep := v.rep.(type) { |
| case repSequence: |
| if v.t.kind != Struct { // Index not allowed on Struct |
| return trep.Index(v.t.elem, index) |
| } |
| case repBytes: |
| // The user is trying to index into a []byte or [N]byte, and we need to |
| // return a valid Value that behaves as usual; e.g. AssignByte should work |
| // correctly and update the underlying byteslice. The strategy is to return |
| // a new Value with rep set to the indexed *byte. |
| return &Value{ByteType, &trep[index]} |
| } |
| panic(v.t.errKind("Index", Array, List)) |
| } |
| |
| // Keys returns all keys present in the underlying Set or Map. The returned |
| // keys are in an arbitrary order; do not rely on the ordering. |
| func (v *Value) Keys() []*Value { |
| v.t.checkKind("Keys", Set, Map) |
| return v.rep.(repMap).Keys() |
| } |
| |
| // ContainsKey returns true iff key is present in the underlying Set or Map. |
| func (v *Value) ContainsKey(key *Value) bool { |
| v.t.checkKind("ContainsKey", Set, Map) |
| _, ok := v.rep.(repMap).Index(typedCopy(v.t.key, key)) |
| return ok |
| } |
| |
| // MapIndex returns the value associated with the key in the underlying Map, or |
| // nil if the key is not found in the map. Panics if the key isn't assignable |
| // to the map's key type. |
| func (v *Value) MapIndex(key *Value) *Value { |
| v.t.checkKind("MapIndex", Map) |
| val, _ := v.rep.(repMap).Index(typedCopy(v.t.key, key)) |
| return val |
| } |
| |
| // StructField returns the Struct field at the given index. Panics if the index |
| // is out of range. |
| func (v *Value) StructField(index int) *Value { |
| v.t.checkKind("StructField", Struct) |
| return v.rep.(repSequence).Index(v.t.fields[index].Type, index) |
| } |
| |
| // StructFieldByName returns the Struct field for the given name. Returns nil |
| // if the name given is not one of the struct's fields. |
| func (v *Value) StructFieldByName(name string) *Value { |
| v.t.checkKind("StructFieldByName", Struct) |
| _, index := v.t.FieldByName(name) |
| if index == -1 { |
| return nil |
| } |
| return v.rep.(repSequence).Index(v.t.fields[index].Type, index) |
| } |
| |
| // UnionField returns the field index and value from the underlying Union. |
| func (v *Value) UnionField() (int, *Value) { |
| v.t.checkKind("UnionField", Union) |
| union := v.rep.(repUnion) |
| return union.index, union.value |
| } |
| |
| // Elem returns the element value contained in the underlying Any or Optional. |
| // Returns nil if v.IsNil() == true. |
| func (v *Value) Elem() *Value { |
| v.t.checkKind("Elem", Any, Optional) |
| return v.rep.(*Value) |
| } |
| |
| // Assign the value v to x. If x is nil, v is set to its zero value. Panics if |
| // the type of v is not assignable from the type of x. |
| func (v *Value) Assign(x *Value) *Value { |
| // The logic here mirrors our definition of Type.AssignableFrom. |
| switch { |
| case x == nil: |
| // Assign(nil) sets the zero value. |
| if v.t.kind == Byte { |
| // Use AssignUint to handle both the value and pointer cases. |
| v.AssignUint(0) |
| } else { |
| v.rep = zeroRep(v.t) |
| } |
| case v.t == x.t: |
| if v.t.kind == Byte { |
| // Use AssignUint to handle both the value and pointer cases. |
| v.AssignUint(x.Uint()) |
| } else { |
| // Types are identical, v is assigned a copy of the underlying rep. |
| v.rep = copyRep(x.t, x.rep) |
| } |
| case v.t.kind == Any: |
| // Assigning into Any, v is assigned a copy of the value. |
| v.rep = CopyValue(x) |
| case v.t.kind == Optional && x.t.kind == Any && x.IsNil(): |
| // Assigning into Optional from Any(nil), v is reset to nil. |
| v.rep = (*Value)(nil) |
| default: |
| panic(fmt.Errorf("vdl: value of type %q not assignable from %q", v.t, x.t)) |
| } |
| return v |
| } |
| |
| // typedCopy makes a copy of v, returning a result of type t. Panics if values |
| // of type t aren't assignable from v. |
| func typedCopy(t *Type, v *Value) *Value { |
| cp := &Value{t: t} |
| cp.Assign(v) |
| return cp |
| } |
| |
| // AssignBool assigns the underlying Bool to x. |
| func (v *Value) AssignBool(x bool) *Value { |
| v.t.checkKind("AssignBool", Bool) |
| v.rep = x |
| return v |
| } |
| |
| // AssignUint assigns the underlying Uint{16,32,64} or Byte to x. |
| func (v *Value) AssignUint(x uint64) *Value { |
| v.t.checkKind("AssignUint", Byte, Uint16, Uint32, Uint64) |
| switch trep := v.rep.(type) { |
| case uint64, nil: |
| // Handle cases where v.rep is a standalone number, or where v.rep == nil. |
| // The nil case occurs when typedCopy is used to copy a uint value. |
| v.rep = x |
| case *byte: |
| // Handle case where v.rep represents a byte in a list or array. |
| *trep = byte(x) |
| default: |
| panic(fmt.Errorf("vdl: AssignUint mismatched rep %v %T %v", v.t, v.rep, v.rep)) |
| } |
| return v |
| } |
| |
| // AssignInt assigns the underlying Int{8,16,32,64} to x. |
| func (v *Value) AssignInt(x int64) *Value { |
| v.t.checkKind("AssignInt", Int8, Int16, Int32, Int64) |
| v.rep = x |
| return v |
| } |
| |
| // AssignFloat assigns the underlying Float{32,64} to x. |
| func (v *Value) AssignFloat(x float64) *Value { |
| v.t.checkKind("AssignFloat", Float32, Float64) |
| v.rep = x |
| return v |
| } |
| |
| // AssignComplex assigns the underlying Complex{64,128} to x. |
| func (v *Value) AssignComplex(x complex128) *Value { |
| v.t.checkKind("AssignComplex", Complex64, Complex128) |
| v.rep = x |
| return v |
| } |
| |
| // AssignString assigns the underlying String to x. |
| func (v *Value) AssignString(x string) *Value { |
| v.t.checkKind("AssignString", String) |
| v.rep = x |
| return v |
| } |
| |
| // AssignBytes assigns the underlying []byte or [N]byte to a copy of x. If the |
| // underlying value is []byte, the resulting v has len == len(x). If the |
| // underlying value is [N]byte, we require len(x) == N, otherwise panics. |
| func (v *Value) AssignBytes(x []byte) *Value { |
| v.t.checkIsBytes("AssignBytes") |
| switch v.t.kind { |
| case Array: |
| rep := v.rep.(repBytes) |
| if v.t.len != len(x) { |
| panic(fmt.Errorf("vdl: AssignBytes on type [%d]byte with len %d", v.t.len, len(x))) |
| } |
| copy(rep, x) |
| case List: |
| oldrep, newlen := v.rep.(repBytes), len(x) |
| var newrep repBytes |
| if newlen <= cap(oldrep) { |
| newrep = oldrep[:newlen] |
| } else { |
| newrep = make(repBytes, newlen) |
| } |
| copy(newrep, x) |
| v.rep = newrep |
| default: |
| panic(v.t.errBytes("AssignBytes")) |
| } |
| return v |
| } |
| |
| // CopyBytes copies bytes from x to v for the underlying []byte or [N]byte. The |
| // semantics are the same as the built-in copy function; min(v.Len(), len(x)) |
| // bytes are copied from x to v. |
| func (v *Value) CopyBytes(x []byte) *Value { |
| v.t.checkIsBytes("CopyBytes") |
| copy(v.rep.(repBytes), x) |
| return v |
| } |
| |
| // AssignEnumIndex assigns the underlying Enum to the label corresponding to |
| // index. Panics if the index is out of range. |
| func (v *Value) AssignEnumIndex(index int) *Value { |
| v.t.checkKind("AssignEnumIndex", Enum) |
| if index < 0 || index >= len(v.t.labels) { |
| panic(fmt.Errorf("vdl: enum %q index %d out of range", v.t.name, index)) |
| } |
| v.rep = enumIndex(index) |
| return v |
| } |
| |
| // AssignEnumLabel assigns the underlying Enum to the label. Panics if the |
| // label doesn't exist in the Enum. |
| func (v *Value) AssignEnumLabel(label string) *Value { |
| v.t.checkKind("AssignEnumLabel", Enum) |
| index := v.t.EnumIndex(label) |
| if index == -1 { |
| panic(fmt.Errorf("vdl: enum %q doesn't have label %q", v.t.name, label)) |
| } |
| v.rep = enumIndex(index) |
| return v |
| } |
| |
| // AssignTypeObject assigns the underlying TypeObject to x. If x == nil we |
| // assign the zero TypeObject. |
| func (v *Value) AssignTypeObject(x *Type) *Value { |
| v.t.checkKind("AssignTypeObject", TypeObject) |
| if x == nil { |
| x = zeroTypeObject |
| } |
| v.rep = x |
| return v |
| } |
| |
| // AssignLen assigns the length of the underlying List to n. Unlike Go slices, |
| // Lists do not have a separate notion of capacity. |
| func (v *Value) AssignLen(n int) *Value { |
| v.t.checkKind("AssignLen", List) |
| if oldrep, ok := v.rep.(repBytes); ok { |
| var newrep repBytes |
| if n <= cap(oldrep) { |
| newrep = oldrep[:n] |
| // Fill newrep[oldlen:n] with zero bytes. |
| for zx := len(oldrep); zx < n; { |
| zx += copy(newrep[zx:], allZeroBytes) |
| } |
| } else { |
| newrep = make(repBytes, n) |
| copy(newrep, oldrep) |
| } |
| v.rep = newrep |
| return v |
| } |
| oldrep := v.rep.(repSequence) |
| var newrep repSequence |
| if n <= cap(oldrep) { |
| newrep = oldrep[:n] |
| for ix := len(oldrep); ix < n; ix++ { |
| newrep[ix] = nil |
| } |
| } else { |
| newrep = make(repSequence, n) |
| copy(newrep, oldrep) |
| } |
| v.rep = newrep |
| return v |
| } |
| |
| // AssignSetKey assigns key to the underlying Set. Panics if the key isn't |
| // assignable to the set's key type. |
| func (v *Value) AssignSetKey(key *Value) *Value { |
| v.t.checkKind("AssignSetKey", Set) |
| v.rep.(repMap).Assign(typedCopy(v.t.key, key), nil) |
| return v |
| } |
| |
| // DeleteSetKey deletes key from the underlying Set. |
| func (v *Value) DeleteSetKey(key *Value) *Value { |
| v.t.checkKind("DeleteSetKey", Set) |
| v.rep.(repMap).Delete(typedCopy(v.t.key, key)) |
| return v |
| } |
| |
| // AssignMapIndex assigns the value associated with key to elem in the |
| // underlying Map. If elem is nil, AssignMapIndex deletes the key from the Map. |
| // Panics if the key isn't assignable to the map's key type, and ditto for elem. |
| func (v *Value) AssignMapIndex(key, elem *Value) *Value { |
| v.t.checkKind("AssignMapIndex", Map) |
| if elem == nil { |
| v.rep.(repMap).Delete(typedCopy(v.t.key, key)) |
| } else { |
| v.rep.(repMap).Assign(typedCopy(v.t.key, key), typedCopy(v.t.elem, elem)) |
| } |
| return v |
| } |
| |
| // AssignUnionField assigns the field index and value to the underlying Union. |
| // Panics if the index is out of range, or if the value isn't assignable to the |
| // field type. |
| func (v *Value) AssignUnionField(index int, value *Value) *Value { |
| v.t.checkKind("AssignUnionField", Union) |
| if index >= len(v.t.fields) { |
| panic(fmt.Errorf("vdl: union %q index %d out of range", v.t, index)) |
| } |
| v.rep = repUnion{index, typedCopy(v.t.fields[index].Type, value)} |
| return v |
| } |
| |
| // SortValuesAsString sorts values by their String representation. The order of |
| // elements in values may be changed, and values is returned; no copy is made. |
| // |
| // The ordering is guaranteed to be deterministic within a single executable, |
| // but may change across different versions of the code. |
| // |
| // Typically used to get a deterministic ordering of set and map keys in tests. |
| // Do not depend on the ordering across versions of the code; it will change. |
| func SortValuesAsString(values []*Value) []*Value { |
| sort.Sort(orderValuesAsString(values)) |
| return values |
| } |
| |
| type orderValuesAsString []*Value |
| |
| func (x orderValuesAsString) Len() int { return len(x) } |
| func (x orderValuesAsString) Less(i, j int) bool { return x[i].String() < x[j].String() } |
| func (x orderValuesAsString) Swap(i, j int) { x[i], x[j] = x[j], x[i] } |