Skip to content

Commit

Permalink
Merge pull request #32301 from vespa-engine/havardpe/slime-in-go
Browse files Browse the repository at this point in the history
slime in go
  • Loading branch information
havardpe authored Sep 2, 2024
2 parents b59ae65 + 6bab15c commit 2764ffd
Show file tree
Hide file tree
Showing 8 changed files with 321 additions and 0 deletions.
29 changes: 29 additions & 0 deletions client/go/internal/vespa/slime/array.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.

package slime

type arrayValue struct {
emptyValue
value []Value
}

func Array() *arrayValue { return &arrayValue{} }
func (*arrayValue) Type() Type { return ARRAY }

func (arr *arrayValue) NumEntries() int { return len(arr.value) }
func (arr *arrayValue) Entry(index int) Value {
if index < len(arr.value) {
return arr.value[index]
}
return Invalid
}
func (arr *arrayValue) EachEntry(f func(index int, value Value)) {
for i, x := range arr.value {
f(i, x)
}
}

func (arr *arrayValue) Add(value Value) Value {
arr.value = append(arr.value, value)
return value
}
42 changes: 42 additions & 0 deletions client/go/internal/vespa/slime/array_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.

package slime

import (
"github.com/stretchr/testify/assert"
"testing"
)

func TestArray(t *testing.T) {
arr := Array()
actual := []Value{
arr.Add(Empty),
arr.Add(Bool(true)),
arr.Add(Long(5)),
arr.Add(Double(5.5)),
arr.Add(String("foo")),
arr.Add(Data([]byte{1, 2, 3}))}

expect := []expectLeaf{
expectLeaf{mytype: EMPTY},
expectLeaf{mytype: BOOL, boolVal: true},
expectLeaf{mytype: LONG, longVal: 5, doubleVal: 5},
expectLeaf{mytype: DOUBLE, longVal: 5, doubleVal: 5.5},
expectLeaf{mytype: STRING, stringVal: "foo"},
expectLeaf{mytype: DATA, dataVal: []byte{1, 2, 3}}}

var expectIndex int
var collect []Value
arr.EachEntry(func(idx int, val Value) {
assert.Equal(t, idx, expectIndex)
collect = append(collect, val)
expectIndex++
})

assert.Equal(t, arr.NumEntries(), len(expect))
for i, e := range expect {
checkLeaf(t, actual[i], e)
checkLeaf(t, collect[i], e)
checkLeaf(t, arr.Entry(i), e)
}
}
50 changes: 50 additions & 0 deletions client/go/internal/vespa/slime/leaf.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.

package slime

type boolValue struct {
emptyValue
value bool
}

func Bool(v bool) Value { return &boolValue{value: v} }
func (*boolValue) Type() Type { return BOOL }
func (v *boolValue) AsBool() bool { return v.value }

type longValue struct {
emptyValue
value int64
}

func Long(v int64) Value { return &longValue{value: v} }
func (*longValue) Type() Type { return LONG }
func (v *longValue) AsLong() int64 { return v.value }
func (v *longValue) AsDouble() float64 { return float64(v.value) }

type doubleValue struct {
emptyValue
value float64
}

func Double(v float64) Value { return &doubleValue{value: v} }
func (*doubleValue) Type() Type { return DOUBLE }
func (v *doubleValue) AsLong() int64 { return int64(v.value) }
func (v *doubleValue) AsDouble() float64 { return v.value }

type stringValue struct {
emptyValue
value string
}

func String(v string) Value { return &stringValue{value: v} }
func (*stringValue) Type() Type { return STRING }
func (v *stringValue) AsString() string { return v.value }

type dataValue struct {
emptyValue
value []byte
}

func Data(v []byte) Value { return &dataValue{value: v} }
func (*dataValue) Type() Type { return DATA }
func (v *dataValue) AsData() []byte { return v.value }
65 changes: 65 additions & 0 deletions client/go/internal/vespa/slime/leaf_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
// Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.

package slime

import (
"github.com/stretchr/testify/assert"
"testing"
)

type expectLeaf struct {
invalid bool
mytype Type
boolVal bool
longVal int64
doubleVal float64
stringVal string
dataVal []byte
}

func checkLeaf(t *testing.T, value Value, expect expectLeaf) {
if expect.dataVal == nil {
expect.dataVal = emptyBytes
}
assert.Equal(t, value.Valid(), !expect.invalid)
assert.Equal(t, value.Type(), expect.mytype)
assert.Equal(t, value.AsBool(), expect.boolVal)
assert.Equal(t, value.AsLong(), expect.longVal)
assert.Equal(t, value.AsDouble(), expect.doubleVal)
assert.Equal(t, value.AsString(), expect.stringVal)
assert.Equal(t, value.AsData(), expect.dataVal)
}

func TestEmpty(t *testing.T) {
checkLeaf(t, Empty, expectLeaf{})
checkLeaf(t, Invalid, expectLeaf{invalid: true})
}

func TestBool(t *testing.T) {
checkLeaf(t, Bool(false), expectLeaf{mytype: BOOL})
checkLeaf(t, Bool(true), expectLeaf{mytype: BOOL, boolVal: true})
}

func TestLong(t *testing.T) {
checkLeaf(t, Long(0), expectLeaf{mytype: LONG})
checkLeaf(t, Long(5), expectLeaf{mytype: LONG, longVal: 5, doubleVal: 5})
checkLeaf(t, Long(7), expectLeaf{mytype: LONG, longVal: 7, doubleVal: 7})
}

