X-Git-Url: https://gerrit.fd.io/r/gitweb?a=blobdiff_plain;f=codec%2Fmarshaler.go;fp=codec%2Fmarshaler.go;h=c6d33a366581204491b6c3ed101b73defd085691;hb=94620e85f0bdbb054af07ce3670fadc1f76cfdf0;hp=0000000000000000000000000000000000000000;hpb=280b1c6c83b676ef4e592f4ecf60cb5b54b6a753;p=govpp.git diff --git a/codec/marshaler.go b/codec/marshaler.go new file mode 100644 index 0000000..c6d33a3 --- /dev/null +++ b/codec/marshaler.go @@ -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)) +}