Files
dolt/types/struct.go
Erik Arvidsson 61f14f8c9a Rename noms UInt* to Uint*
Fixes #673
2015-12-02 12:01:42 -05:00

225 lines
4.4 KiB
Go

package types
import (
"github.com/attic-labs/noms/d"
"github.com/attic-labs/noms/ref"
)
type structData map[string]Value
type Struct struct {
data structData
t Type
typeDef Type
unionIndex uint32
unionValue Value
ref *ref.Ref
}
func newStructFromData(data structData, unionIndex uint32, unionValue Value, typ, typeDef Type) Struct {
d.Chk.Equal(typ.Kind(), UnresolvedKind)
d.Chk.True(typ.HasPackageRef())
d.Chk.True(typ.HasOrdinal())
d.Chk.Equal(typeDef.Kind(), StructKind)
return Struct{data, typ, typeDef, unionIndex, unionValue, &ref.Ref{}}
}
func NewStruct(typ, typeDef Type, data structData) Struct {
newData := make(structData)
unionIndex := uint32(0)
var unionValue Value
desc := typeDef.Desc.(StructDesc)
for _, f := range desc.Fields {
if v, ok := data[f.Name]; ok {
newData[f.Name] = v
} else {
d.Chk.True(f.Optional, "Missing required field %s", f.Name)
}
}
for i, f := range desc.Union {
v, ok := data[f.Name]
if ok {
unionIndex = uint32(i)
unionValue = v
break
}
}
return newStructFromData(newData, unionIndex, unionValue, typ, typeDef)
}
func (s Struct) Equals(other Value) bool {
return other != nil && s.t.Equals(other.Type()) && s.Ref() == other.Ref()
}
func (s Struct) Ref() ref.Ref {
return EnsureRef(s.ref, s)
}
func (s Struct) Chunks() (chunks []ref.Ref) {
chunks = append(chunks, s.t.Chunks()...)
for _, f := range s.desc().Fields {
if v, ok := s.data[f.Name]; ok {
chunks = append(chunks, v.Chunks()...)
} else {
d.Chk.True(f.Optional)
}
}
if s.hasUnion() {
chunks = append(chunks, s.unionValue.Chunks()...)
}
return
}
func (s Struct) ChildValues() (res []Value) {
res = append(res, s.t)
for _, f := range s.desc().Fields {
if v, ok := s.data[f.Name]; ok {
res = append(res, v)
} else {
d.Chk.True(f.Optional)
}
}
if s.hasUnion() {
res = append(res, s.unionValue)
}
return
}
func (s Struct) Type() Type {
return s.t
}
func (s Struct) desc() StructDesc {
return s.typeDef.Desc.(StructDesc)
}
func (s Struct) hasUnion() bool {
return len(s.desc().Union) > 0
}
func (s Struct) MaybeGet(n string) (Value, bool) {
_, idx, ok := s.findField(n)
if !ok {
return nil, false
}
if idx == -1 {
v, ok := s.data[n]
return v, ok
}
if s.unionIndex != uint32(idx) {
return nil, false
}
return s.unionValue, true
}
func (s Struct) Get(n string) Value {
_, idx, ok := s.findField(n)
d.Chk.True(ok, `Struct has no field "%s"`, n)
if idx == -1 {
v, ok := s.data[n]
d.Chk.True(ok)
return v
}
d.Chk.Equal(s.unionIndex, uint32(idx), `Union field "%s" is not set`, n)
return s.unionValue
}
func (s Struct) Set(n string, v Value) Struct {
f, idx, ok := s.findField(n)
d.Chk.True(ok, "Struct has no field %s", n)
assertType(f.T, v)
data := make(structData, len(s.data))
unionIndex := s.unionIndex
unionValue := s.unionValue
for k, v := range s.data {
data[k] = v
}
if idx == -1 {
data[n] = v
} else {
unionIndex = uint32(idx)
unionValue = v
}
return newStructFromData(data, unionIndex, unionValue, s.t, s.typeDef)
}
func (s Struct) UnionIndex() uint32 {
return s.unionIndex
}
func (s Struct) UnionValue() Value {
return s.unionValue
}
func (s Struct) findField(n string) (Field, int32, bool) {
for _, f := range s.desc().Fields {
if f.Name == n {
return f, -1, true
}
}
for i, f := range s.desc().Union {
if f.Name == n {
return f, int32(i), true
}
}
return Field{}, -1, false
}
func structBuilder(values []Value, typ, typeDef Type) Value {
i := 0
desc := typeDef.Desc.(StructDesc)
data := structData{}
unionIndex := uint32(0)
var unionValue Value
for _, f := range desc.Fields {
if f.Optional {
b := bool(values[i].(Bool))
i++
if b {
data[f.Name] = values[i]
i++
}
} else {
data[f.Name] = values[i]
i++
}
}
if len(desc.Union) > 0 {
unionIndex = uint32(values[i].(Uint32))
i++
unionValue = values[i]
i++
}
return newStructFromData(data, unionIndex, unionValue, typ, typeDef)
}
func structReader(s Struct, typ, typeDef Type) []Value {
values := []Value{}
desc := typeDef.Desc.(StructDesc)
for _, f := range desc.Fields {
v, ok := s.data[f.Name]
if f.Optional {
values = append(values, Bool(ok))
if ok {
values = append(values, v)
}
} else {
d.Chk.True(ok)
values = append(values, v)
}
}
if len(desc.Union) > 0 {
values = append(values, Uint32(s.unionIndex), s.unionValue)
}
return values
}