values read themselves

types
Jordan Orelli 8 years ago
parent 4a0872f3ff
commit b5e5280913

@ -20,7 +20,7 @@ func arrayType(spec *typeSpec, env *Env) tÿpe {
elemSpec := *spec
elemSpec.typeName = elemName
elemType := parseTypeSpec(&elemSpec, env)
return array_t{elemType, count}
return &array_t{elemType, count}
}
func parseArrayName(s string) (string, int) {
@ -49,18 +49,28 @@ type array_t struct {
count int
}
func (t *array_t) nü() value { return array{t: t, slots: make([]value, t.count)} }
func (t array_t) typeName() string { return fmt.Sprintf("array:%s", t.elem.typeName()) }
func (t array_t) read(r bit.Reader) (value, error) {
var err error
v := make(array, t.count)
for i := range v {
v[i], err = t.elem.read(r)
if err != nil {
return nil, wrap(err, "array read error at index %d", i)
type array struct {
t *array_t
slots []value
}
func (a array) tÿpe() tÿpe { return a.t }
func (a array) read(r bit.Reader) error {
for i := range a.slots {
if a.slots[i] == nil {
a.slots[i] = a.t.elem.nü()
}
if err := a.slots[i].read(r); err != nil {
return wrap(err, "array read error at index %d", i)
}
}
return v, r.Err()
return r.Err()
}
type array []value
func (a array) String() string {
return fmt.Sprintf("%s%v", a.t.typeName(), a.slots)
}

@ -1,75 +1,254 @@
package ent
import (
"fmt"
"github.com/jordanorelli/hyperstone/bit"
"strconv"
)
var atom_types = []typeLiteral{
{
"bool",
func(r bit.Reader) (value, error) {
return bit.ReadBool(r), r.Err()
},
// ------------------------------------------------------------------------------
// bool
// ------------------------------------------------------------------------------
var bool_t = &typeLiteral{
name: "bool",
newFn: func() value {
return new(bool_v)
},
{
"uint8",
func(r bit.Reader) (value, error) {
// TODO: bounds check here
return uint8(bit.ReadVarInt(r)), r.Err()
},
}
type bool_v bool
func (v bool_v) tÿpe() tÿpe { return bool_t }
func (v *bool_v) read(r bit.Reader) error {
*v = bool_v(bit.ReadBool(r))
return r.Err()
}
func (v bool_v) String() string {
if v {
return "true"
}
return "false"
}
// ------------------------------------------------------------------------------
// uint8
// ------------------------------------------------------------------------------
var uint8_t = &typeLiteral{
name: "uint8",
newFn: func() value {
return new(uint8_v)
},
{
"uint16",
func(r bit.Reader) (value, error) {
// TODO: bounds check here
return uint16(bit.ReadVarInt(r)), r.Err()
},
}
type uint8_v uint8
func (v uint8_v) tÿpe() tÿpe { return uint8_t }
func (v *uint8_v) read(r bit.Reader) error {
u := bit.ReadVarInt(r)
if u > 1<<8-1 {
return fmt.Errorf("uint8 overflow: %d", u)
}
*v = uint8_v(u)
return r.Err()
}
func (v uint8_v) String() string {
return strconv.FormatUint(uint64(v), 10)
}
// ------------------------------------------------------------------------------
// uint16
// ------------------------------------------------------------------------------
var uint16_t = &typeLiteral{
name: "uint16",
newFn: func() value {
return new(uint16_v)
},
{
"uint32",
func(r bit.Reader) (value, error) {
return bit.ReadVarInt32(r), r.Err()
},
}
type uint16_v uint16
func (v uint16_v) tÿpe() tÿpe { return uint16_t }
func (v *uint16_v) read(r bit.Reader) error {
u := bit.ReadVarInt(r)
if u > 1<<16-1 {
return fmt.Errorf("uint16 overflow: %d", u)
}
*v = uint16_v(u)
return r.Err()
}
func (v uint16_v) String() string {
return strconv.FormatUint(uint64(v), 10)
}
// ------------------------------------------------------------------------------
// uint32
// ------------------------------------------------------------------------------
var uint32_t = &typeLiteral{
name: "uint32",
newFn: func() value {
return new(uint32_v)
},
{
"uint64",
func(r bit.Reader) (value, error) {
return bit.ReadVarInt(r), r.Err()
},
}
type uint32_v uint32
func (v uint32_v) tÿpe() tÿpe { return uint32_t }
func (v *uint32_v) read(r bit.Reader) error {
u := bit.ReadVarInt(r)
if u > 1<<32-1 {
return fmt.Errorf("uint32 overflow: %d", u)
}
*v = uint32_v(u)
return r.Err()
}
func (v uint32_v) String() string {
return strconv.FormatUint(uint64(v), 0)
}
// ------------------------------------------------------------------------------
// uint64
// ------------------------------------------------------------------------------
var uint64_t = &typeLiteral{
name: "uint64",
newFn: func() value {
return new(uint64_v)
},
{
"int8",
func(r bit.Reader) (value, error) {
// TODO: bounds check here
return int8(bit.ReadZigZag32(r)), r.Err()
},
}
type uint64_v uint64
func (v uint64_v) tÿpe() tÿpe { return uint64_t }
func (v *uint64_v) read(r bit.Reader) error {
*v = uint64_v(bit.ReadVarInt(r))
return r.Err()
}
func (v uint64_v) String() string {
return strconv.FormatUint(uint64(v), 10)
}
// ------------------------------------------------------------------------------
// int8
// ------------------------------------------------------------------------------
var int8_t = &typeLiteral{
name: "int8",
newFn: func() value {
return new(int8_v)
},
{
"int32",
func(r bit.Reader) (value, error) {
return bit.ReadZigZag32(r), r.Err()
},
}
type int8_v int8
func (v int8_v) tÿpe() tÿpe { return int8_t }
func (v *int8_v) read(r bit.Reader) error {
// TODO: bounds check here?
*v = int8_v(bit.ReadZigZag32(r))
return r.Err()
}
func (v int8_v) String() string {
return strconv.FormatInt(int64(v), 10)
}
// ------------------------------------------------------------------------------
// int32
// ------------------------------------------------------------------------------
var int32_t = &typeLiteral{
name: "int32",
newFn: func() value {
return new(int32_v)
},
{
"CUtlStringToken",
func(r bit.Reader) (value, error) {
return bit.ReadVarInt(r), r.Err()
},
}
type int32_v int32
func (v int32_v) tÿpe() tÿpe { return int32_t }
func (v *int32_v) read(r bit.Reader) error {
*v = int32_v(bit.ReadZigZag32(r))
return r.Err()
}
func (v int32_v) String() string {
return strconv.FormatInt(int64(v), 10)
}
// ------------------------------------------------------------------------------
// CUtlStringToken
//
// weirdly, this type isn't a string; it's actually a number. The number
// presumably indicates some value on a symbol table.
// ------------------------------------------------------------------------------
var stringToken_t = &typeLiteral{
name: "CUtlStringToken",
newFn: func() value {
return new(stringToken_v)
},
{
"Color",
func(r bit.Reader) (value, error) {
u := bit.ReadVarInt(r)
return color{
r: uint8(u >> 6 & 0xff),
g: uint8(u >> 4 & 0xff),
b: uint8(u >> 2 & 0xff),
a: uint8(u >> 0 & 0xff),
}, r.Err()
},
}
type stringToken_v uint64
func (v stringToken_v) tÿpe() tÿpe { return stringToken_t }
func (v *stringToken_v) read(r bit.Reader) error {
*v = stringToken_v(bit.ReadVarInt(r))
return r.Err()
}
func (v stringToken_v) String() string {
return fmt.Sprintf("token:%d", v)
}
// ------------------------------------------------------------------------------
// Color
// ------------------------------------------------------------------------------
var color_t = &typeLiteral{
name: "Color",
newFn: func() value {
return new(color)
},
}
type color struct{ r, g, b, a uint8 }
func (c color) tÿpe() tÿpe { return color_t }
func (c *color) read(r bit.Reader) error {
u := bit.ReadVarInt(r)
c.r = uint8(u >> 6 & 0xff)
c.g = uint8(u >> 4 & 0xff)
c.b = uint8(u >> 2 & 0xff)
c.a = uint8(u >> 0 & 0xff)
return r.Err()
}
func (c color) String() string {
return fmt.Sprintf("#%x%x%x%x", c.r, c.g, c.b, c.a)
}
var atom_types = []tÿpe{
bool_t,
uint8_t,
uint16_t,
uint32_t,
uint64_t,
int8_t,
int32_t,
stringToken_t,
color_t,
}
func atomType(spec *typeSpec, env *Env) tÿpe {
for _, t := range atom_types {
if t.typeName() == spec.typeName {
@ -79,5 +258,3 @@ func atomType(spec *typeSpec, env *Env) tÿpe {
}
return nil
}
type color struct{ r, g, b, a uint8 }

@ -24,8 +24,8 @@ func (c *class) read(r bit.Reader) (value, error) {
return c.nü(), nil
}
func (c *class) nü() entity {
return entity{class: c, slots: make([]value, len(c.fields))}
func (c *class) nü() value {
return &entity{class: c, slots: make([]value, len(c.fields))}
}
type classHistory struct {

@ -1,6 +1,7 @@
package ent
import (
"fmt"
"github.com/jordanorelli/hyperstone/bit"
)
@ -31,6 +32,12 @@ func (e *entity) className() string {
return "<None>"
}
func (e *entity) String() string {
return fmt.Sprintf("%s{%v}", e.class.typeName(), e.slots)
}
func (e *entity) tÿpe() tÿpe { return e.class }
func (e *entity) slotType(i int) tÿpe { return e.class.fields[i].tÿpe }
func (e *entity) slotName(i int) string { return e.class.fields[i].name }
func (e *entity) setSlotValue(i int, v value) { e.slots[i] = v }
func (e *entity) getSlotValue(i int) value { return e.slots[i] }

@ -2,6 +2,7 @@ package ent
import (
"math"
"strconv"
"github.com/jordanorelli/hyperstone/bit"
)
@ -23,12 +24,7 @@ func floatType(spec *typeSpec, env *Env) tÿpe {
}
if spec.encoder == "coord" {
Debug.Printf(" coord float type")
return typeLiteral{
"float:coord",
func(r bit.Reader) (value, error) {
return bit.ReadCoord(r), r.Err()
},
}
return coord_t
}
if spec.serializer == "simulationtime" {
return nil
@ -36,18 +32,50 @@ func floatType(spec *typeSpec, env *Env) tÿpe {
switch spec.bits {
case 0, 32:
Debug.Printf(" std float type")
return typeLiteral{
"float:std",
func(r bit.Reader) (value, error) {
// TODO: check uint32 overflow here?
return math.Float32frombits(uint32(r.ReadBits(32))), r.Err()
},
}
return float_t
default:
return qFloatType(spec, env)
}
}
var coord_t = &typeLiteral{
name: "coord",
newFn: func() value {
return new(coord_v)
},
}
type coord_v float32
func (v coord_v) tÿpe() tÿpe { return coord_t }
func (v *coord_v) read(r bit.Reader) error {
*v = coord_v(bit.ReadCoord(r))
return r.Err()
}
func (v coord_v) String() string {
return strconv.FormatFloat(float64(v), 'f', 3, 32)
}
var float_t = &typeLiteral{
name: "float",
newFn: func() value {
return new(float_v)
},
}
type float_v float32
func (v float_v) tÿpe() tÿpe { return float_t }
func (v *float_v) read(r bit.Reader) error {
*v = float_v(math.Float32frombits(uint32(r.ReadBits(32))))
return r.Err()
}
func (v float_v) String() string {
return strconv.FormatFloat(float64(v), 'f', 3, 32)
}
func qFloatType(spec *typeSpec, env *Env) tÿpe {
if spec.bits < 0 {
return typeError("quantized float has invalid negative bit count specifier")
@ -56,7 +84,7 @@ func qFloatType(spec *typeSpec, env *Env) tÿpe {
return typeError("quantized float has invalid negative range")
}
t := qfloat_t{typeSpec: *spec}
t := &qfloat_t{typeSpec: *spec}
t.span = t.high - t.low
t.intervals = uint(1<<t.bits - 1)
t.interval = t.span / float32(t.intervals)
@ -87,11 +115,24 @@ type qfloat_t struct {
special *float32
}
func (t *qfloat_t) nü() value { return &qfloat_v{t: t} }
func (t qfloat_t) typeName() string { return "qfloat" }
func (t qfloat_t) read(r bit.Reader) (value, error) {
if t.special != nil && bit.ReadBool(r) {
return *t.special, nil
type qfloat_v struct {
t *qfloat_t
v float32
}
func (v qfloat_v) tÿpe() tÿpe { return v.t }
func (v *qfloat_v) read(r bit.Reader) error {
if v.t.special != nil && bit.ReadBool(r) {
v.v = *v.t.special
} else {
v.v = v.t.low + float32(r.ReadBits(v.t.bits))*v.t.interval
}
return t.low + float32(r.ReadBits(t.bits))*t.interval, r.Err()
return r.Err()
}
func (v qfloat_v) String() string {
return strconv.FormatFloat(float64(v.v), 'f', 3, 32)
}

@ -24,14 +24,10 @@ func genericType(spec *typeSpec, env *Env) tÿpe {
switch genericName {
case "CHandle", "CStrongHandle":
return typeLiteral{
fmt.Sprintf("handle:%s", genericName),
func(r bit.Reader) (value, error) {
return handle(bit.ReadVarInt(r)), r.Err()
},
}
t := handle_t(spec.typeName)
return &t
case "CUtlVector":
return cutl_vector_t{elem}
return &cutl_vector_t{elem}
default:
return typeError("unknown generic name: %v", parts[0])
}
@ -75,11 +71,27 @@ type cutl_vector_t struct {
elem tÿpe
}
func (t *cutl_vector_t) nü() value {
return &cutl_vector{t: t}
}
func (t cutl_vector_t) typeName() string {
return fmt.Sprintf("vector:%s", t.elem.typeName())
}
func (t cutl_vector_t) read(r bit.Reader) (value, error) {
type cutl_vector struct {
t tÿpe
slots []value
}
func (v *cutl_vector) tÿpe() tÿpe { return v.t }
func (v *cutl_vector) read(r bit.Reader) error {
count := bit.ReadVarInt32(r)
return make(array, count), r.Err()
v.slots = make([]value, count)
return r.Err()
}
func (v cutl_vector) String() string {
return fmt.Sprintf("%s<%v>", v.t.typeName(), v.slots)
}

@ -1,12 +1,32 @@
package ent
import (
"fmt"
"github.com/jordanorelli/hyperstone/bit"
)
type handle_t string
func (t handle_t) typeName() string { return string(t) }
func (t *handle_t) nü() value { return &handle{t: t} }
// a handle represents a soft pointer to an entity. handles are represented by
// IDs and can cross the client-server divide.
type handle int
type handle struct {
t tÿpe
id uint64
}
func (h handle) tÿpe() tÿpe { return h.t }
func (h *handle) read(r bit.Reader) error {
h.id = bit.ReadVarInt(r)
return r.Err()
}
func (h handle) String() string {
return fmt.Sprintf("handle<%s>: %d", h.t.typeName(), h.id)
}
func handleType(spec *typeSpec, env *Env) tÿpe {
if spec.typeName != "CGameSceneNodeHandle" {
@ -14,10 +34,6 @@ func handleType(spec *typeSpec, env *Env) tÿpe {
}
Debug.Printf(" handle type")
return typeLiteral{
"handle:CGameSceneNodeHandle",
func(r bit.Reader) (value, error) {
return handle(bit.ReadVarInt(r)), r.Err()
},
}
t := handle_t(spec.typeName)
return &t
}

@ -1,19 +1,34 @@
package ent
import (
"fmt"
"github.com/jordanorelli/hyperstone/bit"
)
var hseq_t = &typeLiteral{
name: "HSequence",
newFn: func() value {
return new(hseq_v)
},
}
type hseq_v uint64
func (v hseq_v) tÿpe() tÿpe { return hseq_t }
func (v *hseq_v) read(r bit.Reader) error {
*v = hseq_v(bit.ReadVarInt(r) - 1)
return r.Err()
}
func (v hseq_v) String() string {
return fmt.Sprintf("hseq:%d", uint64(v))
}
func hSeqType(spec *typeSpec, env *Env) tÿpe {
if spec.typeName != "HSequence" {
return nil
}
Debug.Printf(" hsequence type")
return typeLiteral{
"HSequence",
func(r bit.Reader) (value, error) {
return bit.ReadVarInt(r) - 1, r.Err()
},
}
return hseq_t
}

@ -1,12 +1,40 @@
package ent
import (
"github.com/jordanorelli/hyperstone/bit"
"fmt"
"math"
"github.com/jordanorelli/hyperstone/bit"
)
var qangle_t = &typeLiteral{
name: "qangle",
newFn: func() value {
return new(qangle)
},
}
type qangle struct{ pitch, yaw, roll float32 }
func (q qangle) tÿpe() tÿpe { return qangle_t }
func (q *qangle) read(r bit.Reader) error {
pitch, yaw, roll := bit.ReadBool(r), bit.ReadBool(r), bit.ReadBool(r)
if pitch {
q.pitch = bit.ReadCoord(r)
}
if yaw {
q.yaw = bit.ReadCoord(r)
}
if roll {
q.roll = bit.ReadCoord(r)
}
return r.Err()
}
func (q qangle) String() string {
return fmt.Sprintf("qangle{%f %f %f}", q.pitch, q.yaw, q.roll)
}
func qAngleType(spec *typeSpec, env *Env) tÿpe {
if spec.typeName != "QAngle" {
return nil
@ -16,31 +44,16 @@ func qAngleType(spec *typeSpec, env *Env) tÿpe {
case spec.bits <= 0 || spec.bits > 32:
return typeError("qangle pitch_yaw has invalid bit size: %d", spec.bits)
case spec.bits == 32:
return typeLiteral{"qangle:pitchYaw", pitchYaw_t}
return pitchYaw_t
default:
return pitchYawAngles_t(spec.bits)
t := pitchYawAngles_t(spec.bits)
return &t
}
}
switch spec.bits {
case 0:
Debug.Printf(" qangle type")
return typeLiteral{
"qangle",
func(r bit.Reader) (value, error) {
var q qangle
pitch, yaw, roll := bit.ReadBool(r), bit.ReadBool(r), bit.ReadBool(r)
if pitch {
q.pitch = bit.ReadCoord(r)
}
if yaw {
q.yaw = bit.ReadCoord(r)
}
if roll {
q.roll = bit.ReadCoord(r)
}
return q, nil
},
}
return qangle_t
case 32:
return nil
default:
@ -48,20 +61,45 @@ func qAngleType(spec *typeSpec, env *Env) tÿpe {
}
}
func pitchYaw_t(r bit.Reader) (value, error) {
var q qangle
q.pitch = math.Float32frombits(uint32(r.ReadBits(32)))
q.yaw = math.Float32frombits(uint32(r.ReadBits(32)))
return q, r.Err()
var pitchYaw_t = &typeLiteral{
name: "qangle:pitchYaw",
newFn: func() value {
return new(pitchYaw_v)
},
}
type pitchYaw_v qangle
func (v pitchYaw_v) tÿpe() tÿpe { return pitchYaw_t }
func (v *pitchYaw_v) read(r bit.Reader) error {
v.pitch = math.Float32frombits(uint32(r.ReadBits(32)))
v.yaw = math.Float32frombits(uint32(r.ReadBits(32)))
return r.Err()
}
func (v pitchYaw_v) String() string {
return fmt.Sprintf("qangle:pitchYaw{%f %f}", v.pitch, v.yaw)
}
type pitchYawAngles_t uint
func (t pitchYawAngles_t) typeName() string { return "qangle:pitchYawAngles" }
func (t *pitchYawAngles_t) nü() value {
return &pitchYawAngles_v{t: t}
}
type pitchYawAngles_v struct {
t *pitchYawAngles_t
qangle
}
func (v pitchYawAngles_v) tÿpe() tÿpe { return v.t }
func (v *pitchYawAngles_v) read(r bit.Reader) error {
v.pitch = bit.ReadAngle(r, uint(*v.t))
v.yaw = bit.ReadAngle(r, uint(*v.t))
return r.Err()
}
func (t pitchYawAngles_t) read(r bit.Reader) (value, error) {
var q qangle
q.pitch = bit.ReadAngle(r, uint(t))
q.yaw = bit.ReadAngle(r, uint(t))
return q, r.Err()
func (v pitchYawAngles_v) String() string {
return fmt.Sprintf("qangle:pitchYawAngles{%f %f}", v.pitch, v.yaw)
}

@ -20,31 +20,35 @@ func (s selection) String() string { return fmt.Sprint(s.path()) }
func (s selection) path() []int { return s.vals[:s.count] }
func (s selection) fillSlots(v slotted, r bit.Reader) error {
Debug.Printf("%v fill slots into %v", s, v)
return s.fillSlotsIter(0, v, r)
return s.fillSlotsIter(0, v, v.tÿpe().typeName(), r)
}
func (s selection) fillSlotsIter(offset int, dest slotted, r bit.Reader) error {
func (s selection) fillSlotsIter(offset int, dest slotted, path string, r bit.Reader) error {
slot := s.vals[offset]
if s.count-offset <= 0 {
return fmt.Errorf("unable to fill selection %v having count %d at offset %d", s, s.count, offset)
}
switch s.count - offset {
case 1:
t := dest.slotType(slot)
v, err := t.read(r)
if err != nil {
v := dest.slotType(slot).nü()
if err := v.read(r); err != nil {
return fmt.Errorf("unable to fill selection: %v", err)
}
old := dest.getSlotValue(slot)
dest.setSlotValue(slot, v)
Debug.Printf("%v %s.%s (%s) %v -> %v", s, path, dest.slotName(slot), dest.slotType(slot).typeName(), old, v)
return nil
default:
v := dest.getSlotValue(slot)
if v == nil {
v = dest.slotType(slot).nü()
dest.setSlotValue(slot, v)
}
vs, ok := v.(slotted)
if !ok {
return fmt.Errorf("destination is not slotted")
return fmt.Errorf("dest isn't slotted")
}
return s.fillSlotsIter(offset+1, vs, r)
return s.fillSlotsIter(offset+1, vs, fmt.Sprintf("%s.%s", path, dest.slotName(slot)), r)
}
}

@ -1,7 +1,9 @@
package ent
type slotted interface {
value
slotType(int) tÿpe
slotName(int) string
setSlotValue(int, value)
getSlotValue(int) value
}

@ -8,17 +8,17 @@ import (
)
type tÿpe interface {
read(bit.Reader) (value, error)
nü() value
typeName() string
}
type typeLiteral struct {
name string
readFn func(r bit.Reader) (value, error)
name string
newFn func() value
}
func (t typeLiteral) typeName() string { return t.name }
func (t typeLiteral) read(r bit.Reader) (value, error) { return t.readFn(r) }
func (t typeLiteral) nü() value { return t.newFn() }
func (t typeLiteral) typeName() string { return t.name }
type typeParseFn func(*typeSpec, *Env) tÿpe
@ -42,14 +42,32 @@ func parseTypeSpec(spec *typeSpec, env *Env) tÿpe {
hSeqType, genericType, vectorType, classType, unknownType)
}
type unknown_t string
func (t unknown_t) typeName() string { return string(t) }
func (t *unknown_t) nü() value {
return &unknown_v{t: t}
}
type unknown_v struct {
t tÿpe
v uint64
}
func (v unknown_v) tÿpe() tÿpe { return v.t }
func (v *unknown_v) read(r bit.Reader) error {
v.v = bit.ReadVarInt(r)
return r.Err()
}
func (v unknown_v) String() string {
return fmt.Sprintf("%s(unknown):%d", v.t.typeName(), v.v)
}
func unknownType(spec *typeSpec, env *Env) tÿpe {
Debug.Printf("Unknown Type: %v", spec)
return typeLiteral{
name: fmt.Sprintf("unknown:%s", spec.typeName),
readFn: func(r bit.Reader) (value, error) {
return bit.ReadVarInt(r), r.Err()
},
}
t := unknown_t(spec.typeName)
return &t
}
// a type error is both an error and a type. It represents a type that we were
@ -62,11 +80,9 @@ func typeError(t string, args ...interface{}) tÿpe {
type error_t string
func (e error_t) nü() value { panic("can't create an error val like that") }
func (e error_t) typeName() string { return "error" }
func (e error_t) Error() string { return string(e) }
func (e error_t) read(r bit.Reader) (value, error) {
return nil, fmt.Errorf("type error: %s", string(e))
}
type typeSpec struct {
name string

@ -1,3 +1,11 @@
package ent
type value interface{}
import (
"github.com/jordanorelli/hyperstone/bit"
)
type value interface {
String() string
tÿpe() tÿpe
read(bit.Reader) error
}

@ -5,8 +5,6 @@ import (
"github.com/jordanorelli/hyperstone/bit"
)
type vector struct{ x, y, z float32 }
func vectorType(spec *typeSpec, env *Env) tÿpe {
if spec.encoder != "" {
return nil
@ -18,7 +16,7 @@ func vectorType(spec *typeSpec, env *Env) tÿpe {
if t == nil {
return nil
}
return vector_t{elem: t}
return &vector_t{elem: t}
}
type vector_t struct {
@ -29,19 +27,41 @@ func (t vector_t) typeName() string {
return fmt.Sprintf("vector:%s", t.elem.typeName())
}
func (t vector_t) read(r bit.Reader) (value, error) {
var err error
var v interface{}
read := func(f *float32) {
if err != nil {
return
func (t *vector_t) nü() value {
return &vector{t: t}
}
type vector struct {
t tÿpe
x, y, z value
}
func (v vector) tÿpe() tÿpe { return v.t }
func (v *vector) read(r bit.Reader) error {
if v.x == nil {
v.x = v.t.nü()
}
if v.y == nil {
v.y = v.t.nü()
}
if v.z == nil {
v.z = v.t.nü()
}
type fn func(bit.Reader) error
coalesce := func(fns ...fn) error {
for _, f := range fns {
if err := f(r); err != nil {
return err
}
}
v, err = t.elem.read(r)
*f = v.(float32)
return nil
}
var out vector
read(&out.x)
read(&out.y)
read(&out.z)
return out, err
return coalesce(v.x.read, v.y.read, v.z.read)
}
func (v vector) String() string {
return fmt.Sprintf("vector<%s>{%s %s %s}", v.t.typeName, v.x, v.y, v.z)
}

Loading…
Cancel
Save