1 499f8c59 2015-10-27 stephen.d package p9pnew
3 499f8c59 2015-10-27 stephen.d import (
5 499f8c59 2015-10-27 stephen.d "encoding/binary"
9 499f8c59 2015-10-27 stephen.d "reflect"
10 97423e8b 2015-10-29 stephen.d "strings"
14 269e4d4b 2015-11-05 stephen.d // Codec defines the interface for encoding and decoding of 9p types.
15 269e4d4b 2015-11-05 stephen.d // Unsupported types will throw an error.
16 269e4d4b 2015-11-05 stephen.d type Codec interface {
17 269e4d4b 2015-11-05 stephen.d // Unmarshal from data into the value pointed to by v.
18 269e4d4b 2015-11-05 stephen.d Unmarshal(data []byte, v interface{}) error
20 269e4d4b 2015-11-05 stephen.d // Marshal the value v into a byte slice.
21 269e4d4b 2015-11-05 stephen.d Marshal(v interface{}) ([]byte, error)
23 deb98ab4 2015-11-05 stephen.d // Size returns the encoded size for the target of v.
24 deb98ab4 2015-11-05 stephen.d Size(v interface{}) int
27 269e4d4b 2015-11-05 stephen.d func NewCodec() Codec {
28 269e4d4b 2015-11-05 stephen.d return codec9p{}
31 fb37ce2a 2015-10-30 stephen.d type codec9p struct{}
33 fb37ce2a 2015-10-30 stephen.d func (c codec9p) Unmarshal(data []byte, v interface{}) error {
34 fb37ce2a 2015-10-30 stephen.d dec := &decoder{bytes.NewReader(data)}
35 fb37ce2a 2015-10-30 stephen.d return dec.decode(v)
38 269e4d4b 2015-11-05 stephen.d func (c codec9p) Marshal(v interface{}) ([]byte, error) {
39 269e4d4b 2015-11-05 stephen.d var b bytes.Buffer
40 269e4d4b 2015-11-05 stephen.d enc := &encoder{&b}
42 fb37ce2a 2015-10-30 stephen.d if err := enc.encode(v); err != nil {
43 269e4d4b 2015-11-05 stephen.d return nil, err
46 269e4d4b 2015-11-05 stephen.d return b.Bytes(), nil
49 deb98ab4 2015-11-05 stephen.d func (c codec9p) Size(v interface{}) int {
50 deb98ab4 2015-11-05 stephen.d return int(size9p(v))
53 deb98ab4 2015-11-05 stephen.d // DecodeDir decodes a directory entry from rd using the provided codec.
54 deb98ab4 2015-11-05 stephen.d func DecodeDir(codec Codec, rd io.Reader, d *Dir) error {
55 deb98ab4 2015-11-05 stephen.d var ll uint16
57 deb98ab4 2015-11-05 stephen.d // pull the size off the wire
58 deb98ab4 2015-11-05 stephen.d if err := binary.Read(rd, binary.LittleEndian, &ll); err != nil {
59 deb98ab4 2015-11-05 stephen.d return err
62 deb98ab4 2015-11-05 stephen.d p := make([]byte, ll+2)
63 deb98ab4 2015-11-05 stephen.d binary.LittleEndian.PutUint16(p, ll) // must have size at start
65 deb98ab4 2015-11-05 stephen.d // read out the rest of the record
66 deb98ab4 2015-11-05 stephen.d if _, err := io.ReadFull(rd, p[2:]); err != nil {
67 deb98ab4 2015-11-05 stephen.d return err
70 deb98ab4 2015-11-05 stephen.d return codec.Unmarshal(p, d)
73 deb98ab4 2015-11-05 stephen.d // EncodeDir writes the directory to wr.
74 deb98ab4 2015-11-05 stephen.d func EncodeDir(codec Codec, wr io.Writer, d *Dir) error {
75 deb98ab4 2015-11-05 stephen.d p, err := codec.Marshal(d)
76 deb98ab4 2015-11-05 stephen.d if err != nil {
77 deb98ab4 2015-11-05 stephen.d return err
80 deb98ab4 2015-11-05 stephen.d _, err = wr.Write(p)
81 deb98ab4 2015-11-05 stephen.d return err
84 499f8c59 2015-10-27 stephen.d type encoder struct {
85 499f8c59 2015-10-27 stephen.d wr io.Writer
88 499f8c59 2015-10-27 stephen.d func (e *encoder) encode(vs ...interface{}) error {
89 499f8c59 2015-10-27 stephen.d for _, v := range vs {
90 499f8c59 2015-10-27 stephen.d switch v := v.(type) {
91 deb98ab4 2015-11-05 stephen.d case uint8, uint16, uint32, uint64, FcallType, Tag, QType, Fid, Flag,
92 deb98ab4 2015-11-05 stephen.d *uint8, *uint16, *uint32, *uint64, *FcallType, *Tag, *QType, *Fid, *Flag:
93 269e4d4b 2015-11-05 stephen.d if err := binary.Write(e.wr, binary.LittleEndian, v); err != nil {
94 e9f5e414 2015-10-27 stephen.d return err
96 269e4d4b 2015-11-05 stephen.d case []byte:
97 269e4d4b 2015-11-05 stephen.d if err := e.encode(uint32(len(v))); err != nil {
98 e9f5e414 2015-10-27 stephen.d return err
101 269e4d4b 2015-11-05 stephen.d if err := binary.Write(e.wr, binary.LittleEndian, v); err != nil {
102 e9f5e414 2015-10-27 stephen.d return err
105 269e4d4b 2015-11-05 stephen.d case *[]byte:
106 d6198009 2015-10-28 stephen.d if err := e.encode(*v); err != nil {
107 d6198009 2015-10-28 stephen.d return err
109 499f8c59 2015-10-27 stephen.d case string:
110 499f8c59 2015-10-27 stephen.d if err := binary.Write(e.wr, binary.LittleEndian, uint16(len(v))); err != nil {
111 499f8c59 2015-10-27 stephen.d return err
114 499f8c59 2015-10-27 stephen.d _, err := io.WriteString(e.wr, v)
115 499f8c59 2015-10-27 stephen.d if err != nil {
116 499f8c59 2015-10-27 stephen.d return err
118 269e4d4b 2015-11-05 stephen.d case *string:
119 269e4d4b 2015-11-05 stephen.d if err := e.encode(*v); err != nil {
120 499f8c59 2015-10-27 stephen.d return err
123 269e4d4b 2015-11-05 stephen.d case []string:
124 269e4d4b 2015-11-05 stephen.d if err := e.encode(uint16(len(v))); err != nil {
125 499f8c59 2015-10-27 stephen.d return err
128 269e4d4b 2015-11-05 stephen.d for _, m := range v {
129 269e4d4b 2015-11-05 stephen.d if err := e.encode(m); err != nil {
130 269e4d4b 2015-11-05 stephen.d return err
133 269e4d4b 2015-11-05 stephen.d case *[]string:
134 269e4d4b 2015-11-05 stephen.d if err := e.encode(*v); err != nil {
135 74ec7ac9 2015-10-30 stephen.d return err
137 269e4d4b 2015-11-05 stephen.d case time.Time:
138 269e4d4b 2015-11-05 stephen.d if err := e.encode(uint32(v.Unix())); err != nil {
139 269e4d4b 2015-11-05 stephen.d return err
141 269e4d4b 2015-11-05 stephen.d case *time.Time:
142 74ec7ac9 2015-10-30 stephen.d if err := e.encode(*v); err != nil {
143 74ec7ac9 2015-10-30 stephen.d return err
145 74ec7ac9 2015-10-30 stephen.d case Qid:
146 74ec7ac9 2015-10-30 stephen.d if err := e.encode(v.Type, v.Version, v.Path); err != nil {
147 74ec7ac9 2015-10-30 stephen.d return err
149 269e4d4b 2015-11-05 stephen.d case *Qid:
150 d6198009 2015-10-28 stephen.d if err := e.encode(*v); err != nil {
151 d6198009 2015-10-28 stephen.d return err
153 d6198009 2015-10-28 stephen.d case []Qid:
154 d6198009 2015-10-28 stephen.d if err := e.encode(uint16(len(v))); err != nil {
155 d6198009 2015-10-28 stephen.d return err
158 d6198009 2015-10-28 stephen.d elements := make([]interface{}, len(v))
159 d6198009 2015-10-28 stephen.d for i := range v {
160 d6198009 2015-10-28 stephen.d elements[i] = &v[i]
163 d6198009 2015-10-28 stephen.d if err := e.encode(elements...); err != nil {
164 d6198009 2015-10-28 stephen.d return err
166 269e4d4b 2015-11-05 stephen.d case *[]Qid:
167 269e4d4b 2015-11-05 stephen.d if err := e.encode(*v); err != nil {
168 d6198009 2015-10-28 stephen.d return err
170 269e4d4b 2015-11-05 stephen.d case Dir:
171 269e4d4b 2015-11-05 stephen.d elements, err := fields9p(v)
172 269e4d4b 2015-11-05 stephen.d if err != nil {
173 269e4d4b 2015-11-05 stephen.d return err
176 269e4d4b 2015-11-05 stephen.d if err := e.encode(uint16(size9p(elements...))); err != nil {
177 269e4d4b 2015-11-05 stephen.d return err
180 269e4d4b 2015-11-05 stephen.d if err := e.encode(elements...); err != nil {
181 269e4d4b 2015-11-05 stephen.d return err
183 269e4d4b 2015-11-05 stephen.d case *Dir:
184 d6198009 2015-10-28 stephen.d if err := e.encode(*v); err != nil {
185 d6198009 2015-10-28 stephen.d return err
187 499f8c59 2015-10-27 stephen.d case Fcall:
188 269e4d4b 2015-11-05 stephen.d if err := e.encode(v.Type, v.Tag, v.Message); err != nil {
189 499f8c59 2015-10-27 stephen.d return err
191 499f8c59 2015-10-27 stephen.d case *Fcall:
192 269e4d4b 2015-11-05 stephen.d if err := e.encode(*v); err != nil {
193 499f8c59 2015-10-27 stephen.d return err
195 269e4d4b 2015-11-05 stephen.d case Message:
196 269e4d4b 2015-11-05 stephen.d elements, err := fields9p(v)
197 269e4d4b 2015-11-05 stephen.d if err != nil {
198 269e4d4b 2015-11-05 stephen.d return err
201 269e4d4b 2015-11-05 stephen.d switch v.(type) {
202 269e4d4b 2015-11-05 stephen.d case MessageRstat, *MessageRstat:
203 269e4d4b 2015-11-05 stephen.d // NOTE(stevvooe): Prepend size preceeding Dir. See bugs in
204 269e4d4b 2015-11-05 stephen.d // http://man.cat-v.org/plan_9/5/stat to make sense of this.
205 269e4d4b 2015-11-05 stephen.d // The field has been included here but we need to make sure
206 269e4d4b 2015-11-05 stephen.d // to double emit it for Rstat.
207 269e4d4b 2015-11-05 stephen.d if err := e.encode(uint16(size9p(elements...))); err != nil {
208 269e4d4b 2015-11-05 stephen.d return err
212 269e4d4b 2015-11-05 stephen.d if err := e.encode(elements...); err != nil {
213 499f8c59 2015-10-27 stephen.d return err
218 499f8c59 2015-10-27 stephen.d return nil
221 499f8c59 2015-10-27 stephen.d type decoder struct {
222 499f8c59 2015-10-27 stephen.d rd io.Reader
225 499f8c59 2015-10-27 stephen.d // read9p extracts values from rd and unmarshals them to the targets of vs.
226 499f8c59 2015-10-27 stephen.d func (d *decoder) decode(vs ...interface{}) error {
227 499f8c59 2015-10-27 stephen.d for _, v := range vs {
228 499f8c59 2015-10-27 stephen.d switch v := v.(type) {
229 deb98ab4 2015-11-05 stephen.d case *uint8, *uint16, *uint32, *uint64, *FcallType, *Tag, *QType, *Fid, *Flag:
230 269e4d4b 2015-11-05 stephen.d if err := binary.Read(d.rd, binary.LittleEndian, v); err != nil {
231 269e4d4b 2015-11-05 stephen.d return err
233 269e4d4b 2015-11-05 stephen.d case *[]byte:
234 269e4d4b 2015-11-05 stephen.d var ll uint32
236 269e4d4b 2015-11-05 stephen.d if err := d.decode(&ll); err != nil {
237 269e4d4b 2015-11-05 stephen.d return err
240 269e4d4b 2015-11-05 stephen.d *v = make([]byte, int(ll))
242 269e4d4b 2015-11-05 stephen.d if err := binary.Read(d.rd, binary.LittleEndian, v); err != nil {
243 269e4d4b 2015-11-05 stephen.d return err
245 499f8c59 2015-10-27 stephen.d case *string:
246 499f8c59 2015-10-27 stephen.d var ll uint16
248 499f8c59 2015-10-27 stephen.d // implement string[s] encoding
249 e9f5e414 2015-10-27 stephen.d if err := d.decode(&ll); err != nil {
250 499f8c59 2015-10-27 stephen.d return err
253 499f8c59 2015-10-27 stephen.d b := make([]byte, ll)
255 499f8c59 2015-10-27 stephen.d n, err := io.ReadFull(d.rd, b)
256 499f8c59 2015-10-27 stephen.d if err != nil {
257 499f8c59 2015-10-27 stephen.d return err
260 499f8c59 2015-10-27 stephen.d if n != int(ll) {
261 499f8c59 2015-10-27 stephen.d return fmt.Errorf("unexpected string length")
264 499f8c59 2015-10-27 stephen.d *v = string(b)
265 e9f5e414 2015-10-27 stephen.d case *[]string:
266 e9f5e414 2015-10-27 stephen.d var ll uint16
268 e9f5e414 2015-10-27 stephen.d if err := d.decode(&ll); err != nil {
269 e9f5e414 2015-10-27 stephen.d return err
272 e9f5e414 2015-10-27 stephen.d elements := make([]interface{}, int(ll))
273 e9f5e414 2015-10-27 stephen.d *v = make([]string, int(ll))
274 e9f5e414 2015-10-27 stephen.d for i := range elements {
275 e9f5e414 2015-10-27 stephen.d elements[i] = &(*v)[i]
278 e9f5e414 2015-10-27 stephen.d if err := d.decode(elements...); err != nil {
279 d6198009 2015-10-28 stephen.d return err
281 269e4d4b 2015-11-05 stephen.d case *time.Time:
282 269e4d4b 2015-11-05 stephen.d var epoch uint32
283 269e4d4b 2015-11-05 stephen.d if err := d.decode(&epoch); err != nil {
284 d6198009 2015-10-28 stephen.d return err
287 269e4d4b 2015-11-05 stephen.d *v = time.Unix(int64(epoch), 0).UTC()
288 269e4d4b 2015-11-05 stephen.d case *Qid:
289 269e4d4b 2015-11-05 stephen.d if err := d.decode(&v.Type, &v.Version, &v.Path); err != nil {
290 e9f5e414 2015-10-27 stephen.d return err
292 d6198009 2015-10-28 stephen.d case *[]Qid:
293 d6198009 2015-10-28 stephen.d var ll uint16
295 d6198009 2015-10-28 stephen.d if err := d.decode(&ll); err != nil {
296 d6198009 2015-10-28 stephen.d return err
299 d6198009 2015-10-28 stephen.d elements := make([]interface{}, int(ll))
300 d6198009 2015-10-28 stephen.d *v = make([]Qid, int(ll))
301 d6198009 2015-10-28 stephen.d for i := range elements {
302 d6198009 2015-10-28 stephen.d elements[i] = &(*v)[i]
305 d6198009 2015-10-28 stephen.d if err := d.decode(elements...); err != nil {
306 d6198009 2015-10-28 stephen.d return err
308 a8abc687 2015-10-30 stephen.d case *Dir:
309 a8abc687 2015-10-30 stephen.d var ll uint16
311 a8abc687 2015-10-30 stephen.d if err := d.decode(&ll); err != nil {
312 a8abc687 2015-10-30 stephen.d return err
315 a8abc687 2015-10-30 stephen.d b := make([]byte, ll)
316 a8abc687 2015-10-30 stephen.d // must consume entire dir entry.
317 a8abc687 2015-10-30 stephen.d n, err := io.ReadFull(d.rd, b)
318 a8abc687 2015-10-30 stephen.d if err != nil {
319 a8abc687 2015-10-30 stephen.d log.Println("dir readfull failed:", err, ll, n)
320 a8abc687 2015-10-30 stephen.d return err
323 499f8c59 2015-10-27 stephen.d elements, err := fields9p(v)
324 499f8c59 2015-10-27 stephen.d if err != nil {
325 499f8c59 2015-10-27 stephen.d return err
328 a8abc687 2015-10-30 stephen.d dec := &decoder{bytes.NewReader(b)}
330 a8abc687 2015-10-30 stephen.d if err := dec.decode(elements...); err != nil {
331 269e4d4b 2015-11-05 stephen.d return err
333 269e4d4b 2015-11-05 stephen.d case *Fcall:
334 269e4d4b 2015-11-05 stephen.d if err := d.decode(&v.Type, &v.Tag); err != nil {
335 269e4d4b 2015-11-05 stephen.d return err
338 269e4d4b 2015-11-05 stephen.d message, err := newMessage(v.Type)
339 269e4d4b 2015-11-05 stephen.d if err != nil {
340 269e4d4b 2015-11-05 stephen.d return err
343 269e4d4b 2015-11-05 stephen.d // NOTE(stevvooe): We do a little pointer dance to allocate the
344 269e4d4b 2015-11-05 stephen.d // new type, write to it, then assign it back to the interface as
345 269e4d4b 2015-11-05 stephen.d // a concrete type, avoiding a pointer (the interface) to a
346 269e4d4b 2015-11-05 stephen.d // pointer.
347 269e4d4b 2015-11-05 stephen.d rv := reflect.New(reflect.TypeOf(message))
348 269e4d4b 2015-11-05 stephen.d if err := d.decode(rv.Interface()); err != nil {
349 a8abc687 2015-10-30 stephen.d return err
352 269e4d4b 2015-11-05 stephen.d v.Message = rv.Elem().Interface()
353 74ec7ac9 2015-10-30 stephen.d case Message:
354 a8abc687 2015-10-30 stephen.d elements, err := fields9p(v)
355 a8abc687 2015-10-30 stephen.d if err != nil {
356 a8abc687 2015-10-30 stephen.d return err
359 74ec7ac9 2015-10-30 stephen.d switch v.(type) {
360 74ec7ac9 2015-10-30 stephen.d case *MessageRstat, MessageRstat:
361 269e4d4b 2015-11-05 stephen.d // NOTE(stevvooe): Consume extra size preceeding Dir. See bugs
362 269e4d4b 2015-11-05 stephen.d // in http://man.cat-v.org/plan_9/5/stat to make sense of
363 269e4d4b 2015-11-05 stephen.d // this. The field has been included here but we need to make
364 269e4d4b 2015-11-05 stephen.d // sure to double emit it for Rstat. decode extra size header
365 269e4d4b 2015-11-05 stephen.d // for stat structure.
366 74ec7ac9 2015-10-30 stephen.d var ll uint16
367 74ec7ac9 2015-10-30 stephen.d if err := d.decode(&ll); err != nil {
368 74ec7ac9 2015-10-30 stephen.d return err
372 499f8c59 2015-10-27 stephen.d if err := d.decode(elements...); err != nil {
373 499f8c59 2015-10-27 stephen.d return err
378 499f8c59 2015-10-27 stephen.d return nil
381 499f8c59 2015-10-27 stephen.d // size9p calculates the projected size of the values in vs when encoded into
382 499f8c59 2015-10-27 stephen.d // 9p binary protocol. If an element or elements are not valid for 9p encoded,
383 499f8c59 2015-10-27 stephen.d // the value 0 will be used for the size. The error will be detected when
384 499f8c59 2015-10-27 stephen.d // encoding.
385 499f8c59 2015-10-27 stephen.d func size9p(vs ...interface{}) uint32 {
386 499f8c59 2015-10-27 stephen.d var s uint32
387 499f8c59 2015-10-27 stephen.d for _, v := range vs {
388 499f8c59 2015-10-27 stephen.d if v == nil {
389 499f8c59 2015-10-27 stephen.d continue
392 499f8c59 2015-10-27 stephen.d switch v := v.(type) {
393 deb98ab4 2015-11-05 stephen.d case uint8, uint16, uint32, uint64, FcallType, Tag, QType, Fid, Flag,
394 deb98ab4 2015-11-05 stephen.d *uint8, *uint16, *uint32, *uint64, *FcallType, *Tag, *QType, *Fid, *Flag:
395 269e4d4b 2015-11-05 stephen.d s += uint32(binary.Size(v))
396 269e4d4b 2015-11-05 stephen.d case []byte:
397 269e4d4b 2015-11-05 stephen.d s += uint32(binary.Size(uint32(0)) + len(v))
398 269e4d4b 2015-11-05 stephen.d case *[]byte:
399 269e4d4b 2015-11-05 stephen.d s += size9p(uint32(0), *v)
400 499f8c59 2015-10-27 stephen.d case string:
401 499f8c59 2015-10-27 stephen.d s += uint32(binary.Size(uint16(0)) + len(v))
402 269e4d4b 2015-11-05 stephen.d case *string:
403 e9f5e414 2015-10-27 stephen.d s += size9p(*v)
404 e9f5e414 2015-10-27 stephen.d case []string:
405 e9f5e414 2015-10-27 stephen.d s += size9p(uint16(0))
407 269e4d4b 2015-11-05 stephen.d for _, sv := range v {
408 269e4d4b 2015-11-05 stephen.d s += size9p(sv)
410 269e4d4b 2015-11-05 stephen.d case *[]string:
411 d6198009 2015-10-28 stephen.d s += size9p(*v)
412 269e4d4b 2015-11-05 stephen.d case time.Time, *time.Time:
413 269e4d4b 2015-11-05 stephen.d // BUG(stevvooe): Y2038 is coming.
414 269e4d4b 2015-11-05 stephen.d s += size9p(uint32(0))
415 269e4d4b 2015-11-05 stephen.d case Qid:
416 269e4d4b 2015-11-05 stephen.d s += size9p(v.Type, v.Version, v.Path)
417 269e4d4b 2015-11-05 stephen.d case *Qid:
418 269e4d4b 2015-11-05 stephen.d s += size9p(*v)
419 d6198009 2015-10-28 stephen.d case []Qid:
420 d6198009 2015-10-28 stephen.d s += size9p(uint16(0))
421 d6198009 2015-10-28 stephen.d elements := make([]interface{}, len(v))
422 d6198009 2015-10-28 stephen.d for i := range elements {
423 d6198009 2015-10-28 stephen.d elements[i] = &v[i]
425 d6198009 2015-10-28 stephen.d s += size9p(elements...)
426 269e4d4b 2015-11-05 stephen.d case *[]Qid:
427 269e4d4b 2015-11-05 stephen.d s += size9p(*v)
429 74ec7ac9 2015-10-30 stephen.d case Dir:
430 499f8c59 2015-10-27 stephen.d // walk the fields of the message to get the total size. we just
431 499f8c59 2015-10-27 stephen.d // use the field order from the message struct. We may add tag
432 499f8c59 2015-10-27 stephen.d // ignoring if needed.
433 499f8c59 2015-10-27 stephen.d elements, err := fields9p(v)
434 499f8c59 2015-10-27 stephen.d if err != nil {
435 499f8c59 2015-10-27 stephen.d // BUG(stevvooe): The options here are to return 0, panic or
436 499f8c59 2015-10-27 stephen.d // make this return an error. Ideally, we make it safe to
437 499f8c59 2015-10-27 stephen.d // return 0 and have the rest of the package do the right
438 499f8c59 2015-10-27 stephen.d // thing. For now, we do this, but may want to panic until
439 499f8c59 2015-10-27 stephen.d // things are stable.
440 e9f5e414 2015-10-27 stephen.d panic(err)
443 74ec7ac9 2015-10-30 stephen.d s += size9p(elements...) + size9p(uint16(0))
444 269e4d4b 2015-11-05 stephen.d case *Dir:
445 269e4d4b 2015-11-05 stephen.d s += size9p(*v)
446 269e4d4b 2015-11-05 stephen.d case Fcall:
447 269e4d4b 2015-11-05 stephen.d s += size9p(v.Type, v.Tag, v.Message)
448 269e4d4b 2015-11-05 stephen.d case *Fcall:
449 269e4d4b 2015-11-05 stephen.d s += size9p(*v)
450 74ec7ac9 2015-10-30 stephen.d case Message:
451 74ec7ac9 2015-10-30 stephen.d // special case twstat and rstat for size fields. See bugs in
452 74ec7ac9 2015-10-30 stephen.d // http://man.cat-v.org/plan_9/5/stat to make sense of this.
453 74ec7ac9 2015-10-30 stephen.d switch v.(type) {
454 74ec7ac9 2015-10-30 stephen.d case *MessageRstat, MessageRstat:
455 74ec7ac9 2015-10-30 stephen.d s += size9p(uint16(0)) // for extra size field before dir
458 74ec7ac9 2015-10-30 stephen.d // walk the fields of the message to get the total size. we just
459 74ec7ac9 2015-10-30 stephen.d // use the field order from the message struct. We may add tag
460 74ec7ac9 2015-10-30 stephen.d // ignoring if needed.
461 74ec7ac9 2015-10-30 stephen.d elements, err := fields9p(v)
462 74ec7ac9 2015-10-30 stephen.d if err != nil {
463 74ec7ac9 2015-10-30 stephen.d // BUG(stevvooe): The options here are to return 0, panic or
464 74ec7ac9 2015-10-30 stephen.d // make this return an error. Ideally, we make it safe to
465 74ec7ac9 2015-10-30 stephen.d // return 0 and have the rest of the package do the right
466 74ec7ac9 2015-10-30 stephen.d // thing. For now, we do this, but may want to panic until
467 74ec7ac9 2015-10-30 stephen.d // things are stable.
468 74ec7ac9 2015-10-30 stephen.d panic(err)
471 499f8c59 2015-10-27 stephen.d s += size9p(elements...)
475 499f8c59 2015-10-27 stephen.d return s
478 499f8c59 2015-10-27 stephen.d // fields9p lists the settable fields from a struct type for reading and
479 499f8c59 2015-10-27 stephen.d // writing. We are using a lot of reflection here for fairly static
480 499f8c59 2015-10-27 stephen.d // serialization but we can replace this in the future with generated code if
481 499f8c59 2015-10-27 stephen.d // performance is an issue.
482 499f8c59 2015-10-27 stephen.d func fields9p(v interface{}) ([]interface{}, error) {
483 499f8c59 2015-10-27 stephen.d rv := reflect.Indirect(reflect.ValueOf(v))
485 499f8c59 2015-10-27 stephen.d if rv.Kind() != reflect.Struct {
486 499f8c59 2015-10-27 stephen.d return nil, fmt.Errorf("cannot extract fields from non-struct: %v", rv)
489 499f8c59 2015-10-27 stephen.d var elements []interface{}
490 499f8c59 2015-10-27 stephen.d for i := 0; i < rv.NumField(); i++ {
491 499f8c59 2015-10-27 stephen.d f := rv.Field(i)
493 499f8c59 2015-10-27 stephen.d if !f.CanInterface() {
494 499f8c59 2015-10-27 stephen.d return nil, fmt.Errorf("can't interface: %v", f)
497 499f8c59 2015-10-27 stephen.d if f.CanAddr() {
498 499f8c59 2015-10-27 stephen.d f = f.Addr()
501 499f8c59 2015-10-27 stephen.d elements = append(elements, f.Interface())
504 499f8c59 2015-10-27 stephen.d return elements, nil
507 97423e8b 2015-10-29 stephen.d func string9p(v interface{}) string {
508 97423e8b 2015-10-29 stephen.d if v == nil {
509 97423e8b 2015-10-29 stephen.d return "nil"
512 97423e8b 2015-10-29 stephen.d rv := reflect.Indirect(reflect.ValueOf(v))
514 97423e8b 2015-10-29 stephen.d if rv.Kind() != reflect.Struct {
515 97423e8b 2015-10-29 stephen.d panic("not a struct")
518 97423e8b 2015-10-29 stephen.d var s string
520 97423e8b 2015-10-29 stephen.d for i := 0; i < rv.NumField(); i++ {
521 97423e8b 2015-10-29 stephen.d f := rv.Field(i)
523 74ec7ac9 2015-10-30 stephen.d s += fmt.Sprintf(" %v=%v", strings.ToLower(rv.Type().Field(i).Name), f.Interface())
526 97423e8b 2015-10-29 stephen.d return s