Add types.Enum

This is needed to be able to round trip enums.

If there is no codegen for an enum that is read from the datastore we
now return a types.Enum which can be serialized back to the same
sequence.
This commit is contained in:
Erik Arvidsson
2015-11-04 15:52:12 -05:00
parent faca34cc07
commit 7d4e2df45d
14 changed files with 276 additions and 203 deletions

View File

@@ -21,13 +21,15 @@ func (e {{.Name}}) TypeRef() {{$typesPackage}}TypeRef {
func init() {
__typeRefFor{{.Name}} = {{$typesPackage}}MakeTypeRef(__{{.PackageName}}PackageInFile_{{.FileID}}_CachedRef, {{.Ordinal}})
{{$typesPackage}}RegisterFromValFunction(__typeRefFor{{.Name}}, func(v {{$typesPackage}}Value) {{$typesPackage}}Value {
return {{.Name}}(uint32(v.({{$typesPackage}}UInt32)))
})
{{$typesPackage}}RegisterEnum(__typeRefFor{{.Name}}, builderFor{{.Name}}, readerFor{{.Name}})
}
func (e {{.Name}}) InternalImplementation() uint32 {
return uint32(e)
func builderFor{{.Name}}(v uint32) {{$typesPackage}}Value {
return {{.Name}}(v)
}
func readerFor{{.Name}}(v {{$typesPackage}}Value) uint32 {
return uint32(v.({{.Name}}))
}
func (e {{.Name}}) Equals(other {{$typesPackage}}Value) bool {

View File

@@ -47,13 +47,15 @@ func (e Handedness) TypeRef() types.TypeRef {
func init() {
__typeRefForHandedness = types.MakeTypeRef(__genPackageInFile_enum_struct_CachedRef, 0)
types.RegisterFromValFunction(__typeRefForHandedness, func(v types.Value) types.Value {
return Handedness(uint32(v.(types.UInt32)))
})
types.RegisterEnum(__typeRefForHandedness, builderForHandedness, readerForHandedness)
}
func (e Handedness) InternalImplementation() uint32 {
return uint32(e)
func builderForHandedness(v uint32) types.Value {
return Handedness(v)
}
func readerForHandedness(v types.Value) uint32 {
return uint32(v.(Handedness))
}
func (e Handedness) Equals(other types.Value) bool {

View File

@@ -150,13 +150,15 @@ func (e E) TypeRef() types.TypeRef {
func init() {
__typeRefForE = types.MakeTypeRef(__genPackageInFile_sha1_1c216c6_CachedRef, 1)
types.RegisterFromValFunction(__typeRefForE, func(v types.Value) types.Value {
return E(uint32(v.(types.UInt32)))
})
types.RegisterEnum(__typeRefForE, builderForE, readerForE)
}
func (e E) InternalImplementation() uint32 {
return uint32(e)
func builderForE(v uint32) types.Value {
return E(v)
}
func readerForE(v types.Value) uint32 {
return uint32(v.(E))
}
func (e E) Equals(other types.Value) bool {

View File

@@ -109,3 +109,136 @@ func (s StructWithDupList) SetL(val ListOfUInt8) StructWithDupList {
s.ref = &ref.Ref{}
return s
}
// ListOfUInt8
type ListOfUInt8 struct {
l types.List
ref *ref.Ref
}
func NewListOfUInt8() ListOfUInt8 {
return ListOfUInt8{types.NewList(), &ref.Ref{}}
}
type ListOfUInt8Def []uint8
func (def ListOfUInt8Def) New() ListOfUInt8 {
l := make([]types.Value, len(def))
for i, d := range def {
l[i] = types.UInt8(d)
}
return ListOfUInt8{types.NewList(l...), &ref.Ref{}}
}
func (l ListOfUInt8) Def() ListOfUInt8Def {
d := make([]uint8, l.Len())
for i := uint64(0); i < l.Len(); i++ {
d[i] = uint8(l.l.Get(i).(types.UInt8))
}
return d
}
func (l ListOfUInt8) InternalImplementation() types.List {
return l.l
}
func (l ListOfUInt8) Equals(other types.Value) bool {
return other != nil && __typeRefForListOfUInt8.Equals(other.TypeRef()) && l.Ref() == other.Ref()
}
func (l ListOfUInt8) Ref() ref.Ref {
return types.EnsureRef(l.ref, l)
}
func (l ListOfUInt8) Chunks() (chunks []ref.Ref) {
chunks = append(chunks, l.TypeRef().Chunks()...)
chunks = append(chunks, l.l.Chunks()...)
return
}
// A Noms Value that describes ListOfUInt8.
var __typeRefForListOfUInt8 types.TypeRef
func (m ListOfUInt8) TypeRef() types.TypeRef {
return __typeRefForListOfUInt8
}
func init() {
__typeRefForListOfUInt8 = types.MakeCompoundTypeRef(types.ListKind, types.MakePrimitiveTypeRef(types.UInt8Kind))
types.RegisterFromValFunction(__typeRefForListOfUInt8, func(v types.Value) types.Value {
return ListOfUInt8{v.(types.List), &ref.Ref{}}
})
}
func (l ListOfUInt8) Len() uint64 {
return l.l.Len()
}
func (l ListOfUInt8) Empty() bool {
return l.Len() == uint64(0)
}
func (l ListOfUInt8) Get(i uint64) uint8 {
return uint8(l.l.Get(i).(types.UInt8))
}
func (l ListOfUInt8) Slice(idx uint64, end uint64) ListOfUInt8 {
return ListOfUInt8{l.l.Slice(idx, end), &ref.Ref{}}
}
func (l ListOfUInt8) Set(i uint64, val uint8) ListOfUInt8 {
return ListOfUInt8{l.l.Set(i, types.UInt8(val)), &ref.Ref{}}
}
func (l ListOfUInt8) Append(v ...uint8) ListOfUInt8 {
return ListOfUInt8{l.l.Append(l.fromElemSlice(v)...), &ref.Ref{}}
}
func (l ListOfUInt8) Insert(idx uint64, v ...uint8) ListOfUInt8 {
return ListOfUInt8{l.l.Insert(idx, l.fromElemSlice(v)...), &ref.Ref{}}
}
func (l ListOfUInt8) Remove(idx uint64, end uint64) ListOfUInt8 {
return ListOfUInt8{l.l.Remove(idx, end), &ref.Ref{}}
}
func (l ListOfUInt8) RemoveAt(idx uint64) ListOfUInt8 {
return ListOfUInt8{(l.l.RemoveAt(idx)), &ref.Ref{}}
}
func (l ListOfUInt8) fromElemSlice(p []uint8) []types.Value {
r := make([]types.Value, len(p))
for i, v := range p {
r[i] = types.UInt8(v)
}
return r
}
type ListOfUInt8IterCallback func(v uint8, i uint64) (stop bool)
func (l ListOfUInt8) Iter(cb ListOfUInt8IterCallback) {
l.l.Iter(func(v types.Value, i uint64) bool {
return cb(uint8(v.(types.UInt8)), i)
})
}
type ListOfUInt8IterAllCallback func(v uint8, i uint64)
func (l ListOfUInt8) IterAll(cb ListOfUInt8IterAllCallback) {
l.l.IterAll(func(v types.Value, i uint64) {
cb(uint8(v.(types.UInt8)), i)
})
}
type ListOfUInt8FilterCallback func(v uint8, i uint64) (keep bool)
func (l ListOfUInt8) Filter(cb ListOfUInt8FilterCallback) ListOfUInt8 {
nl := NewListOfUInt8()
l.IterAll(func(v uint8, i uint64) {
if cb(v, i) {
nl = nl.Append(v)
}
})
return nl
}

View File

@@ -49,13 +49,15 @@ func (e LocalE) TypeRef() types.TypeRef {
func init() {
__typeRefForLocalE = types.MakeTypeRef(__genPackageInFile_struct_with_imports_CachedRef, 0)
types.RegisterFromValFunction(__typeRefForLocalE, func(v types.Value) types.Value {
return LocalE(uint32(v.(types.UInt32)))
})
types.RegisterEnum(__typeRefForLocalE, builderForLocalE, readerForLocalE)
}
func (e LocalE) InternalImplementation() uint32 {
return uint32(e)
func builderForLocalE(v uint32) types.Value {
return LocalE(v)
}
func readerForLocalE(v types.Value) uint32 {
return uint32(v.(LocalE))
}
func (e LocalE) Equals(other types.Value) bool {

View File

@@ -163,136 +163,3 @@ func (s StructWithList) SetI(val int64) StructWithList {
s.ref = &ref.Ref{}
return s
}
// ListOfUInt8
type ListOfUInt8 struct {
l types.List
ref *ref.Ref
}
func NewListOfUInt8() ListOfUInt8 {
return ListOfUInt8{types.NewList(), &ref.Ref{}}
}
type ListOfUInt8Def []uint8
func (def ListOfUInt8Def) New() ListOfUInt8 {
l := make([]types.Value, len(def))
for i, d := range def {
l[i] = types.UInt8(d)
}
return ListOfUInt8{types.NewList(l...), &ref.Ref{}}
}
func (l ListOfUInt8) Def() ListOfUInt8Def {
d := make([]uint8, l.Len())
for i := uint64(0); i < l.Len(); i++ {
d[i] = uint8(l.l.Get(i).(types.UInt8))
}
return d
}
func (l ListOfUInt8) InternalImplementation() types.List {
return l.l
}
func (l ListOfUInt8) Equals(other types.Value) bool {
return other != nil && __typeRefForListOfUInt8.Equals(other.TypeRef()) && l.Ref() == other.Ref()
}
func (l ListOfUInt8) Ref() ref.Ref {
return types.EnsureRef(l.ref, l)
}
func (l ListOfUInt8) Chunks() (chunks []ref.Ref) {
chunks = append(chunks, l.TypeRef().Chunks()...)
chunks = append(chunks, l.l.Chunks()...)
return
}
// A Noms Value that describes ListOfUInt8.
var __typeRefForListOfUInt8 types.TypeRef
func (m ListOfUInt8) TypeRef() types.TypeRef {
return __typeRefForListOfUInt8
}
func init() {
__typeRefForListOfUInt8 = types.MakeCompoundTypeRef(types.ListKind, types.MakePrimitiveTypeRef(types.UInt8Kind))
types.RegisterFromValFunction(__typeRefForListOfUInt8, func(v types.Value) types.Value {
return ListOfUInt8{v.(types.List), &ref.Ref{}}
})
}
func (l ListOfUInt8) Len() uint64 {
return l.l.Len()
}
func (l ListOfUInt8) Empty() bool {
return l.Len() == uint64(0)
}
func (l ListOfUInt8) Get(i uint64) uint8 {
return uint8(l.l.Get(i).(types.UInt8))
}
func (l ListOfUInt8) Slice(idx uint64, end uint64) ListOfUInt8 {
return ListOfUInt8{l.l.Slice(idx, end), &ref.Ref{}}
}
func (l ListOfUInt8) Set(i uint64, val uint8) ListOfUInt8 {
return ListOfUInt8{l.l.Set(i, types.UInt8(val)), &ref.Ref{}}
}
func (l ListOfUInt8) Append(v ...uint8) ListOfUInt8 {
return ListOfUInt8{l.l.Append(l.fromElemSlice(v)...), &ref.Ref{}}
}
func (l ListOfUInt8) Insert(idx uint64, v ...uint8) ListOfUInt8 {
return ListOfUInt8{l.l.Insert(idx, l.fromElemSlice(v)...), &ref.Ref{}}
}
func (l ListOfUInt8) Remove(idx uint64, end uint64) ListOfUInt8 {
return ListOfUInt8{l.l.Remove(idx, end), &ref.Ref{}}
}
func (l ListOfUInt8) RemoveAt(idx uint64) ListOfUInt8 {
return ListOfUInt8{(l.l.RemoveAt(idx)), &ref.Ref{}}
}
func (l ListOfUInt8) fromElemSlice(p []uint8) []types.Value {
r := make([]types.Value, len(p))
for i, v := range p {
r[i] = types.UInt8(v)
}
return r
}
type ListOfUInt8IterCallback func(v uint8, i uint64) (stop bool)
func (l ListOfUInt8) Iter(cb ListOfUInt8IterCallback) {
l.l.Iter(func(v types.Value, i uint64) bool {
return cb(uint8(v.(types.UInt8)), i)
})
}
type ListOfUInt8IterAllCallback func(v uint8, i uint64)
func (l ListOfUInt8) IterAll(cb ListOfUInt8IterAllCallback) {
l.l.IterAll(func(v types.Value, i uint64) {
cb(uint8(v.(types.UInt8)), i)
})
}
type ListOfUInt8FilterCallback func(v uint8, i uint64) (keep bool)
func (l ListOfUInt8) Filter(cb ListOfUInt8FilterCallback) ListOfUInt8 {
nl := NewListOfUInt8()
l.IterAll(func(v uint8, i uint64) {
if cb(v, i) {
nl = nl.Append(v)
}
})
return nl
}

View File

@@ -150,13 +150,15 @@ func (e E) TypeRef() types.TypeRef {
func init() {
__typeRefForE = types.MakeTypeRef(__leafDepPackageInFile_leafDep_CachedRef, 1)
types.RegisterFromValFunction(__typeRefForE, func(v types.Value) types.Value {
return E(uint32(v.(types.UInt32)))
})
types.RegisterEnum(__typeRefForE, builderForE, readerForE)
}
func (e E) InternalImplementation() uint32 {
return uint32(e)
func builderForE(v uint32) types.Value {
return E(v)
}
func readerForE(v types.Value) uint32 {
return uint32(v.(E))
}
func (e E) Equals(other types.Value) bool {

View File

@@ -150,7 +150,7 @@ func (r *jsonArrayReader) readMap(t TypeRef, pkg *Package) Value {
func (r *jsonArrayReader) readEnum(t TypeRef, pkg *Package) Value {
t = fixupTypeRef(t, pkg)
return ToNomsValueFromTypeRef(t, UInt32(r.read().(float64)))
return enumFromTypeRef(uint32(r.read().(float64)), t)
}
func (r *jsonArrayReader) readPackage(t TypeRef, pkg *Package) Value {

View File

@@ -359,38 +359,30 @@ func TestReadEnum(t *testing.T) {
assert := assert.New(t)
cs := chunks.NewMemoryStore()
tref := MakeEnumTypeRef("E", "a", "b", "c")
pkg := NewPackage([]TypeRef{tref}, []ref.Ref{})
typeDef := MakeEnumTypeRef("E", "a", "b", "c")
pkg := NewPackage([]TypeRef{typeDef}, []ref.Ref{})
pkgRef := RegisterPackage(&pkg)
enumTr := MakeTypeRef(pkgRef, 0)
RegisterFromValFunction(enumTr, func(v Value) Value {
return testEnum{v.(UInt32), enumTr}
})
a := parseJson(`[%d, "%s", 0, 1]`, UnresolvedKind, pkgRef.String())
r := newJsonArrayReader(a, cs)
v := r.readTopLevelValue().(testEnum)
assert.Equal(uint32(1), uint32(v.UInt32))
v := r.readTopLevelValue().(Enum)
assert.Equal(uint32(1), v.v)
}
func TestReadValueEnum(t *testing.T) {
assert := assert.New(t)
cs := chunks.NewMemoryStore()
tref := MakeEnumTypeRef("E", "a", "b", "c")
pkg := NewPackage([]TypeRef{tref}, []ref.Ref{})
typeDef := MakeEnumTypeRef("E", "a", "b", "c")
pkg := NewPackage([]TypeRef{typeDef}, []ref.Ref{})
pkgRef := RegisterPackage(&pkg)
enumTr := MakeTypeRef(pkgRef, 0)
RegisterFromValFunction(enumTr, func(v Value) Value {
return testEnum{v.(UInt32), enumTr}
})
a := parseJson(`[%d, %d, "%s", 0, 1]`, ValueKind, UnresolvedKind, pkgRef.String())
r := newJsonArrayReader(a, cs)
v := r.readTopLevelValue().(testEnum)
assert.Equal(uint32(1), uint32(v.UInt32))
v := r.readTopLevelValue().(Enum)
assert.Equal(uint32(1), v.v)
}
func TestReadRef(t *testing.T) {
@@ -460,14 +452,11 @@ func TestReadStructWithEnum(t *testing.T) {
return v
})
enumTr := MakeTypeRef(pkgRef, 1)
RegisterFromValFunction(enumTr, func(v Value) Value {
return testEnum{v.(UInt32), enumTr}
})
v := r.readTopLevelValue().(Struct)
assert.True(v.Get("x").Equals(Int16(42)))
assert.True(v.Get("e").Equals(UInt32(1)))
assert.True(v.Get("e").Equals(Enum{1, enumTr}))
assert.True(v.Get("b").Equals(Bool(true)))
}

View File

@@ -126,10 +126,6 @@ func (w *jsonArrayWriter) writeValue(v Value, tr TypeRef, pkg *Package) {
}
// TODO: This is ugly. BUG 452
type enumImplementation interface {
InternalImplementation() uint32
}
type listImplementation interface {
InternalImplementation() List
}
@@ -146,10 +142,6 @@ type setImplementation interface {
InternalImplementation() Set
}
func getEnumFromEnumKind(v Value) uint32 {
return v.(enumImplementation).InternalImplementation()
}
func getListFromListKind(v Value) List {
if v, ok := v.(List); ok {
return v
@@ -243,7 +235,7 @@ func (w *jsonArrayWriter) writeUnresolvedKindValue(v Value, tr TypeRef, pkg *Pac
default:
d.Chk.Fail("An Unresolved TypeRef can only reference a StructKind or Enum Kind.", "Actually referenced: %+v", typeDef)
case EnumKind:
w.write(getEnumFromEnumKind(v))
w.writeEnum(v, tr, pkg)
case StructKind:
w.writeStruct(v, tr, typeDef, pkg)
}
@@ -282,3 +274,9 @@ func (w *jsonArrayWriter) writeStruct(v Value, typeRef, typeDef TypeRef, pkg *Pa
w.writeValue(<-c, desc.Union[unionIndex].T, pkg)
}
}
func (w *jsonArrayWriter) writeEnum(v Value, t TypeRef, pkg *Package) {
t = fixupTypeRef(t, pkg)
i := enumPrimitiveValueFromTypeRef(v, t)
w.write(i)
}

View File

@@ -282,19 +282,6 @@ func TestWriteStructWithBlob(t *testing.T) {
assert.EqualValues([]interface{}{UnresolvedKind, pkgRef.String(), int16(0), "AAE="}, w.toArray())
}
type testEnum struct {
UInt32
t TypeRef
}
func (e testEnum) TypeRef() TypeRef {
return e.t
}
func (e testEnum) InternalImplementation() uint32 {
return uint32(e.UInt32)
}
func TestWriteEnum(t *testing.T) {
assert := assert.New(t)
cs := chunks.NewMemoryStore()
@@ -305,7 +292,7 @@ func TestWriteEnum(t *testing.T) {
tref := MakeTypeRef(pkgRef, 0)
w := newJsonArrayWriter(cs)
w.writeTopLevelValue(testEnum{UInt32: UInt32(1), t: tref})
w.writeTopLevelValue(Enum{1, tref})
assert.EqualValues([]interface{}{UnresolvedKind, pkgRef.String(), int16(0), uint32(1)}, w.toArray())
}
@@ -318,7 +305,7 @@ func TestWriteListOfEnum(t *testing.T) {
pkgRef := RegisterPackage(&pkg)
et := MakeTypeRef(pkgRef, 0)
tref := MakeCompoundTypeRef(ListKind, et)
v := NewList(testEnum{UInt32(0), et}, testEnum{UInt32(1), et}, testEnum{UInt32(2), et})
v := NewList(Enum{0, et}, Enum{1, et}, Enum{2, et})
w := newJsonArrayWriter(cs)
w.writeTopLevelValue(testList{List: v, t: tref})

29
types/enum.go Normal file
View File

@@ -0,0 +1,29 @@
package types
import "github.com/attic-labs/noms/ref"
type Enum struct {
v uint32
t TypeRef
}
func newEnum(v uint32, t TypeRef) Enum {
return Enum{v, t}
}
func (e Enum) Equals(other Value) bool {
return other != nil && e.t.Equals(other.TypeRef()) && e.Ref() == other.Ref()
}
func (e Enum) Ref() ref.Ref {
throwaway := ref.Ref{}
return EnsureRef(&throwaway, e)
}
func (e Enum) Chunks() []ref.Ref {
return nil
}
func (e Enum) TypeRef() TypeRef {
return e.t
}

34
types/enum_test.go Normal file
View File

@@ -0,0 +1,34 @@
package types
import (
"testing"
"github.com/attic-labs/noms/Godeps/_workspace/src/github.com/stretchr/testify/assert"
"github.com/attic-labs/noms/chunks"
"github.com/attic-labs/noms/ref"
)
func TestGenericEnumWriteRead(t *testing.T) {
assert := assert.New(t)
cs := chunks.NewMemoryStore()
typeDefA := MakeEnumTypeRef("EA", "aA", "bA")
typeDefB := MakeEnumTypeRef("EB", "aB", "bB")
pkg := NewPackage([]TypeRef{typeDefA, typeDefB}, []ref.Ref{})
pkgRef := RegisterPackage(&pkg)
typeRefA := MakeTypeRef(pkgRef, 0)
typeRefB := MakeTypeRef(pkgRef, 1)
vA := Enum{1, typeRefA}
vB := Enum{1, typeRefB}
assert.False(vA.Equals(vB))
rA := WriteValue(vA, cs)
vA2 := ReadValue(rA, cs)
assert.True(vA.Equals(vA2))
assert.True(vA2.Equals(vA))
assert.False(vB.Equals(vA2))
assert.False(vA2.Equals(vB))
}

View File

@@ -8,6 +8,8 @@ import (
type structBuilderFunc func() chan Value
type structReaderFunc func(v Value) chan Value
type enumBuilderFunc func(v uint32) Value
type enumReaderFunc func(v Value) uint32
type toNomsValueFunc func(v Value) Value
type structFuncs struct {
@@ -15,10 +17,16 @@ type structFuncs struct {
reader structReaderFunc
}
type enumFuncs struct {
builder enumBuilderFunc
reader enumReaderFunc
}
var (
packages map[ref.Ref]*Package = map[ref.Ref]*Package{}
toNomsValueMap map[ref.Ref]toNomsValueFunc = map[ref.Ref]toNomsValueFunc{}
structFuncMap map[ref.Ref]structFuncs = map[ref.Ref]structFuncs{}
enumFuncMap map[ref.Ref]enumFuncs = map[ref.Ref]enumFuncs{}
)
// LookupPackage looks for a Package by ref.Ref in the global cache of Noms type packages.
@@ -68,3 +76,21 @@ func structReaderForTypeRef(v Value, typeRef, typeDef TypeRef) chan Value {
}
return structReader(v.(Struct), typeRef, typeDef)
}
func RegisterEnum(t TypeRef, bf enumBuilderFunc, rf enumReaderFunc) {
enumFuncMap[t.Ref()] = enumFuncs{bf, rf}
}
func enumFromTypeRef(v uint32, t TypeRef) Value {
if s, ok := enumFuncMap[t.Ref()]; ok {
return s.builder(v)
}
return newEnum(v, t)
}
func enumPrimitiveValueFromTypeRef(v Value, t TypeRef) uint32 {
if s, ok := enumFuncMap[t.Ref()]; ok {
return s.reader(v)
}
return v.(Enum).v
}