Refactored binapi generator with message encoding
[govpp.git] / codec / marshaler.go
diff --git a/codec/marshaler.go b/codec/marshaler.go
new file mode 100644 (file)
index 0000000..c6d33a3
--- /dev/null
@@ -0,0 +1,229 @@
+//  Copyright (c) 2020 Cisco and/or its affiliates.
+//
+//  Licensed under the Apache License, Version 2.0 (the "License");
+//  you may not use this file except in compliance with the License.
+//  You may obtain a copy of the License at:
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//  See the License for the specific language governing permissions and
+//  limitations under the License.
+
+package codec
+
+import (
+       "bytes"
+       "encoding/binary"
+       "errors"
+       "fmt"
+       "math"
+       "reflect"
+       "unsafe"
+
+       "github.com/lunixbochs/struc"
+
+       "git.fd.io/govpp.git/api"
+)
+
+var DefaultCodec = &NewCodec{} // &MsgCodec{}
+
+// Marshaler is the interface implemented by the binary API messages that can
+// marshal itself into binary form for the wire.
+type Marshaler interface {
+       Size() int
+       Marshal([]byte) ([]byte, error)
+}
+
+// Unmarshaler is the interface implemented by the binary API messages that can
+// unmarshal a binary representation of itself from the wire.
+type Unmarshaler interface {
+       Unmarshal([]byte) error
+}
+
+type NewCodec struct{}
+
+func (*NewCodec) EncodeMsg(msg api.Message, msgID uint16) (data []byte, err error) {
+       if msg == nil {
+               return nil, errors.New("nil message passed in")
+       }
+       marshaller, ok := msg.(Marshaler)
+       if !ok {
+               return nil, fmt.Errorf("message %s does not implement marshaller", msg.GetMessageName())
+       }
+
+       size := marshaller.Size()
+       offset := getOffset(msg)
+       //fmt.Printf("size=%d offset=%d\n", size, offset)
+
+       b := make([]byte, size+offset)
+       b[0] = byte(msgID >> 8)
+       b[1] = byte(msgID)
+
+       //fmt.Printf("len(b)=%d cap(b)=%d\n", len(b), cap(b))
+       //b = append(b, byte(msgID>>8), byte(msgID))
+
+       //buf := new(bytes.Buffer)
+       //buf.Grow(size)
+
+       // encode msg ID
+       //buf.WriteByte(byte(msgID >> 8))
+       //buf.WriteByte(byte(msgID))
+
+       data, err = marshaller.Marshal(b[offset:])
+       if err != nil {
+               return nil, err
+       }
+       //buf.Write(b)
+
+       return b[0:len(b):len(b)], nil
+}
+
+func getOffset(msg api.Message) (offset int) {
+       switch msg.GetMessageType() {
+       case api.RequestMessage:
+               return 10
+       case api.ReplyMessage:
+               return 6
+       case api.EventMessage:
+               return 6
+       }
+       return 2
+}
+
+func (*NewCodec) DecodeMsg(data []byte, msg api.Message) (err error) {
+       if msg == nil {
+               return errors.New("nil message passed in")
+       }
+       marshaller, ok := msg.(Unmarshaler)
+       if !ok {
+               return fmt.Errorf("message %s does not implement marshaller", msg.GetMessageName())
+       }
+
+       offset := getOffset(msg)
+
+       err = marshaller.Unmarshal(data[offset:len(data)])
+       if err != nil {
+               return err
+       }
+
+       return nil
+}
+
+func (*NewCodec) DecodeMsgContext(data []byte, msg api.Message) (context uint32, err error) {
+       if msg == nil {
+               return 0, errors.New("nil message passed in")
+       }
+
+       switch msg.GetMessageType() {
+       case api.RequestMessage:
+               return order.Uint32(data[6:10]), nil
+       case api.ReplyMessage:
+               return order.Uint32(data[2:6]), nil
+       }
+
+       return 0, nil
+}
+
+type OldCodec struct{}
+
+func (c *OldCodec) Marshal(v interface{}) (b []byte, err error) {
+       buf := new(bytes.Buffer)
+       if err := struc.Pack(buf, v); err != nil {
+               return nil, err
+       }
+       return buf.Bytes(), nil
+}
+
+func (c *OldCodec) Unmarshal(data []byte, v interface{}) error {
+       buf := bytes.NewReader(data)
+       if err := struc.Unpack(buf, v); err != nil {
+               return err
+       }
+       return nil
+}
+
+/*type CodecNew struct{}
+
+func (c *CodecNew) Marshal(v interface{}) (b []byte, err error) {
+       buf := new(bytes.Buffer)
+       if err := binary.Write(buf, binary.BigEndian, v); err != nil {
+               return nil, err
+       }
+       return buf.Bytes(), nil
+}*/
+
+func EncodeBool(b bool) byte {
+       if b {
+               return 1
+       }
+       return 0
+}
+
+func MarshalValue(value interface{}) []byte {
+       switch value.(type) {
+       case int8:
+               return []byte{byte(value.(int8))}
+       case uint8:
+               return []byte{byte(value.(uint8))}
+       }
+       return nil
+}
+
+var order = binary.BigEndian
+
+type Buffer struct {
+       pos int
+       buf []byte
+}
+
+func (b *Buffer) Bytes() []byte {
+       return b.buf[:b.pos]
+}
+
+func (b *Buffer) EncodeUint8(v uint8) {
+       b.buf[b.pos] = v
+       b.pos += 1
+}
+
+func (b *Buffer) EncodeUint16(v uint16) {
+       order.PutUint16(b.buf[b.pos:b.pos+2], v)
+       b.pos += 2
+}
+
+func (b *Buffer) EncodeUint32(v uint32) {
+       order.PutUint32(b.buf[b.pos:b.pos+4], v)
+       b.pos += 4
+}
+
+func (b *Buffer) EncodeUint64(v uint64) {
+       order.PutUint64(b.buf[b.pos:b.pos+8], v)
+       b.pos += 8
+}
+
+func (b *Buffer) EncodeFloat64(v float64) {
+       order.PutUint64(b.buf[b.pos:b.pos+8], math.Float64bits(v))
+       b.pos += 8
+}
+
+func (b *Buffer) EncodeBool(v bool) {
+       if v {
+               b.buf[b.pos] = 1
+       } else {
+               b.buf[b.pos] = 0
+       }
+       b.pos += 1
+}
+
+func (b *Buffer) EncodeString(v string) {
+
+       b.pos += 1
+}
+
+func DecodeString(b []byte) string {
+       sliceHeader := (*reflect.SliceHeader)(unsafe.Pointer(&b))
+       stringHeader := reflect.StringHeader{Data: sliceHeader.Data, Len: sliceHeader.Len}
+       return *(*string)(unsafe.Pointer(&stringHeader))
+}