func (ins *inserter) insertField(s capnp.Struct, f schema.Field, val reflect.Value) error { typ, err := f.Slot().Type() if err != nil { return err } dv, err := f.Slot().DefaultValue() if err != nil { return err } if dv.IsValid() && int(typ.Which()) != int(dv.Which()) { name, _ := f.NameBytes() return fmt.Errorf("insert field %s: default value is a %v, want %v", name, dv.Which(), typ.Which()) } if !isTypeMatch(val.Type(), typ) { name, _ := f.NameBytes() return fmt.Errorf("can't insert field %s of type Go %v into a %v", name, val.Type(), typ.Which()) } if !isFieldInBounds(s.Size(), f.Slot().Offset(), typ) { name, _ := f.NameBytes() return fmt.Errorf("can't insert field %s: allocated struct is too small", name) } switch typ.Which() { case schema.Type_Which_bool: v := val.Bool() d := dv.Bool() s.SetBit(capnp.BitOffset(f.Slot().Offset()), v != d) // != acts as XOR case schema.Type_Which_int8: v := int8(val.Int()) d := dv.Int8() s.SetUint8(capnp.DataOffset(f.Slot().Offset()), uint8(v^d)) case schema.Type_Which_int16: v := int16(val.Int()) d := dv.Int16() s.SetUint16(capnp.DataOffset(f.Slot().Offset()*2), uint16(v^d)) case schema.Type_Which_int32: v := int32(val.Int()) d := dv.Int32() s.SetUint32(capnp.DataOffset(f.Slot().Offset()*4), uint32(v^d)) case schema.Type_Which_int64: v := val.Int() d := dv.Int64() s.SetUint64(capnp.DataOffset(f.Slot().Offset()*8), uint64(v^d)) case schema.Type_Which_uint8: v := uint8(val.Uint()) d := dv.Uint8() s.SetUint8(capnp.DataOffset(f.Slot().Offset()), v^d) case schema.Type_Which_uint16: v := uint16(val.Uint()) d := dv.Uint16() s.SetUint16(capnp.DataOffset(f.Slot().Offset()*2), v^d) case schema.Type_Which_enum: v := uint16(val.Uint()) d := dv.Enum() s.SetUint16(capnp.DataOffset(f.Slot().Offset()*2), v^d) case schema.Type_Which_uint32: v := uint32(val.Uint()) d := dv.Uint32() s.SetUint32(capnp.DataOffset(f.Slot().Offset()*4), v^d) case schema.Type_Which_uint64: v := val.Uint() d := dv.Uint64() s.SetUint64(capnp.DataOffset(f.Slot().Offset()*8), v^d) case schema.Type_Which_float32: v := math.Float32bits(float32(val.Float())) d := math.Float32bits(dv.Float32()) s.SetUint32(capnp.DataOffset(f.Slot().Offset()*4), v^d) case schema.Type_Which_float64: v := math.Float64bits(val.Float()) d := uint64(math.Float64bits(dv.Float64())) s.SetUint64(capnp.DataOffset(f.Slot().Offset()*8), v^d) case schema.Type_Which_text: off := uint16(f.Slot().Offset()) if val.Len() == 0 { if !isEmptyValue(dv) { return s.SetNewText(off, "") } return s.SetText(off, "") } if val.Kind() == reflect.String { return s.SetText(off, val.String()) } else { return s.SetTextFromBytes(off, val.Bytes()) } case schema.Type_Which_data: b := val.Bytes() if b == nil && !isEmptyValue(dv) { b = []byte{} } off := uint16(f.Slot().Offset()) return s.SetData(off, b) case schema.Type_Which_structType: off := uint16(f.Slot().Offset()) sval := val if val.Kind() == reflect.Ptr { if val.IsNil() { return s.SetPtr(off, capnp.Ptr{}) } sval = val.Elem() } id := typ.StructType().TypeId() sz, err := ins.structSize(id) if err != nil { return err } ss, err := capnp.NewStruct(s.Segment(), sz) if err != nil { return err } if err := s.SetPtr(off, ss.ToPtr()); err != nil { return err } return ins.insertStruct(id, ss, sval) case schema.Type_Which_list: off := uint16(f.Slot().Offset()) if val.IsNil() && isEmptyValue(dv) { return s.SetPtr(off, capnp.Ptr{}) } elem, err := typ.List().ElementType() if err != nil { return err } l, err := ins.newList(s.Segment(), elem, int32(val.Len())) if err != nil { return err } if err := s.SetPtr(off, l.ToPtr()); err != nil { return err } return ins.insertList(l, typ, val) default: return fmt.Errorf("unknown field type %v", typ.Which()) } return nil }
func (e *extracter) extractField(val reflect.Value, s capnp.Struct, f schema.Field) error { typ, err := f.Slot().Type() if err != nil { return err } dv, err := f.Slot().DefaultValue() if err != nil { return err } if dv.IsValid() && int(typ.Which()) != int(dv.Which()) { name, _ := f.NameBytes() return fmt.Errorf("extract field %s: default value is a %v, want %v", name, dv.Which(), typ.Which()) } if !isTypeMatch(val.Type(), typ) { name, _ := f.NameBytes() return fmt.Errorf("can't extract field %s of type %v into a Go %v", name, typ.Which(), val.Type()) } switch typ.Which() { case schema.Type_Which_bool: v := s.Bit(capnp.BitOffset(f.Slot().Offset())) d := dv.Bool() val.SetBool(v != d) // != acts as XOR case schema.Type_Which_int8: v := int8(s.Uint8(capnp.DataOffset(f.Slot().Offset()))) d := dv.Int8() val.SetInt(int64(v ^ d)) case schema.Type_Which_int16: v := int16(s.Uint16(capnp.DataOffset(f.Slot().Offset() * 2))) d := dv.Int16() val.SetInt(int64(v ^ d)) case schema.Type_Which_int32: v := int32(s.Uint32(capnp.DataOffset(f.Slot().Offset() * 4))) d := dv.Int32() val.SetInt(int64(v ^ d)) case schema.Type_Which_int64: v := int64(s.Uint64(capnp.DataOffset(f.Slot().Offset() * 8))) d := dv.Int64() val.SetInt(v ^ d) case schema.Type_Which_uint8: v := s.Uint8(capnp.DataOffset(f.Slot().Offset())) d := dv.Uint8() val.SetUint(uint64(v ^ d)) case schema.Type_Which_uint16: v := s.Uint16(capnp.DataOffset(f.Slot().Offset() * 2)) d := dv.Uint16() val.SetUint(uint64(v ^ d)) case schema.Type_Which_enum: v := s.Uint16(capnp.DataOffset(f.Slot().Offset() * 2)) d := dv.Enum() val.SetUint(uint64(v ^ d)) case schema.Type_Which_uint32: v := s.Uint32(capnp.DataOffset(f.Slot().Offset() * 4)) d := dv.Uint32() val.SetUint(uint64(v ^ d)) case schema.Type_Which_uint64: v := s.Uint64(capnp.DataOffset(f.Slot().Offset() * 8)) d := dv.Uint64() val.SetUint(v ^ d) case schema.Type_Which_float32: v := s.Uint32(capnp.DataOffset(f.Slot().Offset() * 4)) d := math.Float32bits(dv.Float32()) val.SetFloat(float64(math.Float32frombits(v ^ d))) case schema.Type_Which_float64: v := s.Uint64(capnp.DataOffset(f.Slot().Offset() * 8)) d := math.Float64bits(dv.Float64()) val.SetFloat(math.Float64frombits(v ^ d)) case schema.Type_Which_text: p, err := s.Ptr(uint16(f.Slot().Offset())) if err != nil { return err } var b []byte if p.IsValid() { b = p.TextBytes() } else { b, _ = dv.TextBytes() } if val.Kind() == reflect.String { val.SetString(string(b)) } else { // byte slice, as guaranteed by isTypeMatch val.SetBytes(b) } case schema.Type_Which_data: p, err := s.Ptr(uint16(f.Slot().Offset())) if err != nil { return err } var b []byte if p.IsValid() { b = p.Data() } else { b, _ = dv.Data() } val.SetBytes(b) case schema.Type_Which_structType: p, err := s.Ptr(uint16(f.Slot().Offset())) if err != nil { return err } ss := p.Struct() if !ss.IsValid() { p, _ = dv.StructValuePtr() ss = p.Struct() } return e.extractStruct(val, typ.StructType().TypeId(), ss) case schema.Type_Which_list: p, err := s.Ptr(uint16(f.Slot().Offset())) if err != nil { return err } l := p.List() if !l.IsValid() { p, _ = dv.ListPtr() l = p.List() } return e.extractList(val, typ, l) default: return fmt.Errorf("unknown field type %v", typ.Which()) } return nil }
func (enc *Encoder) marshalFieldValue(s capnp.Struct, f schema.Field) error { typ, err := f.Slot().Type() if err != nil { return err } dv, err := f.Slot().DefaultValue() if err != nil { return err } if dv.IsValid() && int(typ.Which()) != int(dv.Which()) { name, _ := f.Name() return fmt.Errorf("marshal field %s: default value is a %v, want %v", name, dv.Which(), typ.Which()) } switch typ.Which() { case schema.Type_Which_void: enc.w.WriteString(voidMarker) case schema.Type_Which_bool: v := s.Bit(capnp.BitOffset(f.Slot().Offset())) d := dv.Bool() enc.marshalBool(!d && v || d && !v) case schema.Type_Which_int8: v := s.Uint8(capnp.DataOffset(f.Slot().Offset())) d := uint8(dv.Int8()) enc.marshalInt(int64(int8(v ^ d))) case schema.Type_Which_int16: v := s.Uint16(capnp.DataOffset(f.Slot().Offset() * 2)) d := uint16(dv.Int16()) enc.marshalInt(int64(int16(v ^ d))) case schema.Type_Which_int32: v := s.Uint32(capnp.DataOffset(f.Slot().Offset() * 4)) d := uint32(dv.Int32()) enc.marshalInt(int64(int32(v ^ d))) case schema.Type_Which_int64: v := s.Uint64(capnp.DataOffset(f.Slot().Offset() * 8)) d := uint64(dv.Int64()) enc.marshalInt(int64(v ^ d)) case schema.Type_Which_uint8: v := s.Uint8(capnp.DataOffset(f.Slot().Offset())) d := dv.Uint8() enc.marshalUint(uint64(v ^ d)) case schema.Type_Which_uint16: v := s.Uint16(capnp.DataOffset(f.Slot().Offset() * 2)) d := dv.Uint16() enc.marshalUint(uint64(v ^ d)) case schema.Type_Which_uint32: v := s.Uint32(capnp.DataOffset(f.Slot().Offset() * 4)) d := dv.Uint32() enc.marshalUint(uint64(v ^ d)) case schema.Type_Which_uint64: v := s.Uint64(capnp.DataOffset(f.Slot().Offset() * 8)) d := dv.Uint64() enc.marshalUint(v ^ d) case schema.Type_Which_float32: v := s.Uint32(capnp.DataOffset(f.Slot().Offset() * 4)) d := math.Float32bits(dv.Float32()) enc.marshalFloat32(math.Float32frombits(v ^ d)) case schema.Type_Which_float64: v := s.Uint64(capnp.DataOffset(f.Slot().Offset() * 8)) d := math.Float64bits(dv.Float64()) enc.marshalFloat64(math.Float64frombits(v ^ d)) case schema.Type_Which_structType: p, err := s.Ptr(uint16(f.Slot().Offset())) if err != nil { return err } if !p.IsValid() { p, _ = dv.StructValuePtr() } return enc.marshalStruct(typ.StructType().TypeId(), p.Struct()) case schema.Type_Which_data: p, err := s.Ptr(uint16(f.Slot().Offset())) if err != nil { return err } if !p.IsValid() { b, _ := dv.Data() enc.marshalText(b) return nil } enc.marshalText(p.Data()) case schema.Type_Which_text: p, err := s.Ptr(uint16(f.Slot().Offset())) if err != nil { return err } if !p.IsValid() { b, _ := dv.TextBytes() enc.marshalText(b) return nil } enc.marshalText(p.TextBytes()) case schema.Type_Which_list: elem, err := typ.List().ElementType() if err != nil { return err } p, err := s.Ptr(uint16(f.Slot().Offset())) if err != nil { return err } if !p.IsValid() { p, _ = dv.ListPtr() } return enc.marshalList(elem, p.List()) case schema.Type_Which_enum: v := s.Uint16(capnp.DataOffset(f.Slot().Offset() * 2)) d := dv.Uint16() return enc.marshalEnum(typ.Enum().TypeId(), v^d) case schema.Type_Which_interface: enc.w.WriteString(interfaceMarker) case schema.Type_Which_anyPointer: enc.w.WriteString(anyPointerMarker) default: return fmt.Errorf("unknown field type %v", typ.Which()) } return nil }