From a444ad5e6b1f7665962f2fb1e1e1008d31fd8ffe Mon Sep 17 00:00:00 2001 From: foxxorcat Date: Thu, 9 Jan 2025 20:37:31 +0800 Subject: [PATCH] feat: add Serializer and Deserializer --- marshal.go | 20 ++++++++++++++++++++ struct.go | 6 +++++- types.go | 11 +++++++++++ unmarshal.go | 20 ++++++++++++++++++++ 4 files changed, 56 insertions(+), 1 deletion(-) diff --git a/marshal.go b/marshal.go index 98f5357..9047de3 100644 --- a/marshal.go +++ b/marshal.go @@ -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 @@ -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 { @@ -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 diff --git a/struct.go b/struct.go index f09def3..8c26016 100644 --- a/struct.go +++ b/struct.go @@ -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 @@ -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 diff --git a/types.go b/types.go index 9dd19f4..559bd34 100644 --- a/types.go +++ b/types.go @@ -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) { @@ -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 { diff --git a/unmarshal.go b/unmarshal.go index a5784bf..3764482 100644 --- a/unmarshal.go +++ b/unmarshal.go @@ -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 @@ -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) @@ -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() {