OSDN Git Service

new repo
[bytom/vapor.git] / vendor / google.golang.org / grpc / codec.go
1 /*
2  *
3  * Copyright 2014 gRPC authors.
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  */
18
19 package grpc
20
21 import (
22         "math"
23         "sync"
24
25         "github.com/golang/protobuf/proto"
26 )
27
28 // Codec defines the interface gRPC uses to encode and decode messages.
29 // Note that implementations of this interface must be thread safe;
30 // a Codec's methods can be called from concurrent goroutines.
31 type Codec interface {
32         // Marshal returns the wire format of v.
33         Marshal(v interface{}) ([]byte, error)
34         // Unmarshal parses the wire format into v.
35         Unmarshal(data []byte, v interface{}) error
36         // String returns the name of the Codec implementation. The returned
37         // string will be used as part of content type in transmission.
38         String() string
39 }
40
41 // protoCodec is a Codec implementation with protobuf. It is the default codec for gRPC.
42 type protoCodec struct {
43 }
44
45 type cachedProtoBuffer struct {
46         lastMarshaledSize uint32
47         proto.Buffer
48 }
49
50 func capToMaxInt32(val int) uint32 {
51         if val > math.MaxInt32 {
52                 return uint32(math.MaxInt32)
53         }
54         return uint32(val)
55 }
56
57 func (p protoCodec) marshal(v interface{}, cb *cachedProtoBuffer) ([]byte, error) {
58         protoMsg := v.(proto.Message)
59         newSlice := make([]byte, 0, cb.lastMarshaledSize)
60
61         cb.SetBuf(newSlice)
62         cb.Reset()
63         if err := cb.Marshal(protoMsg); err != nil {
64                 return nil, err
65         }
66         out := cb.Bytes()
67         cb.lastMarshaledSize = capToMaxInt32(len(out))
68         return out, nil
69 }
70
71 func (p protoCodec) Marshal(v interface{}) ([]byte, error) {
72         cb := protoBufferPool.Get().(*cachedProtoBuffer)
73         out, err := p.marshal(v, cb)
74
75         // put back buffer and lose the ref to the slice
76         cb.SetBuf(nil)
77         protoBufferPool.Put(cb)
78         return out, err
79 }
80
81 func (p protoCodec) Unmarshal(data []byte, v interface{}) error {
82         cb := protoBufferPool.Get().(*cachedProtoBuffer)
83         cb.SetBuf(data)
84         v.(proto.Message).Reset()
85         err := cb.Unmarshal(v.(proto.Message))
86         cb.SetBuf(nil)
87         protoBufferPool.Put(cb)
88         return err
89 }
90
91 func (protoCodec) String() string {
92         return "proto"
93 }
94
95 var protoBufferPool = &sync.Pool{
96         New: func() interface{} {
97                 return &cachedProtoBuffer{
98                         Buffer:            proto.Buffer{},
99                         lastMarshaledSize: 16,
100                 }
101         },
102 }