Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions marshal.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,14 @@ import (
"golang.org/x/text/encoding"
)

type Serializer interface {
Serialize(w io.Writer, order ByteOrder) (int, error)
}

var (
SerializerType = reflect.TypeOf((*Serializer)(nil)).Elem()
)

// Marshal encodes a go value into binary data and return it as []byte.
func Marshal(govalue interface{}, order ByteOrder) (encoded []byte, err error) {
var ms Marshaller
Expand Down Expand Up @@ -91,6 +99,10 @@ func (ms *Marshaller) writeMain(w io.Writer, order ByteOrder, v reflect.Value, e
}
}

if option.serializer {
return ms.writeSerializer(w, order, v)
}

if option.isArray {
// write the array
if option.arrayLen == 0 {
Expand Down Expand Up @@ -413,6 +425,14 @@ func (ms *Marshaller) writeScalar(w io.Writer, order ByteOrder, v reflect.Value,
return writeU64(w, order, u64, sz)
}

func (ms *Marshaller) writeSerializer(w io.Writer, order ByteOrder, v reflect.Value) (n int, err error) {
m, ok := v.Interface().(Serializer)
if !ok {
return 0, fmt.Errorf("Serializer: unexpected error occurred")
}
return m.Serialize(w, order)
}

// write bytes according to the byte order
func writeU64(w io.Writer, order ByteOrder, u64 uint64, bytesize int) (n int, err error) {
var buf [8]byte
Expand Down
6 changes: 5 additions & 1 deletion struct.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ var (
mTag = regexp.MustCompile(`^\s*(\[([^\]]*)\])?([^\s\(\)]*)(\(([^\)]+)\))?`)

// single entry of tag-value evaluation
mExpression = regexp.MustCompile(`\s*([\+\-])?\s*([^\s\+\-]+)`)
mExpression = regexp.MustCompile(`\s*([\+\-\*\/])?\s*([^\s\+\-\*\/]+)`)
)

// simple add-sub calculator, with struct field referencing
Expand Down Expand Up @@ -81,6 +81,10 @@ func evaluateTagValue(strc reflect.Value, stmt string) (value int, err error) {
sum = sum + i64
case "-":
sum = sum - i64
case "*":
sum = sum * i64
case "/":
sum = sum / i64
default:
err = fmt.Errorf("invalid operation <%s>", q.operation)
return
Expand Down
11 changes: 11 additions & 0 deletions types.go
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,9 @@ type typeOption struct {
arrayLen int // length of the tagged array
bufLen int // tagged field is a string or a padding of length bufLen: `binary:"STRINGTYPE(buflen)"`
encoding string // string encoding of the field: `binary:"string,encoding=ENC"`

deserializer bool
serializer bool
}

func getITypeFromRType(rt reflect.Type) (it eType) {
Expand Down Expand Up @@ -207,6 +210,14 @@ func getNaturalType(v reflect.Value) (t eType, option typeOption) {
}
}

if typ.Implements(SerializerType) {
option.serializer = true
}

if reflect.PtrTo(typ).Implements(DeserializerType) {
option.deserializer = true
}

t = getITypeFromRType(typ)

if t == iArray {
Expand Down
20 changes: 20 additions & 0 deletions unmarshal.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,14 @@ var (
ErrUnknownLength = errors.New("unknown array, slice or string size")
)

type Deserializer interface {
Deserialize(r io.Reader, order ByteOrder) (int, error)
}

var (
DeserializerType = reflect.TypeOf((*Deserializer)(nil)).Elem()
)

// Unmarshal decodes binary images into a Go value. The Go value must be a writable type such as a slice, a pointer or an interface.
func Unmarshal(input []byte, order ByteOrder, govalue interface{}) (n int, err error) {
var ms Marshaller
Expand Down Expand Up @@ -66,6 +74,10 @@ func (ms *Marshaller) readMain(r io.Reader, order ByteOrder, v reflect.Value, en
}
}

if option.deserializer {
return ms.readSerializer(r, order, v.Addr())
}

if option.isArray {
// read an array
return ms.readArray(r, order, v, encodeType, option)
Expand Down Expand Up @@ -600,6 +612,14 @@ func (ms *Marshaller) readScalar(r io.Reader, order ByteOrder, v reflect.Value,
return
}

func (ms *Marshaller) readSerializer(r io.Reader, order ByteOrder, v reflect.Value) (n int, err error) {
m, ok := v.Interface().(Deserializer)
if !ok {
return 0, fmt.Errorf("Serializer: unexpected error occurred")
}
return m.Deserialize(r, order)
}

// follow pointers to the end
func dereferencePointer(p reflect.Value) (value reflect.Value, indirectCount int) {
if !p.IsValid() {
Expand Down