github.com/shogo-ma/goa@v1.3.1/encoding/gogoprotobuf/encoding.go (about)

     1  package gogoprotobuf
     2  
     3  import (
     4  	"bytes"
     5  	"errors"
     6  	"io"
     7  
     8  	"github.com/goadesign/goa"
     9  	"github.com/gogo/protobuf/proto"
    10  )
    11  
    12  // Enforce that codec.Decoder satisfies goa.ResettableDecoder at compile time
    13  var (
    14  	_ goa.ResettableDecoder = (*ProtoDecoder)(nil)
    15  	_ goa.ResettableEncoder = (*ProtoEncoder)(nil)
    16  )
    17  
    18  type (
    19  	// ProtoDecoder stores state between Reset and Decode
    20  	ProtoDecoder struct {
    21  		pBuf *proto.Buffer
    22  		bBuf *bytes.Buffer
    23  		r    io.Reader
    24  	}
    25  
    26  	// ProtoEncoder stores state between Reset and Encode
    27  	ProtoEncoder struct {
    28  		pBuf *proto.Buffer
    29  		w    io.Writer
    30  	}
    31  )
    32  
    33  // NewDecoder returns a new proto.Decoder that satisfies goa.Decoder
    34  func NewDecoder(r io.Reader) goa.Decoder {
    35  	return &ProtoDecoder{
    36  		pBuf: proto.NewBuffer(nil),
    37  		bBuf: &bytes.Buffer{},
    38  		r:    r,
    39  	}
    40  }
    41  
    42  // Decode unmarshals an io.Reader into proto.Message v
    43  func (dec *ProtoDecoder) Decode(v interface{}) error {
    44  	msg, ok := v.(proto.Message)
    45  	if !ok {
    46  		return errors.New("Cannot decode into struct that doesn't implement proto.Message")
    47  	}
    48  
    49  	var err error
    50  
    51  	// derekperkins TODO: pipe reader directly to proto.Buffer
    52  	if _, err = dec.bBuf.ReadFrom(dec.r); err != nil {
    53  		return err
    54  	}
    55  	dec.pBuf.SetBuf(dec.bBuf.Bytes())
    56  
    57  	return dec.pBuf.Unmarshal(msg)
    58  }
    59  
    60  // Reset stores the new reader and resets its bytes.Buffer and proto.Buffer
    61  func (dec *ProtoDecoder) Reset(r io.Reader) {
    62  	dec.pBuf.Reset()
    63  	dec.bBuf.Reset()
    64  	dec.r = r
    65  }
    66  
    67  // NewEncoder returns a new proto.Encoder that satisfies goa.Encoder
    68  func NewEncoder(w io.Writer) goa.Encoder {
    69  	return &ProtoEncoder{
    70  		pBuf: proto.NewBuffer(nil),
    71  		w:    w,
    72  	}
    73  }
    74  
    75  // Encode marshals a proto.Message and writes it to an io.Writer
    76  func (enc *ProtoEncoder) Encode(v interface{}) error {
    77  	msg, ok := v.(proto.Message)
    78  	if !ok {
    79  		return errors.New("Cannot encode struct that doesn't implement proto.Message")
    80  	}
    81  
    82  	var err error
    83  
    84  	// derekperkins TODO: pipe marshal directly to writer
    85  	if err = enc.pBuf.Marshal(msg); err != nil {
    86  		return err
    87  	}
    88  
    89  	if _, err = enc.w.Write(enc.pBuf.Bytes()); err != nil {
    90  		return err
    91  	}
    92  	return nil
    93  }
    94  
    95  // Reset stores the new writer and resets its proto.Buffer
    96  func (enc *ProtoEncoder) Reset(w io.Writer) {
    97  	enc.pBuf.Reset()
    98  	enc.w = w
    99  }