func TestDouble(t *testing.T) {
checkLeaf(t, Double(0.0), expectLeaf{mytype: DOUBLE})
checkLeaf(t, Double(5.0), expectLeaf{mytype: DOUBLE, longVal: 5, doubleVal: 5.0})
checkLeaf(t, Double(7.5), expectLeaf{mytype: DOUBLE, longVal: 7, doubleVal: 7.5})
}

func TestString(t *testing.T) {
checkLeaf(t, String(""), expectLeaf{mytype: STRING})
checkLeaf(t, String("foo"), expectLeaf{mytype: STRING, stringVal: "foo"})
checkLeaf(t, String("bar"), expectLeaf{mytype: STRING, stringVal: "bar"})
}

func TestData(t *testing.T) {
checkLeaf(t, Data(emptyBytes), expectLeaf{mytype: DATA})
checkLeaf(t, Data([]byte{1, 2, 3}), expectLeaf{mytype: DATA, dataVal: []byte{1, 2, 3}})
checkLeaf(t, Data([]byte{5, 6}), expectLeaf{mytype: DATA, dataVal: []byte{5, 6}})
}
34 changes: 34 additions & 0 deletions client/go/internal/vespa/slime/object.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.

package slime

type objectValue struct {
emptyValue
value map[string]Value
}

func Object() Value { return &objectValue{value: make(map[string]Value)} }
func (*objectValue) Type() Type { return OBJECT }

func (obj *objectValue) NumFields() int { return len(obj.value) }
func (obj *objectValue) Field(name string) Value {
value, found := obj.value[name]
if found {
return value
}
return Invalid
}
func (obj *objectValue) EachField(f func(name string, value Value)) {
for n, x := range obj.value {
f(n, x)
}
}

func (obj *objectValue) Set(name string, value Value) Value {
_, found := obj.value[name]
if found {
return Invalid
}
obj.value[name] = value
return value
}
40 changes: 40 additions & 0 deletions client/go/internal/vespa/slime/object_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.

package slime

import (
"github.com/stretchr/testify/assert"
"testing"
)

func TestObject(t *testing.T) {
obj := Object()
actual := map[string]Value{
"a": obj.Set("a", Empty),
"b": obj.Set("b", Bool(true)),
"c": obj.Set("c", Long(5)),
"d": obj.Set("d", Double(5.5)),
"e": obj.Set("e", String("foo")),
"f": obj.Set("f", Data([]byte{1, 2, 3}))}

expect := map[string]expectLeaf{
"a": expectLeaf{mytype: EMPTY},
"b": expectLeaf{mytype: BOOL, boolVal: true},
"c": expectLeaf{mytype: LONG, longVal: 5, doubleVal: 5},
"d": expectLeaf{mytype: DOUBLE, longVal: 5, doubleVal: 5.5},
"e": expectLeaf{mytype: STRING, stringVal: "foo"},
"f": expectLeaf{mytype: DATA, dataVal: []byte{1, 2, 3}}}

collect := make(map[string]Value)
obj.EachField(func(name string, val Value) {
collect[name] = val
})

assert.Equal(t, obj.NumFields(), len(expect))
assert.Equal(t, len(collect), len(expect))
for n, e := range expect {
checkLeaf(t, actual[n], e)
checkLeaf(t, collect[n], e)
checkLeaf(t, obj.Field(n), e)
}
}
16 changes: 16 additions & 0 deletions client/go/internal/vespa/slime/type.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.

package slime

type Type byte

const (
EMPTY Type = iota
BOOL
LONG
DOUBLE
STRING
DATA
ARRAY
OBJECT
)
45 changes: 45 additions & 0 deletions client/go/internal/vespa/slime/value.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.

package slime

var (
emptyBytes []byte = make([]byte, 0)
Empty Value = &emptyValue{}
Invalid Value = (*emptyValue)(nil)
)

type Value interface {
Valid() bool
Type() Type
AsBool() bool
AsLong() int64
AsDouble() float64
AsString() string
AsData() []byte
NumEntries() int
Entry(index int) Value
EachEntry(func(index int, value Value))
NumFields() int
Field(name string) Value
EachField(func(name string, value Value))
Add(value Value) Value
Set(name string, value Value) Value
}

type emptyValue struct{}

func (v *emptyValue) Valid() bool { return (v != nil) }
func (*emptyValue) Type() Type { return EMPTY }
func (*emptyValue) AsBool() bool { return false }
func (*emptyValue) AsLong() int64 { return 0 }
func (*emptyValue) AsDouble() float64 { return 0 }
func (*emptyValue) AsString() string { return "" }
func (*emptyValue) AsData() []byte { return emptyBytes }
func (*emptyValue) NumEntries() int { return 0 }
func (*emptyValue) Entry(index int) Value { return Invalid }
func (*emptyValue) EachEntry(func(index int, value Value)) {}
func (*emptyValue) NumFields() int { return 0 }
func (*emptyValue) Field(name string) Value { return Invalid }
func (*emptyValue) EachField(func(name string, value Value)) {}
func (*emptyValue) Add(value Value) Value { return Invalid }
func (*emptyValue) Set(name string, value Value) Value { return Invalid }

0 comments on commit 2764ffd

Please sign in to comment.