Improve binapi generator
[govpp.git] / codec / msg_codec.go
1 // Copyright (c) 2017 Cisco and/or its affiliates.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at:
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 package codec
16
17 import (
18         "encoding/binary"
19         "errors"
20         "fmt"
21
22         "git.fd.io/govpp.git/api"
23 )
24
25 var DefaultCodec = new(MsgCodec)
26
27 // MsgCodec provides encoding and decoding functionality of `api.Message` structs into/from
28 // binary format as accepted by VPP.
29 type MsgCodec struct{}
30
31 func (*MsgCodec) EncodeMsg(msg api.Message, msgID uint16) (data []byte, err error) {
32         if msg == nil {
33                 return nil, errors.New("nil message passed in")
34         }
35
36         // try to recover panic which might possibly occur
37         defer func() {
38                 if r := recover(); r != nil {
39                         var ok bool
40                         if err, ok = r.(error); !ok {
41                                 err = fmt.Errorf("%v", r)
42                         }
43                         err = fmt.Errorf("panic occurred during encoding message %s: %v", msg.GetMessageName(), err)
44                 }
45         }()
46
47         marshaller, ok := msg.(Marshaler)
48         if !ok {
49                 marshaller = Wrapper{msg}
50         }
51
52         size := marshaller.Size()
53         offset := getOffset(msg)
54
55         // encode msg ID
56         b := make([]byte, size+offset)
57         b[0] = byte(msgID >> 8)
58         b[1] = byte(msgID)
59
60         data, err = marshaller.Marshal(b[offset:])
61         if err != nil {
62                 return nil, err
63         }
64
65         return b[0:len(b):len(b)], nil
66 }
67
68 func (*MsgCodec) DecodeMsg(data []byte, msg api.Message) (err error) {
69         if msg == nil {
70                 return errors.New("nil message passed in")
71         }
72
73         // try to recover panic which might possibly occur
74         defer func() {
75                 if r := recover(); r != nil {
76                         var ok bool
77                         if err, ok = r.(error); !ok {
78                                 err = fmt.Errorf("%v", r)
79                         }
80                         err = fmt.Errorf("panic occurred during decoding message %s: %v", msg.GetMessageName(), err)
81                 }
82         }()
83
84         marshaller, ok := msg.(Unmarshaler)
85         if !ok {
86                 marshaller = Wrapper{msg}
87         }
88
89         offset := getOffset(msg)
90
91         err = marshaller.Unmarshal(data[offset:len(data)])
92         if err != nil {
93                 return err
94         }
95
96         return nil
97 }
98
99 func (*MsgCodec) DecodeMsgContext(data []byte, msg api.Message) (context uint32, err error) {
100         if msg == nil {
101                 return 0, errors.New("nil message passed in")
102         }
103
104         switch msg.GetMessageType() {
105         case api.RequestMessage:
106                 return binary.BigEndian.Uint32(data[6:10]), nil
107         case api.ReplyMessage:
108                 return binary.BigEndian.Uint32(data[2:6]), nil
109         }
110
111         return 0, nil
112 }
113
114 func getOffset(msg api.Message) (offset int) {
115         switch msg.GetMessageType() {
116         case api.RequestMessage:
117                 return 10
118         case api.ReplyMessage:
119                 return 6
120         case api.EventMessage:
121                 return 6
122         }
123         return 2
124 }