Created
May 27, 2022 18:12
-
-
Save simon-engledew/8ddb3e7a3c52cc86e35d7567a525e298 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package server | |
import ( | |
"fmt" | |
"reflect" | |
"go.starlark.net/starlark" | |
) | |
func toValue(v interface{}) starlark.Value { | |
switch v := v.(type) { | |
case uint8: | |
return starlark.MakeUint64(uint64(v)) | |
case uint16: | |
return starlark.MakeUint64(uint64(v)) | |
case uint32: | |
return starlark.MakeUint64(uint64(v)) | |
case uint64: | |
return starlark.MakeUint64(v) | |
case uintptr: | |
return starlark.MakeUint64(uint64(v)) | |
case uint: | |
return starlark.MakeUint64(uint64(v)) | |
case int8: | |
return starlark.MakeInt64(int64(v)) | |
case int16: | |
return starlark.MakeInt64(int64(v)) | |
case int32: | |
return starlark.MakeInt64(int64(v)) | |
case int64: | |
return starlark.MakeInt64(v) | |
case int: | |
return starlark.MakeInt64(int64(v)) | |
case string: | |
return starlark.String(v) | |
case map[string]uint64: | |
// this is the only map type that we use in the api, if we ever want to | |
// add more maps to the api a more general approach will be necessary. | |
var r starlark.Dict | |
for k, v := range v { | |
r.SetKey(starlark.String(k), starlark.MakeUint64(v)) | |
} | |
return &r | |
case nil: | |
return starlark.None | |
case error: | |
return starlark.String(v.Error()) | |
default: | |
vval := reflect.ValueOf(v) | |
switch vval.Type().Kind() { | |
case reflect.Ptr: | |
if vval.IsNil() { | |
return starlark.None | |
} | |
vval = vval.Elem() | |
if vval.Type().Kind() == reflect.Struct { | |
return structAsStarlarkValue{vval} | |
} | |
case reflect.Struct: | |
return structAsStarlarkValue{vval} | |
case reflect.Slice: | |
return sliceAsStarlarkValue{vval} | |
} | |
return starlark.String(fmt.Sprintf("%v", v)) | |
} | |
} | |
// sliceAsStarlarkValue converts a reflect.Value containing a slice | |
// into a starlark value. | |
// The public methods of sliceAsStarlarkValue implement the Indexable and | |
// Sequence starlark interfaces. | |
type sliceAsStarlarkValue struct { | |
v reflect.Value | |
} | |
var _ starlark.Indexable = sliceAsStarlarkValue{} | |
var _ starlark.Sequence = sliceAsStarlarkValue{} | |
func (v sliceAsStarlarkValue) Freeze() { | |
} | |
func (v sliceAsStarlarkValue) Hash() (uint32, error) { | |
return 0, fmt.Errorf("not hashable") | |
} | |
func (v sliceAsStarlarkValue) String() string { | |
return fmt.Sprintf("%#v", v.v) | |
} | |
func (v sliceAsStarlarkValue) Truth() starlark.Bool { | |
return v.v.Len() != 0 | |
} | |
func (v sliceAsStarlarkValue) Type() string { | |
return v.v.Type().String() | |
} | |
func (v sliceAsStarlarkValue) Index(i int) starlark.Value { | |
if i >= v.v.Len() { | |
return nil | |
} | |
return toValue(v.v.Index(i).Interface()) | |
} | |
func (v sliceAsStarlarkValue) Len() int { | |
return v.v.Len() | |
} | |
func (v sliceAsStarlarkValue) Iterate() starlark.Iterator { | |
return &sliceAsStarlarkValueIterator{0, v.v} | |
} | |
type sliceAsStarlarkValueIterator struct { | |
cur int | |
v reflect.Value | |
} | |
func (it *sliceAsStarlarkValueIterator) Done() { | |
} | |
func (it *sliceAsStarlarkValueIterator) Next(p *starlark.Value) bool { | |
if it.cur >= it.v.Len() { | |
return false | |
} | |
*p = toValue(it.v.Index(it.cur).Interface()) | |
it.cur++ | |
return true | |
} | |
// structAsStarlarkValue converts any Go struct into a starlark.Value. | |
// The public methods of structAsStarlarkValue implement the | |
// starlark.HasAttrs interface. | |
type structAsStarlarkValue struct { | |
v reflect.Value | |
} | |
func (v structAsStarlarkValue) AttrNames() []string { | |
var out []string | |
for i := 0; i < v.v.NumField(); i++ { | |
out = append(out, v.v.Type().Field(i).Name) | |
} | |
return out | |
} | |
var _ starlark.HasAttrs = structAsStarlarkValue{} | |
func (v structAsStarlarkValue) Freeze() { | |
} | |
func (v structAsStarlarkValue) Hash() (uint32, error) { | |
return 0, fmt.Errorf("not hashable") | |
} | |
func (v structAsStarlarkValue) String() string { | |
return fmt.Sprintf("%#v", v.v) | |
} | |
func (v structAsStarlarkValue) Truth() starlark.Bool { | |
return true | |
} | |
func (v structAsStarlarkValue) Type() string { | |
return v.v.Type().String() | |
} | |
func (v structAsStarlarkValue) Attr(name string) (starlark.Value, error) { | |
r := v.v.FieldByName(name) | |
if r == (reflect.Value{}) { | |
return starlark.None, fmt.Errorf("no field named %q in %T", name, v.v.Interface()) | |
} | |
return toValue(r.Interface()), nil | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment