Files
dolt/types/struct.go
Rafael Weinstein d1e2aa01f3 Go: ref.Ref -> hash.Hash (#1583)
ref.Ref -> hash.Hash
2016-05-21 11:38:35 -07:00

166 lines
3.3 KiB
Go

package types
import (
"github.com/attic-labs/noms/d"
"github.com/attic-labs/noms/hash"
)
type structData map[string]Value
type Struct struct {
data structData
t *Type
h *hash.Hash
}
func newStructFromData(data structData, t *Type) Struct {
d.Chk.Equal(t.Kind(), StructKind)
return Struct{data, t, &hash.Hash{}}
}
func NewStruct(name string, data structData) Struct {
fields := make(TypeMap, len(data))
newData := make(structData, len(data))
for k, v := range data {
fields[k] = v.Type()
newData[k] = v
}
t := MakeStructType(name, fields)
return newStructFromData(newData, t)
}
func NewStructWithType(t *Type, data structData) Struct {
newData := make(structData, len(data))
desc := t.Desc.(StructDesc)
for name, t := range desc.Fields {
v, ok := data[name]
d.Chk.True(ok, "Missing required field %s", name)
assertSubtype(t, v)
newData[name] = v
}
return newStructFromData(newData, t)
}
// Value interface
func (s Struct) Equals(other Value) bool {
return other != nil && s.t.Equals(other.Type()) && s.Hash() == other.Hash()
}
func (s Struct) Less(other Value) bool {
return valueLess(s, other)
}
func (s Struct) Hash() hash.Hash {
return EnsureRef(s.h, s)
}
func (s Struct) ChildValues() (res []Value) {
res = append(res, s.t)
for name := range s.desc().Fields {
v, ok := s.data[name]
d.Chk.True(ok)
res = append(res, v)
}
return
}
func (s Struct) Chunks() (chunks []Ref) {
chunks = append(chunks, s.t.Chunks()...)
for name := range s.desc().Fields {
v, ok := s.data[name]
d.Chk.True(ok)
chunks = append(chunks, v.Chunks()...)
}
return
}
func (s Struct) Type() *Type {
return s.t
}
func (s Struct) desc() StructDesc {
return s.t.Desc.(StructDesc)
}
func (s Struct) MaybeGet(n string) (Value, bool) {
_, ok := s.findField(n)
if !ok {
return nil, false
}
v, ok := s.data[n]
return v, ok
}
func (s Struct) Get(n string) Value {
_, ok := s.findField(n)
d.Chk.True(ok, `Struct has no field "%s"`, n)
v, ok := s.data[n]
d.Chk.True(ok)
return v
}
func (s Struct) Set(n string, v Value) Struct {
t, ok := s.findField(n)
d.Chk.True(ok, "Struct has no field %s", n)
assertSubtype(t, v)
data := make(structData, len(s.data))
for k, v := range s.data {
data[k] = v
}
data[n] = v
return newStructFromData(data, s.t)
}
func (s Struct) findField(n string) (*Type, bool) {
for name, typ := range s.desc().Fields {
if name == n {
return typ, true
}
}
return nil, false
}
func structBuilder(values []Value, t *Type) Value {
desc := t.Desc.(StructDesc)
data := structData{}
i := 0
desc.IterFields(func(name string, t *Type) {
data[name] = values[i]
i++
})
return newStructFromData(data, t)
}
func structReader(s Struct, t *Type) []Value {
d.Chk.Equal(t.Kind(), StructKind)
values := []Value{}
desc := t.Desc.(StructDesc)
desc.IterFields(func(name string, t *Type) {
v, ok := s.data[name]
d.Chk.True(ok)
values = append(values, v)
})
return values
}
// s1 & s2 must be of the same type. Returns the set of field names which have different values in the respective structs
func StructDiff(s1, s2 Struct) (changed []string) {
d.Chk.True(s1.Type().Equals(s2.Type()))
s1.desc().IterFields(func(name string, t *Type) {
v1 := s1.data[name]
v2 := s2.data[name]
if !v1.Equals(v2) {
changed = append(changed, name)
}
})
return
}