Signed-off-by: TAGOMORI Satoshi <tagomoris@gmail.com>
| ... | ... |
@@ -3,6 +3,7 @@ package daemon |
| 3 | 3 |
// Importing packages here only to make sure their init gets called and |
| 4 | 4 |
// therefore they register themselves to the logdriver factory. |
| 5 | 5 |
import ( |
| 6 |
+ _ "github.com/docker/docker/daemon/logger/fluentd" |
|
| 6 | 7 |
_ "github.com/docker/docker/daemon/logger/gelf" |
| 7 | 8 |
_ "github.com/docker/docker/daemon/logger/journald" |
| 8 | 9 |
_ "github.com/docker/docker/daemon/logger/jsonfilelog" |
| 9 | 10 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,129 @@ |
| 0 |
+package fluentd |
|
| 1 |
+ |
|
| 2 |
+import ( |
|
| 3 |
+ "bytes" |
|
| 4 |
+ "io" |
|
| 5 |
+ "math" |
|
| 6 |
+ "net" |
|
| 7 |
+ "strconv" |
|
| 8 |
+ "strings" |
|
| 9 |
+ "text/template" |
|
| 10 |
+ |
|
| 11 |
+ "github.com/Sirupsen/logrus" |
|
| 12 |
+ "github.com/docker/docker/daemon/logger" |
|
| 13 |
+ "github.com/fluent/fluent-logger-golang/fluent" |
|
| 14 |
+) |
|
| 15 |
+ |
|
| 16 |
+type Fluentd struct {
|
|
| 17 |
+ tag string |
|
| 18 |
+ containerID string |
|
| 19 |
+ containerName string |
|
| 20 |
+ writer *fluent.Fluent |
|
| 21 |
+} |
|
| 22 |
+ |
|
| 23 |
+type Receiver struct {
|
|
| 24 |
+ ID string |
|
| 25 |
+ FullID string |
|
| 26 |
+ Name string |
|
| 27 |
+} |
|
| 28 |
+ |
|
| 29 |
+const ( |
|
| 30 |
+ name = "fluentd" |
|
| 31 |
+ defaultHostName = "localhost" |
|
| 32 |
+ defaultPort = 24224 |
|
| 33 |
+ defaultTagPrefix = "docker" |
|
| 34 |
+) |
|
| 35 |
+ |
|
| 36 |
+func init() {
|
|
| 37 |
+ if err := logger.RegisterLogDriver(name, New); err != nil {
|
|
| 38 |
+ logrus.Fatal(err) |
|
| 39 |
+ } |
|
| 40 |
+} |
|
| 41 |
+ |
|
| 42 |
+func parseConfig(ctx logger.Context) (string, int, string, error) {
|
|
| 43 |
+ host := defaultHostName |
|
| 44 |
+ port := defaultPort |
|
| 45 |
+ tag := "docker." + ctx.ContainerID[:12] |
|
| 46 |
+ |
|
| 47 |
+ config := ctx.Config |
|
| 48 |
+ |
|
| 49 |
+ if address := config["fluentd-address"]; address != "" {
|
|
| 50 |
+ if h, p, err := net.SplitHostPort(address); err != nil {
|
|
| 51 |
+ if !strings.Contains(err.Error(), "missing port in address") {
|
|
| 52 |
+ return "", 0, "", err |
|
| 53 |
+ } |
|
| 54 |
+ host = h |
|
| 55 |
+ } else {
|
|
| 56 |
+ portnum, err := strconv.Atoi(p) |
|
| 57 |
+ if err != nil {
|
|
| 58 |
+ return "", 0, "", err |
|
| 59 |
+ } |
|
| 60 |
+ host = h |
|
| 61 |
+ port = portnum |
|
| 62 |
+ } |
|
| 63 |
+ } |
|
| 64 |
+ |
|
| 65 |
+ if config["fluentd-tag"] != "" {
|
|
| 66 |
+ receiver := &Receiver{
|
|
| 67 |
+ ID: ctx.ContainerID[:12], |
|
| 68 |
+ FullID: ctx.ContainerID, |
|
| 69 |
+ Name: ctx.ContainerName, |
|
| 70 |
+ } |
|
| 71 |
+ tmpl, err := template.New("tag").Parse(config["fluentd-tag"])
|
|
| 72 |
+ if err != nil {
|
|
| 73 |
+ return "", 0, "", err |
|
| 74 |
+ } |
|
| 75 |
+ buf := new(bytes.Buffer) |
|
| 76 |
+ if err := tmpl.Execute(buf, receiver); err != nil {
|
|
| 77 |
+ return "", 0, "", err |
|
| 78 |
+ } |
|
| 79 |
+ tag = buf.String() |
|
| 80 |
+ } |
|
| 81 |
+ |
|
| 82 |
+ return host, port, tag, nil |
|
| 83 |
+} |
|
| 84 |
+ |
|
| 85 |
+func New(ctx logger.Context) (logger.Logger, error) {
|
|
| 86 |
+ host, port, tag, err := parseConfig(ctx) |
|
| 87 |
+ if err != nil {
|
|
| 88 |
+ return nil, err |
|
| 89 |
+ } |
|
| 90 |
+ logrus.Debugf("logging driver fluentd configured for container:%s, host:%s, port:%d, tag:%s.", ctx.ContainerID, host, port, tag)
|
|
| 91 |
+ |
|
| 92 |
+ // logger tries to recoonect 2**64 - 1 times |
|
| 93 |
+ // failed (and panic) after 204 years [ 1.5 ** (2**32 - 1) - 1 seconds] |
|
| 94 |
+ log, err := fluent.New(fluent.Config{FluentPort: port, FluentHost: host, RetryWait: 1000, MaxRetry: math.MaxUint32})
|
|
| 95 |
+ if err != nil {
|
|
| 96 |
+ return nil, err |
|
| 97 |
+ } |
|
| 98 |
+ return &Fluentd{
|
|
| 99 |
+ tag: tag, |
|
| 100 |
+ containerID: ctx.ContainerID, |
|
| 101 |
+ containerName: ctx.ContainerName, |
|
| 102 |
+ writer: log, |
|
| 103 |
+ }, nil |
|
| 104 |
+} |
|
| 105 |
+ |
|
| 106 |
+func (f *Fluentd) Log(msg *logger.Message) error {
|
|
| 107 |
+ data := map[string]string{
|
|
| 108 |
+ "container_id": f.containerID, |
|
| 109 |
+ "container_name": f.containerName, |
|
| 110 |
+ "source": msg.Source, |
|
| 111 |
+ "log": string(msg.Line), |
|
| 112 |
+ } |
|
| 113 |
+ // fluent-logger-golang buffers logs from failures and disconnections, |
|
| 114 |
+ // and these are transferred again automatically. |
|
| 115 |
+ return f.writer.PostWithTime(f.tag, msg.Timestamp, data) |
|
| 116 |
+} |
|
| 117 |
+ |
|
| 118 |
+func (f *Fluentd) Close() error {
|
|
| 119 |
+ return f.writer.Close() |
|
| 120 |
+} |
|
| 121 |
+ |
|
| 122 |
+func (f *Fluentd) Name() string {
|
|
| 123 |
+ return name |
|
| 124 |
+} |
|
| 125 |
+ |
|
| 126 |
+func (s *Fluentd) GetReader() (io.Reader, error) {
|
|
| 127 |
+ return nil, logger.ReadLogsNotSupported |
|
| 128 |
+} |
| ... | ... |
@@ -884,6 +884,16 @@ container's logging driver. The following options are supported: |
| 884 | 884 |
driver. For detailed information on working with logging drivers, see |
| 885 | 885 |
[Configure a logging driver](reference/logging/). |
| 886 | 886 |
|
| 887 |
+#### Logging driver: fluentd |
|
| 888 |
+ |
|
| 889 |
+Fluentd logging driver for Docker. Writes log messages to fluentd (forward input). `docker logs` |
|
| 890 |
+command is not available for this logging driver. |
|
| 891 |
+ |
|
| 892 |
+Some options are supported by specifying `--log-opt` as many as needed, like `--log-opt fluentd-address=localhost:24224`. |
|
| 893 |
+ |
|
| 894 |
+ - `fluentd-address`: specify `host:port` to connect [localhost:24224] |
|
| 895 |
+ - `fluentd-tag`: specify tag for fluentd message, which interpret some markup, ex `{{.ID}}`, `{{.FullID}}` or `{{.Name}}` [docker.{{.ID}}]
|
|
| 896 |
+ |
|
| 887 | 897 |
## Overriding Dockerfile image defaults |
| 888 | 898 |
|
| 889 | 899 |
When a developer builds an image from a [*Dockerfile*](/reference/builder) |
| ... | ... |
@@ -42,4 +42,9 @@ clone git github.com/syndtr/gocapability 66ef2aa7a23ba682594e2b6f74cf40c0692b49f |
| 42 | 42 |
clone git github.com/golang/protobuf 655cdfa588ea |
| 43 | 43 |
clone git github.com/Graylog2/go-gelf 6c62a85f1d47a67f2a5144c0e745b325889a8120 |
| 44 | 44 |
|
| 45 |
+clone git github.com/fluent/fluent-logger-golang v1.0.0 |
|
| 46 |
+# fluent-logger-golang deps |
|
| 47 |
+clone git github.com/philhofer/fwd 899e4efba8eaa1fea74175308f3fae18ff3319fa |
|
| 48 |
+clone git github.com/tinylib/msgp 75ee40d2601edf122ef667e2a07d600d4c44490c |
|
| 49 |
+ |
|
| 45 | 50 |
clean |
| ... | ... |
@@ -155,7 +155,7 @@ two memory nodes. |
| 155 | 155 |
**--lxc-conf**=[] |
| 156 | 156 |
(lxc exec-driver only) Add custom lxc options --lxc-conf="lxc.cgroup.cpuset.cpus = 0,1" |
| 157 | 157 |
|
| 158 |
-**--log-driver**="|*json-file*|*syslog*|*journald*|*gelf*|*none*" |
|
| 158 |
+**--log-driver**="|*json-file*|*syslog*|*journald*|*gelf*|*fluentd*|*none*" |
|
| 159 | 159 |
Logging driver for container. Default is defined by daemon `--log-driver` flag. |
| 160 | 160 |
**Warning**: `docker logs` command works only for `json-file` logging driver. |
| 161 | 161 |
|
| ... | ... |
@@ -252,7 +252,7 @@ which interface and port to use. |
| 252 | 252 |
**--lxc-conf**=[] |
| 253 | 253 |
(lxc exec-driver only) Add custom lxc options --lxc-conf="lxc.cgroup.cpuset.cpus = 0,1" |
| 254 | 254 |
|
| 255 |
-**--log-driver**="|*json-file*|*syslog*|*journald*|*gelf*|*none*" |
|
| 255 |
+**--log-driver**="|*json-file*|*syslog*|*journald*|*gelf*|*fluentd*|*none*" |
|
| 256 | 256 |
Logging driver for container. Default is defined by daemon `--log-driver` flag. |
| 257 | 257 |
**Warning**: `docker logs` command works only for `json-file` logging driver. |
| 258 | 258 |
|
| ... | ... |
@@ -103,7 +103,7 @@ unix://[/path/to/socket] to use. |
| 103 | 103 |
**--label**="[]" |
| 104 | 104 |
Set key=value labels to the daemon (displayed in `docker info`) |
| 105 | 105 |
|
| 106 |
-**--log-driver**="*json-file*|*syslog*|*journald*|*gelf*|*none*" |
|
| 106 |
+**--log-driver**="*json-file*|*syslog*|*journald*|*gelf*|*fluentd*|*none*" |
|
| 107 | 107 |
Default driver for container logs. Default is `json-file`. |
| 108 | 108 |
**Warning**: `docker logs` command works only for `json-file` logging driver. |
| 109 | 109 |
|
| 110 | 110 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,245 @@ |
| 0 |
+package fluent |
|
| 1 |
+ |
|
| 2 |
+import ( |
|
| 3 |
+ "errors" |
|
| 4 |
+ "fmt" |
|
| 5 |
+ "math" |
|
| 6 |
+ "net" |
|
| 7 |
+ "reflect" |
|
| 8 |
+ "strconv" |
|
| 9 |
+ "sync" |
|
| 10 |
+ "time" |
|
| 11 |
+) |
|
| 12 |
+ |
|
| 13 |
+const ( |
|
| 14 |
+ defaultHost = "127.0.0.1" |
|
| 15 |
+ defaultPort = 24224 |
|
| 16 |
+ defaultTimeout = 3 * time.Second |
|
| 17 |
+ defaultBufferLimit = 8 * 1024 * 1024 |
|
| 18 |
+ defaultRetryWait = 500 |
|
| 19 |
+ defaultMaxRetry = 13 |
|
| 20 |
+ defaultReconnectWaitIncreRate = 1.5 |
|
| 21 |
+) |
|
| 22 |
+ |
|
| 23 |
+type Config struct {
|
|
| 24 |
+ FluentPort int |
|
| 25 |
+ FluentHost string |
|
| 26 |
+ Timeout time.Duration |
|
| 27 |
+ BufferLimit int |
|
| 28 |
+ RetryWait int |
|
| 29 |
+ MaxRetry int |
|
| 30 |
+ TagPrefix string |
|
| 31 |
+} |
|
| 32 |
+ |
|
| 33 |
+type Fluent struct {
|
|
| 34 |
+ Config |
|
| 35 |
+ conn net.Conn |
|
| 36 |
+ pending []byte |
|
| 37 |
+ reconnecting bool |
|
| 38 |
+ mu sync.Mutex |
|
| 39 |
+} |
|
| 40 |
+ |
|
| 41 |
+// New creates a new Logger. |
|
| 42 |
+func New(config Config) (f *Fluent, err error) {
|
|
| 43 |
+ if config.FluentHost == "" {
|
|
| 44 |
+ config.FluentHost = defaultHost |
|
| 45 |
+ } |
|
| 46 |
+ if config.FluentPort == 0 {
|
|
| 47 |
+ config.FluentPort = defaultPort |
|
| 48 |
+ } |
|
| 49 |
+ if config.Timeout == 0 {
|
|
| 50 |
+ config.Timeout = defaultTimeout |
|
| 51 |
+ } |
|
| 52 |
+ if config.BufferLimit == 0 {
|
|
| 53 |
+ config.BufferLimit = defaultBufferLimit |
|
| 54 |
+ } |
|
| 55 |
+ if config.RetryWait == 0 {
|
|
| 56 |
+ config.RetryWait = defaultRetryWait |
|
| 57 |
+ } |
|
| 58 |
+ if config.MaxRetry == 0 {
|
|
| 59 |
+ config.MaxRetry = defaultMaxRetry |
|
| 60 |
+ } |
|
| 61 |
+ f = &Fluent{Config: config, reconnecting: false}
|
|
| 62 |
+ err = f.connect() |
|
| 63 |
+ return |
|
| 64 |
+} |
|
| 65 |
+ |
|
| 66 |
+// Post writes the output for a logging event. |
|
| 67 |
+// |
|
| 68 |
+// Examples: |
|
| 69 |
+// |
|
| 70 |
+// // send string |
|
| 71 |
+// f.Post("tag_name", "data")
|
|
| 72 |
+// |
|
| 73 |
+// // send map[string] |
|
| 74 |
+// mapStringData := map[string]string{
|
|
| 75 |
+// "foo": "bar", |
|
| 76 |
+// } |
|
| 77 |
+// f.Post("tag_name", mapStringData)
|
|
| 78 |
+// |
|
| 79 |
+// // send message with specified time |
|
| 80 |
+// mapStringData := map[string]string{
|
|
| 81 |
+// "foo": "bar", |
|
| 82 |
+// } |
|
| 83 |
+// tm := time.Now() |
|
| 84 |
+// f.PostWithTime("tag_name", tm, mapStringData)
|
|
| 85 |
+// |
|
| 86 |
+// // send struct |
|
| 87 |
+// structData := struct {
|
|
| 88 |
+// Name string `msg:"name"` |
|
| 89 |
+// } {
|
|
| 90 |
+// "john smith", |
|
| 91 |
+// } |
|
| 92 |
+// f.Post("tag_name", structData)
|
|
| 93 |
+// |
|
| 94 |
+func (f *Fluent) Post(tag string, message interface{}) error {
|
|
| 95 |
+ timeNow := time.Now() |
|
| 96 |
+ return f.PostWithTime(tag, timeNow, message) |
|
| 97 |
+} |
|
| 98 |
+ |
|
| 99 |
+func (f *Fluent) PostWithTime(tag string, tm time.Time, message interface{}) error {
|
|
| 100 |
+ if len(f.TagPrefix) > 0 {
|
|
| 101 |
+ tag = f.TagPrefix + "." + tag |
|
| 102 |
+ } |
|
| 103 |
+ |
|
| 104 |
+ msg := reflect.ValueOf(message) |
|
| 105 |
+ msgtype := msg.Type() |
|
| 106 |
+ |
|
| 107 |
+ if msgtype.Kind() == reflect.Struct {
|
|
| 108 |
+ // message should be tagged by "codec" or "msg" |
|
| 109 |
+ kv := make(map[string]interface{})
|
|
| 110 |
+ fields := msgtype.NumField() |
|
| 111 |
+ for i := 0; i < fields; i++ {
|
|
| 112 |
+ field := msgtype.Field(i) |
|
| 113 |
+ name := field.Name |
|
| 114 |
+ if n1 := field.Tag.Get("msg"); n1 != "" {
|
|
| 115 |
+ name = n1 |
|
| 116 |
+ } else if n2 := field.Tag.Get("codec"); n2 != "" {
|
|
| 117 |
+ name = n2 |
|
| 118 |
+ } |
|
| 119 |
+ kv[name] = msg.FieldByIndex(field.Index).Interface() |
|
| 120 |
+ } |
|
| 121 |
+ return f.EncodeAndPostData(tag, tm, kv) |
|
| 122 |
+ } |
|
| 123 |
+ |
|
| 124 |
+ if msgtype.Kind() != reflect.Map {
|
|
| 125 |
+ return errors.New("messge must be a map")
|
|
| 126 |
+ } else if msgtype.Key().Kind() != reflect.String {
|
|
| 127 |
+ return errors.New("map keys must be strings")
|
|
| 128 |
+ } |
|
| 129 |
+ |
|
| 130 |
+ kv := make(map[string]interface{})
|
|
| 131 |
+ for _, k := range msg.MapKeys() {
|
|
| 132 |
+ kv[k.String()] = msg.MapIndex(k).Interface() |
|
| 133 |
+ } |
|
| 134 |
+ |
|
| 135 |
+ return f.EncodeAndPostData(tag, tm, kv) |
|
| 136 |
+} |
|
| 137 |
+ |
|
| 138 |
+func (f *Fluent) EncodeAndPostData(tag string, tm time.Time, message interface{}) error {
|
|
| 139 |
+ if data, dumperr := f.EncodeData(tag, tm, message); dumperr != nil {
|
|
| 140 |
+ return fmt.Errorf("fluent#EncodeAndPostData: can't convert '%s' to msgpack:%s", message, dumperr)
|
|
| 141 |
+ // fmt.Println("fluent#Post: can't convert to msgpack:", message, dumperr)
|
|
| 142 |
+ } else {
|
|
| 143 |
+ f.PostRawData(data) |
|
| 144 |
+ return nil |
|
| 145 |
+ } |
|
| 146 |
+} |
|
| 147 |
+ |
|
| 148 |
+func (f *Fluent) PostRawData(data []byte) {
|
|
| 149 |
+ f.mu.Lock() |
|
| 150 |
+ f.pending = append(f.pending, data...) |
|
| 151 |
+ f.mu.Unlock() |
|
| 152 |
+ if err := f.send(); err != nil {
|
|
| 153 |
+ f.close() |
|
| 154 |
+ if len(f.pending) > f.Config.BufferLimit {
|
|
| 155 |
+ f.flushBuffer() |
|
| 156 |
+ } |
|
| 157 |
+ } else {
|
|
| 158 |
+ f.flushBuffer() |
|
| 159 |
+ } |
|
| 160 |
+} |
|
| 161 |
+ |
|
| 162 |
+func (f *Fluent) EncodeData(tag string, tm time.Time, message interface{}) (data []byte, err error) {
|
|
| 163 |
+ timeUnix := tm.Unix() |
|
| 164 |
+ msg := &Message{Tag: tag, Time: timeUnix, Record: message}
|
|
| 165 |
+ data, err = msg.MarshalMsg(nil) |
|
| 166 |
+ return |
|
| 167 |
+} |
|
| 168 |
+ |
|
| 169 |
+// Close closes the connection. |
|
| 170 |
+func (f *Fluent) Close() (err error) {
|
|
| 171 |
+ if len(f.pending) > 0 {
|
|
| 172 |
+ _ = f.send() |
|
| 173 |
+ } |
|
| 174 |
+ err = f.close() |
|
| 175 |
+ return |
|
| 176 |
+} |
|
| 177 |
+ |
|
| 178 |
+// close closes the connection. |
|
| 179 |
+func (f *Fluent) close() (err error) {
|
|
| 180 |
+ if f.conn != nil {
|
|
| 181 |
+ f.mu.Lock() |
|
| 182 |
+ defer f.mu.Unlock() |
|
| 183 |
+ } else {
|
|
| 184 |
+ return |
|
| 185 |
+ } |
|
| 186 |
+ if f.conn != nil {
|
|
| 187 |
+ f.conn.Close() |
|
| 188 |
+ f.conn = nil |
|
| 189 |
+ } |
|
| 190 |
+ return |
|
| 191 |
+} |
|
| 192 |
+ |
|
| 193 |
+// connect establishes a new connection using the specified transport. |
|
| 194 |
+func (f *Fluent) connect() (err error) {
|
|
| 195 |
+ f.conn, err = net.DialTimeout("tcp", f.Config.FluentHost+":"+strconv.Itoa(f.Config.FluentPort), f.Config.Timeout)
|
|
| 196 |
+ return |
|
| 197 |
+} |
|
| 198 |
+ |
|
| 199 |
+func e(x, y float64) int {
|
|
| 200 |
+ return int(math.Pow(x, y)) |
|
| 201 |
+} |
|
| 202 |
+ |
|
| 203 |
+func (f *Fluent) reconnect() {
|
|
| 204 |
+ go func() {
|
|
| 205 |
+ for i := 0; ; i++ {
|
|
| 206 |
+ err := f.connect() |
|
| 207 |
+ if err == nil {
|
|
| 208 |
+ f.mu.Lock() |
|
| 209 |
+ f.reconnecting = false |
|
| 210 |
+ f.mu.Unlock() |
|
| 211 |
+ break |
|
| 212 |
+ } else {
|
|
| 213 |
+ if i == f.Config.MaxRetry {
|
|
| 214 |
+ panic("fluent#reconnect: failed to reconnect!")
|
|
| 215 |
+ } |
|
| 216 |
+ waitTime := f.Config.RetryWait * e(defaultReconnectWaitIncreRate, float64(i-1)) |
|
| 217 |
+ time.Sleep(time.Duration(waitTime) * time.Millisecond) |
|
| 218 |
+ } |
|
| 219 |
+ } |
|
| 220 |
+ }() |
|
| 221 |
+} |
|
| 222 |
+ |
|
| 223 |
+func (f *Fluent) flushBuffer() {
|
|
| 224 |
+ f.mu.Lock() |
|
| 225 |
+ defer f.mu.Unlock() |
|
| 226 |
+ f.pending = f.pending[0:0] |
|
| 227 |
+} |
|
| 228 |
+ |
|
| 229 |
+func (f *Fluent) send() (err error) {
|
|
| 230 |
+ if f.conn == nil {
|
|
| 231 |
+ if f.reconnecting == false {
|
|
| 232 |
+ f.mu.Lock() |
|
| 233 |
+ f.reconnecting = true |
|
| 234 |
+ f.mu.Unlock() |
|
| 235 |
+ f.reconnect() |
|
| 236 |
+ } |
|
| 237 |
+ err = errors.New("fluent#send: can't send logs, client is reconnecting")
|
|
| 238 |
+ } else {
|
|
| 239 |
+ f.mu.Lock() |
|
| 240 |
+ _, err = f.conn.Write(f.pending) |
|
| 241 |
+ f.mu.Unlock() |
|
| 242 |
+ } |
|
| 243 |
+ return |
|
| 244 |
+} |
| 0 | 245 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,24 @@ |
| 0 |
+//go:generate msgp |
|
| 1 |
+ |
|
| 2 |
+package fluent |
|
| 3 |
+ |
|
| 4 |
+//msgp:tuple Entry |
|
| 5 |
+type Entry struct {
|
|
| 6 |
+ Time int64 `msg:"time"` |
|
| 7 |
+ Record interface{} `msg:"record"`
|
|
| 8 |
+} |
|
| 9 |
+ |
|
| 10 |
+//msgp:tuple Forward |
|
| 11 |
+type Forward struct {
|
|
| 12 |
+ Tag string `msg:"tag"` |
|
| 13 |
+ Entries []Entry `msg:"entries"` |
|
| 14 |
+ Option interface{} `msg:"option"`
|
|
| 15 |
+} |
|
| 16 |
+ |
|
| 17 |
+//msgp:tuple Message |
|
| 18 |
+type Message struct {
|
|
| 19 |
+ Tag string `msg:"tag"` |
|
| 20 |
+ Time int64 `msg:"time"` |
|
| 21 |
+ Record interface{} `msg:"record"`
|
|
| 22 |
+ Option interface{} `msg:"option"`
|
|
| 23 |
+} |
| 0 | 24 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,372 @@ |
| 0 |
+package fluent |
|
| 1 |
+ |
|
| 2 |
+// NOTE: THIS FILE WAS PRODUCED BY THE |
|
| 3 |
+// MSGP CODE GENERATION TOOL (github.com/tinylib/msgp) |
|
| 4 |
+// DO NOT EDIT |
|
| 5 |
+ |
|
| 6 |
+import ( |
|
| 7 |
+ "github.com/tinylib/msgp/msgp" |
|
| 8 |
+) |
|
| 9 |
+ |
|
| 10 |
+// DecodeMsg implements msgp.Decodable |
|
| 11 |
+func (z *Entry) DecodeMsg(dc *msgp.Reader) (err error) {
|
|
| 12 |
+ var ssz uint32 |
|
| 13 |
+ ssz, err = dc.ReadArrayHeader() |
|
| 14 |
+ if err != nil {
|
|
| 15 |
+ return |
|
| 16 |
+ } |
|
| 17 |
+ if ssz != 2 {
|
|
| 18 |
+ err = msgp.ArrayError{Wanted: 2, Got: ssz}
|
|
| 19 |
+ return |
|
| 20 |
+ } |
|
| 21 |
+ z.Time, err = dc.ReadInt64() |
|
| 22 |
+ if err != nil {
|
|
| 23 |
+ return |
|
| 24 |
+ } |
|
| 25 |
+ z.Record, err = dc.ReadIntf() |
|
| 26 |
+ if err != nil {
|
|
| 27 |
+ return |
|
| 28 |
+ } |
|
| 29 |
+ return |
|
| 30 |
+} |
|
| 31 |
+ |
|
| 32 |
+// EncodeMsg implements msgp.Encodable |
|
| 33 |
+func (z Entry) EncodeMsg(en *msgp.Writer) (err error) {
|
|
| 34 |
+ err = en.WriteArrayHeader(2) |
|
| 35 |
+ if err != nil {
|
|
| 36 |
+ return |
|
| 37 |
+ } |
|
| 38 |
+ err = en.WriteInt64(z.Time) |
|
| 39 |
+ if err != nil {
|
|
| 40 |
+ return |
|
| 41 |
+ } |
|
| 42 |
+ err = en.WriteIntf(z.Record) |
|
| 43 |
+ if err != nil {
|
|
| 44 |
+ return |
|
| 45 |
+ } |
|
| 46 |
+ return |
|
| 47 |
+} |
|
| 48 |
+ |
|
| 49 |
+// MarshalMsg implements msgp.Marshaler |
|
| 50 |
+func (z Entry) MarshalMsg(b []byte) (o []byte, err error) {
|
|
| 51 |
+ o = msgp.Require(b, z.Msgsize()) |
|
| 52 |
+ o = msgp.AppendArrayHeader(o, 2) |
|
| 53 |
+ o = msgp.AppendInt64(o, z.Time) |
|
| 54 |
+ o, err = msgp.AppendIntf(o, z.Record) |
|
| 55 |
+ if err != nil {
|
|
| 56 |
+ return |
|
| 57 |
+ } |
|
| 58 |
+ return |
|
| 59 |
+} |
|
| 60 |
+ |
|
| 61 |
+// UnmarshalMsg implements msgp.Unmarshaler |
|
| 62 |
+func (z *Entry) UnmarshalMsg(bts []byte) (o []byte, err error) {
|
|
| 63 |
+ {
|
|
| 64 |
+ var ssz uint32 |
|
| 65 |
+ ssz, bts, err = msgp.ReadArrayHeaderBytes(bts) |
|
| 66 |
+ if err != nil {
|
|
| 67 |
+ return |
|
| 68 |
+ } |
|
| 69 |
+ if ssz != 2 {
|
|
| 70 |
+ err = msgp.ArrayError{Wanted: 2, Got: ssz}
|
|
| 71 |
+ return |
|
| 72 |
+ } |
|
| 73 |
+ } |
|
| 74 |
+ z.Time, bts, err = msgp.ReadInt64Bytes(bts) |
|
| 75 |
+ if err != nil {
|
|
| 76 |
+ return |
|
| 77 |
+ } |
|
| 78 |
+ z.Record, bts, err = msgp.ReadIntfBytes(bts) |
|
| 79 |
+ if err != nil {
|
|
| 80 |
+ return |
|
| 81 |
+ } |
|
| 82 |
+ o = bts |
|
| 83 |
+ return |
|
| 84 |
+} |
|
| 85 |
+ |
|
| 86 |
+func (z Entry) Msgsize() (s int) {
|
|
| 87 |
+ s = msgp.ArrayHeaderSize + msgp.Int64Size + msgp.GuessSize(z.Record) |
|
| 88 |
+ return |
|
| 89 |
+} |
|
| 90 |
+ |
|
| 91 |
+// DecodeMsg implements msgp.Decodable |
|
| 92 |
+func (z *Forward) DecodeMsg(dc *msgp.Reader) (err error) {
|
|
| 93 |
+ var ssz uint32 |
|
| 94 |
+ ssz, err = dc.ReadArrayHeader() |
|
| 95 |
+ if err != nil {
|
|
| 96 |
+ return |
|
| 97 |
+ } |
|
| 98 |
+ if ssz != 3 {
|
|
| 99 |
+ err = msgp.ArrayError{Wanted: 3, Got: ssz}
|
|
| 100 |
+ return |
|
| 101 |
+ } |
|
| 102 |
+ z.Tag, err = dc.ReadString() |
|
| 103 |
+ if err != nil {
|
|
| 104 |
+ return |
|
| 105 |
+ } |
|
| 106 |
+ var xsz uint32 |
|
| 107 |
+ xsz, err = dc.ReadArrayHeader() |
|
| 108 |
+ if err != nil {
|
|
| 109 |
+ return |
|
| 110 |
+ } |
|
| 111 |
+ if cap(z.Entries) >= int(xsz) {
|
|
| 112 |
+ z.Entries = z.Entries[:xsz] |
|
| 113 |
+ } else {
|
|
| 114 |
+ z.Entries = make([]Entry, xsz) |
|
| 115 |
+ } |
|
| 116 |
+ for xvk := range z.Entries {
|
|
| 117 |
+ var ssz uint32 |
|
| 118 |
+ ssz, err = dc.ReadArrayHeader() |
|
| 119 |
+ if err != nil {
|
|
| 120 |
+ return |
|
| 121 |
+ } |
|
| 122 |
+ if ssz != 2 {
|
|
| 123 |
+ err = msgp.ArrayError{Wanted: 2, Got: ssz}
|
|
| 124 |
+ return |
|
| 125 |
+ } |
|
| 126 |
+ z.Entries[xvk].Time, err = dc.ReadInt64() |
|
| 127 |
+ if err != nil {
|
|
| 128 |
+ return |
|
| 129 |
+ } |
|
| 130 |
+ z.Entries[xvk].Record, err = dc.ReadIntf() |
|
| 131 |
+ if err != nil {
|
|
| 132 |
+ return |
|
| 133 |
+ } |
|
| 134 |
+ } |
|
| 135 |
+ z.Option, err = dc.ReadIntf() |
|
| 136 |
+ if err != nil {
|
|
| 137 |
+ return |
|
| 138 |
+ } |
|
| 139 |
+ return |
|
| 140 |
+} |
|
| 141 |
+ |
|
| 142 |
+// EncodeMsg implements msgp.Encodable |
|
| 143 |
+func (z *Forward) EncodeMsg(en *msgp.Writer) (err error) {
|
|
| 144 |
+ err = en.WriteArrayHeader(3) |
|
| 145 |
+ if err != nil {
|
|
| 146 |
+ return |
|
| 147 |
+ } |
|
| 148 |
+ err = en.WriteString(z.Tag) |
|
| 149 |
+ if err != nil {
|
|
| 150 |
+ return |
|
| 151 |
+ } |
|
| 152 |
+ err = en.WriteArrayHeader(uint32(len(z.Entries))) |
|
| 153 |
+ if err != nil {
|
|
| 154 |
+ return |
|
| 155 |
+ } |
|
| 156 |
+ for xvk := range z.Entries {
|
|
| 157 |
+ err = en.WriteArrayHeader(2) |
|
| 158 |
+ if err != nil {
|
|
| 159 |
+ return |
|
| 160 |
+ } |
|
| 161 |
+ err = en.WriteInt64(z.Entries[xvk].Time) |
|
| 162 |
+ if err != nil {
|
|
| 163 |
+ return |
|
| 164 |
+ } |
|
| 165 |
+ err = en.WriteIntf(z.Entries[xvk].Record) |
|
| 166 |
+ if err != nil {
|
|
| 167 |
+ return |
|
| 168 |
+ } |
|
| 169 |
+ } |
|
| 170 |
+ err = en.WriteIntf(z.Option) |
|
| 171 |
+ if err != nil {
|
|
| 172 |
+ return |
|
| 173 |
+ } |
|
| 174 |
+ return |
|
| 175 |
+} |
|
| 176 |
+ |
|
| 177 |
+// MarshalMsg implements msgp.Marshaler |
|
| 178 |
+func (z *Forward) MarshalMsg(b []byte) (o []byte, err error) {
|
|
| 179 |
+ o = msgp.Require(b, z.Msgsize()) |
|
| 180 |
+ o = msgp.AppendArrayHeader(o, 3) |
|
| 181 |
+ o = msgp.AppendString(o, z.Tag) |
|
| 182 |
+ o = msgp.AppendArrayHeader(o, uint32(len(z.Entries))) |
|
| 183 |
+ for xvk := range z.Entries {
|
|
| 184 |
+ o = msgp.AppendArrayHeader(o, 2) |
|
| 185 |
+ o = msgp.AppendInt64(o, z.Entries[xvk].Time) |
|
| 186 |
+ o, err = msgp.AppendIntf(o, z.Entries[xvk].Record) |
|
| 187 |
+ if err != nil {
|
|
| 188 |
+ return |
|
| 189 |
+ } |
|
| 190 |
+ } |
|
| 191 |
+ o, err = msgp.AppendIntf(o, z.Option) |
|
| 192 |
+ if err != nil {
|
|
| 193 |
+ return |
|
| 194 |
+ } |
|
| 195 |
+ return |
|
| 196 |
+} |
|
| 197 |
+ |
|
| 198 |
+// UnmarshalMsg implements msgp.Unmarshaler |
|
| 199 |
+func (z *Forward) UnmarshalMsg(bts []byte) (o []byte, err error) {
|
|
| 200 |
+ {
|
|
| 201 |
+ var ssz uint32 |
|
| 202 |
+ ssz, bts, err = msgp.ReadArrayHeaderBytes(bts) |
|
| 203 |
+ if err != nil {
|
|
| 204 |
+ return |
|
| 205 |
+ } |
|
| 206 |
+ if ssz != 3 {
|
|
| 207 |
+ err = msgp.ArrayError{Wanted: 3, Got: ssz}
|
|
| 208 |
+ return |
|
| 209 |
+ } |
|
| 210 |
+ } |
|
| 211 |
+ z.Tag, bts, err = msgp.ReadStringBytes(bts) |
|
| 212 |
+ if err != nil {
|
|
| 213 |
+ return |
|
| 214 |
+ } |
|
| 215 |
+ var xsz uint32 |
|
| 216 |
+ xsz, bts, err = msgp.ReadArrayHeaderBytes(bts) |
|
| 217 |
+ if err != nil {
|
|
| 218 |
+ return |
|
| 219 |
+ } |
|
| 220 |
+ if cap(z.Entries) >= int(xsz) {
|
|
| 221 |
+ z.Entries = z.Entries[:xsz] |
|
| 222 |
+ } else {
|
|
| 223 |
+ z.Entries = make([]Entry, xsz) |
|
| 224 |
+ } |
|
| 225 |
+ for xvk := range z.Entries {
|
|
| 226 |
+ {
|
|
| 227 |
+ var ssz uint32 |
|
| 228 |
+ ssz, bts, err = msgp.ReadArrayHeaderBytes(bts) |
|
| 229 |
+ if err != nil {
|
|
| 230 |
+ return |
|
| 231 |
+ } |
|
| 232 |
+ if ssz != 2 {
|
|
| 233 |
+ err = msgp.ArrayError{Wanted: 2, Got: ssz}
|
|
| 234 |
+ return |
|
| 235 |
+ } |
|
| 236 |
+ } |
|
| 237 |
+ z.Entries[xvk].Time, bts, err = msgp.ReadInt64Bytes(bts) |
|
| 238 |
+ if err != nil {
|
|
| 239 |
+ return |
|
| 240 |
+ } |
|
| 241 |
+ z.Entries[xvk].Record, bts, err = msgp.ReadIntfBytes(bts) |
|
| 242 |
+ if err != nil {
|
|
| 243 |
+ return |
|
| 244 |
+ } |
|
| 245 |
+ } |
|
| 246 |
+ z.Option, bts, err = msgp.ReadIntfBytes(bts) |
|
| 247 |
+ if err != nil {
|
|
| 248 |
+ return |
|
| 249 |
+ } |
|
| 250 |
+ o = bts |
|
| 251 |
+ return |
|
| 252 |
+} |
|
| 253 |
+ |
|
| 254 |
+func (z *Forward) Msgsize() (s int) {
|
|
| 255 |
+ s = msgp.ArrayHeaderSize + msgp.StringPrefixSize + len(z.Tag) + msgp.ArrayHeaderSize |
|
| 256 |
+ for xvk := range z.Entries {
|
|
| 257 |
+ s += msgp.ArrayHeaderSize + msgp.Int64Size + msgp.GuessSize(z.Entries[xvk].Record) |
|
| 258 |
+ } |
|
| 259 |
+ s += msgp.GuessSize(z.Option) |
|
| 260 |
+ return |
|
| 261 |
+} |
|
| 262 |
+ |
|
| 263 |
+// DecodeMsg implements msgp.Decodable |
|
| 264 |
+func (z *Message) DecodeMsg(dc *msgp.Reader) (err error) {
|
|
| 265 |
+ var ssz uint32 |
|
| 266 |
+ ssz, err = dc.ReadArrayHeader() |
|
| 267 |
+ if err != nil {
|
|
| 268 |
+ return |
|
| 269 |
+ } |
|
| 270 |
+ if ssz != 4 {
|
|
| 271 |
+ err = msgp.ArrayError{Wanted: 4, Got: ssz}
|
|
| 272 |
+ return |
|
| 273 |
+ } |
|
| 274 |
+ z.Tag, err = dc.ReadString() |
|
| 275 |
+ if err != nil {
|
|
| 276 |
+ return |
|
| 277 |
+ } |
|
| 278 |
+ z.Time, err = dc.ReadInt64() |
|
| 279 |
+ if err != nil {
|
|
| 280 |
+ return |
|
| 281 |
+ } |
|
| 282 |
+ z.Record, err = dc.ReadIntf() |
|
| 283 |
+ if err != nil {
|
|
| 284 |
+ return |
|
| 285 |
+ } |
|
| 286 |
+ z.Option, err = dc.ReadIntf() |
|
| 287 |
+ if err != nil {
|
|
| 288 |
+ return |
|
| 289 |
+ } |
|
| 290 |
+ return |
|
| 291 |
+} |
|
| 292 |
+ |
|
| 293 |
+// EncodeMsg implements msgp.Encodable |
|
| 294 |
+func (z *Message) EncodeMsg(en *msgp.Writer) (err error) {
|
|
| 295 |
+ err = en.WriteArrayHeader(4) |
|
| 296 |
+ if err != nil {
|
|
| 297 |
+ return |
|
| 298 |
+ } |
|
| 299 |
+ err = en.WriteString(z.Tag) |
|
| 300 |
+ if err != nil {
|
|
| 301 |
+ return |
|
| 302 |
+ } |
|
| 303 |
+ err = en.WriteInt64(z.Time) |
|
| 304 |
+ if err != nil {
|
|
| 305 |
+ return |
|
| 306 |
+ } |
|
| 307 |
+ err = en.WriteIntf(z.Record) |
|
| 308 |
+ if err != nil {
|
|
| 309 |
+ return |
|
| 310 |
+ } |
|
| 311 |
+ err = en.WriteIntf(z.Option) |
|
| 312 |
+ if err != nil {
|
|
| 313 |
+ return |
|
| 314 |
+ } |
|
| 315 |
+ return |
|
| 316 |
+} |
|
| 317 |
+ |
|
| 318 |
+// MarshalMsg implements msgp.Marshaler |
|
| 319 |
+func (z *Message) MarshalMsg(b []byte) (o []byte, err error) {
|
|
| 320 |
+ o = msgp.Require(b, z.Msgsize()) |
|
| 321 |
+ o = msgp.AppendArrayHeader(o, 4) |
|
| 322 |
+ o = msgp.AppendString(o, z.Tag) |
|
| 323 |
+ o = msgp.AppendInt64(o, z.Time) |
|
| 324 |
+ o, err = msgp.AppendIntf(o, z.Record) |
|
| 325 |
+ if err != nil {
|
|
| 326 |
+ return |
|
| 327 |
+ } |
|
| 328 |
+ o, err = msgp.AppendIntf(o, z.Option) |
|
| 329 |
+ if err != nil {
|
|
| 330 |
+ return |
|
| 331 |
+ } |
|
| 332 |
+ return |
|
| 333 |
+} |
|
| 334 |
+ |
|
| 335 |
+// UnmarshalMsg implements msgp.Unmarshaler |
|
| 336 |
+func (z *Message) UnmarshalMsg(bts []byte) (o []byte, err error) {
|
|
| 337 |
+ {
|
|
| 338 |
+ var ssz uint32 |
|
| 339 |
+ ssz, bts, err = msgp.ReadArrayHeaderBytes(bts) |
|
| 340 |
+ if err != nil {
|
|
| 341 |
+ return |
|
| 342 |
+ } |
|
| 343 |
+ if ssz != 4 {
|
|
| 344 |
+ err = msgp.ArrayError{Wanted: 4, Got: ssz}
|
|
| 345 |
+ return |
|
| 346 |
+ } |
|
| 347 |
+ } |
|
| 348 |
+ z.Tag, bts, err = msgp.ReadStringBytes(bts) |
|
| 349 |
+ if err != nil {
|
|
| 350 |
+ return |
|
| 351 |
+ } |
|
| 352 |
+ z.Time, bts, err = msgp.ReadInt64Bytes(bts) |
|
| 353 |
+ if err != nil {
|
|
| 354 |
+ return |
|
| 355 |
+ } |
|
| 356 |
+ z.Record, bts, err = msgp.ReadIntfBytes(bts) |
|
| 357 |
+ if err != nil {
|
|
| 358 |
+ return |
|
| 359 |
+ } |
|
| 360 |
+ z.Option, bts, err = msgp.ReadIntfBytes(bts) |
|
| 361 |
+ if err != nil {
|
|
| 362 |
+ return |
|
| 363 |
+ } |
|
| 364 |
+ o = bts |
|
| 365 |
+ return |
|
| 366 |
+} |
|
| 367 |
+ |
|
| 368 |
+func (z *Message) Msgsize() (s int) {
|
|
| 369 |
+ s = msgp.ArrayHeaderSize + msgp.StringPrefixSize + len(z.Tag) + msgp.Int64Size + msgp.GuessSize(z.Record) + msgp.GuessSize(z.Option) |
|
| 370 |
+ return |
|
| 371 |
+} |
| 0 | 3 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,311 @@ |
| 0 |
+ |
|
| 1 |
+# fwd |
|
| 2 |
+ import "github.com/philhofer/fwd" |
|
| 3 |
+ |
|
| 4 |
+The `fwd` package provides a buffered reader |
|
| 5 |
+and writer. Each has methods that help improve |
|
| 6 |
+the encoding/decoding performance of some binary |
|
| 7 |
+protocols. |
|
| 8 |
+ |
|
| 9 |
+The `fwd.Writer` and `fwd.Reader` type provide similar |
|
| 10 |
+functionality to their counterparts in `bufio`, plus |
|
| 11 |
+a few extra utility methods that simplify read-ahead |
|
| 12 |
+and write-ahead. I wrote this package to improve serialization |
|
| 13 |
+performance for <a href="http://github.com/philhofer/msgp">http://github.com/philhofer/msgp</a>, |
|
| 14 |
+where it provided about a 2x speedup over `bufio`. However, |
|
| 15 |
+care must be taken to understand the semantics of the |
|
| 16 |
+extra methods provided by this package, as they allow |
|
| 17 |
+the user to access and manipulate the buffer memory |
|
| 18 |
+directly. |
|
| 19 |
+ |
|
| 20 |
+The extra methods for `fwd.Reader` are `Peek`, `Skip` |
|
| 21 |
+and `Next`. `(*fwd.Reader).Peek`, unlike `(*bufio.Reader).Peek`, |
|
| 22 |
+will re-allocate the read buffer in order to accommodate arbitrarily |
|
| 23 |
+large read-ahead. `(*fwd.Reader).Skip` skips the next `n` bytes |
|
| 24 |
+in the stream, and uses the `io.Seeker` interface if the underlying |
|
| 25 |
+stream implements it. `(*fwd.Reader).Next` returns a slice pointing |
|
| 26 |
+to the next `n` bytes in the read buffer (like `Peek`), but also |
|
| 27 |
+increments the read position. This allows users to process streams |
|
| 28 |
+in aribtrary block sizes without having to manage appropriately-sized |
|
| 29 |
+slices. Additionally, obviating the need to copy the data from the |
|
| 30 |
+buffer to another location in memory can improve performance dramatically |
|
| 31 |
+in CPU-bound applications. |
|
| 32 |
+ |
|
| 33 |
+`fwd.Writer` only has one extra method, which is `(*fwd.Writer).Next`, which |
|
| 34 |
+returns a slice pointing to the next `n` bytes of the writer, and increments |
|
| 35 |
+the write position by the length of the returned slice. This allows users |
|
| 36 |
+to write directly to the end of the buffer. |
|
| 37 |
+ |
|
| 38 |
+ |
|
| 39 |
+ |
|
| 40 |
+ |
|
| 41 |
+## Constants |
|
| 42 |
+``` go |
|
| 43 |
+const ( |
|
| 44 |
+ // DefaultReaderSize is the default size of the read buffer |
|
| 45 |
+ DefaultReaderSize = 2048 |
|
| 46 |
+) |
|
| 47 |
+``` |
|
| 48 |
+``` go |
|
| 49 |
+const ( |
|
| 50 |
+ // DefaultWriterSize is the |
|
| 51 |
+ // default write buffer size. |
|
| 52 |
+ DefaultWriterSize = 2048 |
|
| 53 |
+) |
|
| 54 |
+``` |
|
| 55 |
+ |
|
| 56 |
+ |
|
| 57 |
+ |
|
| 58 |
+## type Reader |
|
| 59 |
+``` go |
|
| 60 |
+type Reader struct {
|
|
| 61 |
+ // contains filtered or unexported fields |
|
| 62 |
+} |
|
| 63 |
+``` |
|
| 64 |
+Reader is a buffered look-ahead reader |
|
| 65 |
+ |
|
| 66 |
+ |
|
| 67 |
+ |
|
| 68 |
+ |
|
| 69 |
+ |
|
| 70 |
+ |
|
| 71 |
+ |
|
| 72 |
+ |
|
| 73 |
+ |
|
| 74 |
+### func NewReader |
|
| 75 |
+``` go |
|
| 76 |
+func NewReader(r io.Reader) *Reader |
|
| 77 |
+``` |
|
| 78 |
+NewReader returns a new *Reader that reads from 'r' |
|
| 79 |
+ |
|
| 80 |
+ |
|
| 81 |
+### func NewReaderSize |
|
| 82 |
+``` go |
|
| 83 |
+func NewReaderSize(r io.Reader, n int) *Reader |
|
| 84 |
+``` |
|
| 85 |
+NewReaderSize returns a new *Reader that |
|
| 86 |
+reads from 'r' and has a buffer size 'n' |
|
| 87 |
+ |
|
| 88 |
+ |
|
| 89 |
+ |
|
| 90 |
+ |
|
| 91 |
+### func (\*Reader) BufferSize |
|
| 92 |
+``` go |
|
| 93 |
+func (r *Reader) BufferSize() int |
|
| 94 |
+``` |
|
| 95 |
+BufferSize returns the total size of the buffer |
|
| 96 |
+ |
|
| 97 |
+ |
|
| 98 |
+ |
|
| 99 |
+### func (\*Reader) Buffered |
|
| 100 |
+``` go |
|
| 101 |
+func (r *Reader) Buffered() int |
|
| 102 |
+``` |
|
| 103 |
+Buffered returns the number of bytes currently in the buffer |
|
| 104 |
+ |
|
| 105 |
+ |
|
| 106 |
+ |
|
| 107 |
+### func (\*Reader) Next |
|
| 108 |
+``` go |
|
| 109 |
+func (r *Reader) Next(n int) ([]byte, error) |
|
| 110 |
+``` |
|
| 111 |
+Next returns the next 'n' bytes in the stream. |
|
| 112 |
+If the returned slice has a length less than 'n', |
|
| 113 |
+an error will also be returned. |
|
| 114 |
+Unlike Peek, Next advances the reader position. |
|
| 115 |
+The returned bytes point to the same |
|
| 116 |
+data as the buffer, so the slice is |
|
| 117 |
+only valid until the next reader method call. |
|
| 118 |
+An EOF is considered an unexpected error. |
|
| 119 |
+ |
|
| 120 |
+ |
|
| 121 |
+ |
|
| 122 |
+### func (\*Reader) Peek |
|
| 123 |
+``` go |
|
| 124 |
+func (r *Reader) Peek(n int) ([]byte, error) |
|
| 125 |
+``` |
|
| 126 |
+Peek returns the next 'n' buffered bytes, |
|
| 127 |
+reading from the underlying reader if necessary. |
|
| 128 |
+It will only return a slice shorter than 'n' bytes |
|
| 129 |
+if it also returns an error. Peek does not advance |
|
| 130 |
+the reader. EOF errors are *not* returned as |
|
| 131 |
+io.ErrUnexpectedEOF. |
|
| 132 |
+ |
|
| 133 |
+ |
|
| 134 |
+ |
|
| 135 |
+### func (\*Reader) Read |
|
| 136 |
+``` go |
|
| 137 |
+func (r *Reader) Read(b []byte) (int, error) |
|
| 138 |
+``` |
|
| 139 |
+Read implements `io.Reader` |
|
| 140 |
+ |
|
| 141 |
+ |
|
| 142 |
+ |
|
| 143 |
+### func (\*Reader) ReadByte |
|
| 144 |
+``` go |
|
| 145 |
+func (r *Reader) ReadByte() (byte, error) |
|
| 146 |
+``` |
|
| 147 |
+ReadByte implements `io.ByteReader` |
|
| 148 |
+ |
|
| 149 |
+ |
|
| 150 |
+ |
|
| 151 |
+### func (\*Reader) ReadFull |
|
| 152 |
+``` go |
|
| 153 |
+func (r *Reader) ReadFull(b []byte) (int, error) |
|
| 154 |
+``` |
|
| 155 |
+ReadFull attempts to read len(b) bytes into |
|
| 156 |
+'b'. It returns the number of bytes read into |
|
| 157 |
+'b', and an error if it does not return len(b). |
|
| 158 |
+ |
|
| 159 |
+ |
|
| 160 |
+ |
|
| 161 |
+### func (\*Reader) Reset |
|
| 162 |
+``` go |
|
| 163 |
+func (r *Reader) Reset(rd io.Reader) |
|
| 164 |
+``` |
|
| 165 |
+Reset resets the underlying reader |
|
| 166 |
+and the read buffer. |
|
| 167 |
+ |
|
| 168 |
+ |
|
| 169 |
+ |
|
| 170 |
+### func (\*Reader) Skip |
|
| 171 |
+``` go |
|
| 172 |
+func (r *Reader) Skip(n int) (int, error) |
|
| 173 |
+``` |
|
| 174 |
+Skip moves the reader forward 'n' bytes. |
|
| 175 |
+Returns the number of bytes skipped and any |
|
| 176 |
+errors encountered. It is analagous to Seek(n, 1). |
|
| 177 |
+If the underlying reader implements io.Seeker, then |
|
| 178 |
+that method will be used to skip forward. |
|
| 179 |
+ |
|
| 180 |
+If the reader encounters |
|
| 181 |
+an EOF before skipping 'n' bytes, it |
|
| 182 |
+returns io.ErrUnexpectedEOF. If the |
|
| 183 |
+underlying reader implements io.Seeker, then |
|
| 184 |
+those rules apply instead. (Many implementations |
|
| 185 |
+will not return `io.EOF` until the next call |
|
| 186 |
+to Read.) |
|
| 187 |
+ |
|
| 188 |
+ |
|
| 189 |
+ |
|
| 190 |
+### func (\*Reader) WriteTo |
|
| 191 |
+``` go |
|
| 192 |
+func (r *Reader) WriteTo(w io.Writer) (int64, error) |
|
| 193 |
+``` |
|
| 194 |
+WriteTo implements `io.WriterTo` |
|
| 195 |
+ |
|
| 196 |
+ |
|
| 197 |
+ |
|
| 198 |
+## type Writer |
|
| 199 |
+``` go |
|
| 200 |
+type Writer struct {
|
|
| 201 |
+ // contains filtered or unexported fields |
|
| 202 |
+} |
|
| 203 |
+``` |
|
| 204 |
+Writer is a buffered writer |
|
| 205 |
+ |
|
| 206 |
+ |
|
| 207 |
+ |
|
| 208 |
+ |
|
| 209 |
+ |
|
| 210 |
+ |
|
| 211 |
+ |
|
| 212 |
+ |
|
| 213 |
+ |
|
| 214 |
+### func NewWriter |
|
| 215 |
+``` go |
|
| 216 |
+func NewWriter(w io.Writer) *Writer |
|
| 217 |
+``` |
|
| 218 |
+NewWriter returns a new writer |
|
| 219 |
+that writes to 'w' and has a buffer |
|
| 220 |
+that is `DefaultWriterSize` bytes. |
|
| 221 |
+ |
|
| 222 |
+ |
|
| 223 |
+### func NewWriterSize |
|
| 224 |
+``` go |
|
| 225 |
+func NewWriterSize(w io.Writer, size int) *Writer |
|
| 226 |
+``` |
|
| 227 |
+NewWriterSize returns a new writer |
|
| 228 |
+that writes to 'w' and has a buffer |
|
| 229 |
+that is 'size' bytes. |
|
| 230 |
+ |
|
| 231 |
+ |
|
| 232 |
+ |
|
| 233 |
+ |
|
| 234 |
+### func (\*Writer) BufferSize |
|
| 235 |
+``` go |
|
| 236 |
+func (w *Writer) BufferSize() int |
|
| 237 |
+``` |
|
| 238 |
+BufferSize returns the maximum size of the buffer. |
|
| 239 |
+ |
|
| 240 |
+ |
|
| 241 |
+ |
|
| 242 |
+### func (\*Writer) Buffered |
|
| 243 |
+``` go |
|
| 244 |
+func (w *Writer) Buffered() int |
|
| 245 |
+``` |
|
| 246 |
+Buffered returns the number of buffered bytes |
|
| 247 |
+in the reader. |
|
| 248 |
+ |
|
| 249 |
+ |
|
| 250 |
+ |
|
| 251 |
+### func (\*Writer) Flush |
|
| 252 |
+``` go |
|
| 253 |
+func (w *Writer) Flush() error |
|
| 254 |
+``` |
|
| 255 |
+Flush flushes any buffered bytes |
|
| 256 |
+to the underlying writer. |
|
| 257 |
+ |
|
| 258 |
+ |
|
| 259 |
+ |
|
| 260 |
+### func (\*Writer) Next |
|
| 261 |
+``` go |
|
| 262 |
+func (w *Writer) Next(n int) ([]byte, error) |
|
| 263 |
+``` |
|
| 264 |
+Next returns the next 'n' free bytes |
|
| 265 |
+in the write buffer, flushing the writer |
|
| 266 |
+as necessary. Next will return `io.ErrShortBuffer` |
|
| 267 |
+if 'n' is greater than the size of the write buffer. |
|
| 268 |
+ |
|
| 269 |
+ |
|
| 270 |
+ |
|
| 271 |
+### func (\*Writer) ReadFrom |
|
| 272 |
+``` go |
|
| 273 |
+func (w *Writer) ReadFrom(r io.Reader) (int64, error) |
|
| 274 |
+``` |
|
| 275 |
+ReadFrom implements `io.ReaderFrom` |
|
| 276 |
+ |
|
| 277 |
+ |
|
| 278 |
+ |
|
| 279 |
+### func (\*Writer) Write |
|
| 280 |
+``` go |
|
| 281 |
+func (w *Writer) Write(p []byte) (int, error) |
|
| 282 |
+``` |
|
| 283 |
+Write implements `io.Writer` |
|
| 284 |
+ |
|
| 285 |
+ |
|
| 286 |
+ |
|
| 287 |
+### func (\*Writer) WriteByte |
|
| 288 |
+``` go |
|
| 289 |
+func (w *Writer) WriteByte(b byte) error |
|
| 290 |
+``` |
|
| 291 |
+WriteByte implements `io.ByteWriter` |
|
| 292 |
+ |
|
| 293 |
+ |
|
| 294 |
+ |
|
| 295 |
+### func (\*Writer) WriteString |
|
| 296 |
+``` go |
|
| 297 |
+func (w *Writer) WriteString(s string) (int, error) |
|
| 298 |
+``` |
|
| 299 |
+WriteString is analagous to Write, but it takes a string. |
|
| 300 |
+ |
|
| 301 |
+ |
|
| 302 |
+ |
|
| 303 |
+ |
|
| 304 |
+ |
|
| 305 |
+ |
|
| 306 |
+ |
|
| 307 |
+ |
|
| 308 |
+ |
|
| 309 |
+- - - |
|
| 310 |
+Generated by [godoc2md](http://godoc.org/github.com/davecheney/godoc2md) |
|
| 0 | 311 |
\ No newline at end of file |
| 1 | 312 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,358 @@ |
| 0 |
+// The `fwd` package provides a buffered reader |
|
| 1 |
+// and writer. Each has methods that help improve |
|
| 2 |
+// the encoding/decoding performance of some binary |
|
| 3 |
+// protocols. |
|
| 4 |
+// |
|
| 5 |
+// The `fwd.Writer` and `fwd.Reader` type provide similar |
|
| 6 |
+// functionality to their counterparts in `bufio`, plus |
|
| 7 |
+// a few extra utility methods that simplify read-ahead |
|
| 8 |
+// and write-ahead. I wrote this package to improve serialization |
|
| 9 |
+// performance for http://github.com/tinylib/msgp, |
|
| 10 |
+// where it provided about a 2x speedup over `bufio` for certain |
|
| 11 |
+// workloads. However, care must be taken to understand the semantics of the |
|
| 12 |
+// extra methods provided by this package, as they allow |
|
| 13 |
+// the user to access and manipulate the buffer memory |
|
| 14 |
+// directly. |
|
| 15 |
+// |
|
| 16 |
+// The extra methods for `fwd.Reader` are `Peek`, `Skip` |
|
| 17 |
+// and `Next`. `(*fwd.Reader).Peek`, unlike `(*bufio.Reader).Peek`, |
|
| 18 |
+// will re-allocate the read buffer in order to accommodate arbitrarily |
|
| 19 |
+// large read-ahead. `(*fwd.Reader).Skip` skips the next `n` bytes |
|
| 20 |
+// in the stream, and uses the `io.Seeker` interface if the underlying |
|
| 21 |
+// stream implements it. `(*fwd.Reader).Next` returns a slice pointing |
|
| 22 |
+// to the next `n` bytes in the read buffer (like `Peek`), but also |
|
| 23 |
+// increments the read position. This allows users to process streams |
|
| 24 |
+// in aribtrary block sizes without having to manage appropriately-sized |
|
| 25 |
+// slices. Additionally, obviating the need to copy the data from the |
|
| 26 |
+// buffer to another location in memory can improve performance dramatically |
|
| 27 |
+// in CPU-bound applications. |
|
| 28 |
+// |
|
| 29 |
+// `fwd.Writer` only has one extra method, which is `(*fwd.Writer).Next`, which |
|
| 30 |
+// returns a slice pointing to the next `n` bytes of the writer, and increments |
|
| 31 |
+// the write position by the length of the returned slice. This allows users |
|
| 32 |
+// to write directly to the end of the buffer. |
|
| 33 |
+// |
|
| 34 |
+package fwd |
|
| 35 |
+ |
|
| 36 |
+import "io" |
|
| 37 |
+ |
|
| 38 |
+const ( |
|
| 39 |
+ // DefaultReaderSize is the default size of the read buffer |
|
| 40 |
+ DefaultReaderSize = 2048 |
|
| 41 |
+ |
|
| 42 |
+ // minimum read buffer; straight from bufio |
|
| 43 |
+ minReaderSize = 16 |
|
| 44 |
+) |
|
| 45 |
+ |
|
| 46 |
+// NewReader returns a new *Reader that reads from 'r' |
|
| 47 |
+func NewReader(r io.Reader) *Reader {
|
|
| 48 |
+ return NewReaderSize(r, DefaultReaderSize) |
|
| 49 |
+} |
|
| 50 |
+ |
|
| 51 |
+// NewReaderSize returns a new *Reader that |
|
| 52 |
+// reads from 'r' and has a buffer size 'n' |
|
| 53 |
+func NewReaderSize(r io.Reader, n int) *Reader {
|
|
| 54 |
+ rd := &Reader{
|
|
| 55 |
+ r: r, |
|
| 56 |
+ data: make([]byte, 0, max(minReaderSize, n)), |
|
| 57 |
+ } |
|
| 58 |
+ if s, ok := r.(io.Seeker); ok {
|
|
| 59 |
+ rd.rs = s |
|
| 60 |
+ } |
|
| 61 |
+ return rd |
|
| 62 |
+} |
|
| 63 |
+ |
|
| 64 |
+// Reader is a buffered look-ahead reader |
|
| 65 |
+type Reader struct {
|
|
| 66 |
+ r io.Reader // underlying reader |
|
| 67 |
+ |
|
| 68 |
+ // data[n:len(data)] is buffered data; data[len(data):cap(data)] is free buffer space |
|
| 69 |
+ data []byte // data |
|
| 70 |
+ n int // read offset |
|
| 71 |
+ state error // last read error |
|
| 72 |
+ |
|
| 73 |
+ // if the reader past to NewReader was |
|
| 74 |
+ // also an io.Seeker, this is non-nil |
|
| 75 |
+ rs io.Seeker |
|
| 76 |
+} |
|
| 77 |
+ |
|
| 78 |
+// Reset resets the underlying reader |
|
| 79 |
+// and the read buffer. |
|
| 80 |
+func (r *Reader) Reset(rd io.Reader) {
|
|
| 81 |
+ r.r = rd |
|
| 82 |
+ r.data = r.data[0:0] |
|
| 83 |
+ r.n = 0 |
|
| 84 |
+ r.state = nil |
|
| 85 |
+ if s, ok := rd.(io.Seeker); ok {
|
|
| 86 |
+ r.rs = s |
|
| 87 |
+ } else {
|
|
| 88 |
+ r.rs = nil |
|
| 89 |
+ } |
|
| 90 |
+} |
|
| 91 |
+ |
|
| 92 |
+// more() does one read on the underlying reader |
|
| 93 |
+func (r *Reader) more() {
|
|
| 94 |
+ // move data backwards so that |
|
| 95 |
+ // the read offset is 0; this way |
|
| 96 |
+ // we can supply the maximum number of |
|
| 97 |
+ // bytes to the reader |
|
| 98 |
+ if r.n != 0 {
|
|
| 99 |
+ r.data = r.data[:copy(r.data[0:], r.data[r.n:])] |
|
| 100 |
+ r.n = 0 |
|
| 101 |
+ } |
|
| 102 |
+ var a int |
|
| 103 |
+ a, r.state = r.r.Read(r.data[len(r.data):cap(r.data)]) |
|
| 104 |
+ if a == 0 && r.state == nil {
|
|
| 105 |
+ r.state = io.ErrNoProgress |
|
| 106 |
+ return |
|
| 107 |
+ } |
|
| 108 |
+ r.data = r.data[:len(r.data)+a] |
|
| 109 |
+} |
|
| 110 |
+ |
|
| 111 |
+// pop error |
|
| 112 |
+func (r *Reader) err() (e error) {
|
|
| 113 |
+ e, r.state = r.state, nil |
|
| 114 |
+ return |
|
| 115 |
+} |
|
| 116 |
+ |
|
| 117 |
+// pop error; EOF -> io.ErrUnexpectedEOF |
|
| 118 |
+func (r *Reader) noEOF() (e error) {
|
|
| 119 |
+ e, r.state = r.state, nil |
|
| 120 |
+ if e == io.EOF {
|
|
| 121 |
+ e = io.ErrUnexpectedEOF |
|
| 122 |
+ } |
|
| 123 |
+ return |
|
| 124 |
+} |
|
| 125 |
+ |
|
| 126 |
+// buffered bytes |
|
| 127 |
+func (r *Reader) buffered() int { return len(r.data) - r.n }
|
|
| 128 |
+ |
|
| 129 |
+// Buffered returns the number of bytes currently in the buffer |
|
| 130 |
+func (r *Reader) Buffered() int { return len(r.data) - r.n }
|
|
| 131 |
+ |
|
| 132 |
+// BufferSize returns the total size of the buffer |
|
| 133 |
+func (r *Reader) BufferSize() int { return cap(r.data) }
|
|
| 134 |
+ |
|
| 135 |
+// Peek returns the next 'n' buffered bytes, |
|
| 136 |
+// reading from the underlying reader if necessary. |
|
| 137 |
+// It will only return a slice shorter than 'n' bytes |
|
| 138 |
+// if it also returns an error. Peek does not advance |
|
| 139 |
+// the reader. EOF errors are *not* returned as |
|
| 140 |
+// io.ErrUnexpectedEOF. |
|
| 141 |
+func (r *Reader) Peek(n int) ([]byte, error) {
|
|
| 142 |
+ // in the degenerate case, |
|
| 143 |
+ // we may need to realloc |
|
| 144 |
+ // (the caller asked for more |
|
| 145 |
+ // bytes than the size of the buffer) |
|
| 146 |
+ if cap(r.data) < n {
|
|
| 147 |
+ old := r.data[r.n:] |
|
| 148 |
+ r.data = make([]byte, n+r.buffered()) |
|
| 149 |
+ r.data = r.data[:copy(r.data, old)] |
|
| 150 |
+ } |
|
| 151 |
+ |
|
| 152 |
+ // keep filling until |
|
| 153 |
+ // we hit an error or |
|
| 154 |
+ // read enough bytes |
|
| 155 |
+ for r.buffered() < n && r.state == nil {
|
|
| 156 |
+ r.more() |
|
| 157 |
+ } |
|
| 158 |
+ |
|
| 159 |
+ // we must have hit an error |
|
| 160 |
+ if r.buffered() < n {
|
|
| 161 |
+ return r.data[r.n:], r.err() |
|
| 162 |
+ } |
|
| 163 |
+ |
|
| 164 |
+ return r.data[r.n : r.n+n], nil |
|
| 165 |
+} |
|
| 166 |
+ |
|
| 167 |
+// Skip moves the reader forward 'n' bytes. |
|
| 168 |
+// Returns the number of bytes skipped and any |
|
| 169 |
+// errors encountered. It is analagous to Seek(n, 1). |
|
| 170 |
+// If the underlying reader implements io.Seeker, then |
|
| 171 |
+// that method will be used to skip forward. |
|
| 172 |
+// |
|
| 173 |
+// If the reader encounters |
|
| 174 |
+// an EOF before skipping 'n' bytes, it |
|
| 175 |
+// returns io.ErrUnexpectedEOF. If the |
|
| 176 |
+// underlying reader implements io.Seeker, then |
|
| 177 |
+// those rules apply instead. (Many implementations |
|
| 178 |
+// will not return `io.EOF` until the next call |
|
| 179 |
+// to Read.) |
|
| 180 |
+func (r *Reader) Skip(n int) (int, error) {
|
|
| 181 |
+ |
|
| 182 |
+ // fast path |
|
| 183 |
+ if r.buffered() >= n {
|
|
| 184 |
+ r.n += n |
|
| 185 |
+ return n, nil |
|
| 186 |
+ } |
|
| 187 |
+ |
|
| 188 |
+ // use seeker implementation |
|
| 189 |
+ // if we can |
|
| 190 |
+ if r.rs != nil {
|
|
| 191 |
+ return r.skipSeek(n) |
|
| 192 |
+ } |
|
| 193 |
+ |
|
| 194 |
+ // loop on filling |
|
| 195 |
+ // and then erasing |
|
| 196 |
+ o := n |
|
| 197 |
+ for r.buffered() < n && r.state == nil {
|
|
| 198 |
+ r.more() |
|
| 199 |
+ // we can skip forward |
|
| 200 |
+ // up to r.buffered() bytes |
|
| 201 |
+ step := min(r.buffered(), n) |
|
| 202 |
+ r.n += step |
|
| 203 |
+ n -= step |
|
| 204 |
+ } |
|
| 205 |
+ // at this point, n should be |
|
| 206 |
+ // 0 if everything went smoothly |
|
| 207 |
+ return o - n, r.noEOF() |
|
| 208 |
+} |
|
| 209 |
+ |
|
| 210 |
+// Next returns the next 'n' bytes in the stream. |
|
| 211 |
+// Unlike Peek, Next advances the reader position. |
|
| 212 |
+// The returned bytes point to the same |
|
| 213 |
+// data as the buffer, so the slice is |
|
| 214 |
+// only valid until the next reader method call. |
|
| 215 |
+// An EOF is considered an unexpected error. |
|
| 216 |
+// If an the returned slice is less than the |
|
| 217 |
+// length asked for, an error will be returned, |
|
| 218 |
+// and the reader position will not be incremented. |
|
| 219 |
+func (r *Reader) Next(n int) ([]byte, error) {
|
|
| 220 |
+ |
|
| 221 |
+ // in case the buffer is too small |
|
| 222 |
+ if cap(r.data) < n {
|
|
| 223 |
+ old := r.data[r.n:] |
|
| 224 |
+ r.data = make([]byte, n+r.buffered()) |
|
| 225 |
+ r.data = r.data[:copy(r.data, old)] |
|
| 226 |
+ } |
|
| 227 |
+ |
|
| 228 |
+ // fill at least 'n' bytes |
|
| 229 |
+ for r.buffered() < n && r.state == nil {
|
|
| 230 |
+ r.more() |
|
| 231 |
+ } |
|
| 232 |
+ |
|
| 233 |
+ if r.buffered() < n {
|
|
| 234 |
+ return r.data[r.n:], r.noEOF() |
|
| 235 |
+ } |
|
| 236 |
+ out := r.data[r.n : r.n+n] |
|
| 237 |
+ r.n += n |
|
| 238 |
+ return out, nil |
|
| 239 |
+} |
|
| 240 |
+ |
|
| 241 |
+// skipSeek uses the io.Seeker to seek forward. |
|
| 242 |
+// only call this function when n > r.buffered() |
|
| 243 |
+func (r *Reader) skipSeek(n int) (int, error) {
|
|
| 244 |
+ o := r.buffered() |
|
| 245 |
+ // first, clear buffer |
|
| 246 |
+ n -= o |
|
| 247 |
+ r.n = 0 |
|
| 248 |
+ r.data = r.data[:0] |
|
| 249 |
+ |
|
| 250 |
+ // then seek forward remaning bytes |
|
| 251 |
+ i, err := r.rs.Seek(int64(n), 1) |
|
| 252 |
+ return int(i) + o, err |
|
| 253 |
+} |
|
| 254 |
+ |
|
| 255 |
+// Read implements `io.Reader` |
|
| 256 |
+func (r *Reader) Read(b []byte) (int, error) {
|
|
| 257 |
+ if len(b) <= r.buffered() {
|
|
| 258 |
+ x := copy(b, r.data[r.n:]) |
|
| 259 |
+ r.n += x |
|
| 260 |
+ return x, nil |
|
| 261 |
+ } |
|
| 262 |
+ r.more() |
|
| 263 |
+ if r.buffered() > 0 {
|
|
| 264 |
+ x := copy(b, r.data[r.n:]) |
|
| 265 |
+ r.n += x |
|
| 266 |
+ return x, nil |
|
| 267 |
+ } |
|
| 268 |
+ |
|
| 269 |
+ // io.Reader is supposed to return |
|
| 270 |
+ // 0 read bytes on error |
|
| 271 |
+ return 0, r.err() |
|
| 272 |
+} |
|
| 273 |
+ |
|
| 274 |
+// ReadFull attempts to read len(b) bytes into |
|
| 275 |
+// 'b'. It returns the number of bytes read into |
|
| 276 |
+// 'b', and an error if it does not return len(b). |
|
| 277 |
+// EOF is considered an unexpected error. |
|
| 278 |
+func (r *Reader) ReadFull(b []byte) (int, error) {
|
|
| 279 |
+ var x int |
|
| 280 |
+ l := len(b) |
|
| 281 |
+ for x < l {
|
|
| 282 |
+ if r.buffered() == 0 {
|
|
| 283 |
+ r.more() |
|
| 284 |
+ } |
|
| 285 |
+ c := copy(b[x:], r.data[r.n:]) |
|
| 286 |
+ x += c |
|
| 287 |
+ r.n += c |
|
| 288 |
+ if r.state != nil {
|
|
| 289 |
+ return x, r.noEOF() |
|
| 290 |
+ } |
|
| 291 |
+ } |
|
| 292 |
+ return x, nil |
|
| 293 |
+} |
|
| 294 |
+ |
|
| 295 |
+// ReadByte implements `io.ByteReader` |
|
| 296 |
+func (r *Reader) ReadByte() (byte, error) {
|
|
| 297 |
+ for r.buffered() < 1 && r.state == nil {
|
|
| 298 |
+ r.more() |
|
| 299 |
+ } |
|
| 300 |
+ if r.buffered() < 1 {
|
|
| 301 |
+ return 0, r.err() |
|
| 302 |
+ } |
|
| 303 |
+ b := r.data[r.n] |
|
| 304 |
+ r.n++ |
|
| 305 |
+ return b, nil |
|
| 306 |
+} |
|
| 307 |
+ |
|
| 308 |
+// WriteTo implements `io.WriterTo` |
|
| 309 |
+func (r *Reader) WriteTo(w io.Writer) (int64, error) {
|
|
| 310 |
+ var ( |
|
| 311 |
+ i int64 |
|
| 312 |
+ ii int |
|
| 313 |
+ err error |
|
| 314 |
+ ) |
|
| 315 |
+ // first, clear buffer |
|
| 316 |
+ if r.buffered() > 0 {
|
|
| 317 |
+ ii, err = w.Write(r.data[r.n:]) |
|
| 318 |
+ i += int64(ii) |
|
| 319 |
+ if err != nil {
|
|
| 320 |
+ return i, err |
|
| 321 |
+ } |
|
| 322 |
+ r.data = r.data[0:0] |
|
| 323 |
+ r.n = 0 |
|
| 324 |
+ } |
|
| 325 |
+ for r.state == nil {
|
|
| 326 |
+ // here we just do |
|
| 327 |
+ // 1:1 reads and writes |
|
| 328 |
+ r.more() |
|
| 329 |
+ if r.buffered() > 0 {
|
|
| 330 |
+ ii, err = w.Write(r.data) |
|
| 331 |
+ i += int64(ii) |
|
| 332 |
+ if err != nil {
|
|
| 333 |
+ return i, err |
|
| 334 |
+ } |
|
| 335 |
+ r.data = r.data[0:0] |
|
| 336 |
+ r.n = 0 |
|
| 337 |
+ } |
|
| 338 |
+ } |
|
| 339 |
+ if r.state != io.EOF {
|
|
| 340 |
+ return i, r.err() |
|
| 341 |
+ } |
|
| 342 |
+ return i, nil |
|
| 343 |
+} |
|
| 344 |
+ |
|
| 345 |
+func min(a int, b int) int {
|
|
| 346 |
+ if a < b {
|
|
| 347 |
+ return a |
|
| 348 |
+ } |
|
| 349 |
+ return b |
|
| 350 |
+} |
|
| 351 |
+ |
|
| 352 |
+func max(a int, b int) int {
|
|
| 353 |
+ if a < b {
|
|
| 354 |
+ return b |
|
| 355 |
+ } |
|
| 356 |
+ return a |
|
| 357 |
+} |
| 0 | 358 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,224 @@ |
| 0 |
+package fwd |
|
| 1 |
+ |
|
| 2 |
+import "io" |
|
| 3 |
+ |
|
| 4 |
+const ( |
|
| 5 |
+ // DefaultWriterSize is the |
|
| 6 |
+ // default write buffer size. |
|
| 7 |
+ DefaultWriterSize = 2048 |
|
| 8 |
+ |
|
| 9 |
+ minWriterSize = minReaderSize |
|
| 10 |
+) |
|
| 11 |
+ |
|
| 12 |
+// Writer is a buffered writer |
|
| 13 |
+type Writer struct {
|
|
| 14 |
+ w io.Writer // writer |
|
| 15 |
+ buf []byte // 0:len(buf) is bufered data |
|
| 16 |
+} |
|
| 17 |
+ |
|
| 18 |
+// NewWriter returns a new writer |
|
| 19 |
+// that writes to 'w' and has a buffer |
|
| 20 |
+// that is `DefaultWriterSize` bytes. |
|
| 21 |
+func NewWriter(w io.Writer) *Writer {
|
|
| 22 |
+ if wr, ok := w.(*Writer); ok {
|
|
| 23 |
+ return wr |
|
| 24 |
+ } |
|
| 25 |
+ return &Writer{
|
|
| 26 |
+ w: w, |
|
| 27 |
+ buf: make([]byte, 0, DefaultWriterSize), |
|
| 28 |
+ } |
|
| 29 |
+} |
|
| 30 |
+ |
|
| 31 |
+// NewWriterSize returns a new writer |
|
| 32 |
+// that writes to 'w' and has a buffer |
|
| 33 |
+// that is 'size' bytes. |
|
| 34 |
+func NewWriterSize(w io.Writer, size int) *Writer {
|
|
| 35 |
+ if wr, ok := w.(*Writer); ok && cap(wr.buf) >= size {
|
|
| 36 |
+ return wr |
|
| 37 |
+ } |
|
| 38 |
+ return &Writer{
|
|
| 39 |
+ w: w, |
|
| 40 |
+ buf: make([]byte, 0, max(size, minWriterSize)), |
|
| 41 |
+ } |
|
| 42 |
+} |
|
| 43 |
+ |
|
| 44 |
+// Buffered returns the number of buffered bytes |
|
| 45 |
+// in the reader. |
|
| 46 |
+func (w *Writer) Buffered() int { return len(w.buf) }
|
|
| 47 |
+ |
|
| 48 |
+// BufferSize returns the maximum size of the buffer. |
|
| 49 |
+func (w *Writer) BufferSize() int { return cap(w.buf) }
|
|
| 50 |
+ |
|
| 51 |
+// Flush flushes any buffered bytes |
|
| 52 |
+// to the underlying writer. |
|
| 53 |
+func (w *Writer) Flush() error {
|
|
| 54 |
+ l := len(w.buf) |
|
| 55 |
+ if l > 0 {
|
|
| 56 |
+ n, err := w.w.Write(w.buf) |
|
| 57 |
+ |
|
| 58 |
+ // if we didn't write the whole |
|
| 59 |
+ // thing, copy the unwritten |
|
| 60 |
+ // bytes to the beginnning of the |
|
| 61 |
+ // buffer. |
|
| 62 |
+ if n < l && n > 0 {
|
|
| 63 |
+ w.pushback(n) |
|
| 64 |
+ if err == nil {
|
|
| 65 |
+ err = io.ErrShortWrite |
|
| 66 |
+ } |
|
| 67 |
+ } |
|
| 68 |
+ if err != nil {
|
|
| 69 |
+ return err |
|
| 70 |
+ } |
|
| 71 |
+ w.buf = w.buf[:0] |
|
| 72 |
+ return nil |
|
| 73 |
+ } |
|
| 74 |
+ return nil |
|
| 75 |
+} |
|
| 76 |
+ |
|
| 77 |
+// Write implements `io.Writer` |
|
| 78 |
+func (w *Writer) Write(p []byte) (int, error) {
|
|
| 79 |
+ c, l, ln := cap(w.buf), len(w.buf), len(p) |
|
| 80 |
+ avail := c - l |
|
| 81 |
+ |
|
| 82 |
+ // requires flush |
|
| 83 |
+ if avail < ln {
|
|
| 84 |
+ if err := w.Flush(); err != nil {
|
|
| 85 |
+ return 0, err |
|
| 86 |
+ } |
|
| 87 |
+ l = len(w.buf) |
|
| 88 |
+ } |
|
| 89 |
+ // too big to fit in buffer; |
|
| 90 |
+ // write directly to w.w |
|
| 91 |
+ if c < ln {
|
|
| 92 |
+ return w.w.Write(p) |
|
| 93 |
+ } |
|
| 94 |
+ |
|
| 95 |
+ // grow buf slice; copy; return |
|
| 96 |
+ w.buf = w.buf[:l+ln] |
|
| 97 |
+ return copy(w.buf[l:], p), nil |
|
| 98 |
+} |
|
| 99 |
+ |
|
| 100 |
+// WriteString is analagous to Write, but it takes a string. |
|
| 101 |
+func (w *Writer) WriteString(s string) (int, error) {
|
|
| 102 |
+ c, l, ln := cap(w.buf), len(w.buf), len(s) |
|
| 103 |
+ avail := c - l |
|
| 104 |
+ |
|
| 105 |
+ // requires flush |
|
| 106 |
+ if avail < ln {
|
|
| 107 |
+ if err := w.Flush(); err != nil {
|
|
| 108 |
+ return 0, err |
|
| 109 |
+ } |
|
| 110 |
+ l = len(w.buf) |
|
| 111 |
+ } |
|
| 112 |
+ // too big to fit in buffer; |
|
| 113 |
+ // write directly to w.w |
|
| 114 |
+ // |
|
| 115 |
+ // yes, this is unsafe. *but* |
|
| 116 |
+ // io.Writer is not allowed |
|
| 117 |
+ // to mutate its input or |
|
| 118 |
+ // maintain a reference to it, |
|
| 119 |
+ // per the spec in package io. |
|
| 120 |
+ // |
|
| 121 |
+ // plus, if the string is really |
|
| 122 |
+ // too big to fit in the buffer, then |
|
| 123 |
+ // creating a copy to write it is |
|
| 124 |
+ // expensive (and, strictly speaking, |
|
| 125 |
+ // unnecessary) |
|
| 126 |
+ if c < ln {
|
|
| 127 |
+ return w.w.Write(unsafestr(s)) |
|
| 128 |
+ } |
|
| 129 |
+ |
|
| 130 |
+ // grow buf slice; copy; return |
|
| 131 |
+ w.buf = w.buf[:l+ln] |
|
| 132 |
+ return copy(w.buf[l:], s), nil |
|
| 133 |
+} |
|
| 134 |
+ |
|
| 135 |
+// WriteByte implements `io.ByteWriter` |
|
| 136 |
+func (w *Writer) WriteByte(b byte) error {
|
|
| 137 |
+ if len(w.buf) == cap(w.buf) {
|
|
| 138 |
+ if err := w.Flush(); err != nil {
|
|
| 139 |
+ return err |
|
| 140 |
+ } |
|
| 141 |
+ } |
|
| 142 |
+ w.buf = append(w.buf, b) |
|
| 143 |
+ return nil |
|
| 144 |
+} |
|
| 145 |
+ |
|
| 146 |
+// Next returns the next 'n' free bytes |
|
| 147 |
+// in the write buffer, flushing the writer |
|
| 148 |
+// as necessary. Next will return `io.ErrShortBuffer` |
|
| 149 |
+// if 'n' is greater than the size of the write buffer. |
|
| 150 |
+// Calls to 'next' increment the write position by |
|
| 151 |
+// the size of the returned buffer. |
|
| 152 |
+func (w *Writer) Next(n int) ([]byte, error) {
|
|
| 153 |
+ c, l := cap(w.buf), len(w.buf) |
|
| 154 |
+ if n > c {
|
|
| 155 |
+ return nil, io.ErrShortBuffer |
|
| 156 |
+ } |
|
| 157 |
+ avail := c - l |
|
| 158 |
+ if avail < n {
|
|
| 159 |
+ if err := w.Flush(); err != nil {
|
|
| 160 |
+ return nil, err |
|
| 161 |
+ } |
|
| 162 |
+ l = len(w.buf) |
|
| 163 |
+ } |
|
| 164 |
+ w.buf = w.buf[:l+n] |
|
| 165 |
+ return w.buf[l:], nil |
|
| 166 |
+} |
|
| 167 |
+ |
|
| 168 |
+// take the bytes from w.buf[n:len(w.buf)] |
|
| 169 |
+// and put them at the beginning of w.buf, |
|
| 170 |
+// and resize to the length of the copied segment. |
|
| 171 |
+func (w *Writer) pushback(n int) {
|
|
| 172 |
+ w.buf = w.buf[:copy(w.buf, w.buf[n:])] |
|
| 173 |
+} |
|
| 174 |
+ |
|
| 175 |
+// ReadFrom implements `io.ReaderFrom` |
|
| 176 |
+func (w *Writer) ReadFrom(r io.Reader) (int64, error) {
|
|
| 177 |
+ // anticipatory flush |
|
| 178 |
+ if err := w.Flush(); err != nil {
|
|
| 179 |
+ return 0, err |
|
| 180 |
+ } |
|
| 181 |
+ |
|
| 182 |
+ w.buf = w.buf[0:cap(w.buf)] // expand buffer |
|
| 183 |
+ |
|
| 184 |
+ var nn int64 // written |
|
| 185 |
+ var err error // error |
|
| 186 |
+ var x int // read |
|
| 187 |
+ |
|
| 188 |
+ // 1:1 reads and writes |
|
| 189 |
+ for err == nil {
|
|
| 190 |
+ x, err = r.Read(w.buf) |
|
| 191 |
+ if x > 0 {
|
|
| 192 |
+ n, werr := w.w.Write(w.buf[:x]) |
|
| 193 |
+ nn += int64(n) |
|
| 194 |
+ |
|
| 195 |
+ if err != nil {
|
|
| 196 |
+ if n < x && n > 0 {
|
|
| 197 |
+ w.pushback(n - x) |
|
| 198 |
+ } |
|
| 199 |
+ return nn, werr |
|
| 200 |
+ } |
|
| 201 |
+ if n < x {
|
|
| 202 |
+ w.pushback(n - x) |
|
| 203 |
+ return nn, io.ErrShortWrite |
|
| 204 |
+ } |
|
| 205 |
+ } else if err == nil {
|
|
| 206 |
+ err = io.ErrNoProgress |
|
| 207 |
+ break |
|
| 208 |
+ } |
|
| 209 |
+ } |
|
| 210 |
+ if err != io.EOF {
|
|
| 211 |
+ return nn, err |
|
| 212 |
+ } |
|
| 213 |
+ |
|
| 214 |
+ // we only clear here |
|
| 215 |
+ // because we are sure |
|
| 216 |
+ // the writes have |
|
| 217 |
+ // suceeded. otherwise, |
|
| 218 |
+ // we retain the data in case |
|
| 219 |
+ // future writes succeed. |
|
| 220 |
+ w.buf = w.buf[0:0] |
|
| 221 |
+ |
|
| 222 |
+ return nn, nil |
|
| 223 |
+} |
| 0 | 5 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,18 @@ |
| 0 |
+// +build !appengine |
|
| 1 |
+ |
|
| 2 |
+package fwd |
|
| 3 |
+ |
|
| 4 |
+import ( |
|
| 5 |
+ "reflect" |
|
| 6 |
+ "unsafe" |
|
| 7 |
+) |
|
| 8 |
+ |
|
| 9 |
+// unsafe cast string as []byte |
|
| 10 |
+func unsafestr(b string) []byte {
|
|
| 11 |
+ l := len(b) |
|
| 12 |
+ return *(*[]byte)(unsafe.Pointer(&reflect.SliceHeader{
|
|
| 13 |
+ Len: l, |
|
| 14 |
+ Cap: l, |
|
| 15 |
+ Data: (*reflect.StringHeader)(unsafe.Pointer(&b)).Data, |
|
| 16 |
+ })) |
|
| 17 |
+} |
| 0 | 18 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,38 @@ |
| 0 |
+package msgp |
|
| 1 |
+ |
|
| 2 |
+import ( |
|
| 3 |
+ "testing" |
|
| 4 |
+) |
|
| 5 |
+ |
|
| 6 |
+// EndlessReader is an io.Reader |
|
| 7 |
+// that loops over the same data |
|
| 8 |
+// endlessly. It is used for benchmarking. |
|
| 9 |
+type EndlessReader struct {
|
|
| 10 |
+ tb *testing.B |
|
| 11 |
+ data []byte |
|
| 12 |
+ offset int |
|
| 13 |
+} |
|
| 14 |
+ |
|
| 15 |
+// NewEndlessReader returns a new endless reader |
|
| 16 |
+func NewEndlessReader(b []byte, tb *testing.B) *EndlessReader {
|
|
| 17 |
+ return &EndlessReader{tb: tb, data: b, offset: 0}
|
|
| 18 |
+} |
|
| 19 |
+ |
|
| 20 |
+// Read implements io.Reader. In practice, it |
|
| 21 |
+// always returns (len(p), nil), although it |
|
| 22 |
+// fills the supplied slice while the benchmark |
|
| 23 |
+// timer is stopped. |
|
| 24 |
+func (c *EndlessReader) Read(p []byte) (int, error) {
|
|
| 25 |
+ c.tb.StopTimer() |
|
| 26 |
+ var n int |
|
| 27 |
+ l := len(p) |
|
| 28 |
+ m := len(c.data) |
|
| 29 |
+ for n < l {
|
|
| 30 |
+ nn := copy(p[n:], c.data[c.offset:]) |
|
| 31 |
+ n += nn |
|
| 32 |
+ c.offset += nn |
|
| 33 |
+ c.offset %= m |
|
| 34 |
+ } |
|
| 35 |
+ c.tb.StartTimer() |
|
| 36 |
+ return n, nil |
|
| 37 |
+} |
| 0 | 38 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,142 @@ |
| 0 |
+// This package is the support library for the msgp code generator (http://github.com/tinylib/msgp). |
|
| 1 |
+// |
|
| 2 |
+// This package defines the utilites used by the msgp code generator for encoding and decoding MessagePack |
|
| 3 |
+// from []byte and io.Reader/io.Writer types. Much of this package is devoted to helping the msgp code |
|
| 4 |
+// generator implement the Marshaler/Unmarshaler and Encodable/Decodable interfaces. |
|
| 5 |
+// |
|
| 6 |
+// This package defines four "families" of functions: |
|
| 7 |
+// - AppendXxxx() appends an object to a []byte in MessagePack encoding. |
|
| 8 |
+// - ReadXxxxBytes() reads an object from a []byte and returns the remaining bytes. |
|
| 9 |
+// - (*Writer).WriteXxxx() writes an object to the buffered *Writer type. |
|
| 10 |
+// - (*Reader).ReadXxxx() reads an object from a buffered *Reader type. |
|
| 11 |
+// |
|
| 12 |
+// Once a type has satisfied the `Encodable` and `Decodable` interfaces, |
|
| 13 |
+// it can be written and read from arbitrary `io.Writer`s and `io.Reader`s using |
|
| 14 |
+// msgp.Encode(io.Writer, msgp.Encodable) |
|
| 15 |
+// and |
|
| 16 |
+// msgp.Decode(io.Reader, msgp.Decodable) |
|
| 17 |
+// |
|
| 18 |
+// There are also methods for converting MessagePack to JSON without |
|
| 19 |
+// an explicit de-serialization step. |
|
| 20 |
+// |
|
| 21 |
+// For additional tips, tricks, and gotchas, please visit |
|
| 22 |
+// the wiki at http://github.com/tinylib/msgp |
|
| 23 |
+package msgp |
|
| 24 |
+ |
|
| 25 |
+const last4 = 0x0f |
|
| 26 |
+const first4 = 0xf0 |
|
| 27 |
+const last5 = 0x1f |
|
| 28 |
+const first3 = 0xe0 |
|
| 29 |
+const last7 = 0x7f |
|
| 30 |
+ |
|
| 31 |
+func isfixint(b byte) bool {
|
|
| 32 |
+ return b>>7 == 0 |
|
| 33 |
+} |
|
| 34 |
+ |
|
| 35 |
+func isnfixint(b byte) bool {
|
|
| 36 |
+ return b&first3 == mnfixint |
|
| 37 |
+} |
|
| 38 |
+ |
|
| 39 |
+func isfixmap(b byte) bool {
|
|
| 40 |
+ return b&first4 == mfixmap |
|
| 41 |
+} |
|
| 42 |
+ |
|
| 43 |
+func isfixarray(b byte) bool {
|
|
| 44 |
+ return b&first4 == mfixarray |
|
| 45 |
+} |
|
| 46 |
+ |
|
| 47 |
+func isfixstr(b byte) bool {
|
|
| 48 |
+ return b&first3 == mfixstr |
|
| 49 |
+} |
|
| 50 |
+ |
|
| 51 |
+func wfixint(u uint8) byte {
|
|
| 52 |
+ return u & last7 |
|
| 53 |
+} |
|
| 54 |
+ |
|
| 55 |
+func rfixint(b byte) uint8 {
|
|
| 56 |
+ return b |
|
| 57 |
+} |
|
| 58 |
+ |
|
| 59 |
+func wnfixint(i int8) byte {
|
|
| 60 |
+ return byte(i) | mnfixint |
|
| 61 |
+} |
|
| 62 |
+ |
|
| 63 |
+func rnfixint(b byte) int8 {
|
|
| 64 |
+ return int8(b) |
|
| 65 |
+} |
|
| 66 |
+ |
|
| 67 |
+func rfixmap(b byte) uint8 {
|
|
| 68 |
+ return b & last4 |
|
| 69 |
+} |
|
| 70 |
+ |
|
| 71 |
+func wfixmap(u uint8) byte {
|
|
| 72 |
+ return mfixmap | (u & last4) |
|
| 73 |
+} |
|
| 74 |
+ |
|
| 75 |
+func rfixstr(b byte) uint8 {
|
|
| 76 |
+ return b & last5 |
|
| 77 |
+} |
|
| 78 |
+ |
|
| 79 |
+func wfixstr(u uint8) byte {
|
|
| 80 |
+ return (u & last5) | mfixstr |
|
| 81 |
+} |
|
| 82 |
+ |
|
| 83 |
+func rfixarray(b byte) uint8 {
|
|
| 84 |
+ return (b & last4) |
|
| 85 |
+} |
|
| 86 |
+ |
|
| 87 |
+func wfixarray(u uint8) byte {
|
|
| 88 |
+ return (u & last4) | mfixarray |
|
| 89 |
+} |
|
| 90 |
+ |
|
| 91 |
+// These are all the byte |
|
| 92 |
+// prefixes defined by the |
|
| 93 |
+// msgpack standard |
|
| 94 |
+const ( |
|
| 95 |
+ // 0XXXXXXX |
|
| 96 |
+ mfixint uint8 = 0x00 |
|
| 97 |
+ |
|
| 98 |
+ // 111XXXXX |
|
| 99 |
+ mnfixint uint8 = 0xe0 |
|
| 100 |
+ |
|
| 101 |
+ // 1000XXXX |
|
| 102 |
+ mfixmap uint8 = 0x80 |
|
| 103 |
+ |
|
| 104 |
+ // 1001XXXX |
|
| 105 |
+ mfixarray uint8 = 0x90 |
|
| 106 |
+ |
|
| 107 |
+ // 101XXXXX |
|
| 108 |
+ mfixstr uint8 = 0xa0 |
|
| 109 |
+ |
|
| 110 |
+ mnil uint8 = 0xc0 |
|
| 111 |
+ mfalse uint8 = 0xc2 |
|
| 112 |
+ mtrue uint8 = 0xc3 |
|
| 113 |
+ mbin8 uint8 = 0xc4 |
|
| 114 |
+ mbin16 uint8 = 0xc5 |
|
| 115 |
+ mbin32 uint8 = 0xc6 |
|
| 116 |
+ mext8 uint8 = 0xc7 |
|
| 117 |
+ mext16 uint8 = 0xc8 |
|
| 118 |
+ mext32 uint8 = 0xc9 |
|
| 119 |
+ mfloat32 uint8 = 0xca |
|
| 120 |
+ mfloat64 uint8 = 0xcb |
|
| 121 |
+ muint8 uint8 = 0xcc |
|
| 122 |
+ muint16 uint8 = 0xcd |
|
| 123 |
+ muint32 uint8 = 0xce |
|
| 124 |
+ muint64 uint8 = 0xcf |
|
| 125 |
+ mint8 uint8 = 0xd0 |
|
| 126 |
+ mint16 uint8 = 0xd1 |
|
| 127 |
+ mint32 uint8 = 0xd2 |
|
| 128 |
+ mint64 uint8 = 0xd3 |
|
| 129 |
+ mfixext1 uint8 = 0xd4 |
|
| 130 |
+ mfixext2 uint8 = 0xd5 |
|
| 131 |
+ mfixext4 uint8 = 0xd6 |
|
| 132 |
+ mfixext8 uint8 = 0xd7 |
|
| 133 |
+ mfixext16 uint8 = 0xd8 |
|
| 134 |
+ mstr8 uint8 = 0xd9 |
|
| 135 |
+ mstr16 uint8 = 0xda |
|
| 136 |
+ mstr32 uint8 = 0xdb |
|
| 137 |
+ marray16 uint8 = 0xdc |
|
| 138 |
+ marray32 uint8 = 0xdd |
|
| 139 |
+ mmap16 uint8 = 0xde |
|
| 140 |
+ mmap32 uint8 = 0xdf |
|
| 141 |
+) |
| 0 | 142 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,241 @@ |
| 0 |
+package msgp |
|
| 1 |
+ |
|
| 2 |
+import ( |
|
| 3 |
+ "math" |
|
| 4 |
+) |
|
| 5 |
+ |
|
| 6 |
+// Locate returns a []byte pointing to the field |
|
| 7 |
+// in a messagepack map with the provided key. (The returned []byte |
|
| 8 |
+// points to a sub-slice of 'raw'; Locate does no allocations.) If the |
|
| 9 |
+// key doesn't exist in the map, a zero-length []byte will be returned. |
|
| 10 |
+func Locate(key string, raw []byte) []byte {
|
|
| 11 |
+ s, n := locate(raw, key) |
|
| 12 |
+ return raw[s:n] |
|
| 13 |
+} |
|
| 14 |
+ |
|
| 15 |
+// Replace takes a key ("key") in a messagepack map ("raw")
|
|
| 16 |
+// and replaces its value with the one provided and returns |
|
| 17 |
+// the new []byte. The returned []byte may point to the same |
|
| 18 |
+// memory as "raw". Replace makes no effort to evaluate the validity |
|
| 19 |
+// of the contents of 'val'. It may use up to the full capacity of 'raw.' |
|
| 20 |
+// Replace returns 'nil' if the field doesn't exist or if the object in 'raw' |
|
| 21 |
+// is not a map. |
|
| 22 |
+func Replace(key string, raw []byte, val []byte) []byte {
|
|
| 23 |
+ start, end := locate(raw, key) |
|
| 24 |
+ if start == end {
|
|
| 25 |
+ return nil |
|
| 26 |
+ } |
|
| 27 |
+ return replace(raw, start, end, val, true) |
|
| 28 |
+} |
|
| 29 |
+ |
|
| 30 |
+// CopyReplace works similarly to Replace except that the returned |
|
| 31 |
+// byte slice does not point to the same memory as 'raw'. CopyReplace |
|
| 32 |
+// returns 'nil' if the field doesn't exist or 'raw' isn't a map. |
|
| 33 |
+func CopyReplace(key string, raw []byte, val []byte) []byte {
|
|
| 34 |
+ start, end := locate(raw, key) |
|
| 35 |
+ if start == end {
|
|
| 36 |
+ return nil |
|
| 37 |
+ } |
|
| 38 |
+ return replace(raw, start, end, val, false) |
|
| 39 |
+} |
|
| 40 |
+ |
|
| 41 |
+// Remove removes a key-value pair from 'raw'. It returns |
|
| 42 |
+// 'raw' unchanged if the key didn't exist. |
|
| 43 |
+func Remove(key string, raw []byte) []byte {
|
|
| 44 |
+ start, end := locateKV(raw, key) |
|
| 45 |
+ if start == end {
|
|
| 46 |
+ return raw |
|
| 47 |
+ } |
|
| 48 |
+ raw = raw[:start+copy(raw[start:], raw[end:])] |
|
| 49 |
+ return resizeMap(raw, -1) |
|
| 50 |
+} |
|
| 51 |
+ |
|
| 52 |
+// HasKey returns whether the map in 'raw' has |
|
| 53 |
+// a field with key 'key' |
|
| 54 |
+func HasKey(key string, raw []byte) bool {
|
|
| 55 |
+ sz, bts, err := ReadMapHeaderBytes(raw) |
|
| 56 |
+ if err != nil {
|
|
| 57 |
+ return false |
|
| 58 |
+ } |
|
| 59 |
+ var field []byte |
|
| 60 |
+ for i := uint32(0); i < sz; i++ {
|
|
| 61 |
+ field, bts, err = ReadStringZC(bts) |
|
| 62 |
+ if err != nil {
|
|
| 63 |
+ return false |
|
| 64 |
+ } |
|
| 65 |
+ if UnsafeString(field) == key {
|
|
| 66 |
+ return true |
|
| 67 |
+ } |
|
| 68 |
+ } |
|
| 69 |
+ return false |
|
| 70 |
+} |
|
| 71 |
+ |
|
| 72 |
+func replace(raw []byte, start int, end int, val []byte, inplace bool) []byte {
|
|
| 73 |
+ ll := end - start // length of segment to replace |
|
| 74 |
+ lv := len(val) |
|
| 75 |
+ |
|
| 76 |
+ if inplace {
|
|
| 77 |
+ extra := lv - ll |
|
| 78 |
+ |
|
| 79 |
+ // fastest case: we're doing |
|
| 80 |
+ // a 1:1 replacement |
|
| 81 |
+ if extra == 0 {
|
|
| 82 |
+ copy(raw[start:], val) |
|
| 83 |
+ return raw |
|
| 84 |
+ |
|
| 85 |
+ } else if extra < 0 {
|
|
| 86 |
+ // 'val' smaller than replaced value |
|
| 87 |
+ // copy in place and shift back |
|
| 88 |
+ |
|
| 89 |
+ x := copy(raw[start:], val) |
|
| 90 |
+ y := copy(raw[start+x:], raw[end:]) |
|
| 91 |
+ return raw[:start+x+y] |
|
| 92 |
+ |
|
| 93 |
+ } else if extra < cap(raw)-len(raw) {
|
|
| 94 |
+ // 'val' less than (cap-len) extra bytes |
|
| 95 |
+ // copy in place and shift forward |
|
| 96 |
+ raw = raw[0 : len(raw)+extra] |
|
| 97 |
+ // shift end forward |
|
| 98 |
+ copy(raw[end+extra:], raw[end:]) |
|
| 99 |
+ copy(raw[start:], val) |
|
| 100 |
+ return raw |
|
| 101 |
+ } |
|
| 102 |
+ } |
|
| 103 |
+ |
|
| 104 |
+ // we have to allocate new space |
|
| 105 |
+ out := make([]byte, len(raw)+len(val)-ll) |
|
| 106 |
+ x := copy(out, raw[:start]) |
|
| 107 |
+ y := copy(out[x:], val) |
|
| 108 |
+ copy(out[x+y:], raw[end:]) |
|
| 109 |
+ return out |
|
| 110 |
+} |
|
| 111 |
+ |
|
| 112 |
+// locate does a naive O(n) search for the map key; returns start, end |
|
| 113 |
+// (returns 0,0 on error) |
|
| 114 |
+func locate(raw []byte, key string) (start int, end int) {
|
|
| 115 |
+ var ( |
|
| 116 |
+ sz uint32 |
|
| 117 |
+ bts []byte |
|
| 118 |
+ field []byte |
|
| 119 |
+ err error |
|
| 120 |
+ ) |
|
| 121 |
+ sz, bts, err = ReadMapHeaderBytes(raw) |
|
| 122 |
+ if err != nil {
|
|
| 123 |
+ return |
|
| 124 |
+ } |
|
| 125 |
+ |
|
| 126 |
+ // loop and locate field |
|
| 127 |
+ for i := uint32(0); i < sz; i++ {
|
|
| 128 |
+ field, bts, err = ReadStringZC(bts) |
|
| 129 |
+ if err != nil {
|
|
| 130 |
+ return 0, 0 |
|
| 131 |
+ } |
|
| 132 |
+ if UnsafeString(field) == key {
|
|
| 133 |
+ // start location |
|
| 134 |
+ l := len(raw) |
|
| 135 |
+ start = l - len(bts) |
|
| 136 |
+ bts, err = Skip(bts) |
|
| 137 |
+ if err != nil {
|
|
| 138 |
+ return 0, 0 |
|
| 139 |
+ } |
|
| 140 |
+ end = l - len(bts) |
|
| 141 |
+ return |
|
| 142 |
+ } |
|
| 143 |
+ bts, err = Skip(bts) |
|
| 144 |
+ if err != nil {
|
|
| 145 |
+ return 0, 0 |
|
| 146 |
+ } |
|
| 147 |
+ } |
|
| 148 |
+ return 0, 0 |
|
| 149 |
+} |
|
| 150 |
+ |
|
| 151 |
+// locate key AND value |
|
| 152 |
+func locateKV(raw []byte, key string) (start int, end int) {
|
|
| 153 |
+ var ( |
|
| 154 |
+ sz uint32 |
|
| 155 |
+ bts []byte |
|
| 156 |
+ field []byte |
|
| 157 |
+ err error |
|
| 158 |
+ ) |
|
| 159 |
+ sz, bts, err = ReadMapHeaderBytes(raw) |
|
| 160 |
+ if err != nil {
|
|
| 161 |
+ return 0, 0 |
|
| 162 |
+ } |
|
| 163 |
+ |
|
| 164 |
+ for i := uint32(0); i < sz; i++ {
|
|
| 165 |
+ tmp := len(bts) |
|
| 166 |
+ field, bts, err = ReadStringZC(bts) |
|
| 167 |
+ if err != nil {
|
|
| 168 |
+ return 0, 0 |
|
| 169 |
+ } |
|
| 170 |
+ if UnsafeString(field) == key {
|
|
| 171 |
+ start = len(raw) - tmp |
|
| 172 |
+ bts, err = Skip(bts) |
|
| 173 |
+ if err != nil {
|
|
| 174 |
+ return 0, 0 |
|
| 175 |
+ } |
|
| 176 |
+ end = len(raw) - len(bts) |
|
| 177 |
+ return |
|
| 178 |
+ } |
|
| 179 |
+ bts, err = Skip(bts) |
|
| 180 |
+ if err != nil {
|
|
| 181 |
+ return 0, 0 |
|
| 182 |
+ } |
|
| 183 |
+ } |
|
| 184 |
+ return 0, 0 |
|
| 185 |
+} |
|
| 186 |
+ |
|
| 187 |
+// delta is delta on map size |
|
| 188 |
+func resizeMap(raw []byte, delta int64) []byte {
|
|
| 189 |
+ var sz int64 |
|
| 190 |
+ switch raw[0] {
|
|
| 191 |
+ case mmap16: |
|
| 192 |
+ sz = int64(big.Uint16(raw[1:])) |
|
| 193 |
+ if sz+delta <= math.MaxUint16 {
|
|
| 194 |
+ big.PutUint16(raw[1:], uint16(sz+delta)) |
|
| 195 |
+ return raw |
|
| 196 |
+ } |
|
| 197 |
+ if cap(raw)-len(raw) >= 2 {
|
|
| 198 |
+ raw = raw[0 : len(raw)+2] |
|
| 199 |
+ copy(raw[5:], raw[3:]) |
|
| 200 |
+ big.PutUint32(raw[1:], uint32(sz+delta)) |
|
| 201 |
+ return raw |
|
| 202 |
+ } |
|
| 203 |
+ n := make([]byte, 0, len(raw)+5) |
|
| 204 |
+ n = AppendMapHeader(n, uint32(sz+delta)) |
|
| 205 |
+ return append(n, raw[3:]...) |
|
| 206 |
+ |
|
| 207 |
+ case mmap32: |
|
| 208 |
+ sz = int64(big.Uint32(raw[1:])) |
|
| 209 |
+ big.PutUint32(raw[1:], uint32(sz+delta)) |
|
| 210 |
+ return raw |
|
| 211 |
+ |
|
| 212 |
+ default: |
|
| 213 |
+ sz = int64(rfixmap(raw[0])) |
|
| 214 |
+ if sz+delta < 16 {
|
|
| 215 |
+ raw[0] = wfixmap(uint8(sz + delta)) |
|
| 216 |
+ return raw |
|
| 217 |
+ } else if sz+delta <= math.MaxUint16 {
|
|
| 218 |
+ if cap(raw)-len(raw) >= 2 {
|
|
| 219 |
+ raw = raw[0 : len(raw)+2] |
|
| 220 |
+ copy(raw[3:], raw[1:]) |
|
| 221 |
+ raw[0] = mmap16 |
|
| 222 |
+ big.PutUint16(raw[1:], uint16(sz+delta)) |
|
| 223 |
+ return raw |
|
| 224 |
+ } |
|
| 225 |
+ n := make([]byte, 0, len(raw)+5) |
|
| 226 |
+ n = AppendMapHeader(n, uint32(sz+delta)) |
|
| 227 |
+ return append(n, raw[1:]...) |
|
| 228 |
+ } |
|
| 229 |
+ if cap(raw)-len(raw) >= 4 {
|
|
| 230 |
+ raw = raw[0 : len(raw)+4] |
|
| 231 |
+ copy(raw[5:], raw[1:]) |
|
| 232 |
+ raw[0] = mmap32 |
|
| 233 |
+ big.PutUint32(raw[1:], uint32(sz+delta)) |
|
| 234 |
+ return raw |
|
| 235 |
+ } |
|
| 236 |
+ n := make([]byte, 0, len(raw)+5) |
|
| 237 |
+ n = AppendMapHeader(n, uint32(sz+delta)) |
|
| 238 |
+ return append(n, raw[1:]...) |
|
| 239 |
+ } |
|
| 240 |
+} |
| 0 | 241 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,99 @@ |
| 0 |
+package msgp |
|
| 1 |
+ |
|
| 2 |
+// size of every object on the wire, |
|
| 3 |
+// plus type information. gives us |
|
| 4 |
+// constant-time type information |
|
| 5 |
+// for traversing composite objects. |
|
| 6 |
+// |
|
| 7 |
+var sizes = [256]bytespec{
|
|
| 8 |
+ mnil: {size: 1, extra: constsize, typ: NilType},
|
|
| 9 |
+ mfalse: {size: 1, extra: constsize, typ: BoolType},
|
|
| 10 |
+ mtrue: {size: 1, extra: constsize, typ: BoolType},
|
|
| 11 |
+ mbin8: {size: 2, extra: extra8, typ: BinType},
|
|
| 12 |
+ mbin16: {size: 3, extra: extra16, typ: BinType},
|
|
| 13 |
+ mbin32: {size: 5, extra: extra32, typ: BinType},
|
|
| 14 |
+ mext8: {size: 3, extra: extra8, typ: ExtensionType},
|
|
| 15 |
+ mext16: {size: 4, extra: extra16, typ: ExtensionType},
|
|
| 16 |
+ mext32: {size: 6, extra: extra32, typ: ExtensionType},
|
|
| 17 |
+ mfloat32: {size: 5, extra: constsize, typ: Float32Type},
|
|
| 18 |
+ mfloat64: {size: 9, extra: constsize, typ: Float64Type},
|
|
| 19 |
+ muint8: {size: 2, extra: constsize, typ: UintType},
|
|
| 20 |
+ muint16: {size: 3, extra: constsize, typ: UintType},
|
|
| 21 |
+ muint32: {size: 5, extra: constsize, typ: UintType},
|
|
| 22 |
+ muint64: {size: 9, extra: constsize, typ: UintType},
|
|
| 23 |
+ mint8: {size: 2, extra: constsize, typ: IntType},
|
|
| 24 |
+ mint16: {size: 3, extra: constsize, typ: IntType},
|
|
| 25 |
+ mint32: {size: 5, extra: constsize, typ: IntType},
|
|
| 26 |
+ mint64: {size: 9, extra: constsize, typ: IntType},
|
|
| 27 |
+ mfixext1: {size: 3, extra: constsize, typ: ExtensionType},
|
|
| 28 |
+ mfixext2: {size: 4, extra: constsize, typ: ExtensionType},
|
|
| 29 |
+ mfixext4: {size: 6, extra: constsize, typ: ExtensionType},
|
|
| 30 |
+ mfixext8: {size: 10, extra: constsize, typ: ExtensionType},
|
|
| 31 |
+ mfixext16: {size: 18, extra: constsize, typ: ExtensionType},
|
|
| 32 |
+ mstr8: {size: 2, extra: extra8, typ: StrType},
|
|
| 33 |
+ mstr16: {size: 3, extra: extra16, typ: StrType},
|
|
| 34 |
+ mstr32: {size: 5, extra: extra32, typ: StrType},
|
|
| 35 |
+ marray16: {size: 3, extra: array16v, typ: ArrayType},
|
|
| 36 |
+ marray32: {size: 5, extra: array32v, typ: ArrayType},
|
|
| 37 |
+ mmap16: {size: 3, extra: map16v, typ: MapType},
|
|
| 38 |
+ mmap32: {size: 5, extra: map32v, typ: MapType},
|
|
| 39 |
+} |
|
| 40 |
+ |
|
| 41 |
+func init() {
|
|
| 42 |
+ // set up fixed fields |
|
| 43 |
+ |
|
| 44 |
+ // fixint |
|
| 45 |
+ for i := mfixint; i < 0x80; i++ {
|
|
| 46 |
+ sizes[i] = bytespec{size: 1, extra: constsize, typ: IntType}
|
|
| 47 |
+ } |
|
| 48 |
+ |
|
| 49 |
+ // nfixint |
|
| 50 |
+ for i := uint16(mnfixint); i < 0x100; i++ {
|
|
| 51 |
+ sizes[uint8(i)] = bytespec{size: 1, extra: constsize, typ: IntType}
|
|
| 52 |
+ } |
|
| 53 |
+ |
|
| 54 |
+ // fixstr gets constsize, |
|
| 55 |
+ // since the prefix yields the size |
|
| 56 |
+ for i := mfixstr; i < 0xc0; i++ {
|
|
| 57 |
+ sizes[i] = bytespec{size: 1 + rfixstr(i), extra: constsize, typ: StrType}
|
|
| 58 |
+ } |
|
| 59 |
+ |
|
| 60 |
+ // fixmap |
|
| 61 |
+ for i := mfixmap; i < 0x90; i++ {
|
|
| 62 |
+ sizes[i] = bytespec{size: 1, extra: varmode(2 * rfixmap(i)), typ: MapType}
|
|
| 63 |
+ } |
|
| 64 |
+ |
|
| 65 |
+ // fixarray |
|
| 66 |
+ for i := mfixarray; i < 0xa0; i++ {
|
|
| 67 |
+ sizes[i] = bytespec{size: 1, extra: varmode(rfixarray(i)), typ: ArrayType}
|
|
| 68 |
+ } |
|
| 69 |
+} |
|
| 70 |
+ |
|
| 71 |
+// a valid bytespsec has |
|
| 72 |
+// non-zero 'size' and |
|
| 73 |
+// non-zero 'typ' |
|
| 74 |
+type bytespec struct {
|
|
| 75 |
+ size uint8 // prefix size information |
|
| 76 |
+ extra varmode // extra size information |
|
| 77 |
+ typ Type // type |
|
| 78 |
+ _ byte // makes bytespec 4 bytes (yes, this matters) |
|
| 79 |
+} |
|
| 80 |
+ |
|
| 81 |
+// size mode |
|
| 82 |
+// if positive, # elements for composites |
|
| 83 |
+type varmode int8 |
|
| 84 |
+ |
|
| 85 |
+const ( |
|
| 86 |
+ constsize varmode = 0 // constant size (size bytes + uint8(varmode) objects) |
|
| 87 |
+ extra8 = -1 // has uint8(p[1]) extra bytes |
|
| 88 |
+ extra16 = -2 // has be16(p[1:]) extra bytes |
|
| 89 |
+ extra32 = -3 // has be32(p[1:]) extra bytes |
|
| 90 |
+ map16v = -4 // use map16 |
|
| 91 |
+ map32v = -5 // use map32 |
|
| 92 |
+ array16v = -6 // use array16 |
|
| 93 |
+ array32v = -7 // use array32 |
|
| 94 |
+) |
|
| 95 |
+ |
|
| 96 |
+func getType(v byte) Type {
|
|
| 97 |
+ return sizes[v].typ |
|
| 98 |
+} |
| 0 | 99 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,142 @@ |
| 0 |
+package msgp |
|
| 1 |
+ |
|
| 2 |
+import ( |
|
| 3 |
+ "fmt" |
|
| 4 |
+ "reflect" |
|
| 5 |
+) |
|
| 6 |
+ |
|
| 7 |
+var ( |
|
| 8 |
+ // ErrShortBytes is returned when the |
|
| 9 |
+ // slice being decoded is too short to |
|
| 10 |
+ // contain the contents of the message |
|
| 11 |
+ ErrShortBytes error = errShort{}
|
|
| 12 |
+ |
|
| 13 |
+ // this error is only returned |
|
| 14 |
+ // if we reach code that should |
|
| 15 |
+ // be unreachable |
|
| 16 |
+ fatal error = errFatal{}
|
|
| 17 |
+) |
|
| 18 |
+ |
|
| 19 |
+// Error is the interface satisfied |
|
| 20 |
+// by all of the errors that originate |
|
| 21 |
+// from this package. |
|
| 22 |
+type Error interface {
|
|
| 23 |
+ error |
|
| 24 |
+ |
|
| 25 |
+ // Resumable returns whether |
|
| 26 |
+ // or not the error means that |
|
| 27 |
+ // the stream of data is malformed |
|
| 28 |
+ // and the information is unrecoverable. |
|
| 29 |
+ Resumable() bool |
|
| 30 |
+} |
|
| 31 |
+ |
|
| 32 |
+type errShort struct{}
|
|
| 33 |
+ |
|
| 34 |
+func (e errShort) Error() string { return "msgp: too few bytes left to read object" }
|
|
| 35 |
+func (e errShort) Resumable() bool { return false }
|
|
| 36 |
+ |
|
| 37 |
+type errFatal struct{}
|
|
| 38 |
+ |
|
| 39 |
+func (f errFatal) Error() string { return "msgp: fatal decoding error (unreachable code)" }
|
|
| 40 |
+func (f errFatal) Resumable() bool { return false }
|
|
| 41 |
+ |
|
| 42 |
+// ArrayError is an error returned |
|
| 43 |
+// when decoding a fix-sized array |
|
| 44 |
+// of the wrong size |
|
| 45 |
+type ArrayError struct {
|
|
| 46 |
+ Wanted uint32 |
|
| 47 |
+ Got uint32 |
|
| 48 |
+} |
|
| 49 |
+ |
|
| 50 |
+// Error implements the error interface |
|
| 51 |
+func (a ArrayError) Error() string {
|
|
| 52 |
+ return fmt.Sprintf("msgp: wanted array of size %d; got %d", a.Wanted, a.Got)
|
|
| 53 |
+} |
|
| 54 |
+ |
|
| 55 |
+// Resumable is always 'true' for ArrayErrors |
|
| 56 |
+func (a ArrayError) Resumable() bool { return true }
|
|
| 57 |
+ |
|
| 58 |
+// IntOverflow is returned when a call |
|
| 59 |
+// would downcast an integer to a type |
|
| 60 |
+// with too few bits to hold its value. |
|
| 61 |
+type IntOverflow struct {
|
|
| 62 |
+ Value int64 // the value of the integer |
|
| 63 |
+ FailedBitsize int // the bit size that the int64 could not fit into |
|
| 64 |
+} |
|
| 65 |
+ |
|
| 66 |
+// Error implements the error interface |
|
| 67 |
+func (i IntOverflow) Error() string {
|
|
| 68 |
+ return fmt.Sprintf("msgp: %d overflows int%d", i.Value, i.FailedBitsize)
|
|
| 69 |
+} |
|
| 70 |
+ |
|
| 71 |
+// Resumable is always 'true' for overflows |
|
| 72 |
+func (i IntOverflow) Resumable() bool { return true }
|
|
| 73 |
+ |
|
| 74 |
+// UintOverflow is returned when a call |
|
| 75 |
+// would downcast an unsigned integer to a type |
|
| 76 |
+// with too few bits to hold its value |
|
| 77 |
+type UintOverflow struct {
|
|
| 78 |
+ Value uint64 // value of the uint |
|
| 79 |
+ FailedBitsize int // the bit size that couldn't fit the value |
|
| 80 |
+} |
|
| 81 |
+ |
|
| 82 |
+// Error implements the error interface |
|
| 83 |
+func (u UintOverflow) Error() string {
|
|
| 84 |
+ return fmt.Sprintf("msgp: %d overflows uint%d", u.Value, u.FailedBitsize)
|
|
| 85 |
+} |
|
| 86 |
+ |
|
| 87 |
+// Resumable is always 'true' for overflows |
|
| 88 |
+func (u UintOverflow) Resumable() bool { return true }
|
|
| 89 |
+ |
|
| 90 |
+// A TypeError is returned when a particular |
|
| 91 |
+// decoding method is unsuitable for decoding |
|
| 92 |
+// a particular MessagePack value. |
|
| 93 |
+type TypeError struct {
|
|
| 94 |
+ Method Type // Type expected by method |
|
| 95 |
+ Encoded Type // Type actually encoded |
|
| 96 |
+} |
|
| 97 |
+ |
|
| 98 |
+// Error implements the error interface |
|
| 99 |
+func (t TypeError) Error() string {
|
|
| 100 |
+ return fmt.Sprintf("msgp: attempted to decode type %q with method for %q", t.Encoded, t.Method)
|
|
| 101 |
+} |
|
| 102 |
+ |
|
| 103 |
+// Resumable returns 'true' for TypeErrors |
|
| 104 |
+func (t TypeError) Resumable() bool { return true }
|
|
| 105 |
+ |
|
| 106 |
+// returns either InvalidPrefixError or |
|
| 107 |
+// TypeError depending on whether or not |
|
| 108 |
+// the prefix is recognized |
|
| 109 |
+func badPrefix(want Type, lead byte) error {
|
|
| 110 |
+ t := sizes[lead].typ |
|
| 111 |
+ if t == InvalidType {
|
|
| 112 |
+ return InvalidPrefixError(lead) |
|
| 113 |
+ } |
|
| 114 |
+ return TypeError{Method: want, Encoded: t}
|
|
| 115 |
+} |
|
| 116 |
+ |
|
| 117 |
+// InvalidPrefixError is returned when a bad encoding |
|
| 118 |
+// uses a prefix that is not recognized in the MessagePack standard. |
|
| 119 |
+// This kind of error is unrecoverable. |
|
| 120 |
+type InvalidPrefixError byte |
|
| 121 |
+ |
|
| 122 |
+// Error implements the error interface |
|
| 123 |
+func (i InvalidPrefixError) Error() string {
|
|
| 124 |
+ return fmt.Sprintf("msgp: unrecognized type prefix 0x%x", byte(i))
|
|
| 125 |
+} |
|
| 126 |
+ |
|
| 127 |
+// Resumable returns 'false' for InvalidPrefixErrors |
|
| 128 |
+func (i InvalidPrefixError) Resumable() bool { return false }
|
|
| 129 |
+ |
|
| 130 |
+// ErrUnsupportedType is returned |
|
| 131 |
+// when a bad argument is supplied |
|
| 132 |
+// to a function that takes `interface{}`.
|
|
| 133 |
+type ErrUnsupportedType struct {
|
|
| 134 |
+ T reflect.Type |
|
| 135 |
+} |
|
| 136 |
+ |
|
| 137 |
+// Error implements error |
|
| 138 |
+func (e *ErrUnsupportedType) Error() string { return fmt.Sprintf("msgp: type %q not supported", e.T) }
|
|
| 139 |
+ |
|
| 140 |
+// Resumable returns 'true' for ErrUnsupportedType |
|
| 141 |
+func (e *ErrUnsupportedType) Resumable() bool { return true }
|
| 0 | 142 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,548 @@ |
| 0 |
+package msgp |
|
| 1 |
+ |
|
| 2 |
+import ( |
|
| 3 |
+ "fmt" |
|
| 4 |
+ "math" |
|
| 5 |
+) |
|
| 6 |
+ |
|
| 7 |
+const ( |
|
| 8 |
+ // Complex64Extension is the extension number used for complex64 |
|
| 9 |
+ Complex64Extension = 3 |
|
| 10 |
+ |
|
| 11 |
+ // Complex128Extension is the extension number used for complex128 |
|
| 12 |
+ Complex128Extension = 4 |
|
| 13 |
+ |
|
| 14 |
+ // TimeExtension is the extension number used for time.Time |
|
| 15 |
+ TimeExtension = 5 |
|
| 16 |
+) |
|
| 17 |
+ |
|
| 18 |
+// our extensions live here |
|
| 19 |
+var extensionReg = make(map[int8]func() Extension) |
|
| 20 |
+ |
|
| 21 |
+// RegisterExtension registers extensions so that they |
|
| 22 |
+// can be initialized and returned by methods that |
|
| 23 |
+// decode `interface{}` values. This should only
|
|
| 24 |
+// be called during initialization. f() should return |
|
| 25 |
+// a newly-initialized zero value of the extension. Keep in |
|
| 26 |
+// mind that extensions 3, 4, and 5 are reserved for |
|
| 27 |
+// complex64, complex128, and time.Time, respectively, |
|
| 28 |
+// and that MessagePack reserves extension types from -127 to -1. |
|
| 29 |
+// |
|
| 30 |
+// For example, if you wanted to register a user-defined struct: |
|
| 31 |
+// |
|
| 32 |
+// msgp.RegisterExtension(10, func() msgp.Extension { &MyExtension{} })
|
|
| 33 |
+// |
|
| 34 |
+// RegisterExtension will panic if you call it multiple times |
|
| 35 |
+// with the same 'typ' argument, or if you use a reserved |
|
| 36 |
+// type (3, 4, or 5). |
|
| 37 |
+func RegisterExtension(typ int8, f func() Extension) {
|
|
| 38 |
+ switch typ {
|
|
| 39 |
+ case Complex64Extension, Complex128Extension, TimeExtension: |
|
| 40 |
+ panic(fmt.Sprint("msgp: forbidden extension type:", typ))
|
|
| 41 |
+ } |
|
| 42 |
+ if _, ok := extensionReg[typ]; ok {
|
|
| 43 |
+ panic(fmt.Sprint("msgp: RegisterExtension() called with typ", typ, "more than once"))
|
|
| 44 |
+ } |
|
| 45 |
+ extensionReg[typ] = f |
|
| 46 |
+} |
|
| 47 |
+ |
|
| 48 |
+// ExtensionTypeError is an error type returned |
|
| 49 |
+// when there is a mis-match between an extension type |
|
| 50 |
+// and the type encoded on the wire |
|
| 51 |
+type ExtensionTypeError struct {
|
|
| 52 |
+ Got int8 |
|
| 53 |
+ Want int8 |
|
| 54 |
+} |
|
| 55 |
+ |
|
| 56 |
+// Error implements the error interface |
|
| 57 |
+func (e ExtensionTypeError) Error() string {
|
|
| 58 |
+ return fmt.Sprintf("msgp: error decoding extension: wanted type %d; got type %d", e.Want, e.Got)
|
|
| 59 |
+} |
|
| 60 |
+ |
|
| 61 |
+// Resumable returns 'true' for ExtensionTypeErrors |
|
| 62 |
+func (e ExtensionTypeError) Resumable() bool { return true }
|
|
| 63 |
+ |
|
| 64 |
+func errExt(got int8, wanted int8) error {
|
|
| 65 |
+ return ExtensionTypeError{Got: got, Want: wanted}
|
|
| 66 |
+} |
|
| 67 |
+ |
|
| 68 |
+// Extension is the interface fulfilled |
|
| 69 |
+// by types that want to define their |
|
| 70 |
+// own binary encoding. |
|
| 71 |
+type Extension interface {
|
|
| 72 |
+ // ExtensionType should return |
|
| 73 |
+ // a int8 that identifies the concrete |
|
| 74 |
+ // type of the extension. (Types <0 are |
|
| 75 |
+ // officially reserved by the MessagePack |
|
| 76 |
+ // specifications.) |
|
| 77 |
+ ExtensionType() int8 |
|
| 78 |
+ |
|
| 79 |
+ // Len should return the length |
|
| 80 |
+ // of the data to be encoded |
|
| 81 |
+ Len() int |
|
| 82 |
+ |
|
| 83 |
+ // MarshalBinaryTo should copy |
|
| 84 |
+ // the data into the supplied slice, |
|
| 85 |
+ // assuming that the slice has length Len() |
|
| 86 |
+ MarshalBinaryTo([]byte) error |
|
| 87 |
+ |
|
| 88 |
+ UnmarshalBinary([]byte) error |
|
| 89 |
+} |
|
| 90 |
+ |
|
| 91 |
+// RawExtension implements the Extension interface |
|
| 92 |
+type RawExtension struct {
|
|
| 93 |
+ Data []byte |
|
| 94 |
+ Type int8 |
|
| 95 |
+} |
|
| 96 |
+ |
|
| 97 |
+// ExtensionType implements Extension.ExtensionType, and returns r.Type |
|
| 98 |
+func (r *RawExtension) ExtensionType() int8 { return r.Type }
|
|
| 99 |
+ |
|
| 100 |
+// Len implements Extension.Len, and returns len(r.Data) |
|
| 101 |
+func (r *RawExtension) Len() int { return len(r.Data) }
|
|
| 102 |
+ |
|
| 103 |
+// MarshalBinaryTo implements Extension.MarshalBinaryTo, |
|
| 104 |
+// and returns a copy of r.Data |
|
| 105 |
+func (r *RawExtension) MarshalBinaryTo(d []byte) error {
|
|
| 106 |
+ copy(d, r.Data) |
|
| 107 |
+ return nil |
|
| 108 |
+} |
|
| 109 |
+ |
|
| 110 |
+// UnmarshalBinary implements Extension.UnmarshalBinary, |
|
| 111 |
+// and sets r.Data to the contents of the provided slice |
|
| 112 |
+func (r *RawExtension) UnmarshalBinary(b []byte) error {
|
|
| 113 |
+ if cap(r.Data) >= len(b) {
|
|
| 114 |
+ r.Data = r.Data[0:len(b)] |
|
| 115 |
+ } else {
|
|
| 116 |
+ r.Data = make([]byte, len(b)) |
|
| 117 |
+ } |
|
| 118 |
+ copy(r.Data, b) |
|
| 119 |
+ return nil |
|
| 120 |
+} |
|
| 121 |
+ |
|
| 122 |
+// WriteExtension writes an extension type to the writer |
|
| 123 |
+func (mw *Writer) WriteExtension(e Extension) error {
|
|
| 124 |
+ l := e.Len() |
|
| 125 |
+ var err error |
|
| 126 |
+ switch l {
|
|
| 127 |
+ case 0: |
|
| 128 |
+ o, err := mw.require(3) |
|
| 129 |
+ if err != nil {
|
|
| 130 |
+ return err |
|
| 131 |
+ } |
|
| 132 |
+ mw.buf[o] = mext8 |
|
| 133 |
+ mw.buf[o+1] = 0 |
|
| 134 |
+ mw.buf[o+2] = byte(e.ExtensionType()) |
|
| 135 |
+ case 1: |
|
| 136 |
+ o, err := mw.require(2) |
|
| 137 |
+ if err != nil {
|
|
| 138 |
+ return err |
|
| 139 |
+ } |
|
| 140 |
+ mw.buf[o] = mfixext1 |
|
| 141 |
+ mw.buf[o+1] = byte(e.ExtensionType()) |
|
| 142 |
+ case 2: |
|
| 143 |
+ o, err := mw.require(2) |
|
| 144 |
+ if err != nil {
|
|
| 145 |
+ return err |
|
| 146 |
+ } |
|
| 147 |
+ mw.buf[o] = mfixext2 |
|
| 148 |
+ mw.buf[o+1] = byte(e.ExtensionType()) |
|
| 149 |
+ case 4: |
|
| 150 |
+ o, err := mw.require(2) |
|
| 151 |
+ if err != nil {
|
|
| 152 |
+ return err |
|
| 153 |
+ } |
|
| 154 |
+ mw.buf[o] = mfixext4 |
|
| 155 |
+ mw.buf[o+1] = byte(e.ExtensionType()) |
|
| 156 |
+ case 8: |
|
| 157 |
+ o, err := mw.require(2) |
|
| 158 |
+ if err != nil {
|
|
| 159 |
+ return err |
|
| 160 |
+ } |
|
| 161 |
+ mw.buf[o] = mfixext8 |
|
| 162 |
+ mw.buf[o+1] = byte(e.ExtensionType()) |
|
| 163 |
+ case 16: |
|
| 164 |
+ o, err := mw.require(2) |
|
| 165 |
+ if err != nil {
|
|
| 166 |
+ return err |
|
| 167 |
+ } |
|
| 168 |
+ mw.buf[o] = mfixext16 |
|
| 169 |
+ mw.buf[o+1] = byte(e.ExtensionType()) |
|
| 170 |
+ default: |
|
| 171 |
+ switch {
|
|
| 172 |
+ case l < math.MaxUint8: |
|
| 173 |
+ o, err := mw.require(3) |
|
| 174 |
+ if err != nil {
|
|
| 175 |
+ return err |
|
| 176 |
+ } |
|
| 177 |
+ mw.buf[o] = mext8 |
|
| 178 |
+ mw.buf[o+1] = byte(uint8(l)) |
|
| 179 |
+ mw.buf[o+2] = byte(e.ExtensionType()) |
|
| 180 |
+ case l < math.MaxUint16: |
|
| 181 |
+ o, err := mw.require(4) |
|
| 182 |
+ if err != nil {
|
|
| 183 |
+ return err |
|
| 184 |
+ } |
|
| 185 |
+ mw.buf[o] = mext16 |
|
| 186 |
+ big.PutUint16(mw.buf[o+1:], uint16(l)) |
|
| 187 |
+ mw.buf[o+3] = byte(e.ExtensionType()) |
|
| 188 |
+ default: |
|
| 189 |
+ o, err := mw.require(6) |
|
| 190 |
+ if err != nil {
|
|
| 191 |
+ return err |
|
| 192 |
+ } |
|
| 193 |
+ mw.buf[o] = mext32 |
|
| 194 |
+ big.PutUint32(mw.buf[o+1:], uint32(l)) |
|
| 195 |
+ mw.buf[o+5] = byte(e.ExtensionType()) |
|
| 196 |
+ } |
|
| 197 |
+ } |
|
| 198 |
+ // we can only write directly to the |
|
| 199 |
+ // buffer if we're sure that it |
|
| 200 |
+ // fits the object |
|
| 201 |
+ if l <= mw.bufsize() {
|
|
| 202 |
+ o, err := mw.require(l) |
|
| 203 |
+ if err != nil {
|
|
| 204 |
+ return err |
|
| 205 |
+ } |
|
| 206 |
+ return e.MarshalBinaryTo(mw.buf[o:]) |
|
| 207 |
+ } |
|
| 208 |
+ // here we create a new buffer |
|
| 209 |
+ // just large enough for the body |
|
| 210 |
+ // and save it as the write buffer |
|
| 211 |
+ err = mw.flush() |
|
| 212 |
+ if err != nil {
|
|
| 213 |
+ return err |
|
| 214 |
+ } |
|
| 215 |
+ buf := make([]byte, l) |
|
| 216 |
+ err = e.MarshalBinaryTo(buf) |
|
| 217 |
+ if err != nil {
|
|
| 218 |
+ return err |
|
| 219 |
+ } |
|
| 220 |
+ mw.buf = buf |
|
| 221 |
+ mw.wloc = l |
|
| 222 |
+ return nil |
|
| 223 |
+} |
|
| 224 |
+ |
|
| 225 |
+// peek at the extension type, assuming the next |
|
| 226 |
+// kind to be read is Extension |
|
| 227 |
+func (m *Reader) peekExtensionType() (int8, error) {
|
|
| 228 |
+ p, err := m.r.Peek(2) |
|
| 229 |
+ if err != nil {
|
|
| 230 |
+ return 0, err |
|
| 231 |
+ } |
|
| 232 |
+ spec := sizes[p[0]] |
|
| 233 |
+ if spec.typ != ExtensionType {
|
|
| 234 |
+ return 0, badPrefix(ExtensionType, p[0]) |
|
| 235 |
+ } |
|
| 236 |
+ if spec.extra == constsize {
|
|
| 237 |
+ return int8(p[1]), nil |
|
| 238 |
+ } |
|
| 239 |
+ size := spec.size |
|
| 240 |
+ p, err = m.r.Peek(int(size)) |
|
| 241 |
+ if err != nil {
|
|
| 242 |
+ return 0, err |
|
| 243 |
+ } |
|
| 244 |
+ return int8(p[size-1]), nil |
|
| 245 |
+} |
|
| 246 |
+ |
|
| 247 |
+// peekExtension peeks at the extension encoding type |
|
| 248 |
+// (must guarantee at least 1 byte in 'b') |
|
| 249 |
+func peekExtension(b []byte) (int8, error) {
|
|
| 250 |
+ spec := sizes[b[0]] |
|
| 251 |
+ size := spec.size |
|
| 252 |
+ if spec.typ != ExtensionType {
|
|
| 253 |
+ return 0, badPrefix(ExtensionType, b[0]) |
|
| 254 |
+ } |
|
| 255 |
+ if len(b) < int(size) {
|
|
| 256 |
+ return 0, ErrShortBytes |
|
| 257 |
+ } |
|
| 258 |
+ // for fixed extensions, |
|
| 259 |
+ // the type information is in |
|
| 260 |
+ // the second byte |
|
| 261 |
+ if spec.extra == constsize {
|
|
| 262 |
+ return int8(b[1]), nil |
|
| 263 |
+ } |
|
| 264 |
+ // otherwise, it's in the last |
|
| 265 |
+ // part of the prefix |
|
| 266 |
+ return int8(b[size-1]), nil |
|
| 267 |
+} |
|
| 268 |
+ |
|
| 269 |
+// ReadExtension reads the next object from the reader |
|
| 270 |
+// as an extension. ReadExtension will fail if the next |
|
| 271 |
+// object in the stream is not an extension, or if |
|
| 272 |
+// e.Type() is not the same as the wire type. |
|
| 273 |
+func (m *Reader) ReadExtension(e Extension) (err error) {
|
|
| 274 |
+ var p []byte |
|
| 275 |
+ p, err = m.r.Peek(2) |
|
| 276 |
+ if err != nil {
|
|
| 277 |
+ return |
|
| 278 |
+ } |
|
| 279 |
+ lead := p[0] |
|
| 280 |
+ var read int |
|
| 281 |
+ var off int |
|
| 282 |
+ switch lead {
|
|
| 283 |
+ case mfixext1: |
|
| 284 |
+ if int8(p[1]) != e.ExtensionType() {
|
|
| 285 |
+ err = errExt(int8(p[1]), e.ExtensionType()) |
|
| 286 |
+ return |
|
| 287 |
+ } |
|
| 288 |
+ p, err = m.r.Peek(3) |
|
| 289 |
+ if err != nil {
|
|
| 290 |
+ return |
|
| 291 |
+ } |
|
| 292 |
+ err = e.UnmarshalBinary(p[2:]) |
|
| 293 |
+ if err == nil {
|
|
| 294 |
+ _, err = m.r.Skip(3) |
|
| 295 |
+ } |
|
| 296 |
+ return |
|
| 297 |
+ |
|
| 298 |
+ case mfixext2: |
|
| 299 |
+ if int8(p[1]) != e.ExtensionType() {
|
|
| 300 |
+ err = errExt(int8(p[1]), e.ExtensionType()) |
|
| 301 |
+ return |
|
| 302 |
+ } |
|
| 303 |
+ p, err = m.r.Peek(4) |
|
| 304 |
+ if err != nil {
|
|
| 305 |
+ return |
|
| 306 |
+ } |
|
| 307 |
+ err = e.UnmarshalBinary(p[2:]) |
|
| 308 |
+ if err == nil {
|
|
| 309 |
+ _, err = m.r.Skip(4) |
|
| 310 |
+ } |
|
| 311 |
+ return |
|
| 312 |
+ |
|
| 313 |
+ case mfixext4: |
|
| 314 |
+ if int8(p[1]) != e.ExtensionType() {
|
|
| 315 |
+ err = errExt(int8(p[1]), e.ExtensionType()) |
|
| 316 |
+ return |
|
| 317 |
+ } |
|
| 318 |
+ p, err = m.r.Peek(6) |
|
| 319 |
+ if err != nil {
|
|
| 320 |
+ return |
|
| 321 |
+ } |
|
| 322 |
+ err = e.UnmarshalBinary(p[2:]) |
|
| 323 |
+ if err == nil {
|
|
| 324 |
+ _, err = m.r.Skip(6) |
|
| 325 |
+ } |
|
| 326 |
+ return |
|
| 327 |
+ |
|
| 328 |
+ case mfixext8: |
|
| 329 |
+ if int8(p[1]) != e.ExtensionType() {
|
|
| 330 |
+ err = errExt(int8(p[1]), e.ExtensionType()) |
|
| 331 |
+ return |
|
| 332 |
+ } |
|
| 333 |
+ p, err = m.r.Peek(10) |
|
| 334 |
+ if err != nil {
|
|
| 335 |
+ return |
|
| 336 |
+ } |
|
| 337 |
+ err = e.UnmarshalBinary(p[2:]) |
|
| 338 |
+ if err == nil {
|
|
| 339 |
+ _, err = m.r.Skip(10) |
|
| 340 |
+ } |
|
| 341 |
+ return |
|
| 342 |
+ |
|
| 343 |
+ case mfixext16: |
|
| 344 |
+ if int8(p[1]) != e.ExtensionType() {
|
|
| 345 |
+ err = errExt(int8(p[1]), e.ExtensionType()) |
|
| 346 |
+ return |
|
| 347 |
+ } |
|
| 348 |
+ p, err = m.r.Peek(18) |
|
| 349 |
+ if err != nil {
|
|
| 350 |
+ return |
|
| 351 |
+ } |
|
| 352 |
+ err = e.UnmarshalBinary(p[2:]) |
|
| 353 |
+ if err == nil {
|
|
| 354 |
+ _, err = m.r.Skip(18) |
|
| 355 |
+ } |
|
| 356 |
+ return |
|
| 357 |
+ |
|
| 358 |
+ case mext8: |
|
| 359 |
+ p, err = m.r.Peek(3) |
|
| 360 |
+ if err != nil {
|
|
| 361 |
+ return |
|
| 362 |
+ } |
|
| 363 |
+ if int8(p[2]) != e.ExtensionType() {
|
|
| 364 |
+ err = errExt(int8(p[2]), e.ExtensionType()) |
|
| 365 |
+ return |
|
| 366 |
+ } |
|
| 367 |
+ read = int(uint8(p[1])) |
|
| 368 |
+ off = 3 |
|
| 369 |
+ |
|
| 370 |
+ case mext16: |
|
| 371 |
+ p, err = m.r.Peek(4) |
|
| 372 |
+ if err != nil {
|
|
| 373 |
+ return |
|
| 374 |
+ } |
|
| 375 |
+ if int8(p[3]) != e.ExtensionType() {
|
|
| 376 |
+ err = errExt(int8(p[3]), e.ExtensionType()) |
|
| 377 |
+ return |
|
| 378 |
+ } |
|
| 379 |
+ read = int(big.Uint16(p[1:])) |
|
| 380 |
+ off = 4 |
|
| 381 |
+ |
|
| 382 |
+ case mext32: |
|
| 383 |
+ p, err = m.r.Peek(6) |
|
| 384 |
+ if err != nil {
|
|
| 385 |
+ return |
|
| 386 |
+ } |
|
| 387 |
+ if int8(p[5]) != e.ExtensionType() {
|
|
| 388 |
+ err = errExt(int8(p[5]), e.ExtensionType()) |
|
| 389 |
+ return |
|
| 390 |
+ } |
|
| 391 |
+ read = int(big.Uint32(p[1:])) |
|
| 392 |
+ off = 6 |
|
| 393 |
+ |
|
| 394 |
+ default: |
|
| 395 |
+ err = badPrefix(ExtensionType, lead) |
|
| 396 |
+ return |
|
| 397 |
+ } |
|
| 398 |
+ |
|
| 399 |
+ p, err = m.r.Peek(read + off) |
|
| 400 |
+ if err != nil {
|
|
| 401 |
+ return |
|
| 402 |
+ } |
|
| 403 |
+ err = e.UnmarshalBinary(p[off:]) |
|
| 404 |
+ if err == nil {
|
|
| 405 |
+ _, err = m.r.Skip(read + off) |
|
| 406 |
+ } |
|
| 407 |
+ return |
|
| 408 |
+} |
|
| 409 |
+ |
|
| 410 |
+// AppendExtension appends a MessagePack extension to the provided slice |
|
| 411 |
+func AppendExtension(b []byte, e Extension) ([]byte, error) {
|
|
| 412 |
+ l := e.Len() |
|
| 413 |
+ var o []byte |
|
| 414 |
+ var n int |
|
| 415 |
+ switch l {
|
|
| 416 |
+ case 0: |
|
| 417 |
+ o, n = ensure(b, 3) |
|
| 418 |
+ o[n] = mext8 |
|
| 419 |
+ o[n+1] = 0 |
|
| 420 |
+ o[n+2] = byte(e.ExtensionType()) |
|
| 421 |
+ return o[:n+3], nil |
|
| 422 |
+ case 1: |
|
| 423 |
+ o, n = ensure(b, 3) |
|
| 424 |
+ o[n] = mfixext1 |
|
| 425 |
+ o[n+1] = byte(e.ExtensionType()) |
|
| 426 |
+ n += 2 |
|
| 427 |
+ case 2: |
|
| 428 |
+ o, n = ensure(b, 4) |
|
| 429 |
+ o[n] = mfixext2 |
|
| 430 |
+ o[n+1] = byte(e.ExtensionType()) |
|
| 431 |
+ n += 2 |
|
| 432 |
+ case 4: |
|
| 433 |
+ o, n = ensure(b, 6) |
|
| 434 |
+ o[n] = mfixext4 |
|
| 435 |
+ o[n+1] = byte(e.ExtensionType()) |
|
| 436 |
+ n += 2 |
|
| 437 |
+ case 8: |
|
| 438 |
+ o, n = ensure(b, 10) |
|
| 439 |
+ o[n] = mfixext8 |
|
| 440 |
+ o[n+1] = byte(e.ExtensionType()) |
|
| 441 |
+ n += 2 |
|
| 442 |
+ case 16: |
|
| 443 |
+ o, n = ensure(b, 18) |
|
| 444 |
+ o[n] = mfixext16 |
|
| 445 |
+ o[n+1] = byte(e.ExtensionType()) |
|
| 446 |
+ n += 2 |
|
| 447 |
+ } |
|
| 448 |
+ switch {
|
|
| 449 |
+ case l < math.MaxUint8: |
|
| 450 |
+ o, n = ensure(b, l+3) |
|
| 451 |
+ o[n] = mext8 |
|
| 452 |
+ o[n+1] = byte(uint8(l)) |
|
| 453 |
+ o[n+2] = byte(e.ExtensionType()) |
|
| 454 |
+ n += 3 |
|
| 455 |
+ case l < math.MaxUint16: |
|
| 456 |
+ o, n = ensure(b, l+4) |
|
| 457 |
+ o[n] = mext16 |
|
| 458 |
+ big.PutUint16(o[n+1:], uint16(l)) |
|
| 459 |
+ o[n+3] = byte(e.ExtensionType()) |
|
| 460 |
+ n += 4 |
|
| 461 |
+ default: |
|
| 462 |
+ o, n = ensure(b, l+6) |
|
| 463 |
+ o[n] = mext32 |
|
| 464 |
+ big.PutUint32(o[n+1:], uint32(l)) |
|
| 465 |
+ o[n+5] = byte(e.ExtensionType()) |
|
| 466 |
+ n += 6 |
|
| 467 |
+ } |
|
| 468 |
+ return o, e.MarshalBinaryTo(o[n:]) |
|
| 469 |
+} |
|
| 470 |
+ |
|
| 471 |
+// ReadExtensionBytes reads an extension from 'b' into 'e' |
|
| 472 |
+// and returns any remaining bytes. |
|
| 473 |
+// Possible errors: |
|
| 474 |
+// - ErrShortBytes ('b' not long enough)
|
|
| 475 |
+// - ExtensionTypeErorr{} (wire type not the same as e.Type())
|
|
| 476 |
+// - TypeErorr{} (next object not an extension)
|
|
| 477 |
+// - InvalidPrefixError |
|
| 478 |
+// - An umarshal error returned from e.UnmarshalBinary |
|
| 479 |
+func ReadExtensionBytes(b []byte, e Extension) ([]byte, error) {
|
|
| 480 |
+ l := len(b) |
|
| 481 |
+ if l < 3 {
|
|
| 482 |
+ return b, ErrShortBytes |
|
| 483 |
+ } |
|
| 484 |
+ lead := b[0] |
|
| 485 |
+ var ( |
|
| 486 |
+ sz int // size of 'data' |
|
| 487 |
+ off int // offset of 'data' |
|
| 488 |
+ typ int8 |
|
| 489 |
+ ) |
|
| 490 |
+ switch lead {
|
|
| 491 |
+ case mfixext1: |
|
| 492 |
+ typ = int8(b[1]) |
|
| 493 |
+ sz = 1 |
|
| 494 |
+ off = 2 |
|
| 495 |
+ case mfixext2: |
|
| 496 |
+ typ = int8(b[1]) |
|
| 497 |
+ sz = 2 |
|
| 498 |
+ off = 2 |
|
| 499 |
+ case mfixext4: |
|
| 500 |
+ typ = int8(b[1]) |
|
| 501 |
+ sz = 4 |
|
| 502 |
+ off = 2 |
|
| 503 |
+ case mfixext8: |
|
| 504 |
+ typ = int8(b[1]) |
|
| 505 |
+ sz = 8 |
|
| 506 |
+ off = 2 |
|
| 507 |
+ case mfixext16: |
|
| 508 |
+ typ = int8(b[1]) |
|
| 509 |
+ sz = 16 |
|
| 510 |
+ off = 2 |
|
| 511 |
+ case mext8: |
|
| 512 |
+ sz = int(uint8(b[1])) |
|
| 513 |
+ typ = int8(b[2]) |
|
| 514 |
+ off = 3 |
|
| 515 |
+ if sz == 0 {
|
|
| 516 |
+ return b[3:], e.UnmarshalBinary(b[3:3]) |
|
| 517 |
+ } |
|
| 518 |
+ case mext16: |
|
| 519 |
+ if l < 4 {
|
|
| 520 |
+ return b, ErrShortBytes |
|
| 521 |
+ } |
|
| 522 |
+ sz = int(big.Uint16(b[1:])) |
|
| 523 |
+ typ = int8(b[3]) |
|
| 524 |
+ off = 4 |
|
| 525 |
+ case mext32: |
|
| 526 |
+ if l < 6 {
|
|
| 527 |
+ return b, ErrShortBytes |
|
| 528 |
+ } |
|
| 529 |
+ sz = int(big.Uint32(b[1:])) |
|
| 530 |
+ typ = int8(b[5]) |
|
| 531 |
+ off = 6 |
|
| 532 |
+ default: |
|
| 533 |
+ return b, badPrefix(ExtensionType, lead) |
|
| 534 |
+ } |
|
| 535 |
+ |
|
| 536 |
+ if typ != e.ExtensionType() {
|
|
| 537 |
+ return b, errExt(typ, e.ExtensionType()) |
|
| 538 |
+ } |
|
| 539 |
+ |
|
| 540 |
+ // the data of the extension starts |
|
| 541 |
+ // at 'off' and is 'sz' bytes long |
|
| 542 |
+ if len(b[off:]) < sz {
|
|
| 543 |
+ return b, ErrShortBytes |
|
| 544 |
+ } |
|
| 545 |
+ tot := off + sz |
|
| 546 |
+ return b[tot:], e.UnmarshalBinary(b[off:tot]) |
|
| 547 |
+} |
| 0 | 548 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,174 @@ |
| 0 |
+package msgp |
|
| 1 |
+ |
|
| 2 |
+/* ---------------------------------- |
|
| 3 |
+ integer encoding utilities |
|
| 4 |
+ (inline-able) |
|
| 5 |
+ |
|
| 6 |
+ TODO(tinylib): there are faster, |
|
| 7 |
+ albeit non-portable solutions |
|
| 8 |
+ to the code below. implement |
|
| 9 |
+ byteswap? |
|
| 10 |
+ ---------------------------------- */ |
|
| 11 |
+ |
|
| 12 |
+func putMint64(b []byte, i int64) {
|
|
| 13 |
+ b[0] = mint64 |
|
| 14 |
+ b[1] = byte(i >> 56) |
|
| 15 |
+ b[2] = byte(i >> 48) |
|
| 16 |
+ b[3] = byte(i >> 40) |
|
| 17 |
+ b[4] = byte(i >> 32) |
|
| 18 |
+ b[5] = byte(i >> 24) |
|
| 19 |
+ b[6] = byte(i >> 16) |
|
| 20 |
+ b[7] = byte(i >> 8) |
|
| 21 |
+ b[8] = byte(i) |
|
| 22 |
+} |
|
| 23 |
+ |
|
| 24 |
+func getMint64(b []byte) int64 {
|
|
| 25 |
+ return (int64(b[1]) << 56) | (int64(b[2]) << 48) | |
|
| 26 |
+ (int64(b[3]) << 40) | (int64(b[4]) << 32) | |
|
| 27 |
+ (int64(b[5]) << 24) | (int64(b[6]) << 16) | |
|
| 28 |
+ (int64(b[7]) << 8) | (int64(b[8])) |
|
| 29 |
+} |
|
| 30 |
+ |
|
| 31 |
+func putMint32(b []byte, i int32) {
|
|
| 32 |
+ b[0] = mint32 |
|
| 33 |
+ b[1] = byte(i >> 24) |
|
| 34 |
+ b[2] = byte(i >> 16) |
|
| 35 |
+ b[3] = byte(i >> 8) |
|
| 36 |
+ b[4] = byte(i) |
|
| 37 |
+} |
|
| 38 |
+ |
|
| 39 |
+func getMint32(b []byte) int32 {
|
|
| 40 |
+ return (int32(b[1]) << 24) | (int32(b[2]) << 16) | (int32(b[3]) << 8) | (int32(b[4])) |
|
| 41 |
+} |
|
| 42 |
+ |
|
| 43 |
+func putMint16(b []byte, i int16) {
|
|
| 44 |
+ b[0] = mint16 |
|
| 45 |
+ b[1] = byte(i >> 8) |
|
| 46 |
+ b[2] = byte(i) |
|
| 47 |
+} |
|
| 48 |
+ |
|
| 49 |
+func getMint16(b []byte) (i int16) {
|
|
| 50 |
+ return (int16(b[1]) << 8) | int16(b[2]) |
|
| 51 |
+} |
|
| 52 |
+ |
|
| 53 |
+func putMint8(b []byte, i int8) {
|
|
| 54 |
+ b[0] = mint8 |
|
| 55 |
+ b[1] = byte(i) |
|
| 56 |
+} |
|
| 57 |
+ |
|
| 58 |
+func getMint8(b []byte) (i int8) {
|
|
| 59 |
+ return int8(b[1]) |
|
| 60 |
+} |
|
| 61 |
+ |
|
| 62 |
+func putMuint64(b []byte, u uint64) {
|
|
| 63 |
+ b[0] = muint64 |
|
| 64 |
+ b[1] = byte(u >> 56) |
|
| 65 |
+ b[2] = byte(u >> 48) |
|
| 66 |
+ b[3] = byte(u >> 40) |
|
| 67 |
+ b[4] = byte(u >> 32) |
|
| 68 |
+ b[5] = byte(u >> 24) |
|
| 69 |
+ b[6] = byte(u >> 16) |
|
| 70 |
+ b[7] = byte(u >> 8) |
|
| 71 |
+ b[8] = byte(u) |
|
| 72 |
+} |
|
| 73 |
+ |
|
| 74 |
+func getMuint64(b []byte) uint64 {
|
|
| 75 |
+ return (uint64(b[1]) << 56) | (uint64(b[2]) << 48) | |
|
| 76 |
+ (uint64(b[3]) << 40) | (uint64(b[4]) << 32) | |
|
| 77 |
+ (uint64(b[5]) << 24) | (uint64(b[6]) << 16) | |
|
| 78 |
+ (uint64(b[7]) << 8) | (uint64(b[8])) |
|
| 79 |
+} |
|
| 80 |
+ |
|
| 81 |
+func putMuint32(b []byte, u uint32) {
|
|
| 82 |
+ b[0] = muint32 |
|
| 83 |
+ b[1] = byte(u >> 24) |
|
| 84 |
+ b[2] = byte(u >> 16) |
|
| 85 |
+ b[3] = byte(u >> 8) |
|
| 86 |
+ b[4] = byte(u) |
|
| 87 |
+} |
|
| 88 |
+ |
|
| 89 |
+func getMuint32(b []byte) uint32 {
|
|
| 90 |
+ return (uint32(b[1]) << 24) | (uint32(b[2]) << 16) | (uint32(b[3]) << 8) | (uint32(b[4])) |
|
| 91 |
+} |
|
| 92 |
+ |
|
| 93 |
+func putMuint16(b []byte, u uint16) {
|
|
| 94 |
+ b[0] = muint16 |
|
| 95 |
+ b[1] = byte(u >> 8) |
|
| 96 |
+ b[2] = byte(u) |
|
| 97 |
+} |
|
| 98 |
+ |
|
| 99 |
+func getMuint16(b []byte) uint16 {
|
|
| 100 |
+ return (uint16(b[1]) << 8) | uint16(b[2]) |
|
| 101 |
+} |
|
| 102 |
+ |
|
| 103 |
+func putMuint8(b []byte, u uint8) {
|
|
| 104 |
+ b[0] = muint8 |
|
| 105 |
+ b[1] = byte(u) |
|
| 106 |
+} |
|
| 107 |
+ |
|
| 108 |
+func getMuint8(b []byte) uint8 {
|
|
| 109 |
+ return uint8(b[1]) |
|
| 110 |
+} |
|
| 111 |
+ |
|
| 112 |
+func getUnix(b []byte) (sec int64, nsec int32) {
|
|
| 113 |
+ sec = (int64(b[0]) << 56) | (int64(b[1]) << 48) | |
|
| 114 |
+ (int64(b[2]) << 40) | (int64(b[3]) << 32) | |
|
| 115 |
+ (int64(b[4]) << 24) | (int64(b[5]) << 16) | |
|
| 116 |
+ (int64(b[6]) << 8) | (int64(b[7])) |
|
| 117 |
+ |
|
| 118 |
+ nsec = (int32(b[8]) << 24) | (int32(b[9]) << 16) | (int32(b[10]) << 8) | (int32(b[11])) |
|
| 119 |
+ return |
|
| 120 |
+} |
|
| 121 |
+ |
|
| 122 |
+func putUnix(b []byte, sec int64, nsec int32) {
|
|
| 123 |
+ b[0] = byte(sec >> 56) |
|
| 124 |
+ b[1] = byte(sec >> 48) |
|
| 125 |
+ b[2] = byte(sec >> 40) |
|
| 126 |
+ b[3] = byte(sec >> 32) |
|
| 127 |
+ b[4] = byte(sec >> 24) |
|
| 128 |
+ b[5] = byte(sec >> 16) |
|
| 129 |
+ b[6] = byte(sec >> 8) |
|
| 130 |
+ b[7] = byte(sec) |
|
| 131 |
+ b[8] = byte(nsec >> 24) |
|
| 132 |
+ b[9] = byte(nsec >> 16) |
|
| 133 |
+ b[10] = byte(nsec >> 8) |
|
| 134 |
+ b[11] = byte(nsec) |
|
| 135 |
+} |
|
| 136 |
+ |
|
| 137 |
+/* ----------------------------- |
|
| 138 |
+ prefix utilities |
|
| 139 |
+ ----------------------------- */ |
|
| 140 |
+ |
|
| 141 |
+// write prefix and uint8 |
|
| 142 |
+func prefixu8(b []byte, pre byte, sz uint8) {
|
|
| 143 |
+ b[0] = pre |
|
| 144 |
+ b[1] = byte(sz) |
|
| 145 |
+} |
|
| 146 |
+ |
|
| 147 |
+// write prefix and big-endian uint16 |
|
| 148 |
+func prefixu16(b []byte, pre byte, sz uint16) {
|
|
| 149 |
+ b[0] = pre |
|
| 150 |
+ b[1] = byte(sz >> 8) |
|
| 151 |
+ b[2] = byte(sz) |
|
| 152 |
+} |
|
| 153 |
+ |
|
| 154 |
+// write prefix and big-endian uint32 |
|
| 155 |
+func prefixu32(b []byte, pre byte, sz uint32) {
|
|
| 156 |
+ b[0] = pre |
|
| 157 |
+ b[1] = byte(sz >> 24) |
|
| 158 |
+ b[2] = byte(sz >> 16) |
|
| 159 |
+ b[3] = byte(sz >> 8) |
|
| 160 |
+ b[4] = byte(sz) |
|
| 161 |
+} |
|
| 162 |
+ |
|
| 163 |
+func prefixu64(b []byte, pre byte, sz uint64) {
|
|
| 164 |
+ b[0] = pre |
|
| 165 |
+ b[1] = byte(sz >> 56) |
|
| 166 |
+ b[2] = byte(sz >> 48) |
|
| 167 |
+ b[3] = byte(sz >> 40) |
|
| 168 |
+ b[4] = byte(sz >> 32) |
|
| 169 |
+ b[5] = byte(sz >> 24) |
|
| 170 |
+ b[6] = byte(sz >> 16) |
|
| 171 |
+ b[7] = byte(sz >> 8) |
|
| 172 |
+ b[8] = byte(sz) |
|
| 173 |
+} |
| 0 | 174 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,542 @@ |
| 0 |
+package msgp |
|
| 1 |
+ |
|
| 2 |
+import ( |
|
| 3 |
+ "bufio" |
|
| 4 |
+ "encoding/base64" |
|
| 5 |
+ "encoding/json" |
|
| 6 |
+ "io" |
|
| 7 |
+ "strconv" |
|
| 8 |
+ "unicode/utf8" |
|
| 9 |
+) |
|
| 10 |
+ |
|
| 11 |
+var ( |
|
| 12 |
+ null = []byte("null")
|
|
| 13 |
+ hex = []byte("0123456789abcdef")
|
|
| 14 |
+) |
|
| 15 |
+ |
|
| 16 |
+var defuns [_maxtype]func(jsWriter, *Reader) (int, error) |
|
| 17 |
+ |
|
| 18 |
+// note: there is an initialization loop if |
|
| 19 |
+// this isn't set up during init() |
|
| 20 |
+func init() {
|
|
| 21 |
+ // since none of these functions are inline-able, |
|
| 22 |
+ // there is not much of a penalty to the indirect |
|
| 23 |
+ // call. however, this is best expressed as a jump-table... |
|
| 24 |
+ defuns = [_maxtype]func(jsWriter, *Reader) (int, error){
|
|
| 25 |
+ StrType: rwString, |
|
| 26 |
+ BinType: rwBytes, |
|
| 27 |
+ MapType: rwMap, |
|
| 28 |
+ ArrayType: rwArray, |
|
| 29 |
+ Float64Type: rwFloat64, |
|
| 30 |
+ Float32Type: rwFloat32, |
|
| 31 |
+ BoolType: rwBool, |
|
| 32 |
+ IntType: rwInt, |
|
| 33 |
+ UintType: rwUint, |
|
| 34 |
+ NilType: rwNil, |
|
| 35 |
+ ExtensionType: rwExtension, |
|
| 36 |
+ Complex64Type: rwExtension, |
|
| 37 |
+ Complex128Type: rwExtension, |
|
| 38 |
+ TimeType: rwTime, |
|
| 39 |
+ } |
|
| 40 |
+} |
|
| 41 |
+ |
|
| 42 |
+// this is the interface |
|
| 43 |
+// used to write json |
|
| 44 |
+type jsWriter interface {
|
|
| 45 |
+ io.Writer |
|
| 46 |
+ io.ByteWriter |
|
| 47 |
+ WriteString(string) (int, error) |
|
| 48 |
+} |
|
| 49 |
+ |
|
| 50 |
+// CopyToJSON reads MessagePack from 'src' and copies it |
|
| 51 |
+// as JSON to 'dst' until EOF. |
|
| 52 |
+func CopyToJSON(dst io.Writer, src io.Reader) (n int64, err error) {
|
|
| 53 |
+ r := NewReader(src) |
|
| 54 |
+ n, err = r.WriteToJSON(dst) |
|
| 55 |
+ freeR(r) |
|
| 56 |
+ return |
|
| 57 |
+} |
|
| 58 |
+ |
|
| 59 |
+// WriteToJSON translates MessagePack from 'r' and writes it as |
|
| 60 |
+// JSON to 'w' until the underlying reader returns io.EOF. It returns |
|
| 61 |
+// the number of bytes written, and an error if it stopped before EOF. |
|
| 62 |
+func (r *Reader) WriteToJSON(w io.Writer) (n int64, err error) {
|
|
| 63 |
+ var j jsWriter |
|
| 64 |
+ var bf *bufio.Writer |
|
| 65 |
+ if jsw, ok := w.(jsWriter); ok {
|
|
| 66 |
+ j = jsw |
|
| 67 |
+ } else {
|
|
| 68 |
+ bf = bufio.NewWriterSize(w, 512) |
|
| 69 |
+ j = bf |
|
| 70 |
+ } |
|
| 71 |
+ var nn int |
|
| 72 |
+ for err == nil {
|
|
| 73 |
+ nn, err = rwNext(j, r) |
|
| 74 |
+ n += int64(nn) |
|
| 75 |
+ } |
|
| 76 |
+ if err != io.EOF {
|
|
| 77 |
+ if bf != nil {
|
|
| 78 |
+ bf.Flush() |
|
| 79 |
+ } |
|
| 80 |
+ return |
|
| 81 |
+ } |
|
| 82 |
+ err = nil |
|
| 83 |
+ if bf != nil {
|
|
| 84 |
+ err = bf.Flush() |
|
| 85 |
+ } |
|
| 86 |
+ return |
|
| 87 |
+} |
|
| 88 |
+ |
|
| 89 |
+func rwNext(w jsWriter, src *Reader) (int, error) {
|
|
| 90 |
+ t, err := src.NextType() |
|
| 91 |
+ if err != nil {
|
|
| 92 |
+ return 0, err |
|
| 93 |
+ } |
|
| 94 |
+ return defuns[t](w, src) |
|
| 95 |
+} |
|
| 96 |
+ |
|
| 97 |
+func rwMap(dst jsWriter, src *Reader) (n int, err error) {
|
|
| 98 |
+ var comma bool |
|
| 99 |
+ var sz uint32 |
|
| 100 |
+ var field []byte |
|
| 101 |
+ |
|
| 102 |
+ sz, err = src.ReadMapHeader() |
|
| 103 |
+ if err != nil {
|
|
| 104 |
+ return |
|
| 105 |
+ } |
|
| 106 |
+ |
|
| 107 |
+ if sz == 0 {
|
|
| 108 |
+ return dst.WriteString("{}")
|
|
| 109 |
+ } |
|
| 110 |
+ |
|
| 111 |
+ err = dst.WriteByte('{')
|
|
| 112 |
+ if err != nil {
|
|
| 113 |
+ return |
|
| 114 |
+ } |
|
| 115 |
+ n++ |
|
| 116 |
+ var nn int |
|
| 117 |
+ for i := uint32(0); i < sz; i++ {
|
|
| 118 |
+ if comma {
|
|
| 119 |
+ err = dst.WriteByte(',')
|
|
| 120 |
+ if err != nil {
|
|
| 121 |
+ return |
|
| 122 |
+ } |
|
| 123 |
+ n++ |
|
| 124 |
+ } |
|
| 125 |
+ |
|
| 126 |
+ field, err = src.ReadMapKeyPtr() |
|
| 127 |
+ if err != nil {
|
|
| 128 |
+ return |
|
| 129 |
+ } |
|
| 130 |
+ nn, err = rwquoted(dst, field) |
|
| 131 |
+ n += nn |
|
| 132 |
+ if err != nil {
|
|
| 133 |
+ return |
|
| 134 |
+ } |
|
| 135 |
+ |
|
| 136 |
+ err = dst.WriteByte(':')
|
|
| 137 |
+ if err != nil {
|
|
| 138 |
+ return |
|
| 139 |
+ } |
|
| 140 |
+ n++ |
|
| 141 |
+ nn, err = rwNext(dst, src) |
|
| 142 |
+ n += nn |
|
| 143 |
+ if err != nil {
|
|
| 144 |
+ return |
|
| 145 |
+ } |
|
| 146 |
+ if !comma {
|
|
| 147 |
+ comma = true |
|
| 148 |
+ } |
|
| 149 |
+ } |
|
| 150 |
+ |
|
| 151 |
+ err = dst.WriteByte('}')
|
|
| 152 |
+ if err != nil {
|
|
| 153 |
+ return |
|
| 154 |
+ } |
|
| 155 |
+ n++ |
|
| 156 |
+ return |
|
| 157 |
+} |
|
| 158 |
+ |
|
| 159 |
+func rwArray(dst jsWriter, src *Reader) (n int, err error) {
|
|
| 160 |
+ err = dst.WriteByte('[')
|
|
| 161 |
+ if err != nil {
|
|
| 162 |
+ return |
|
| 163 |
+ } |
|
| 164 |
+ var sz uint32 |
|
| 165 |
+ var nn int |
|
| 166 |
+ sz, err = src.ReadArrayHeader() |
|
| 167 |
+ if err != nil {
|
|
| 168 |
+ return |
|
| 169 |
+ } |
|
| 170 |
+ comma := false |
|
| 171 |
+ for i := uint32(0); i < sz; i++ {
|
|
| 172 |
+ if comma {
|
|
| 173 |
+ err = dst.WriteByte(',')
|
|
| 174 |
+ if err != nil {
|
|
| 175 |
+ return |
|
| 176 |
+ } |
|
| 177 |
+ n++ |
|
| 178 |
+ } |
|
| 179 |
+ nn, err = rwNext(dst, src) |
|
| 180 |
+ n += nn |
|
| 181 |
+ if err != nil {
|
|
| 182 |
+ return |
|
| 183 |
+ } |
|
| 184 |
+ comma = true |
|
| 185 |
+ } |
|
| 186 |
+ |
|
| 187 |
+ err = dst.WriteByte(']')
|
|
| 188 |
+ if err != nil {
|
|
| 189 |
+ return |
|
| 190 |
+ } |
|
| 191 |
+ n++ |
|
| 192 |
+ return |
|
| 193 |
+} |
|
| 194 |
+ |
|
| 195 |
+func rwNil(dst jsWriter, src *Reader) (int, error) {
|
|
| 196 |
+ err := src.ReadNil() |
|
| 197 |
+ if err != nil {
|
|
| 198 |
+ return 0, err |
|
| 199 |
+ } |
|
| 200 |
+ return dst.Write(null) |
|
| 201 |
+} |
|
| 202 |
+ |
|
| 203 |
+func rwFloat32(dst jsWriter, src *Reader) (int, error) {
|
|
| 204 |
+ f, err := src.ReadFloat32() |
|
| 205 |
+ if err != nil {
|
|
| 206 |
+ return 0, err |
|
| 207 |
+ } |
|
| 208 |
+ src.scratch = strconv.AppendFloat(src.scratch[:0], float64(f), 'f', -1, 64) |
|
| 209 |
+ return dst.Write(src.scratch) |
|
| 210 |
+} |
|
| 211 |
+ |
|
| 212 |
+func rwFloat64(dst jsWriter, src *Reader) (int, error) {
|
|
| 213 |
+ f, err := src.ReadFloat64() |
|
| 214 |
+ if err != nil {
|
|
| 215 |
+ return 0, err |
|
| 216 |
+ } |
|
| 217 |
+ src.scratch = strconv.AppendFloat(src.scratch[:0], f, 'f', -1, 32) |
|
| 218 |
+ return dst.Write(src.scratch) |
|
| 219 |
+} |
|
| 220 |
+ |
|
| 221 |
+func rwInt(dst jsWriter, src *Reader) (int, error) {
|
|
| 222 |
+ i, err := src.ReadInt64() |
|
| 223 |
+ if err != nil {
|
|
| 224 |
+ return 0, err |
|
| 225 |
+ } |
|
| 226 |
+ src.scratch = strconv.AppendInt(src.scratch[:0], i, 10) |
|
| 227 |
+ return dst.Write(src.scratch) |
|
| 228 |
+} |
|
| 229 |
+ |
|
| 230 |
+func rwUint(dst jsWriter, src *Reader) (int, error) {
|
|
| 231 |
+ u, err := src.ReadUint64() |
|
| 232 |
+ if err != nil {
|
|
| 233 |
+ return 0, err |
|
| 234 |
+ } |
|
| 235 |
+ src.scratch = strconv.AppendUint(src.scratch[:0], u, 10) |
|
| 236 |
+ return dst.Write(src.scratch) |
|
| 237 |
+} |
|
| 238 |
+ |
|
| 239 |
+func rwBool(dst jsWriter, src *Reader) (int, error) {
|
|
| 240 |
+ b, err := src.ReadBool() |
|
| 241 |
+ if err != nil {
|
|
| 242 |
+ return 0, err |
|
| 243 |
+ } |
|
| 244 |
+ if b {
|
|
| 245 |
+ return dst.WriteString("true")
|
|
| 246 |
+ } |
|
| 247 |
+ return dst.WriteString("false")
|
|
| 248 |
+} |
|
| 249 |
+ |
|
| 250 |
+func rwTime(dst jsWriter, src *Reader) (int, error) {
|
|
| 251 |
+ t, err := src.ReadTime() |
|
| 252 |
+ if err != nil {
|
|
| 253 |
+ return 0, err |
|
| 254 |
+ } |
|
| 255 |
+ bts, err := t.MarshalJSON() |
|
| 256 |
+ if err != nil {
|
|
| 257 |
+ return 0, err |
|
| 258 |
+ } |
|
| 259 |
+ return dst.Write(bts) |
|
| 260 |
+} |
|
| 261 |
+ |
|
| 262 |
+func rwExtension(dst jsWriter, src *Reader) (n int, err error) {
|
|
| 263 |
+ et, err := src.peekExtensionType() |
|
| 264 |
+ if err != nil {
|
|
| 265 |
+ return 0, err |
|
| 266 |
+ } |
|
| 267 |
+ |
|
| 268 |
+ // registered extensions can override |
|
| 269 |
+ // the JSON encoding |
|
| 270 |
+ if j, ok := extensionReg[et]; ok {
|
|
| 271 |
+ var bts []byte |
|
| 272 |
+ e := j() |
|
| 273 |
+ err = src.ReadExtension(e) |
|
| 274 |
+ if err != nil {
|
|
| 275 |
+ return |
|
| 276 |
+ } |
|
| 277 |
+ bts, err = json.Marshal(e) |
|
| 278 |
+ if err != nil {
|
|
| 279 |
+ return |
|
| 280 |
+ } |
|
| 281 |
+ return dst.Write(bts) |
|
| 282 |
+ } |
|
| 283 |
+ |
|
| 284 |
+ e := RawExtension{}
|
|
| 285 |
+ e.Type = et |
|
| 286 |
+ err = src.ReadExtension(&e) |
|
| 287 |
+ if err != nil {
|
|
| 288 |
+ return |
|
| 289 |
+ } |
|
| 290 |
+ |
|
| 291 |
+ var nn int |
|
| 292 |
+ err = dst.WriteByte('{')
|
|
| 293 |
+ if err != nil {
|
|
| 294 |
+ return |
|
| 295 |
+ } |
|
| 296 |
+ n++ |
|
| 297 |
+ |
|
| 298 |
+ nn, err = dst.WriteString(`"type:"`) |
|
| 299 |
+ n += nn |
|
| 300 |
+ if err != nil {
|
|
| 301 |
+ return |
|
| 302 |
+ } |
|
| 303 |
+ |
|
| 304 |
+ src.scratch = strconv.AppendInt(src.scratch[0:0], int64(e.Type), 10) |
|
| 305 |
+ nn, err = dst.Write(src.scratch) |
|
| 306 |
+ n += nn |
|
| 307 |
+ if err != nil {
|
|
| 308 |
+ return |
|
| 309 |
+ } |
|
| 310 |
+ |
|
| 311 |
+ nn, err = dst.WriteString(`,"data":"`) |
|
| 312 |
+ n += nn |
|
| 313 |
+ if err != nil {
|
|
| 314 |
+ return |
|
| 315 |
+ } |
|
| 316 |
+ |
|
| 317 |
+ enc := base64.NewEncoder(base64.StdEncoding, dst) |
|
| 318 |
+ |
|
| 319 |
+ nn, err = enc.Write(e.Data) |
|
| 320 |
+ n += nn |
|
| 321 |
+ if err != nil {
|
|
| 322 |
+ return |
|
| 323 |
+ } |
|
| 324 |
+ err = enc.Close() |
|
| 325 |
+ if err != nil {
|
|
| 326 |
+ return |
|
| 327 |
+ } |
|
| 328 |
+ nn, err = dst.WriteString(`"}`) |
|
| 329 |
+ n += nn |
|
| 330 |
+ return |
|
| 331 |
+} |
|
| 332 |
+ |
|
| 333 |
+func rwString(dst jsWriter, src *Reader) (n int, err error) {
|
|
| 334 |
+ var p []byte |
|
| 335 |
+ p, err = src.r.Peek(1) |
|
| 336 |
+ if err != nil {
|
|
| 337 |
+ return |
|
| 338 |
+ } |
|
| 339 |
+ lead := p[0] |
|
| 340 |
+ var read int |
|
| 341 |
+ |
|
| 342 |
+ if isfixstr(lead) {
|
|
| 343 |
+ read = int(rfixstr(lead)) |
|
| 344 |
+ src.r.Skip(1) |
|
| 345 |
+ goto write |
|
| 346 |
+ } |
|
| 347 |
+ |
|
| 348 |
+ switch lead {
|
|
| 349 |
+ case mstr8: |
|
| 350 |
+ p, err = src.r.Next(2) |
|
| 351 |
+ if err != nil {
|
|
| 352 |
+ return |
|
| 353 |
+ } |
|
| 354 |
+ read = int(uint8(p[1])) |
|
| 355 |
+ case mstr16: |
|
| 356 |
+ p, err = src.r.Next(3) |
|
| 357 |
+ if err != nil {
|
|
| 358 |
+ return |
|
| 359 |
+ } |
|
| 360 |
+ read = int(big.Uint16(p[1:])) |
|
| 361 |
+ case mstr32: |
|
| 362 |
+ p, err = src.r.Next(5) |
|
| 363 |
+ if err != nil {
|
|
| 364 |
+ return |
|
| 365 |
+ } |
|
| 366 |
+ read = int(big.Uint32(p[1:])) |
|
| 367 |
+ default: |
|
| 368 |
+ err = badPrefix(StrType, lead) |
|
| 369 |
+ return |
|
| 370 |
+ } |
|
| 371 |
+write: |
|
| 372 |
+ p, err = src.r.Next(read) |
|
| 373 |
+ if err != nil {
|
|
| 374 |
+ return |
|
| 375 |
+ } |
|
| 376 |
+ n, err = rwquoted(dst, p) |
|
| 377 |
+ return |
|
| 378 |
+} |
|
| 379 |
+ |
|
| 380 |
+func rwBytes(dst jsWriter, src *Reader) (n int, err error) {
|
|
| 381 |
+ var nn int |
|
| 382 |
+ err = dst.WriteByte('"')
|
|
| 383 |
+ if err != nil {
|
|
| 384 |
+ return |
|
| 385 |
+ } |
|
| 386 |
+ n++ |
|
| 387 |
+ src.scratch, err = src.ReadBytes(src.scratch[:0]) |
|
| 388 |
+ if err != nil {
|
|
| 389 |
+ return |
|
| 390 |
+ } |
|
| 391 |
+ enc := base64.NewEncoder(base64.StdEncoding, dst) |
|
| 392 |
+ nn, err = enc.Write(src.scratch) |
|
| 393 |
+ n += nn |
|
| 394 |
+ if err != nil {
|
|
| 395 |
+ return |
|
| 396 |
+ } |
|
| 397 |
+ err = enc.Close() |
|
| 398 |
+ if err != nil {
|
|
| 399 |
+ return |
|
| 400 |
+ } |
|
| 401 |
+ err = dst.WriteByte('"')
|
|
| 402 |
+ if err != nil {
|
|
| 403 |
+ return |
|
| 404 |
+ } |
|
| 405 |
+ n++ |
|
| 406 |
+ return |
|
| 407 |
+} |
|
| 408 |
+ |
|
| 409 |
+// Below (c) The Go Authors, 2009-2014 |
|
| 410 |
+// Subject to the BSD-style license found at http://golang.org |
|
| 411 |
+// |
|
| 412 |
+// see: encoding/json/encode.go:(*encodeState).stringbytes() |
|
| 413 |
+func rwquoted(dst jsWriter, s []byte) (n int, err error) {
|
|
| 414 |
+ var nn int |
|
| 415 |
+ err = dst.WriteByte('"')
|
|
| 416 |
+ if err != nil {
|
|
| 417 |
+ return |
|
| 418 |
+ } |
|
| 419 |
+ n++ |
|
| 420 |
+ start := 0 |
|
| 421 |
+ for i := 0; i < len(s); {
|
|
| 422 |
+ if b := s[i]; b < utf8.RuneSelf {
|
|
| 423 |
+ if 0x20 <= b && b != '\\' && b != '"' && b != '<' && b != '>' && b != '&' {
|
|
| 424 |
+ i++ |
|
| 425 |
+ continue |
|
| 426 |
+ } |
|
| 427 |
+ if start < i {
|
|
| 428 |
+ nn, err = dst.Write(s[start:i]) |
|
| 429 |
+ n += nn |
|
| 430 |
+ if err != nil {
|
|
| 431 |
+ return |
|
| 432 |
+ } |
|
| 433 |
+ } |
|
| 434 |
+ switch b {
|
|
| 435 |
+ case '\\', '"': |
|
| 436 |
+ err = dst.WriteByte('\\')
|
|
| 437 |
+ if err != nil {
|
|
| 438 |
+ return |
|
| 439 |
+ } |
|
| 440 |
+ n++ |
|
| 441 |
+ err = dst.WriteByte(b) |
|
| 442 |
+ if err != nil {
|
|
| 443 |
+ return |
|
| 444 |
+ } |
|
| 445 |
+ n++ |
|
| 446 |
+ case '\n': |
|
| 447 |
+ err = dst.WriteByte('\\')
|
|
| 448 |
+ if err != nil {
|
|
| 449 |
+ return |
|
| 450 |
+ } |
|
| 451 |
+ n++ |
|
| 452 |
+ err = dst.WriteByte('n')
|
|
| 453 |
+ if err != nil {
|
|
| 454 |
+ return |
|
| 455 |
+ } |
|
| 456 |
+ n++ |
|
| 457 |
+ case '\r': |
|
| 458 |
+ err = dst.WriteByte('\\')
|
|
| 459 |
+ if err != nil {
|
|
| 460 |
+ return |
|
| 461 |
+ } |
|
| 462 |
+ n++ |
|
| 463 |
+ err = dst.WriteByte('r')
|
|
| 464 |
+ if err != nil {
|
|
| 465 |
+ return |
|
| 466 |
+ } |
|
| 467 |
+ n++ |
|
| 468 |
+ default: |
|
| 469 |
+ nn, err = dst.WriteString(`\u00`) |
|
| 470 |
+ n += nn |
|
| 471 |
+ if err != nil {
|
|
| 472 |
+ return |
|
| 473 |
+ } |
|
| 474 |
+ err = dst.WriteByte(hex[b>>4]) |
|
| 475 |
+ if err != nil {
|
|
| 476 |
+ return |
|
| 477 |
+ } |
|
| 478 |
+ n++ |
|
| 479 |
+ err = dst.WriteByte(hex[b&0xF]) |
|
| 480 |
+ if err != nil {
|
|
| 481 |
+ return |
|
| 482 |
+ } |
|
| 483 |
+ n++ |
|
| 484 |
+ } |
|
| 485 |
+ i++ |
|
| 486 |
+ start = i |
|
| 487 |
+ continue |
|
| 488 |
+ } |
|
| 489 |
+ c, size := utf8.DecodeRune(s[i:]) |
|
| 490 |
+ if c == utf8.RuneError && size == 1 {
|
|
| 491 |
+ if start < i {
|
|
| 492 |
+ nn, err = dst.Write(s[start:i]) |
|
| 493 |
+ n += nn |
|
| 494 |
+ if err != nil {
|
|
| 495 |
+ return |
|
| 496 |
+ } |
|
| 497 |
+ nn, err = dst.WriteString(`\ufffd`) |
|
| 498 |
+ n += nn |
|
| 499 |
+ if err != nil {
|
|
| 500 |
+ return |
|
| 501 |
+ } |
|
| 502 |
+ i += size |
|
| 503 |
+ start = i |
|
| 504 |
+ continue |
|
| 505 |
+ } |
|
| 506 |
+ } |
|
| 507 |
+ if c == '\u2028' || c == '\u2029' {
|
|
| 508 |
+ if start < i {
|
|
| 509 |
+ nn, err = dst.Write(s[start:i]) |
|
| 510 |
+ n += nn |
|
| 511 |
+ if err != nil {
|
|
| 512 |
+ return |
|
| 513 |
+ } |
|
| 514 |
+ nn, err = dst.WriteString(`\u202`) |
|
| 515 |
+ n += nn |
|
| 516 |
+ if err != nil {
|
|
| 517 |
+ return |
|
| 518 |
+ } |
|
| 519 |
+ err = dst.WriteByte(hex[c&0xF]) |
|
| 520 |
+ if err != nil {
|
|
| 521 |
+ return |
|
| 522 |
+ } |
|
| 523 |
+ n++ |
|
| 524 |
+ } |
|
| 525 |
+ } |
|
| 526 |
+ i += size |
|
| 527 |
+ } |
|
| 528 |
+ if start < len(s) {
|
|
| 529 |
+ nn, err = dst.Write(s[start:]) |
|
| 530 |
+ n += nn |
|
| 531 |
+ if err != nil {
|
|
| 532 |
+ return |
|
| 533 |
+ } |
|
| 534 |
+ } |
|
| 535 |
+ err = dst.WriteByte('"')
|
|
| 536 |
+ if err != nil {
|
|
| 537 |
+ return |
|
| 538 |
+ } |
|
| 539 |
+ n++ |
|
| 540 |
+ return |
|
| 541 |
+} |
| 0 | 542 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,363 @@ |
| 0 |
+package msgp |
|
| 1 |
+ |
|
| 2 |
+import ( |
|
| 3 |
+ "bufio" |
|
| 4 |
+ "encoding/base64" |
|
| 5 |
+ "encoding/json" |
|
| 6 |
+ "io" |
|
| 7 |
+ "strconv" |
|
| 8 |
+ "time" |
|
| 9 |
+) |
|
| 10 |
+ |
|
| 11 |
+var unfuns [_maxtype]func(jsWriter, []byte, []byte) ([]byte, []byte, error) |
|
| 12 |
+ |
|
| 13 |
+func init() {
|
|
| 14 |
+ |
|
| 15 |
+ // NOTE(pmh): this is best expressed as a jump table, |
|
| 16 |
+ // but gc doesn't do that yet. revisit post-go1.5. |
|
| 17 |
+ unfuns = [_maxtype]func(jsWriter, []byte, []byte) ([]byte, []byte, error){
|
|
| 18 |
+ StrType: rwStringBytes, |
|
| 19 |
+ BinType: rwBytesBytes, |
|
| 20 |
+ MapType: rwMapBytes, |
|
| 21 |
+ ArrayType: rwArrayBytes, |
|
| 22 |
+ Float64Type: rwFloat64Bytes, |
|
| 23 |
+ Float32Type: rwFloat32Bytes, |
|
| 24 |
+ BoolType: rwBoolBytes, |
|
| 25 |
+ IntType: rwIntBytes, |
|
| 26 |
+ UintType: rwUintBytes, |
|
| 27 |
+ NilType: rwNullBytes, |
|
| 28 |
+ ExtensionType: rwExtensionBytes, |
|
| 29 |
+ Complex64Type: rwExtensionBytes, |
|
| 30 |
+ Complex128Type: rwExtensionBytes, |
|
| 31 |
+ TimeType: rwTimeBytes, |
|
| 32 |
+ } |
|
| 33 |
+} |
|
| 34 |
+ |
|
| 35 |
+// UnmarshalAsJSON takes raw messagepack and writes |
|
| 36 |
+// it as JSON to 'w'. If an error is returned, the |
|
| 37 |
+// bytes not translated will also be returned. If |
|
| 38 |
+// no errors are encountered, the length of the returned |
|
| 39 |
+// slice will be zero. |
|
| 40 |
+func UnmarshalAsJSON(w io.Writer, msg []byte) ([]byte, error) {
|
|
| 41 |
+ var ( |
|
| 42 |
+ scratch []byte |
|
| 43 |
+ cast bool |
|
| 44 |
+ dst jsWriter |
|
| 45 |
+ err error |
|
| 46 |
+ ) |
|
| 47 |
+ if jsw, ok := w.(jsWriter); ok {
|
|
| 48 |
+ dst = jsw |
|
| 49 |
+ cast = true |
|
| 50 |
+ } else {
|
|
| 51 |
+ dst = bufio.NewWriterSize(w, 512) |
|
| 52 |
+ } |
|
| 53 |
+ for len(msg) > 0 && err == nil {
|
|
| 54 |
+ msg, scratch, err = writeNext(dst, msg, scratch) |
|
| 55 |
+ } |
|
| 56 |
+ if !cast && err == nil {
|
|
| 57 |
+ err = dst.(*bufio.Writer).Flush() |
|
| 58 |
+ } |
|
| 59 |
+ return msg, err |
|
| 60 |
+} |
|
| 61 |
+ |
|
| 62 |
+func writeNext(w jsWriter, msg []byte, scratch []byte) ([]byte, []byte, error) {
|
|
| 63 |
+ if len(msg) < 1 {
|
|
| 64 |
+ return msg, scratch, ErrShortBytes |
|
| 65 |
+ } |
|
| 66 |
+ t := getType(msg[0]) |
|
| 67 |
+ if t == InvalidType {
|
|
| 68 |
+ return msg, scratch, InvalidPrefixError(msg[0]) |
|
| 69 |
+ } |
|
| 70 |
+ if t == ExtensionType {
|
|
| 71 |
+ et, err := peekExtension(msg) |
|
| 72 |
+ if err != nil {
|
|
| 73 |
+ return nil, scratch, err |
|
| 74 |
+ } |
|
| 75 |
+ if et == TimeExtension {
|
|
| 76 |
+ t = TimeType |
|
| 77 |
+ } |
|
| 78 |
+ } |
|
| 79 |
+ return unfuns[t](w, msg, scratch) |
|
| 80 |
+} |
|
| 81 |
+ |
|
| 82 |
+func rwArrayBytes(w jsWriter, msg []byte, scratch []byte) ([]byte, []byte, error) {
|
|
| 83 |
+ sz, msg, err := ReadArrayHeaderBytes(msg) |
|
| 84 |
+ if err != nil {
|
|
| 85 |
+ return msg, scratch, err |
|
| 86 |
+ } |
|
| 87 |
+ err = w.WriteByte('[')
|
|
| 88 |
+ if err != nil {
|
|
| 89 |
+ return msg, scratch, err |
|
| 90 |
+ } |
|
| 91 |
+ for i := uint32(0); i < sz; i++ {
|
|
| 92 |
+ if i != 0 {
|
|
| 93 |
+ err = w.WriteByte(',')
|
|
| 94 |
+ if err != nil {
|
|
| 95 |
+ return msg, scratch, err |
|
| 96 |
+ } |
|
| 97 |
+ } |
|
| 98 |
+ msg, scratch, err = writeNext(w, msg, scratch) |
|
| 99 |
+ if err != nil {
|
|
| 100 |
+ return msg, scratch, err |
|
| 101 |
+ } |
|
| 102 |
+ } |
|
| 103 |
+ err = w.WriteByte(']')
|
|
| 104 |
+ return msg, scratch, err |
|
| 105 |
+} |
|
| 106 |
+ |
|
| 107 |
+func rwMapBytes(w jsWriter, msg []byte, scratch []byte) ([]byte, []byte, error) {
|
|
| 108 |
+ sz, msg, err := ReadMapHeaderBytes(msg) |
|
| 109 |
+ if err != nil {
|
|
| 110 |
+ return msg, scratch, err |
|
| 111 |
+ } |
|
| 112 |
+ err = w.WriteByte('{')
|
|
| 113 |
+ if err != nil {
|
|
| 114 |
+ return msg, scratch, err |
|
| 115 |
+ } |
|
| 116 |
+ for i := uint32(0); i < sz; i++ {
|
|
| 117 |
+ if i != 0 {
|
|
| 118 |
+ err = w.WriteByte(',')
|
|
| 119 |
+ if err != nil {
|
|
| 120 |
+ return msg, scratch, err |
|
| 121 |
+ } |
|
| 122 |
+ } |
|
| 123 |
+ msg, scratch, err = rwMapKeyBytes(w, msg, scratch) |
|
| 124 |
+ if err != nil {
|
|
| 125 |
+ return msg, scratch, err |
|
| 126 |
+ } |
|
| 127 |
+ err = w.WriteByte(':')
|
|
| 128 |
+ if err != nil {
|
|
| 129 |
+ return msg, scratch, err |
|
| 130 |
+ } |
|
| 131 |
+ msg, scratch, err = writeNext(w, msg, scratch) |
|
| 132 |
+ if err != nil {
|
|
| 133 |
+ return msg, scratch, err |
|
| 134 |
+ } |
|
| 135 |
+ } |
|
| 136 |
+ err = w.WriteByte('}')
|
|
| 137 |
+ return msg, scratch, err |
|
| 138 |
+} |
|
| 139 |
+ |
|
| 140 |
+func rwMapKeyBytes(w jsWriter, msg []byte, scratch []byte) ([]byte, []byte, error) {
|
|
| 141 |
+ msg, scratch, err := rwStringBytes(w, msg, scratch) |
|
| 142 |
+ if err != nil {
|
|
| 143 |
+ if tperr, ok := err.(TypeError); ok && tperr.Encoded == BinType {
|
|
| 144 |
+ return rwBytesBytes(w, msg, scratch) |
|
| 145 |
+ } |
|
| 146 |
+ } |
|
| 147 |
+ return msg, scratch, err |
|
| 148 |
+} |
|
| 149 |
+ |
|
| 150 |
+func rwStringBytes(w jsWriter, msg []byte, scratch []byte) ([]byte, []byte, error) {
|
|
| 151 |
+ str, msg, err := ReadStringZC(msg) |
|
| 152 |
+ if err != nil {
|
|
| 153 |
+ return msg, scratch, err |
|
| 154 |
+ } |
|
| 155 |
+ _, err = rwquoted(w, str) |
|
| 156 |
+ return msg, scratch, err |
|
| 157 |
+} |
|
| 158 |
+ |
|
| 159 |
+func rwBytesBytes(w jsWriter, msg []byte, scratch []byte) ([]byte, []byte, error) {
|
|
| 160 |
+ bts, msg, err := ReadBytesZC(msg) |
|
| 161 |
+ if err != nil {
|
|
| 162 |
+ return msg, scratch, err |
|
| 163 |
+ } |
|
| 164 |
+ l := base64.StdEncoding.EncodedLen(len(bts)) |
|
| 165 |
+ if cap(scratch) >= l {
|
|
| 166 |
+ scratch = scratch[0:l] |
|
| 167 |
+ } else {
|
|
| 168 |
+ scratch = make([]byte, l) |
|
| 169 |
+ } |
|
| 170 |
+ base64.StdEncoding.Encode(scratch, bts) |
|
| 171 |
+ err = w.WriteByte('"')
|
|
| 172 |
+ if err != nil {
|
|
| 173 |
+ return msg, scratch, err |
|
| 174 |
+ } |
|
| 175 |
+ _, err = w.Write(scratch) |
|
| 176 |
+ if err != nil {
|
|
| 177 |
+ return msg, scratch, err |
|
| 178 |
+ } |
|
| 179 |
+ err = w.WriteByte('"')
|
|
| 180 |
+ return msg, scratch, err |
|
| 181 |
+} |
|
| 182 |
+ |
|
| 183 |
+func rwNullBytes(w jsWriter, msg []byte, scratch []byte) ([]byte, []byte, error) {
|
|
| 184 |
+ msg, err := ReadNilBytes(msg) |
|
| 185 |
+ if err != nil {
|
|
| 186 |
+ return msg, scratch, err |
|
| 187 |
+ } |
|
| 188 |
+ _, err = w.Write(null) |
|
| 189 |
+ return msg, scratch, err |
|
| 190 |
+} |
|
| 191 |
+ |
|
| 192 |
+func rwBoolBytes(w jsWriter, msg []byte, scratch []byte) ([]byte, []byte, error) {
|
|
| 193 |
+ b, msg, err := ReadBoolBytes(msg) |
|
| 194 |
+ if err != nil {
|
|
| 195 |
+ return msg, scratch, err |
|
| 196 |
+ } |
|
| 197 |
+ if b {
|
|
| 198 |
+ _, err = w.WriteString("true")
|
|
| 199 |
+ return msg, scratch, err |
|
| 200 |
+ } |
|
| 201 |
+ _, err = w.WriteString("false")
|
|
| 202 |
+ return msg, scratch, err |
|
| 203 |
+} |
|
| 204 |
+ |
|
| 205 |
+func rwIntBytes(w jsWriter, msg []byte, scratch []byte) ([]byte, []byte, error) {
|
|
| 206 |
+ i, msg, err := ReadInt64Bytes(msg) |
|
| 207 |
+ if err != nil {
|
|
| 208 |
+ return msg, scratch, err |
|
| 209 |
+ } |
|
| 210 |
+ scratch = strconv.AppendInt(scratch[0:0], i, 10) |
|
| 211 |
+ _, err = w.Write(scratch) |
|
| 212 |
+ return msg, scratch, err |
|
| 213 |
+} |
|
| 214 |
+ |
|
| 215 |
+func rwUintBytes(w jsWriter, msg []byte, scratch []byte) ([]byte, []byte, error) {
|
|
| 216 |
+ u, msg, err := ReadUint64Bytes(msg) |
|
| 217 |
+ if err != nil {
|
|
| 218 |
+ return msg, scratch, err |
|
| 219 |
+ } |
|
| 220 |
+ scratch = strconv.AppendUint(scratch[0:0], u, 10) |
|
| 221 |
+ _, err = w.Write(scratch) |
|
| 222 |
+ return msg, scratch, err |
|
| 223 |
+} |
|
| 224 |
+ |
|
| 225 |
+func rwFloatBytes(w jsWriter, msg []byte, f64 bool, scratch []byte) ([]byte, []byte, error) {
|
|
| 226 |
+ var f float64 |
|
| 227 |
+ var err error |
|
| 228 |
+ var sz int |
|
| 229 |
+ if f64 {
|
|
| 230 |
+ sz = 64 |
|
| 231 |
+ f, msg, err = ReadFloat64Bytes(msg) |
|
| 232 |
+ } else {
|
|
| 233 |
+ sz = 32 |
|
| 234 |
+ var v float32 |
|
| 235 |
+ v, msg, err = ReadFloat32Bytes(msg) |
|
| 236 |
+ f = float64(v) |
|
| 237 |
+ } |
|
| 238 |
+ if err != nil {
|
|
| 239 |
+ return msg, scratch, err |
|
| 240 |
+ } |
|
| 241 |
+ scratch = strconv.AppendFloat(scratch, f, 'f', -1, sz) |
|
| 242 |
+ _, err = w.Write(scratch) |
|
| 243 |
+ return msg, scratch, err |
|
| 244 |
+} |
|
| 245 |
+ |
|
| 246 |
+func rwFloat32Bytes(w jsWriter, msg []byte, scratch []byte) ([]byte, []byte, error) {
|
|
| 247 |
+ var f float32 |
|
| 248 |
+ var err error |
|
| 249 |
+ f, msg, err = ReadFloat32Bytes(msg) |
|
| 250 |
+ if err != nil {
|
|
| 251 |
+ return msg, scratch, err |
|
| 252 |
+ } |
|
| 253 |
+ scratch = strconv.AppendFloat(scratch[:0], float64(f), 'f', -1, 32) |
|
| 254 |
+ _, err = w.Write(scratch) |
|
| 255 |
+ return msg, scratch, err |
|
| 256 |
+} |
|
| 257 |
+ |
|
| 258 |
+func rwFloat64Bytes(w jsWriter, msg []byte, scratch []byte) ([]byte, []byte, error) {
|
|
| 259 |
+ var f float64 |
|
| 260 |
+ var err error |
|
| 261 |
+ f, msg, err = ReadFloat64Bytes(msg) |
|
| 262 |
+ if err != nil {
|
|
| 263 |
+ return msg, scratch, err |
|
| 264 |
+ } |
|
| 265 |
+ scratch = strconv.AppendFloat(scratch[:0], f, 'f', -1, 64) |
|
| 266 |
+ _, err = w.Write(scratch) |
|
| 267 |
+ return msg, scratch, err |
|
| 268 |
+} |
|
| 269 |
+ |
|
| 270 |
+func rwTimeBytes(w jsWriter, msg []byte, scratch []byte) ([]byte, []byte, error) {
|
|
| 271 |
+ var t time.Time |
|
| 272 |
+ var err error |
|
| 273 |
+ t, msg, err = ReadTimeBytes(msg) |
|
| 274 |
+ if err != nil {
|
|
| 275 |
+ return msg, scratch, err |
|
| 276 |
+ } |
|
| 277 |
+ bts, err := t.MarshalJSON() |
|
| 278 |
+ if err != nil {
|
|
| 279 |
+ return msg, scratch, err |
|
| 280 |
+ } |
|
| 281 |
+ _, err = w.Write(bts) |
|
| 282 |
+ return msg, scratch, err |
|
| 283 |
+} |
|
| 284 |
+ |
|
| 285 |
+func rwExtensionBytes(w jsWriter, msg []byte, scratch []byte) ([]byte, []byte, error) {
|
|
| 286 |
+ var err error |
|
| 287 |
+ var et int8 |
|
| 288 |
+ et, err = peekExtension(msg) |
|
| 289 |
+ if err != nil {
|
|
| 290 |
+ return msg, scratch, err |
|
| 291 |
+ } |
|
| 292 |
+ |
|
| 293 |
+ // if it's time.Time |
|
| 294 |
+ if et == TimeExtension {
|
|
| 295 |
+ var tm time.Time |
|
| 296 |
+ tm, msg, err = ReadTimeBytes(msg) |
|
| 297 |
+ if err != nil {
|
|
| 298 |
+ return msg, scratch, err |
|
| 299 |
+ } |
|
| 300 |
+ bts, err := tm.MarshalJSON() |
|
| 301 |
+ if err != nil {
|
|
| 302 |
+ return msg, scratch, err |
|
| 303 |
+ } |
|
| 304 |
+ _, err = w.Write(bts) |
|
| 305 |
+ return msg, scratch, err |
|
| 306 |
+ } |
|
| 307 |
+ |
|
| 308 |
+ // if the extension is registered, |
|
| 309 |
+ // use its canonical JSON form |
|
| 310 |
+ if f, ok := extensionReg[et]; ok {
|
|
| 311 |
+ e := f() |
|
| 312 |
+ msg, err = ReadExtensionBytes(msg, e) |
|
| 313 |
+ if err != nil {
|
|
| 314 |
+ return msg, scratch, err |
|
| 315 |
+ } |
|
| 316 |
+ bts, err := json.Marshal(e) |
|
| 317 |
+ if err != nil {
|
|
| 318 |
+ return msg, scratch, err |
|
| 319 |
+ } |
|
| 320 |
+ _, err = w.Write(bts) |
|
| 321 |
+ return msg, scratch, err |
|
| 322 |
+ } |
|
| 323 |
+ |
|
| 324 |
+ // otherwise, write `{"type": <num>, "data": "<base64data>"}`
|
|
| 325 |
+ r := RawExtension{}
|
|
| 326 |
+ r.Type = et |
|
| 327 |
+ msg, err = ReadExtensionBytes(msg, &r) |
|
| 328 |
+ if err != nil {
|
|
| 329 |
+ return msg, scratch, err |
|
| 330 |
+ } |
|
| 331 |
+ scratch, err = writeExt(w, r, scratch) |
|
| 332 |
+ return msg, scratch, err |
|
| 333 |
+} |
|
| 334 |
+ |
|
| 335 |
+func writeExt(w jsWriter, r RawExtension, scratch []byte) ([]byte, error) {
|
|
| 336 |
+ _, err := w.WriteString(`{"type":`)
|
|
| 337 |
+ if err != nil {
|
|
| 338 |
+ return scratch, err |
|
| 339 |
+ } |
|
| 340 |
+ scratch = strconv.AppendInt(scratch[0:0], int64(r.Type), 10) |
|
| 341 |
+ _, err = w.Write(scratch) |
|
| 342 |
+ if err != nil {
|
|
| 343 |
+ return scratch, err |
|
| 344 |
+ } |
|
| 345 |
+ _, err = w.WriteString(`,"data":"`) |
|
| 346 |
+ if err != nil {
|
|
| 347 |
+ return scratch, err |
|
| 348 |
+ } |
|
| 349 |
+ l := base64.StdEncoding.EncodedLen(len(r.Data)) |
|
| 350 |
+ if cap(scratch) >= l {
|
|
| 351 |
+ scratch = scratch[0:l] |
|
| 352 |
+ } else {
|
|
| 353 |
+ scratch = make([]byte, l) |
|
| 354 |
+ } |
|
| 355 |
+ base64.StdEncoding.Encode(scratch, r.Data) |
|
| 356 |
+ _, err = w.Write(scratch) |
|
| 357 |
+ if err != nil {
|
|
| 358 |
+ return scratch, err |
|
| 359 |
+ } |
|
| 360 |
+ _, err = w.WriteString(`"}`) |
|
| 361 |
+ return scratch, err |
|
| 362 |
+} |
| 0 | 363 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,140 @@ |
| 0 |
+package msgp |
|
| 1 |
+ |
|
| 2 |
+import ( |
|
| 3 |
+ "strconv" |
|
| 4 |
+) |
|
| 5 |
+ |
|
| 6 |
+// The portable parts of the Number implementation |
|
| 7 |
+ |
|
| 8 |
+// DecodeMsg implements msgp.Decodable |
|
| 9 |
+func (n *Number) DecodeMsg(r *Reader) error {
|
|
| 10 |
+ typ, err := r.NextType() |
|
| 11 |
+ if err != nil {
|
|
| 12 |
+ return err |
|
| 13 |
+ } |
|
| 14 |
+ switch typ {
|
|
| 15 |
+ case Float32Type: |
|
| 16 |
+ f, err := r.ReadFloat32() |
|
| 17 |
+ if err != nil {
|
|
| 18 |
+ return err |
|
| 19 |
+ } |
|
| 20 |
+ n.AsFloat32(f) |
|
| 21 |
+ return nil |
|
| 22 |
+ case Float64Type: |
|
| 23 |
+ f, err := r.ReadFloat64() |
|
| 24 |
+ if err != nil {
|
|
| 25 |
+ return err |
|
| 26 |
+ } |
|
| 27 |
+ n.AsFloat64(f) |
|
| 28 |
+ return nil |
|
| 29 |
+ case IntType: |
|
| 30 |
+ i, err := r.ReadInt64() |
|
| 31 |
+ if err != nil {
|
|
| 32 |
+ return err |
|
| 33 |
+ } |
|
| 34 |
+ n.AsInt(i) |
|
| 35 |
+ return nil |
|
| 36 |
+ case UintType: |
|
| 37 |
+ u, err := r.ReadUint64() |
|
| 38 |
+ if err != nil {
|
|
| 39 |
+ return err |
|
| 40 |
+ } |
|
| 41 |
+ n.AsUint(u) |
|
| 42 |
+ return nil |
|
| 43 |
+ default: |
|
| 44 |
+ return TypeError{Encoded: typ, Method: IntType}
|
|
| 45 |
+ } |
|
| 46 |
+} |
|
| 47 |
+ |
|
| 48 |
+// UnmarshalMsg implements msgp.Unmarshaler |
|
| 49 |
+func (n *Number) UnmarshalMsg(b []byte) ([]byte, error) {
|
|
| 50 |
+ typ := NextType(b) |
|
| 51 |
+ switch typ {
|
|
| 52 |
+ case IntType: |
|
| 53 |
+ i, o, err := ReadInt64Bytes(b) |
|
| 54 |
+ if err != nil {
|
|
| 55 |
+ return b, err |
|
| 56 |
+ } |
|
| 57 |
+ n.AsInt(i) |
|
| 58 |
+ return o, nil |
|
| 59 |
+ case UintType: |
|
| 60 |
+ u, o, err := ReadUint64Bytes(b) |
|
| 61 |
+ if err != nil {
|
|
| 62 |
+ return b, err |
|
| 63 |
+ } |
|
| 64 |
+ n.AsUint(u) |
|
| 65 |
+ return o, nil |
|
| 66 |
+ case Float64Type: |
|
| 67 |
+ f, o, err := ReadFloat64Bytes(b) |
|
| 68 |
+ if err != nil {
|
|
| 69 |
+ return b, err |
|
| 70 |
+ } |
|
| 71 |
+ n.AsFloat64(f) |
|
| 72 |
+ return o, nil |
|
| 73 |
+ case Float32Type: |
|
| 74 |
+ f, o, err := ReadFloat32Bytes(b) |
|
| 75 |
+ if err != nil {
|
|
| 76 |
+ return b, err |
|
| 77 |
+ } |
|
| 78 |
+ n.AsFloat32(f) |
|
| 79 |
+ return o, nil |
|
| 80 |
+ default: |
|
| 81 |
+ return b, TypeError{Method: IntType, Encoded: typ}
|
|
| 82 |
+ } |
|
| 83 |
+} |
|
| 84 |
+ |
|
| 85 |
+// Msgsize implements msgp.Sizer |
|
| 86 |
+func (n *Number) Msgsize() int {
|
|
| 87 |
+ switch n.typ {
|
|
| 88 |
+ case Float32Type: |
|
| 89 |
+ return Float32Size |
|
| 90 |
+ case Float64Type: |
|
| 91 |
+ return Float64Size |
|
| 92 |
+ case IntType: |
|
| 93 |
+ return Int64Size |
|
| 94 |
+ case UintType: |
|
| 95 |
+ return Uint64Size |
|
| 96 |
+ default: |
|
| 97 |
+ return 1 // fixint(0) |
|
| 98 |
+ } |
|
| 99 |
+} |
|
| 100 |
+ |
|
| 101 |
+// MarshalJSON implements json.Marshaler |
|
| 102 |
+func (n *Number) MarshalJSON() ([]byte, error) {
|
|
| 103 |
+ t := n.Type() |
|
| 104 |
+ if t == InvalidType {
|
|
| 105 |
+ return []byte{'0'}, nil
|
|
| 106 |
+ } |
|
| 107 |
+ out := make([]byte, 0, 32) |
|
| 108 |
+ switch t {
|
|
| 109 |
+ case Float32Type, Float64Type: |
|
| 110 |
+ f, _ := n.Float() |
|
| 111 |
+ return strconv.AppendFloat(out, f, 'f', -1, 64), nil |
|
| 112 |
+ case IntType: |
|
| 113 |
+ i, _ := n.Int() |
|
| 114 |
+ return strconv.AppendInt(out, i, 10), nil |
|
| 115 |
+ case UintType: |
|
| 116 |
+ u, _ := n.Uint() |
|
| 117 |
+ return strconv.AppendUint(out, u, 10), nil |
|
| 118 |
+ default: |
|
| 119 |
+ panic("(*Number).typ is invalid")
|
|
| 120 |
+ } |
|
| 121 |
+} |
|
| 122 |
+ |
|
| 123 |
+func (n *Number) String() string {
|
|
| 124 |
+ switch n.typ {
|
|
| 125 |
+ case InvalidType: |
|
| 126 |
+ return "0" |
|
| 127 |
+ case Float32Type, Float64Type: |
|
| 128 |
+ f, _ := n.Float() |
|
| 129 |
+ return strconv.FormatFloat(f, 'f', -1, 64) |
|
| 130 |
+ case IntType: |
|
| 131 |
+ i, _ := n.Int() |
|
| 132 |
+ return strconv.FormatInt(i, 10) |
|
| 133 |
+ case UintType: |
|
| 134 |
+ u, _ := n.Uint() |
|
| 135 |
+ return strconv.FormatUint(u, 10) |
|
| 136 |
+ default: |
|
| 137 |
+ panic("(*Number).typ is invalid")
|
|
| 138 |
+ } |
|
| 139 |
+} |
| 0 | 140 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,101 @@ |
| 0 |
+// +build appengine |
|
| 1 |
+ |
|
| 2 |
+package msgp |
|
| 3 |
+ |
|
| 4 |
+// let's just assume appengine |
|
| 5 |
+// uses 64-bit hardware... |
|
| 6 |
+const smallint = false |
|
| 7 |
+ |
|
| 8 |
+func UnsafeString(b []byte) string {
|
|
| 9 |
+ return string(b) |
|
| 10 |
+} |
|
| 11 |
+ |
|
| 12 |
+func UnsafeBytes(s string) []byte {
|
|
| 13 |
+ return []byte(s) |
|
| 14 |
+} |
|
| 15 |
+ |
|
| 16 |
+type Number struct {
|
|
| 17 |
+ ibits uint64 // zero or bits |
|
| 18 |
+ fbits float64 // zero or bits |
|
| 19 |
+ typ Type // zero or type |
|
| 20 |
+} |
|
| 21 |
+ |
|
| 22 |
+func (n *Number) AsFloat64(f float64) {
|
|
| 23 |
+ n.typ = Float64Type |
|
| 24 |
+ n.fbits = f |
|
| 25 |
+ n.ibits = 0 |
|
| 26 |
+} |
|
| 27 |
+ |
|
| 28 |
+func (n *Number) AsFloat32(f float32) {
|
|
| 29 |
+ n.typ = Float32Type |
|
| 30 |
+ n.fbits = float64(f) |
|
| 31 |
+ n.ibits = 0 |
|
| 32 |
+} |
|
| 33 |
+ |
|
| 34 |
+func (n *Number) AsInt(i int64) {
|
|
| 35 |
+ n.fbits = 0 |
|
| 36 |
+ if i == 0 {
|
|
| 37 |
+ n.typ = InvalidType |
|
| 38 |
+ n.ibits = 0 |
|
| 39 |
+ return |
|
| 40 |
+ } |
|
| 41 |
+ n.ibits = uint64(i) |
|
| 42 |
+ n.typ = IntType |
|
| 43 |
+} |
|
| 44 |
+ |
|
| 45 |
+func (n *Number) AsUint(u uint64) {
|
|
| 46 |
+ n.ibits = u |
|
| 47 |
+ n.fbits = 0 |
|
| 48 |
+ n.typ = UintType |
|
| 49 |
+} |
|
| 50 |
+ |
|
| 51 |
+func (n *Number) Float() (float64, bool) {
|
|
| 52 |
+ return n.fbits, n.typ == Float64Type || n.typ == Float32Type |
|
| 53 |
+} |
|
| 54 |
+ |
|
| 55 |
+func (n *Number) Int() (int64, bool) {
|
|
| 56 |
+ return int64(n.ibits), n.typ == IntType |
|
| 57 |
+} |
|
| 58 |
+ |
|
| 59 |
+func (n *Number) Uint() (uint64, bool) {
|
|
| 60 |
+ return n.ibits, n.typ == UintType |
|
| 61 |
+} |
|
| 62 |
+ |
|
| 63 |
+func (n *Number) Type() Type {
|
|
| 64 |
+ if n.typ == InvalidType {
|
|
| 65 |
+ return IntType |
|
| 66 |
+ } |
|
| 67 |
+ return n.typ |
|
| 68 |
+} |
|
| 69 |
+ |
|
| 70 |
+func (n *Number) MarshalMsg(o []byte) ([]byte, error) {
|
|
| 71 |
+ switch n.typ {
|
|
| 72 |
+ case InvalidType: |
|
| 73 |
+ return AppendInt64(o, 0), nil |
|
| 74 |
+ case IntType: |
|
| 75 |
+ return AppendInt64(o, int64(n.ibits)), nil |
|
| 76 |
+ case UintType: |
|
| 77 |
+ return AppendUint64(o, n.ibits), nil |
|
| 78 |
+ case Float32Type: |
|
| 79 |
+ return AppendFloat32(o, float32(n.fbits)), nil |
|
| 80 |
+ case Float64Type: |
|
| 81 |
+ return AppendFloat64(o, n.fbits), nil |
|
| 82 |
+ } |
|
| 83 |
+ panic("unreachable code!")
|
|
| 84 |
+} |
|
| 85 |
+ |
|
| 86 |
+func (n *Number) EncodeMsg(w *Writer) error {
|
|
| 87 |
+ switch n.typ {
|
|
| 88 |
+ case InvalidType: |
|
| 89 |
+ return w.WriteInt64(0) |
|
| 90 |
+ case IntType: |
|
| 91 |
+ return w.WriteInt64(int64(n.ibits)) |
|
| 92 |
+ case UintType: |
|
| 93 |
+ return w.WriteUint64(n.ibits) |
|
| 94 |
+ case Float32Type: |
|
| 95 |
+ return w.WriteFloat32(float32(n.fbits)) |
|
| 96 |
+ case Float64Type: |
|
| 97 |
+ return w.WriteFloat64(n.fbits) |
|
| 98 |
+ } |
|
| 99 |
+ panic("unreachable code!")
|
|
| 100 |
+} |
| 0 | 101 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,159 @@ |
| 0 |
+// +build !appengine |
|
| 1 |
+ |
|
| 2 |
+package msgp |
|
| 3 |
+ |
|
| 4 |
+import ( |
|
| 5 |
+ "reflect" |
|
| 6 |
+ "unsafe" |
|
| 7 |
+) |
|
| 8 |
+ |
|
| 9 |
+const ( |
|
| 10 |
+ // spec says int and uint are always |
|
| 11 |
+ // the same size, but that int/uint |
|
| 12 |
+ // size may not be machine word size |
|
| 13 |
+ smallint = unsafe.Sizeof(int(0)) == 4 |
|
| 14 |
+) |
|
| 15 |
+ |
|
| 16 |
+// UnsafeString returns the byte slice as a volatile string |
|
| 17 |
+// THIS SHOULD ONLY BE USED BY THE CODE GENERATOR. |
|
| 18 |
+// THIS IS EVIL CODE. |
|
| 19 |
+// YOU HAVE BEEN WARNED. |
|
| 20 |
+func UnsafeString(b []byte) string {
|
|
| 21 |
+ return *(*string)(unsafe.Pointer(&reflect.StringHeader{Data: uintptr(unsafe.Pointer(&b[0])), Len: len(b)}))
|
|
| 22 |
+} |
|
| 23 |
+ |
|
| 24 |
+// UnsafeBytes returns the string as a byte slice |
|
| 25 |
+// THIS SHOULD ONLY BE USED BY THE CODE GENERATOR. |
|
| 26 |
+// THIS IS EVIL CODE. |
|
| 27 |
+// YOU HAVE BEEN WARNED. |
|
| 28 |
+func UnsafeBytes(s string) []byte {
|
|
| 29 |
+ return *(*[]byte)(unsafe.Pointer(&reflect.SliceHeader{
|
|
| 30 |
+ Len: len(s), |
|
| 31 |
+ Cap: len(s), |
|
| 32 |
+ Data: (*(*reflect.StringHeader)(unsafe.Pointer(&s))).Data, |
|
| 33 |
+ })) |
|
| 34 |
+} |
|
| 35 |
+ |
|
| 36 |
+// Number can be |
|
| 37 |
+// an int64, uint64, float32, |
|
| 38 |
+// or float64 internally. |
|
| 39 |
+// It can decode itself |
|
| 40 |
+// from any of the native |
|
| 41 |
+// messagepack number types. |
|
| 42 |
+// The zero-value of Number |
|
| 43 |
+// is Int(0). Using the equality |
|
| 44 |
+// operator with Number compares |
|
| 45 |
+// both the type and the value |
|
| 46 |
+// of the number. |
|
| 47 |
+type Number struct {
|
|
| 48 |
+ // internally, this |
|
| 49 |
+ // is just a tagged union. |
|
| 50 |
+ // the raw bits of the number |
|
| 51 |
+ // are stored the same way regardless. |
|
| 52 |
+ bits uint64 |
|
| 53 |
+ typ Type |
|
| 54 |
+} |
|
| 55 |
+ |
|
| 56 |
+// AsFloat64 sets the number to |
|
| 57 |
+// a float64. |
|
| 58 |
+func (n *Number) AsFloat64(f float64) {
|
|
| 59 |
+ n.typ = Float64Type |
|
| 60 |
+ n.bits = *(*uint64)(unsafe.Pointer(&f)) |
|
| 61 |
+} |
|
| 62 |
+ |
|
| 63 |
+// AsInt sets the number to an int64. |
|
| 64 |
+func (n *Number) AsInt(i int64) {
|
|
| 65 |
+ |
|
| 66 |
+ // we always store int(0) |
|
| 67 |
+ // as {0, InvalidType} in
|
|
| 68 |
+ // order to preserve |
|
| 69 |
+ // the behavior of the == operator |
|
| 70 |
+ if i == 0 {
|
|
| 71 |
+ n.typ = InvalidType |
|
| 72 |
+ n.bits = 0 |
|
| 73 |
+ return |
|
| 74 |
+ } |
|
| 75 |
+ |
|
| 76 |
+ n.typ = IntType |
|
| 77 |
+ n.bits = uint64(i) |
|
| 78 |
+} |
|
| 79 |
+ |
|
| 80 |
+// AsUint sets the number to a uint64. |
|
| 81 |
+func (n *Number) AsUint(u uint64) {
|
|
| 82 |
+ n.typ = UintType |
|
| 83 |
+ n.bits = u |
|
| 84 |
+} |
|
| 85 |
+ |
|
| 86 |
+// AsFloat32 sets the number to a float32. |
|
| 87 |
+func (n *Number) AsFloat32(f float32) {
|
|
| 88 |
+ n.typ = Float32Type |
|
| 89 |
+ g := float64(f) |
|
| 90 |
+ n.bits = *(*uint64)(unsafe.Pointer(&g)) |
|
| 91 |
+} |
|
| 92 |
+ |
|
| 93 |
+// Type will return one of: |
|
| 94 |
+// Float64Type, Float32Type, UintType, or IntType. |
|
| 95 |
+func (n *Number) Type() Type {
|
|
| 96 |
+ if n.typ == InvalidType {
|
|
| 97 |
+ return IntType |
|
| 98 |
+ } |
|
| 99 |
+ return n.typ |
|
| 100 |
+} |
|
| 101 |
+ |
|
| 102 |
+// Float casts the number of the float, |
|
| 103 |
+// and returns whether or not that was |
|
| 104 |
+// the underlying type. (This is legal |
|
| 105 |
+// for both float32 and float64 types.) |
|
| 106 |
+func (n *Number) Float() (float64, bool) {
|
|
| 107 |
+ return *(*float64)(unsafe.Pointer(&n.bits)), n.typ == Float64Type || n.typ == Float32Type |
|
| 108 |
+} |
|
| 109 |
+ |
|
| 110 |
+// Int casts the number as an int64, and |
|
| 111 |
+// returns whether or not that was the |
|
| 112 |
+// underlying type. |
|
| 113 |
+func (n *Number) Int() (int64, bool) {
|
|
| 114 |
+ return int64(n.bits), n.typ == IntType || n.typ == InvalidType |
|
| 115 |
+} |
|
| 116 |
+ |
|
| 117 |
+// Uint casts the number as a uint64, and returns |
|
| 118 |
+// whether or not that was the underlying type. |
|
| 119 |
+func (n *Number) Uint() (uint64, bool) {
|
|
| 120 |
+ return n.bits, n.typ == UintType |
|
| 121 |
+} |
|
| 122 |
+ |
|
| 123 |
+// EncodeMsg implements msgp.Encodable |
|
| 124 |
+func (n *Number) EncodeMsg(w *Writer) error {
|
|
| 125 |
+ switch n.typ {
|
|
| 126 |
+ case InvalidType: |
|
| 127 |
+ return w.WriteInt(0) |
|
| 128 |
+ case IntType: |
|
| 129 |
+ return w.WriteInt64(int64(n.bits)) |
|
| 130 |
+ case UintType: |
|
| 131 |
+ return w.WriteUint64(n.bits) |
|
| 132 |
+ case Float64Type: |
|
| 133 |
+ return w.WriteFloat64(*(*float64)(unsafe.Pointer(&n.bits))) |
|
| 134 |
+ case Float32Type: |
|
| 135 |
+ return w.WriteFloat32(float32(*(*float64)(unsafe.Pointer(&n.bits)))) |
|
| 136 |
+ default: |
|
| 137 |
+ // this should never ever happen |
|
| 138 |
+ panic("(*Number).typ is invalid")
|
|
| 139 |
+ } |
|
| 140 |
+} |
|
| 141 |
+ |
|
| 142 |
+// MarshalMsg implements msgp.Marshaler |
|
| 143 |
+func (n *Number) MarshalMsg(b []byte) ([]byte, error) {
|
|
| 144 |
+ switch n.typ {
|
|
| 145 |
+ case InvalidType: |
|
| 146 |
+ return AppendInt(b, 0), nil |
|
| 147 |
+ case IntType: |
|
| 148 |
+ return AppendInt64(b, int64(n.bits)), nil |
|
| 149 |
+ case UintType: |
|
| 150 |
+ return AppendUint64(b, n.bits), nil |
|
| 151 |
+ case Float64Type: |
|
| 152 |
+ return AppendFloat64(b, *(*float64)(unsafe.Pointer(&n.bits))), nil |
|
| 153 |
+ case Float32Type: |
|
| 154 |
+ return AppendFloat32(b, float32(*(*float64)(unsafe.Pointer(&n.bits)))), nil |
|
| 155 |
+ default: |
|
| 156 |
+ panic("(*Number).typ is invalid")
|
|
| 157 |
+ } |
|
| 158 |
+} |
| 0 | 159 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,1118 @@ |
| 0 |
+package msgp |
|
| 1 |
+ |
|
| 2 |
+import ( |
|
| 3 |
+ "github.com/philhofer/fwd" |
|
| 4 |
+ "io" |
|
| 5 |
+ "math" |
|
| 6 |
+ "sync" |
|
| 7 |
+ "time" |
|
| 8 |
+) |
|
| 9 |
+ |
|
| 10 |
+// where we keep old *Readers |
|
| 11 |
+var readerPool = sync.Pool{New: func() interface{} { return &Reader{} }}
|
|
| 12 |
+ |
|
| 13 |
+// Type is a MessagePack wire type, |
|
| 14 |
+// including this package's built-in |
|
| 15 |
+// extension types. |
|
| 16 |
+type Type byte |
|
| 17 |
+ |
|
| 18 |
+// MessagePack Types |
|
| 19 |
+// |
|
| 20 |
+// The zero value of Type |
|
| 21 |
+// is InvalidType. |
|
| 22 |
+const ( |
|
| 23 |
+ InvalidType Type = iota |
|
| 24 |
+ |
|
| 25 |
+ // MessagePack built-in types |
|
| 26 |
+ |
|
| 27 |
+ StrType |
|
| 28 |
+ BinType |
|
| 29 |
+ MapType |
|
| 30 |
+ ArrayType |
|
| 31 |
+ Float64Type |
|
| 32 |
+ Float32Type |
|
| 33 |
+ BoolType |
|
| 34 |
+ IntType |
|
| 35 |
+ UintType |
|
| 36 |
+ NilType |
|
| 37 |
+ ExtensionType |
|
| 38 |
+ |
|
| 39 |
+ // pseudo-types provided |
|
| 40 |
+ // by extensions |
|
| 41 |
+ |
|
| 42 |
+ Complex64Type |
|
| 43 |
+ Complex128Type |
|
| 44 |
+ TimeType |
|
| 45 |
+ |
|
| 46 |
+ _maxtype |
|
| 47 |
+) |
|
| 48 |
+ |
|
| 49 |
+// String implements fmt.Stringer |
|
| 50 |
+func (t Type) String() string {
|
|
| 51 |
+ switch t {
|
|
| 52 |
+ case StrType: |
|
| 53 |
+ return "str" |
|
| 54 |
+ case BinType: |
|
| 55 |
+ return "bin" |
|
| 56 |
+ case MapType: |
|
| 57 |
+ return "map" |
|
| 58 |
+ case ArrayType: |
|
| 59 |
+ return "array" |
|
| 60 |
+ case Float64Type: |
|
| 61 |
+ return "float64" |
|
| 62 |
+ case Float32Type: |
|
| 63 |
+ return "float32" |
|
| 64 |
+ case BoolType: |
|
| 65 |
+ return "bool" |
|
| 66 |
+ case UintType: |
|
| 67 |
+ return "uint" |
|
| 68 |
+ case IntType: |
|
| 69 |
+ return "int" |
|
| 70 |
+ case ExtensionType: |
|
| 71 |
+ return "ext" |
|
| 72 |
+ case NilType: |
|
| 73 |
+ return "nil" |
|
| 74 |
+ default: |
|
| 75 |
+ return "<invalid>" |
|
| 76 |
+ } |
|
| 77 |
+} |
|
| 78 |
+ |
|
| 79 |
+func freeR(m *Reader) {
|
|
| 80 |
+ readerPool.Put(m) |
|
| 81 |
+} |
|
| 82 |
+ |
|
| 83 |
+// Unmarshaler is the interface fulfilled |
|
| 84 |
+// by objects that know how to unmarshal |
|
| 85 |
+// themselves from MessagePack. |
|
| 86 |
+// UnmarshalMsg unmarshals the object |
|
| 87 |
+// from binary, returing any leftover |
|
| 88 |
+// bytes and any errors encountered. |
|
| 89 |
+type Unmarshaler interface {
|
|
| 90 |
+ UnmarshalMsg([]byte) ([]byte, error) |
|
| 91 |
+} |
|
| 92 |
+ |
|
| 93 |
+// Decodable is the interface fulfilled |
|
| 94 |
+// by objects that know how to read |
|
| 95 |
+// themselves from a *Reader. |
|
| 96 |
+type Decodable interface {
|
|
| 97 |
+ DecodeMsg(*Reader) error |
|
| 98 |
+} |
|
| 99 |
+ |
|
| 100 |
+// Decode decodes 'd' from 'r'. |
|
| 101 |
+func Decode(r io.Reader, d Decodable) error {
|
|
| 102 |
+ rd := NewReader(r) |
|
| 103 |
+ err := d.DecodeMsg(rd) |
|
| 104 |
+ freeR(rd) |
|
| 105 |
+ return err |
|
| 106 |
+} |
|
| 107 |
+ |
|
| 108 |
+// NewReader returns a *Reader that |
|
| 109 |
+// reads from the provided reader. The |
|
| 110 |
+// reader will be buffered. |
|
| 111 |
+func NewReader(r io.Reader) *Reader {
|
|
| 112 |
+ p := readerPool.Get().(*Reader) |
|
| 113 |
+ if p.r == nil {
|
|
| 114 |
+ p.r = fwd.NewReader(r) |
|
| 115 |
+ } else {
|
|
| 116 |
+ p.r.Reset(r) |
|
| 117 |
+ } |
|
| 118 |
+ return p |
|
| 119 |
+} |
|
| 120 |
+ |
|
| 121 |
+// NewReaderSize returns a *Reader with a buffer of the given size. |
|
| 122 |
+// (This is vastly preferable to passing the decoder a reader that is already buffered.) |
|
| 123 |
+func NewReaderSize(r io.Reader, sz int) *Reader {
|
|
| 124 |
+ return &Reader{r: fwd.NewReaderSize(r, sz)}
|
|
| 125 |
+} |
|
| 126 |
+ |
|
| 127 |
+// Reader wraps an io.Reader and provides |
|
| 128 |
+// methods to read MessagePack-encoded values |
|
| 129 |
+// from it. Readers are buffered. |
|
| 130 |
+type Reader struct {
|
|
| 131 |
+ r *fwd.Reader |
|
| 132 |
+ scratch []byte |
|
| 133 |
+} |
|
| 134 |
+ |
|
| 135 |
+// Read implements `io.Reader` |
|
| 136 |
+func (m *Reader) Read(p []byte) (int, error) {
|
|
| 137 |
+ return m.r.Read(p) |
|
| 138 |
+} |
|
| 139 |
+ |
|
| 140 |
+// ReadFull implements `io.ReadFull` |
|
| 141 |
+func (m *Reader) ReadFull(p []byte) (int, error) {
|
|
| 142 |
+ return m.r.ReadFull(p) |
|
| 143 |
+} |
|
| 144 |
+ |
|
| 145 |
+// Reset resets the underlying reader. |
|
| 146 |
+func (m *Reader) Reset(r io.Reader) { m.r.Reset(r) }
|
|
| 147 |
+ |
|
| 148 |
+// Buffered returns the number of bytes currently in the read buffer. |
|
| 149 |
+func (m *Reader) Buffered() int { return m.r.Buffered() }
|
|
| 150 |
+ |
|
| 151 |
+// BufferSize returns the capacity of the read buffer. |
|
| 152 |
+func (m *Reader) BufferSize() int { return m.r.BufferSize() }
|
|
| 153 |
+ |
|
| 154 |
+// NextType returns the next object type to be decoded. |
|
| 155 |
+func (m *Reader) NextType() (Type, error) {
|
|
| 156 |
+ p, err := m.r.Peek(1) |
|
| 157 |
+ if err != nil {
|
|
| 158 |
+ return InvalidType, err |
|
| 159 |
+ } |
|
| 160 |
+ t := getType(p[0]) |
|
| 161 |
+ if t == InvalidType {
|
|
| 162 |
+ return t, InvalidPrefixError(p[0]) |
|
| 163 |
+ } |
|
| 164 |
+ if t == ExtensionType {
|
|
| 165 |
+ v, err := m.peekExtensionType() |
|
| 166 |
+ if err != nil {
|
|
| 167 |
+ return InvalidType, err |
|
| 168 |
+ } |
|
| 169 |
+ switch v {
|
|
| 170 |
+ case Complex64Extension: |
|
| 171 |
+ return Complex64Type, nil |
|
| 172 |
+ case Complex128Extension: |
|
| 173 |
+ return Complex128Type, nil |
|
| 174 |
+ case TimeExtension: |
|
| 175 |
+ return TimeType, nil |
|
| 176 |
+ } |
|
| 177 |
+ } |
|
| 178 |
+ return t, nil |
|
| 179 |
+} |
|
| 180 |
+ |
|
| 181 |
+// IsNil returns whether or not |
|
| 182 |
+// the next byte is a null messagepack byte |
|
| 183 |
+func (m *Reader) IsNil() bool {
|
|
| 184 |
+ p, err := m.r.Peek(1) |
|
| 185 |
+ return err == nil && p[0] == mnil |
|
| 186 |
+} |
|
| 187 |
+ |
|
| 188 |
+// returns (obj size, obj elements, error) |
|
| 189 |
+// only maps and arrays have non-zero obj elements |
|
| 190 |
+// |
|
| 191 |
+// use uintptr b/c it's guaranteed to be large enough |
|
| 192 |
+// to hold whatever we can fit in memory. |
|
| 193 |
+func getNextSize(r *fwd.Reader) (uintptr, uintptr, error) {
|
|
| 194 |
+ b, err := r.Peek(1) |
|
| 195 |
+ if err != nil {
|
|
| 196 |
+ return 0, 0, err |
|
| 197 |
+ } |
|
| 198 |
+ lead := b[0] |
|
| 199 |
+ spec := &sizes[lead] |
|
| 200 |
+ size, mode := spec.size, spec.extra |
|
| 201 |
+ if size == 0 {
|
|
| 202 |
+ return 0, 0, InvalidPrefixError(lead) |
|
| 203 |
+ } |
|
| 204 |
+ if mode >= 0 {
|
|
| 205 |
+ return uintptr(size), uintptr(mode), nil |
|
| 206 |
+ } |
|
| 207 |
+ b, err = r.Peek(int(size)) |
|
| 208 |
+ if err != nil {
|
|
| 209 |
+ return 0, 0, err |
|
| 210 |
+ } |
|
| 211 |
+ switch mode {
|
|
| 212 |
+ case extra8: |
|
| 213 |
+ return uintptr(size) + uintptr(b[1]), 0, nil |
|
| 214 |
+ case extra16: |
|
| 215 |
+ return uintptr(size) + uintptr(big.Uint16(b[1:])), 0, nil |
|
| 216 |
+ case extra32: |
|
| 217 |
+ return uintptr(size) + uintptr(big.Uint32(b[1:])), 0, nil |
|
| 218 |
+ case map16v: |
|
| 219 |
+ return uintptr(size), 2 * uintptr(big.Uint16(b[1:])), nil |
|
| 220 |
+ case map32v: |
|
| 221 |
+ return uintptr(size), 2 * uintptr(big.Uint32(b[1:])), nil |
|
| 222 |
+ case array16v: |
|
| 223 |
+ return uintptr(size), uintptr(big.Uint16(b[1:])), nil |
|
| 224 |
+ case array32v: |
|
| 225 |
+ return uintptr(size), uintptr(big.Uint32(b[1:])), nil |
|
| 226 |
+ default: |
|
| 227 |
+ return 0, 0, fatal |
|
| 228 |
+ } |
|
| 229 |
+} |
|
| 230 |
+ |
|
| 231 |
+// Skip skips over the next object, regardless of |
|
| 232 |
+// its type. If it is an array or map, the whole array |
|
| 233 |
+// or map will be skipped. |
|
| 234 |
+func (m *Reader) Skip() error {
|
|
| 235 |
+ var ( |
|
| 236 |
+ v uintptr // bytes |
|
| 237 |
+ o uintptr // objects |
|
| 238 |
+ err error |
|
| 239 |
+ p []byte |
|
| 240 |
+ ) |
|
| 241 |
+ |
|
| 242 |
+ // we can use the faster |
|
| 243 |
+ // method if we have enough |
|
| 244 |
+ // buffered data |
|
| 245 |
+ if m.r.Buffered() >= 5 {
|
|
| 246 |
+ p, err = m.r.Peek(5) |
|
| 247 |
+ if err != nil {
|
|
| 248 |
+ return err |
|
| 249 |
+ } |
|
| 250 |
+ v, o, err = getSize(p) |
|
| 251 |
+ if err != nil {
|
|
| 252 |
+ return err |
|
| 253 |
+ } |
|
| 254 |
+ } else {
|
|
| 255 |
+ v, o, err = getNextSize(m.r) |
|
| 256 |
+ if err != nil {
|
|
| 257 |
+ return err |
|
| 258 |
+ } |
|
| 259 |
+ } |
|
| 260 |
+ |
|
| 261 |
+ // 'v' is always non-zero |
|
| 262 |
+ // if err == nil |
|
| 263 |
+ _, err = m.r.Skip(int(v)) |
|
| 264 |
+ if err != nil {
|
|
| 265 |
+ return err |
|
| 266 |
+ } |
|
| 267 |
+ |
|
| 268 |
+ // for maps and slices, skip elements |
|
| 269 |
+ for x := uintptr(0); x < o; x++ {
|
|
| 270 |
+ err = m.Skip() |
|
| 271 |
+ if err != nil {
|
|
| 272 |
+ return err |
|
| 273 |
+ } |
|
| 274 |
+ } |
|
| 275 |
+ return nil |
|
| 276 |
+} |
|
| 277 |
+ |
|
| 278 |
+// ReadMapHeader reads the next object |
|
| 279 |
+// as a map header and returns the size |
|
| 280 |
+// of the map and the number of bytes written. |
|
| 281 |
+// It will return a TypeError{} if the next
|
|
| 282 |
+// object is not a map. |
|
| 283 |
+func (m *Reader) ReadMapHeader() (sz uint32, err error) {
|
|
| 284 |
+ var p []byte |
|
| 285 |
+ var lead byte |
|
| 286 |
+ p, err = m.r.Peek(1) |
|
| 287 |
+ if err != nil {
|
|
| 288 |
+ return |
|
| 289 |
+ } |
|
| 290 |
+ lead = p[0] |
|
| 291 |
+ if isfixmap(lead) {
|
|
| 292 |
+ sz = uint32(rfixmap(lead)) |
|
| 293 |
+ _, err = m.r.Skip(1) |
|
| 294 |
+ return |
|
| 295 |
+ } |
|
| 296 |
+ switch lead {
|
|
| 297 |
+ case mmap16: |
|
| 298 |
+ p, err = m.r.Next(3) |
|
| 299 |
+ if err != nil {
|
|
| 300 |
+ return |
|
| 301 |
+ } |
|
| 302 |
+ sz = uint32(big.Uint16(p[1:])) |
|
| 303 |
+ return |
|
| 304 |
+ case mmap32: |
|
| 305 |
+ p, err = m.r.Next(5) |
|
| 306 |
+ if err != nil {
|
|
| 307 |
+ return |
|
| 308 |
+ } |
|
| 309 |
+ sz = big.Uint32(p[1:]) |
|
| 310 |
+ return |
|
| 311 |
+ default: |
|
| 312 |
+ err = badPrefix(MapType, lead) |
|
| 313 |
+ return |
|
| 314 |
+ } |
|
| 315 |
+} |
|
| 316 |
+ |
|
| 317 |
+// ReadMapKey reads either a 'str' or 'bin' field from |
|
| 318 |
+// the reader and returns the value as a []byte. It uses |
|
| 319 |
+// scratch for storage if it is large enough. |
|
| 320 |
+func (m *Reader) ReadMapKey(scratch []byte) ([]byte, error) {
|
|
| 321 |
+ out, err := m.ReadStringAsBytes(scratch) |
|
| 322 |
+ if err != nil {
|
|
| 323 |
+ if tperr, ok := err.(TypeError); ok && tperr.Encoded == BinType {
|
|
| 324 |
+ return m.ReadBytes(scratch) |
|
| 325 |
+ } |
|
| 326 |
+ return nil, err |
|
| 327 |
+ } |
|
| 328 |
+ return out, nil |
|
| 329 |
+} |
|
| 330 |
+ |
|
| 331 |
+// MapKeyPtr returns a []byte pointing to the contents |
|
| 332 |
+// of a valid map key. The key cannot be empty, and it |
|
| 333 |
+// must be shorter than the total buffer size of the |
|
| 334 |
+// *Reader. Additionally, the returned slice is only |
|
| 335 |
+// valid until the next *Reader method call. Users |
|
| 336 |
+// should exercise extreme care when using this |
|
| 337 |
+// method; writing into the returned slice may |
|
| 338 |
+// corrupt future reads. |
|
| 339 |
+func (m *Reader) ReadMapKeyPtr() ([]byte, error) {
|
|
| 340 |
+ p, err := m.r.Peek(1) |
|
| 341 |
+ if err != nil {
|
|
| 342 |
+ return nil, err |
|
| 343 |
+ } |
|
| 344 |
+ lead := p[0] |
|
| 345 |
+ var read int |
|
| 346 |
+ if isfixstr(lead) {
|
|
| 347 |
+ read = int(rfixstr(lead)) |
|
| 348 |
+ m.r.Skip(1) |
|
| 349 |
+ goto fill |
|
| 350 |
+ } |
|
| 351 |
+ switch lead {
|
|
| 352 |
+ case mstr8, mbin8: |
|
| 353 |
+ p, err = m.r.Next(2) |
|
| 354 |
+ if err != nil {
|
|
| 355 |
+ return nil, err |
|
| 356 |
+ } |
|
| 357 |
+ read = int(p[1]) |
|
| 358 |
+ case mstr16, mbin16: |
|
| 359 |
+ p, err = m.r.Next(3) |
|
| 360 |
+ if err != nil {
|
|
| 361 |
+ return nil, err |
|
| 362 |
+ } |
|
| 363 |
+ read = int(big.Uint16(p[1:])) |
|
| 364 |
+ case mstr32, mbin32: |
|
| 365 |
+ p, err = m.r.Next(5) |
|
| 366 |
+ if err != nil {
|
|
| 367 |
+ return nil, err |
|
| 368 |
+ } |
|
| 369 |
+ read = int(big.Uint32(p[1:])) |
|
| 370 |
+ default: |
|
| 371 |
+ return nil, badPrefix(StrType, lead) |
|
| 372 |
+ } |
|
| 373 |
+fill: |
|
| 374 |
+ if read == 0 {
|
|
| 375 |
+ return nil, ErrShortBytes |
|
| 376 |
+ } |
|
| 377 |
+ return m.r.Next(read) |
|
| 378 |
+} |
|
| 379 |
+ |
|
| 380 |
+// ReadArrayHeader reads the next object as an |
|
| 381 |
+// array header and returns the size of the array |
|
| 382 |
+// and the number of bytes read. |
|
| 383 |
+func (m *Reader) ReadArrayHeader() (sz uint32, err error) {
|
|
| 384 |
+ var lead byte |
|
| 385 |
+ var p []byte |
|
| 386 |
+ p, err = m.r.Peek(1) |
|
| 387 |
+ if err != nil {
|
|
| 388 |
+ return |
|
| 389 |
+ } |
|
| 390 |
+ lead = p[0] |
|
| 391 |
+ if isfixarray(lead) {
|
|
| 392 |
+ sz = uint32(rfixarray(lead)) |
|
| 393 |
+ _, err = m.r.Skip(1) |
|
| 394 |
+ return |
|
| 395 |
+ } |
|
| 396 |
+ switch lead {
|
|
| 397 |
+ case marray16: |
|
| 398 |
+ p, err = m.r.Next(3) |
|
| 399 |
+ if err != nil {
|
|
| 400 |
+ return |
|
| 401 |
+ } |
|
| 402 |
+ sz = uint32(big.Uint16(p[1:])) |
|
| 403 |
+ return |
|
| 404 |
+ |
|
| 405 |
+ case marray32: |
|
| 406 |
+ p, err = m.r.Next(5) |
|
| 407 |
+ if err != nil {
|
|
| 408 |
+ return |
|
| 409 |
+ } |
|
| 410 |
+ sz = big.Uint32(p[1:]) |
|
| 411 |
+ return |
|
| 412 |
+ |
|
| 413 |
+ default: |
|
| 414 |
+ err = badPrefix(ArrayType, lead) |
|
| 415 |
+ return |
|
| 416 |
+ } |
|
| 417 |
+} |
|
| 418 |
+ |
|
| 419 |
+// ReadNil reads a 'nil' MessagePack byte from the reader |
|
| 420 |
+func (m *Reader) ReadNil() error {
|
|
| 421 |
+ p, err := m.r.Peek(1) |
|
| 422 |
+ if err != nil {
|
|
| 423 |
+ return err |
|
| 424 |
+ } |
|
| 425 |
+ if p[0] != mnil {
|
|
| 426 |
+ return badPrefix(NilType, p[0]) |
|
| 427 |
+ } |
|
| 428 |
+ _, err = m.r.Skip(1) |
|
| 429 |
+ return err |
|
| 430 |
+} |
|
| 431 |
+ |
|
| 432 |
+// ReadFloat64 reads a float64 from the reader. |
|
| 433 |
+// (If the value on the wire is encoded as a float32, |
|
| 434 |
+// it will be up-cast to a float64.) |
|
| 435 |
+func (m *Reader) ReadFloat64() (f float64, err error) {
|
|
| 436 |
+ var p []byte |
|
| 437 |
+ p, err = m.r.Peek(9) |
|
| 438 |
+ if err != nil {
|
|
| 439 |
+ // we'll allow a coversion from float32 to float64, |
|
| 440 |
+ // since we don't lose any precision |
|
| 441 |
+ if err == io.EOF && len(p) > 0 && p[0] == mfloat32 {
|
|
| 442 |
+ ef, err := m.ReadFloat32() |
|
| 443 |
+ return float64(ef), err |
|
| 444 |
+ } |
|
| 445 |
+ return |
|
| 446 |
+ } |
|
| 447 |
+ if p[0] != mfloat64 {
|
|
| 448 |
+ // see above |
|
| 449 |
+ if p[0] == mfloat32 {
|
|
| 450 |
+ ef, err := m.ReadFloat32() |
|
| 451 |
+ return float64(ef), err |
|
| 452 |
+ } |
|
| 453 |
+ err = badPrefix(Float64Type, p[0]) |
|
| 454 |
+ return |
|
| 455 |
+ } |
|
| 456 |
+ f = math.Float64frombits(getMuint64(p)) |
|
| 457 |
+ _, err = m.r.Skip(9) |
|
| 458 |
+ return |
|
| 459 |
+} |
|
| 460 |
+ |
|
| 461 |
+// ReadFloat32 reads a float32 from the reader |
|
| 462 |
+func (m *Reader) ReadFloat32() (f float32, err error) {
|
|
| 463 |
+ var p []byte |
|
| 464 |
+ p, err = m.r.Peek(5) |
|
| 465 |
+ if err != nil {
|
|
| 466 |
+ return |
|
| 467 |
+ } |
|
| 468 |
+ if p[0] != mfloat32 {
|
|
| 469 |
+ err = badPrefix(Float32Type, p[0]) |
|
| 470 |
+ return |
|
| 471 |
+ } |
|
| 472 |
+ f = math.Float32frombits(getMuint32(p)) |
|
| 473 |
+ _, err = m.r.Skip(5) |
|
| 474 |
+ return |
|
| 475 |
+} |
|
| 476 |
+ |
|
| 477 |
+// ReadBool reads a bool from the reader |
|
| 478 |
+func (m *Reader) ReadBool() (b bool, err error) {
|
|
| 479 |
+ var p []byte |
|
| 480 |
+ p, err = m.r.Peek(1) |
|
| 481 |
+ if err != nil {
|
|
| 482 |
+ return |
|
| 483 |
+ } |
|
| 484 |
+ switch p[0] {
|
|
| 485 |
+ case mtrue: |
|
| 486 |
+ b = true |
|
| 487 |
+ case mfalse: |
|
| 488 |
+ default: |
|
| 489 |
+ err = badPrefix(BoolType, p[0]) |
|
| 490 |
+ return |
|
| 491 |
+ } |
|
| 492 |
+ _, err = m.r.Skip(1) |
|
| 493 |
+ return |
|
| 494 |
+} |
|
| 495 |
+ |
|
| 496 |
+// ReadInt64 reads an int64 from the reader |
|
| 497 |
+func (m *Reader) ReadInt64() (i int64, err error) {
|
|
| 498 |
+ var p []byte |
|
| 499 |
+ var lead byte |
|
| 500 |
+ p, err = m.r.Peek(1) |
|
| 501 |
+ if err != nil {
|
|
| 502 |
+ return |
|
| 503 |
+ } |
|
| 504 |
+ lead = p[0] |
|
| 505 |
+ |
|
| 506 |
+ if isfixint(lead) {
|
|
| 507 |
+ i = int64(rfixint(lead)) |
|
| 508 |
+ _, err = m.r.Skip(1) |
|
| 509 |
+ return |
|
| 510 |
+ } else if isnfixint(lead) {
|
|
| 511 |
+ i = int64(rnfixint(lead)) |
|
| 512 |
+ _, err = m.r.Skip(1) |
|
| 513 |
+ return |
|
| 514 |
+ } |
|
| 515 |
+ |
|
| 516 |
+ switch lead {
|
|
| 517 |
+ case mint8: |
|
| 518 |
+ p, err = m.r.Next(2) |
|
| 519 |
+ if err != nil {
|
|
| 520 |
+ return |
|
| 521 |
+ } |
|
| 522 |
+ i = int64(getMint8(p)) |
|
| 523 |
+ return |
|
| 524 |
+ |
|
| 525 |
+ case mint16: |
|
| 526 |
+ p, err = m.r.Next(3) |
|
| 527 |
+ if err != nil {
|
|
| 528 |
+ return |
|
| 529 |
+ } |
|
| 530 |
+ i = int64(getMint16(p)) |
|
| 531 |
+ return |
|
| 532 |
+ |
|
| 533 |
+ case mint32: |
|
| 534 |
+ p, err = m.r.Next(5) |
|
| 535 |
+ if err != nil {
|
|
| 536 |
+ return |
|
| 537 |
+ } |
|
| 538 |
+ i = int64(getMint32(p)) |
|
| 539 |
+ return |
|
| 540 |
+ |
|
| 541 |
+ case mint64: |
|
| 542 |
+ p, err = m.r.Next(9) |
|
| 543 |
+ if err != nil {
|
|
| 544 |
+ return |
|
| 545 |
+ } |
|
| 546 |
+ i = getMint64(p) |
|
| 547 |
+ return |
|
| 548 |
+ |
|
| 549 |
+ default: |
|
| 550 |
+ err = badPrefix(IntType, lead) |
|
| 551 |
+ return |
|
| 552 |
+ } |
|
| 553 |
+} |
|
| 554 |
+ |
|
| 555 |
+// ReadInt32 reads an int32 from the reader |
|
| 556 |
+func (m *Reader) ReadInt32() (i int32, err error) {
|
|
| 557 |
+ var in int64 |
|
| 558 |
+ in, err = m.ReadInt64() |
|
| 559 |
+ if in > math.MaxInt32 || in < math.MinInt32 {
|
|
| 560 |
+ err = IntOverflow{Value: in, FailedBitsize: 32}
|
|
| 561 |
+ return |
|
| 562 |
+ } |
|
| 563 |
+ i = int32(in) |
|
| 564 |
+ return |
|
| 565 |
+} |
|
| 566 |
+ |
|
| 567 |
+// ReadInt16 reads an int16 from the reader |
|
| 568 |
+func (m *Reader) ReadInt16() (i int16, err error) {
|
|
| 569 |
+ var in int64 |
|
| 570 |
+ in, err = m.ReadInt64() |
|
| 571 |
+ if in > math.MaxInt16 || in < math.MinInt16 {
|
|
| 572 |
+ err = IntOverflow{Value: in, FailedBitsize: 16}
|
|
| 573 |
+ return |
|
| 574 |
+ } |
|
| 575 |
+ i = int16(in) |
|
| 576 |
+ return |
|
| 577 |
+} |
|
| 578 |
+ |
|
| 579 |
+// ReadInt8 reads an int8 from the reader |
|
| 580 |
+func (m *Reader) ReadInt8() (i int8, err error) {
|
|
| 581 |
+ var in int64 |
|
| 582 |
+ in, err = m.ReadInt64() |
|
| 583 |
+ if in > math.MaxInt8 || in < math.MinInt8 {
|
|
| 584 |
+ err = IntOverflow{Value: in, FailedBitsize: 8}
|
|
| 585 |
+ return |
|
| 586 |
+ } |
|
| 587 |
+ i = int8(in) |
|
| 588 |
+ return |
|
| 589 |
+} |
|
| 590 |
+ |
|
| 591 |
+// ReadInt reads an int from the reader |
|
| 592 |
+func (m *Reader) ReadInt() (i int, err error) {
|
|
| 593 |
+ if smallint {
|
|
| 594 |
+ var in int32 |
|
| 595 |
+ in, err = m.ReadInt32() |
|
| 596 |
+ i = int(in) |
|
| 597 |
+ return |
|
| 598 |
+ } |
|
| 599 |
+ var in int64 |
|
| 600 |
+ in, err = m.ReadInt64() |
|
| 601 |
+ i = int(in) |
|
| 602 |
+ return |
|
| 603 |
+} |
|
| 604 |
+ |
|
| 605 |
+// ReadUint64 reads a uint64 from the reader |
|
| 606 |
+func (m *Reader) ReadUint64() (u uint64, err error) {
|
|
| 607 |
+ var p []byte |
|
| 608 |
+ var lead byte |
|
| 609 |
+ p, err = m.r.Peek(1) |
|
| 610 |
+ if err != nil {
|
|
| 611 |
+ return |
|
| 612 |
+ } |
|
| 613 |
+ lead = p[0] |
|
| 614 |
+ if isfixint(lead) {
|
|
| 615 |
+ u = uint64(rfixint(lead)) |
|
| 616 |
+ _, err = m.r.Skip(1) |
|
| 617 |
+ return |
|
| 618 |
+ } |
|
| 619 |
+ switch lead {
|
|
| 620 |
+ case muint8: |
|
| 621 |
+ p, err = m.r.Next(2) |
|
| 622 |
+ if err != nil {
|
|
| 623 |
+ return |
|
| 624 |
+ } |
|
| 625 |
+ u = uint64(getMuint8(p)) |
|
| 626 |
+ return |
|
| 627 |
+ |
|
| 628 |
+ case muint16: |
|
| 629 |
+ p, err = m.r.Next(3) |
|
| 630 |
+ if err != nil {
|
|
| 631 |
+ return |
|
| 632 |
+ } |
|
| 633 |
+ u = uint64(getMuint16(p)) |
|
| 634 |
+ return |
|
| 635 |
+ |
|
| 636 |
+ case muint32: |
|
| 637 |
+ p, err = m.r.Next(5) |
|
| 638 |
+ if err != nil {
|
|
| 639 |
+ return |
|
| 640 |
+ } |
|
| 641 |
+ u = uint64(getMuint32(p)) |
|
| 642 |
+ return |
|
| 643 |
+ |
|
| 644 |
+ case muint64: |
|
| 645 |
+ p, err = m.r.Next(9) |
|
| 646 |
+ if err != nil {
|
|
| 647 |
+ return |
|
| 648 |
+ } |
|
| 649 |
+ u = getMuint64(p) |
|
| 650 |
+ return |
|
| 651 |
+ |
|
| 652 |
+ default: |
|
| 653 |
+ err = badPrefix(UintType, lead) |
|
| 654 |
+ return |
|
| 655 |
+ |
|
| 656 |
+ } |
|
| 657 |
+} |
|
| 658 |
+ |
|
| 659 |
+// ReadUint32 reads a uint32 from the reader |
|
| 660 |
+func (m *Reader) ReadUint32() (u uint32, err error) {
|
|
| 661 |
+ var in uint64 |
|
| 662 |
+ in, err = m.ReadUint64() |
|
| 663 |
+ if in > math.MaxUint32 {
|
|
| 664 |
+ err = UintOverflow{Value: in, FailedBitsize: 32}
|
|
| 665 |
+ return |
|
| 666 |
+ } |
|
| 667 |
+ u = uint32(in) |
|
| 668 |
+ return |
|
| 669 |
+} |
|
| 670 |
+ |
|
| 671 |
+// ReadUint16 reads a uint16 from the reader |
|
| 672 |
+func (m *Reader) ReadUint16() (u uint16, err error) {
|
|
| 673 |
+ var in uint64 |
|
| 674 |
+ in, err = m.ReadUint64() |
|
| 675 |
+ if in > math.MaxUint16 {
|
|
| 676 |
+ err = UintOverflow{Value: in, FailedBitsize: 16}
|
|
| 677 |
+ return |
|
| 678 |
+ } |
|
| 679 |
+ u = uint16(in) |
|
| 680 |
+ return |
|
| 681 |
+} |
|
| 682 |
+ |
|
| 683 |
+// ReadUint8 reads a uint8 from the reader |
|
| 684 |
+func (m *Reader) ReadUint8() (u uint8, err error) {
|
|
| 685 |
+ var in uint64 |
|
| 686 |
+ in, err = m.ReadUint64() |
|
| 687 |
+ if in > math.MaxUint8 {
|
|
| 688 |
+ err = UintOverflow{Value: in, FailedBitsize: 8}
|
|
| 689 |
+ return |
|
| 690 |
+ } |
|
| 691 |
+ u = uint8(in) |
|
| 692 |
+ return |
|
| 693 |
+} |
|
| 694 |
+ |
|
| 695 |
+// ReadUint reads a uint from the reader |
|
| 696 |
+func (m *Reader) ReadUint() (u uint, err error) {
|
|
| 697 |
+ if smallint {
|
|
| 698 |
+ var un uint32 |
|
| 699 |
+ un, err = m.ReadUint32() |
|
| 700 |
+ u = uint(un) |
|
| 701 |
+ return |
|
| 702 |
+ } |
|
| 703 |
+ var un uint64 |
|
| 704 |
+ un, err = m.ReadUint64() |
|
| 705 |
+ u = uint(un) |
|
| 706 |
+ return |
|
| 707 |
+} |
|
| 708 |
+ |
|
| 709 |
+func (m *Reader) ReadByte() (b byte, err error) {
|
|
| 710 |
+ var in uint64 |
|
| 711 |
+ in, err = m.ReadUint64() |
|
| 712 |
+ if in > math.MaxUint8 {
|
|
| 713 |
+ err = UintOverflow{Value: in, FailedBitsize: 8}
|
|
| 714 |
+ return |
|
| 715 |
+ } |
|
| 716 |
+ b = byte(in) |
|
| 717 |
+ return |
|
| 718 |
+} |
|
| 719 |
+ |
|
| 720 |
+// ReadBytes reads a MessagePack 'bin' object |
|
| 721 |
+// from the reader and returns its value. It may |
|
| 722 |
+// use 'scratch' for storage if it is non-nil. |
|
| 723 |
+func (m *Reader) ReadBytes(scratch []byte) (b []byte, err error) {
|
|
| 724 |
+ var p []byte |
|
| 725 |
+ var lead byte |
|
| 726 |
+ p, err = m.r.Peek(2) |
|
| 727 |
+ if err != nil {
|
|
| 728 |
+ return |
|
| 729 |
+ } |
|
| 730 |
+ lead = p[0] |
|
| 731 |
+ var read int64 |
|
| 732 |
+ switch lead {
|
|
| 733 |
+ case mbin8: |
|
| 734 |
+ read = int64(p[1]) |
|
| 735 |
+ m.r.Skip(2) |
|
| 736 |
+ case mbin16: |
|
| 737 |
+ p, err = m.r.Next(3) |
|
| 738 |
+ if err != nil {
|
|
| 739 |
+ return |
|
| 740 |
+ } |
|
| 741 |
+ read = int64(big.Uint16(p[1:])) |
|
| 742 |
+ case mbin32: |
|
| 743 |
+ p, err = m.r.Next(5) |
|
| 744 |
+ if err != nil {
|
|
| 745 |
+ return |
|
| 746 |
+ } |
|
| 747 |
+ read = int64(big.Uint32(p[1:])) |
|
| 748 |
+ default: |
|
| 749 |
+ err = badPrefix(BinType, lead) |
|
| 750 |
+ return |
|
| 751 |
+ } |
|
| 752 |
+ if int64(cap(scratch)) < read {
|
|
| 753 |
+ b = make([]byte, read) |
|
| 754 |
+ } else {
|
|
| 755 |
+ b = scratch[0:read] |
|
| 756 |
+ } |
|
| 757 |
+ _, err = m.r.ReadFull(b) |
|
| 758 |
+ return |
|
| 759 |
+} |
|
| 760 |
+ |
|
| 761 |
+// ReadExactBytes reads a MessagePack 'bin'-encoded |
|
| 762 |
+// object off of the wire into the provided slice. An |
|
| 763 |
+// ArrayError will be returned if the object is not |
|
| 764 |
+// exactly the length of the input slice. |
|
| 765 |
+func (m *Reader) ReadExactBytes(into []byte) error {
|
|
| 766 |
+ p, err := m.r.Peek(2) |
|
| 767 |
+ if err != nil {
|
|
| 768 |
+ return err |
|
| 769 |
+ } |
|
| 770 |
+ lead := p[0] |
|
| 771 |
+ var read int64 // bytes to read |
|
| 772 |
+ var skip int // prefix size to skip |
|
| 773 |
+ switch lead {
|
|
| 774 |
+ case mbin8: |
|
| 775 |
+ read = int64(p[1]) |
|
| 776 |
+ skip = 2 |
|
| 777 |
+ case mbin16: |
|
| 778 |
+ p, err = m.r.Peek(3) |
|
| 779 |
+ if err != nil {
|
|
| 780 |
+ return err |
|
| 781 |
+ } |
|
| 782 |
+ read = int64(big.Uint16(p[1:])) |
|
| 783 |
+ skip = 3 |
|
| 784 |
+ case mbin32: |
|
| 785 |
+ p, err = m.r.Peek(5) |
|
| 786 |
+ if err != nil {
|
|
| 787 |
+ return err |
|
| 788 |
+ } |
|
| 789 |
+ read = int64(big.Uint32(p[1:])) |
|
| 790 |
+ skip = 5 |
|
| 791 |
+ default: |
|
| 792 |
+ return badPrefix(BinType, lead) |
|
| 793 |
+ } |
|
| 794 |
+ if read != int64(len(into)) {
|
|
| 795 |
+ return ArrayError{Wanted: uint32(len(into)), Got: uint32(read)}
|
|
| 796 |
+ } |
|
| 797 |
+ m.r.Skip(skip) |
|
| 798 |
+ _, err = m.r.ReadFull(into) |
|
| 799 |
+ return err |
|
| 800 |
+} |
|
| 801 |
+ |
|
| 802 |
+// ReadStringAsBytes reads a MessagePack 'str' (utf-8) string |
|
| 803 |
+// and returns its value as bytes. It may use 'scratch' for storage |
|
| 804 |
+// if it is non-nil. |
|
| 805 |
+func (m *Reader) ReadStringAsBytes(scratch []byte) (b []byte, err error) {
|
|
| 806 |
+ var p []byte |
|
| 807 |
+ var lead byte |
|
| 808 |
+ p, err = m.r.Peek(1) |
|
| 809 |
+ if err != nil {
|
|
| 810 |
+ return |
|
| 811 |
+ } |
|
| 812 |
+ lead = p[0] |
|
| 813 |
+ var read int64 |
|
| 814 |
+ |
|
| 815 |
+ if isfixstr(lead) {
|
|
| 816 |
+ read = int64(rfixstr(lead)) |
|
| 817 |
+ m.r.Skip(1) |
|
| 818 |
+ goto fill |
|
| 819 |
+ } |
|
| 820 |
+ |
|
| 821 |
+ switch lead {
|
|
| 822 |
+ case mstr8: |
|
| 823 |
+ p, err = m.r.Next(2) |
|
| 824 |
+ if err != nil {
|
|
| 825 |
+ return |
|
| 826 |
+ } |
|
| 827 |
+ read = int64(uint8(p[1])) |
|
| 828 |
+ case mstr16: |
|
| 829 |
+ p, err = m.r.Next(3) |
|
| 830 |
+ if err != nil {
|
|
| 831 |
+ return |
|
| 832 |
+ } |
|
| 833 |
+ read = int64(big.Uint16(p[1:])) |
|
| 834 |
+ case mstr32: |
|
| 835 |
+ p, err = m.r.Next(5) |
|
| 836 |
+ if err != nil {
|
|
| 837 |
+ return |
|
| 838 |
+ } |
|
| 839 |
+ read = int64(big.Uint32(p[1:])) |
|
| 840 |
+ default: |
|
| 841 |
+ err = badPrefix(StrType, lead) |
|
| 842 |
+ return |
|
| 843 |
+ } |
|
| 844 |
+fill: |
|
| 845 |
+ if int64(cap(scratch)) < read {
|
|
| 846 |
+ b = make([]byte, read) |
|
| 847 |
+ } else {
|
|
| 848 |
+ b = scratch[0:read] |
|
| 849 |
+ } |
|
| 850 |
+ _, err = m.r.ReadFull(b) |
|
| 851 |
+ return |
|
| 852 |
+} |
|
| 853 |
+ |
|
| 854 |
+// ReadString reads a utf-8 string from the reader |
|
| 855 |
+func (m *Reader) ReadString() (s string, err error) {
|
|
| 856 |
+ var p []byte |
|
| 857 |
+ var lead byte |
|
| 858 |
+ var read int64 |
|
| 859 |
+ p, err = m.r.Peek(1) |
|
| 860 |
+ if err != nil {
|
|
| 861 |
+ return |
|
| 862 |
+ } |
|
| 863 |
+ lead = p[0] |
|
| 864 |
+ |
|
| 865 |
+ if isfixstr(lead) {
|
|
| 866 |
+ read = int64(rfixstr(lead)) |
|
| 867 |
+ m.r.Skip(1) |
|
| 868 |
+ goto fill |
|
| 869 |
+ } |
|
| 870 |
+ |
|
| 871 |
+ switch lead {
|
|
| 872 |
+ case mstr8: |
|
| 873 |
+ p, err = m.r.Next(2) |
|
| 874 |
+ if err != nil {
|
|
| 875 |
+ return |
|
| 876 |
+ } |
|
| 877 |
+ read = int64(uint8(p[1])) |
|
| 878 |
+ case mstr16: |
|
| 879 |
+ p, err = m.r.Next(3) |
|
| 880 |
+ if err != nil {
|
|
| 881 |
+ return |
|
| 882 |
+ } |
|
| 883 |
+ read = int64(big.Uint16(p[1:])) |
|
| 884 |
+ case mstr32: |
|
| 885 |
+ p, err = m.r.Next(5) |
|
| 886 |
+ if err != nil {
|
|
| 887 |
+ return |
|
| 888 |
+ } |
|
| 889 |
+ read = int64(big.Uint32(p[1:])) |
|
| 890 |
+ default: |
|
| 891 |
+ err = badPrefix(StrType, lead) |
|
| 892 |
+ return |
|
| 893 |
+ } |
|
| 894 |
+fill: |
|
| 895 |
+ if read == 0 {
|
|
| 896 |
+ s, err = "", nil |
|
| 897 |
+ return |
|
| 898 |
+ } |
|
| 899 |
+ // reading into the memory |
|
| 900 |
+ // that will become the string |
|
| 901 |
+ // itself has vastly superior |
|
| 902 |
+ // worst-case performance, because |
|
| 903 |
+ // the reader buffer doesn't have |
|
| 904 |
+ // to be large enough to hold the string. |
|
| 905 |
+ // the idea here is to make it more |
|
| 906 |
+ // difficult for someone malicious |
|
| 907 |
+ // to cause the system to run out of |
|
| 908 |
+ // memory by sending very large strings. |
|
| 909 |
+ // |
|
| 910 |
+ // NOTE: this works because the argument |
|
| 911 |
+ // passed to (*fwd.Reader).ReadFull escapes |
|
| 912 |
+ // to the heap; its argument may, in turn, |
|
| 913 |
+ // be passed to the underlying reader, and |
|
| 914 |
+ // thus escape analysis *must* conclude that |
|
| 915 |
+ // 'out' escapes. |
|
| 916 |
+ out := make([]byte, read) |
|
| 917 |
+ _, err = m.r.ReadFull(out) |
|
| 918 |
+ if err != nil {
|
|
| 919 |
+ return |
|
| 920 |
+ } |
|
| 921 |
+ s = UnsafeString(out) |
|
| 922 |
+ return |
|
| 923 |
+} |
|
| 924 |
+ |
|
| 925 |
+// ReadComplex64 reads a complex64 from the reader |
|
| 926 |
+func (m *Reader) ReadComplex64() (f complex64, err error) {
|
|
| 927 |
+ var p []byte |
|
| 928 |
+ p, err = m.r.Peek(10) |
|
| 929 |
+ if err != nil {
|
|
| 930 |
+ return |
|
| 931 |
+ } |
|
| 932 |
+ if p[0] != mfixext8 {
|
|
| 933 |
+ err = badPrefix(Complex64Type, p[0]) |
|
| 934 |
+ return |
|
| 935 |
+ } |
|
| 936 |
+ if int8(p[1]) != Complex64Extension {
|
|
| 937 |
+ err = errExt(int8(p[1]), Complex64Extension) |
|
| 938 |
+ return |
|
| 939 |
+ } |
|
| 940 |
+ f = complex(math.Float32frombits(big.Uint32(p[2:])), |
|
| 941 |
+ math.Float32frombits(big.Uint32(p[6:]))) |
|
| 942 |
+ _, err = m.r.Skip(10) |
|
| 943 |
+ return |
|
| 944 |
+} |
|
| 945 |
+ |
|
| 946 |
+// ReadComplex128 reads a complex128 from the reader |
|
| 947 |
+func (m *Reader) ReadComplex128() (f complex128, err error) {
|
|
| 948 |
+ var p []byte |
|
| 949 |
+ p, err = m.r.Peek(18) |
|
| 950 |
+ if err != nil {
|
|
| 951 |
+ return |
|
| 952 |
+ } |
|
| 953 |
+ if p[0] != mfixext16 {
|
|
| 954 |
+ err = badPrefix(Complex128Type, p[0]) |
|
| 955 |
+ return |
|
| 956 |
+ } |
|
| 957 |
+ if int8(p[1]) != Complex128Extension {
|
|
| 958 |
+ err = errExt(int8(p[1]), Complex128Extension) |
|
| 959 |
+ return |
|
| 960 |
+ } |
|
| 961 |
+ f = complex(math.Float64frombits(big.Uint64(p[2:])), |
|
| 962 |
+ math.Float64frombits(big.Uint64(p[10:]))) |
|
| 963 |
+ _, err = m.r.Skip(18) |
|
| 964 |
+ return |
|
| 965 |
+} |
|
| 966 |
+ |
|
| 967 |
+// ReadMapStrIntf reads a MessagePack map into a map[string]interface{}.
|
|
| 968 |
+// (You must pass a non-nil map into the function.) |
|
| 969 |
+func (m *Reader) ReadMapStrIntf(mp map[string]interface{}) (err error) {
|
|
| 970 |
+ var sz uint32 |
|
| 971 |
+ sz, err = m.ReadMapHeader() |
|
| 972 |
+ if err != nil {
|
|
| 973 |
+ return |
|
| 974 |
+ } |
|
| 975 |
+ for key := range mp {
|
|
| 976 |
+ delete(mp, key) |
|
| 977 |
+ } |
|
| 978 |
+ for i := uint32(0); i < sz; i++ {
|
|
| 979 |
+ var key string |
|
| 980 |
+ var val interface{}
|
|
| 981 |
+ key, err = m.ReadString() |
|
| 982 |
+ if err != nil {
|
|
| 983 |
+ return |
|
| 984 |
+ } |
|
| 985 |
+ val, err = m.ReadIntf() |
|
| 986 |
+ if err != nil {
|
|
| 987 |
+ return |
|
| 988 |
+ } |
|
| 989 |
+ mp[key] = val |
|
| 990 |
+ } |
|
| 991 |
+ return |
|
| 992 |
+} |
|
| 993 |
+ |
|
| 994 |
+// ReadTime reads a time.Time object from the reader. |
|
| 995 |
+// The returned time's location will be set to time.Local. |
|
| 996 |
+func (m *Reader) ReadTime() (t time.Time, err error) {
|
|
| 997 |
+ var p []byte |
|
| 998 |
+ p, err = m.r.Peek(15) |
|
| 999 |
+ if err != nil {
|
|
| 1000 |
+ return |
|
| 1001 |
+ } |
|
| 1002 |
+ if p[0] != mext8 || p[1] != 12 {
|
|
| 1003 |
+ err = badPrefix(TimeType, p[0]) |
|
| 1004 |
+ return |
|
| 1005 |
+ } |
|
| 1006 |
+ if int8(p[2]) != TimeExtension {
|
|
| 1007 |
+ err = errExt(int8(p[2]), TimeExtension) |
|
| 1008 |
+ return |
|
| 1009 |
+ } |
|
| 1010 |
+ sec, nsec := getUnix(p[3:]) |
|
| 1011 |
+ t = time.Unix(sec, int64(nsec)).Local() |
|
| 1012 |
+ _, err = m.r.Skip(15) |
|
| 1013 |
+ return |
|
| 1014 |
+} |
|
| 1015 |
+ |
|
| 1016 |
+// ReadIntf reads out the next object as a raw interface{}.
|
|
| 1017 |
+// Arrays are decoded as []interface{}, and maps are decoded
|
|
| 1018 |
+// as map[string]interface{}. Integers are decoded as int64
|
|
| 1019 |
+// and unsigned integers are decoded as uint64. |
|
| 1020 |
+func (m *Reader) ReadIntf() (i interface{}, err error) {
|
|
| 1021 |
+ var t Type |
|
| 1022 |
+ t, err = m.NextType() |
|
| 1023 |
+ if err != nil {
|
|
| 1024 |
+ return |
|
| 1025 |
+ } |
|
| 1026 |
+ switch t {
|
|
| 1027 |
+ case BoolType: |
|
| 1028 |
+ i, err = m.ReadBool() |
|
| 1029 |
+ return |
|
| 1030 |
+ |
|
| 1031 |
+ case IntType: |
|
| 1032 |
+ i, err = m.ReadInt64() |
|
| 1033 |
+ return |
|
| 1034 |
+ |
|
| 1035 |
+ case UintType: |
|
| 1036 |
+ i, err = m.ReadUint64() |
|
| 1037 |
+ return |
|
| 1038 |
+ |
|
| 1039 |
+ case BinType: |
|
| 1040 |
+ i, err = m.ReadBytes(nil) |
|
| 1041 |
+ return |
|
| 1042 |
+ |
|
| 1043 |
+ case StrType: |
|
| 1044 |
+ i, err = m.ReadString() |
|
| 1045 |
+ return |
|
| 1046 |
+ |
|
| 1047 |
+ case Complex64Type: |
|
| 1048 |
+ i, err = m.ReadComplex64() |
|
| 1049 |
+ return |
|
| 1050 |
+ |
|
| 1051 |
+ case Complex128Type: |
|
| 1052 |
+ i, err = m.ReadComplex128() |
|
| 1053 |
+ return |
|
| 1054 |
+ |
|
| 1055 |
+ case TimeType: |
|
| 1056 |
+ i, err = m.ReadTime() |
|
| 1057 |
+ return |
|
| 1058 |
+ |
|
| 1059 |
+ case ExtensionType: |
|
| 1060 |
+ var t int8 |
|
| 1061 |
+ t, err = m.peekExtensionType() |
|
| 1062 |
+ if err != nil {
|
|
| 1063 |
+ return |
|
| 1064 |
+ } |
|
| 1065 |
+ f, ok := extensionReg[t] |
|
| 1066 |
+ if ok {
|
|
| 1067 |
+ e := f() |
|
| 1068 |
+ err = m.ReadExtension(e) |
|
| 1069 |
+ i = e |
|
| 1070 |
+ return |
|
| 1071 |
+ } |
|
| 1072 |
+ var e RawExtension |
|
| 1073 |
+ e.Type = t |
|
| 1074 |
+ err = m.ReadExtension(&e) |
|
| 1075 |
+ i = &e |
|
| 1076 |
+ return |
|
| 1077 |
+ |
|
| 1078 |
+ case MapType: |
|
| 1079 |
+ mp := make(map[string]interface{})
|
|
| 1080 |
+ err = m.ReadMapStrIntf(mp) |
|
| 1081 |
+ i = mp |
|
| 1082 |
+ return |
|
| 1083 |
+ |
|
| 1084 |
+ case NilType: |
|
| 1085 |
+ err = m.ReadNil() |
|
| 1086 |
+ i = nil |
|
| 1087 |
+ return |
|
| 1088 |
+ |
|
| 1089 |
+ case Float32Type: |
|
| 1090 |
+ i, err = m.ReadFloat32() |
|
| 1091 |
+ return |
|
| 1092 |
+ |
|
| 1093 |
+ case Float64Type: |
|
| 1094 |
+ i, err = m.ReadFloat64() |
|
| 1095 |
+ return |
|
| 1096 |
+ |
|
| 1097 |
+ case ArrayType: |
|
| 1098 |
+ var sz uint32 |
|
| 1099 |
+ sz, err = m.ReadArrayHeader() |
|
| 1100 |
+ |
|
| 1101 |
+ if err != nil {
|
|
| 1102 |
+ return |
|
| 1103 |
+ } |
|
| 1104 |
+ out := make([]interface{}, int(sz))
|
|
| 1105 |
+ for j := range out {
|
|
| 1106 |
+ out[j], err = m.ReadIntf() |
|
| 1107 |
+ if err != nil {
|
|
| 1108 |
+ return |
|
| 1109 |
+ } |
|
| 1110 |
+ } |
|
| 1111 |
+ i = out |
|
| 1112 |
+ return |
|
| 1113 |
+ |
|
| 1114 |
+ default: |
|
| 1115 |
+ return nil, fatal // unreachable |
|
| 1116 |
+ } |
|
| 1117 |
+} |
| 0 | 1118 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,1073 @@ |
| 0 |
+package msgp |
|
| 1 |
+ |
|
| 2 |
+import ( |
|
| 3 |
+ "bytes" |
|
| 4 |
+ "encoding/binary" |
|
| 5 |
+ "math" |
|
| 6 |
+ "time" |
|
| 7 |
+) |
|
| 8 |
+ |
|
| 9 |
+var big = binary.BigEndian |
|
| 10 |
+ |
|
| 11 |
+// NextType returns the type of the next |
|
| 12 |
+// object in the slice. If the length |
|
| 13 |
+// of the input is zero, it returns |
|
| 14 |
+// InvalidType. |
|
| 15 |
+func NextType(b []byte) Type {
|
|
| 16 |
+ if len(b) == 0 {
|
|
| 17 |
+ return InvalidType |
|
| 18 |
+ } |
|
| 19 |
+ spec := sizes[b[0]] |
|
| 20 |
+ t := spec.typ |
|
| 21 |
+ if t == ExtensionType && len(b) > int(spec.size) {
|
|
| 22 |
+ var tp int8 |
|
| 23 |
+ if spec.extra == constsize {
|
|
| 24 |
+ tp = int8(b[1]) |
|
| 25 |
+ } else {
|
|
| 26 |
+ tp = int8(b[spec.size-1]) |
|
| 27 |
+ } |
|
| 28 |
+ switch tp {
|
|
| 29 |
+ case TimeExtension: |
|
| 30 |
+ return TimeType |
|
| 31 |
+ case Complex128Extension: |
|
| 32 |
+ return Complex128Type |
|
| 33 |
+ case Complex64Extension: |
|
| 34 |
+ return Complex64Type |
|
| 35 |
+ default: |
|
| 36 |
+ return ExtensionType |
|
| 37 |
+ } |
|
| 38 |
+ } |
|
| 39 |
+ return t |
|
| 40 |
+} |
|
| 41 |
+ |
|
| 42 |
+// IsNil returns true if len(b)>0 and |
|
| 43 |
+// the leading byte is a 'nil' MessagePack |
|
| 44 |
+// byte; false otherwise |
|
| 45 |
+func IsNil(b []byte) bool {
|
|
| 46 |
+ if len(b) != 0 && b[0] == mnil {
|
|
| 47 |
+ return true |
|
| 48 |
+ } |
|
| 49 |
+ return false |
|
| 50 |
+} |
|
| 51 |
+ |
|
| 52 |
+// Raw is raw MessagePack. |
|
| 53 |
+// Raw allows you to read and write |
|
| 54 |
+// data without interpreting its contents. |
|
| 55 |
+type Raw []byte |
|
| 56 |
+ |
|
| 57 |
+// MarshalMsg implements msgp.Marshaler. |
|
| 58 |
+// It appends the raw contents of 'raw' |
|
| 59 |
+// to the provided byte slice. If 'raw' |
|
| 60 |
+// is 0 bytes, 'nil' will be appended instead. |
|
| 61 |
+func (r Raw) MarshalMsg(b []byte) ([]byte, error) {
|
|
| 62 |
+ i := len(r) |
|
| 63 |
+ if i == 0 {
|
|
| 64 |
+ return AppendNil(b), nil |
|
| 65 |
+ } |
|
| 66 |
+ o, l := ensure(b, i) |
|
| 67 |
+ copy(o[l:], []byte(r)) |
|
| 68 |
+ return o, nil |
|
| 69 |
+} |
|
| 70 |
+ |
|
| 71 |
+// UnmarshalMsg implements msgp.Unmarshaler. |
|
| 72 |
+// It sets the contents of *Raw to be the next |
|
| 73 |
+// object in the provided byte slice. |
|
| 74 |
+func (r *Raw) UnmarshalMsg(b []byte) ([]byte, error) {
|
|
| 75 |
+ l := len(b) |
|
| 76 |
+ out, err := Skip(b) |
|
| 77 |
+ if err != nil {
|
|
| 78 |
+ return b, err |
|
| 79 |
+ } |
|
| 80 |
+ rlen := l - len(out) |
|
| 81 |
+ if cap(*r) < rlen {
|
|
| 82 |
+ *r = make(Raw, rlen) |
|
| 83 |
+ } else {
|
|
| 84 |
+ *r = (*r)[0:rlen] |
|
| 85 |
+ } |
|
| 86 |
+ copy(*r, b[:rlen]) |
|
| 87 |
+ return out, nil |
|
| 88 |
+} |
|
| 89 |
+ |
|
| 90 |
+// EncodeMsg implements msgp.Encodable. |
|
| 91 |
+// It writes the raw bytes to the writer. |
|
| 92 |
+// If r is empty, it writes 'nil' instead. |
|
| 93 |
+func (r Raw) EncodeMsg(w *Writer) error {
|
|
| 94 |
+ if len(r) == 0 {
|
|
| 95 |
+ return w.WriteNil() |
|
| 96 |
+ } |
|
| 97 |
+ _, err := w.Write([]byte(r)) |
|
| 98 |
+ return err |
|
| 99 |
+} |
|
| 100 |
+ |
|
| 101 |
+// DecodeMsg implements msgp.Decodable. |
|
| 102 |
+// It sets the value of *Raw to be the |
|
| 103 |
+// next object on the wire. |
|
| 104 |
+func (r *Raw) DecodeMsg(f *Reader) error {
|
|
| 105 |
+ *r = (*r)[:0] |
|
| 106 |
+ return appendNext(f, (*[]byte)(r)) |
|
| 107 |
+} |
|
| 108 |
+ |
|
| 109 |
+// Msgsize implements msgp.Sizer |
|
| 110 |
+func (r Raw) Msgsize() int {
|
|
| 111 |
+ l := len(r) |
|
| 112 |
+ if l == 0 {
|
|
| 113 |
+ return 1 // for 'nil' |
|
| 114 |
+ } |
|
| 115 |
+ return l |
|
| 116 |
+} |
|
| 117 |
+ |
|
| 118 |
+func appendNext(f *Reader, d *[]byte) error {
|
|
| 119 |
+ amt, o, err := getNextSize(f.r) |
|
| 120 |
+ if err != nil {
|
|
| 121 |
+ return err |
|
| 122 |
+ } |
|
| 123 |
+ var i int |
|
| 124 |
+ *d, i = ensure(*d, int(amt)) |
|
| 125 |
+ _, err = f.r.ReadFull((*d)[i:]) |
|
| 126 |
+ if err != nil {
|
|
| 127 |
+ return err |
|
| 128 |
+ } |
|
| 129 |
+ for o > 0 {
|
|
| 130 |
+ err = appendNext(f, d) |
|
| 131 |
+ if err != nil {
|
|
| 132 |
+ return err |
|
| 133 |
+ } |
|
| 134 |
+ o-- |
|
| 135 |
+ } |
|
| 136 |
+ return nil |
|
| 137 |
+} |
|
| 138 |
+ |
|
| 139 |
+// MarshalJSON implements json.Marshaler |
|
| 140 |
+func (r *Raw) MarshalJSON() ([]byte, error) {
|
|
| 141 |
+ var buf bytes.Buffer |
|
| 142 |
+ _, err := UnmarshalAsJSON(&buf, []byte(*r)) |
|
| 143 |
+ return buf.Bytes(), err |
|
| 144 |
+} |
|
| 145 |
+ |
|
| 146 |
+// ReadMapHeaderBytes reads a map header size |
|
| 147 |
+// from 'b' and returns the remaining bytes. |
|
| 148 |
+// Possible errors: |
|
| 149 |
+// - ErrShortBytes (too few bytes) |
|
| 150 |
+// - TypeError{} (not a map)
|
|
| 151 |
+func ReadMapHeaderBytes(b []byte) (sz uint32, o []byte, err error) {
|
|
| 152 |
+ l := len(b) |
|
| 153 |
+ if l < 1 {
|
|
| 154 |
+ err = ErrShortBytes |
|
| 155 |
+ return |
|
| 156 |
+ } |
|
| 157 |
+ |
|
| 158 |
+ lead := b[0] |
|
| 159 |
+ if isfixmap(lead) {
|
|
| 160 |
+ sz = uint32(rfixmap(lead)) |
|
| 161 |
+ o = b[1:] |
|
| 162 |
+ return |
|
| 163 |
+ } |
|
| 164 |
+ |
|
| 165 |
+ switch lead {
|
|
| 166 |
+ case mmap16: |
|
| 167 |
+ if l < 3 {
|
|
| 168 |
+ err = ErrShortBytes |
|
| 169 |
+ return |
|
| 170 |
+ } |
|
| 171 |
+ sz = uint32(big.Uint16(b[1:])) |
|
| 172 |
+ o = b[3:] |
|
| 173 |
+ return |
|
| 174 |
+ |
|
| 175 |
+ case mmap32: |
|
| 176 |
+ if l < 5 {
|
|
| 177 |
+ err = ErrShortBytes |
|
| 178 |
+ return |
|
| 179 |
+ } |
|
| 180 |
+ sz = big.Uint32(b[1:]) |
|
| 181 |
+ o = b[5:] |
|
| 182 |
+ return |
|
| 183 |
+ |
|
| 184 |
+ default: |
|
| 185 |
+ err = badPrefix(MapType, lead) |
|
| 186 |
+ return |
|
| 187 |
+ } |
|
| 188 |
+} |
|
| 189 |
+ |
|
| 190 |
+// ReadMapKeyZC attempts to read a map key |
|
| 191 |
+// from 'b' and returns the key bytes and the remaining bytes |
|
| 192 |
+// Possible errors: |
|
| 193 |
+// - ErrShortBytes (too few bytes) |
|
| 194 |
+// - TypeError{} (not a str or bin)
|
|
| 195 |
+func ReadMapKeyZC(b []byte) ([]byte, []byte, error) {
|
|
| 196 |
+ o, b, err := ReadStringZC(b) |
|
| 197 |
+ if err != nil {
|
|
| 198 |
+ if tperr, ok := err.(TypeError); ok && tperr.Encoded == BinType {
|
|
| 199 |
+ return ReadBytesZC(b) |
|
| 200 |
+ } |
|
| 201 |
+ return nil, b, err |
|
| 202 |
+ } |
|
| 203 |
+ return o, b, nil |
|
| 204 |
+} |
|
| 205 |
+ |
|
| 206 |
+// ReadArrayHeaderBytes attempts to read |
|
| 207 |
+// the array header size off of 'b' and return |
|
| 208 |
+// the size and remaining bytes. |
|
| 209 |
+// Possible errors: |
|
| 210 |
+// - ErrShortBytes (too few bytes) |
|
| 211 |
+// - TypeError{} (not an array)
|
|
| 212 |
+func ReadArrayHeaderBytes(b []byte) (sz uint32, o []byte, err error) {
|
|
| 213 |
+ if len(b) < 1 {
|
|
| 214 |
+ return 0, nil, ErrShortBytes |
|
| 215 |
+ } |
|
| 216 |
+ lead := b[0] |
|
| 217 |
+ if isfixarray(lead) {
|
|
| 218 |
+ sz = uint32(rfixarray(lead)) |
|
| 219 |
+ o = b[1:] |
|
| 220 |
+ return |
|
| 221 |
+ } |
|
| 222 |
+ |
|
| 223 |
+ switch lead {
|
|
| 224 |
+ case marray16: |
|
| 225 |
+ if len(b) < 3 {
|
|
| 226 |
+ err = ErrShortBytes |
|
| 227 |
+ return |
|
| 228 |
+ } |
|
| 229 |
+ sz = uint32(big.Uint16(b[1:])) |
|
| 230 |
+ o = b[3:] |
|
| 231 |
+ return |
|
| 232 |
+ |
|
| 233 |
+ case marray32: |
|
| 234 |
+ if len(b) < 5 {
|
|
| 235 |
+ err = ErrShortBytes |
|
| 236 |
+ return |
|
| 237 |
+ } |
|
| 238 |
+ sz = big.Uint32(b[1:]) |
|
| 239 |
+ o = b[5:] |
|
| 240 |
+ return |
|
| 241 |
+ |
|
| 242 |
+ default: |
|
| 243 |
+ err = badPrefix(ArrayType, lead) |
|
| 244 |
+ return |
|
| 245 |
+ } |
|
| 246 |
+} |
|
| 247 |
+ |
|
| 248 |
+// ReadNilBytes tries to read a "nil" byte |
|
| 249 |
+// off of 'b' and return the remaining bytes. |
|
| 250 |
+// Possible errors: |
|
| 251 |
+// - ErrShortBytes (too few bytes) |
|
| 252 |
+// - TypeError{} (not a 'nil')
|
|
| 253 |
+// - InvalidPrefixError |
|
| 254 |
+func ReadNilBytes(b []byte) ([]byte, error) {
|
|
| 255 |
+ if len(b) < 1 {
|
|
| 256 |
+ return nil, ErrShortBytes |
|
| 257 |
+ } |
|
| 258 |
+ if b[0] != mnil {
|
|
| 259 |
+ return b, badPrefix(NilType, b[0]) |
|
| 260 |
+ } |
|
| 261 |
+ return b[1:], nil |
|
| 262 |
+} |
|
| 263 |
+ |
|
| 264 |
+// ReadFloat64Bytes tries to read a float64 |
|
| 265 |
+// from 'b' and return the value and the remaining bytes. |
|
| 266 |
+// Possible errors: |
|
| 267 |
+// - ErrShortBytes (too few bytes) |
|
| 268 |
+// - TypeError{} (not a float64)
|
|
| 269 |
+func ReadFloat64Bytes(b []byte) (f float64, o []byte, err error) {
|
|
| 270 |
+ if len(b) < 9 {
|
|
| 271 |
+ if len(b) >= 5 && b[0] == mfloat32 {
|
|
| 272 |
+ var tf float32 |
|
| 273 |
+ tf, o, err = ReadFloat32Bytes(b) |
|
| 274 |
+ f = float64(tf) |
|
| 275 |
+ return |
|
| 276 |
+ } |
|
| 277 |
+ err = ErrShortBytes |
|
| 278 |
+ return |
|
| 279 |
+ } |
|
| 280 |
+ |
|
| 281 |
+ if b[0] != mfloat64 {
|
|
| 282 |
+ if b[0] == mfloat32 {
|
|
| 283 |
+ var tf float32 |
|
| 284 |
+ tf, o, err = ReadFloat32Bytes(b) |
|
| 285 |
+ f = float64(tf) |
|
| 286 |
+ return |
|
| 287 |
+ } |
|
| 288 |
+ err = badPrefix(Float64Type, b[0]) |
|
| 289 |
+ return |
|
| 290 |
+ } |
|
| 291 |
+ |
|
| 292 |
+ f = math.Float64frombits(getMuint64(b)) |
|
| 293 |
+ o = b[9:] |
|
| 294 |
+ return |
|
| 295 |
+} |
|
| 296 |
+ |
|
| 297 |
+// ReadFloat32Bytes tries to read a float64 |
|
| 298 |
+// from 'b' and return the value and the remaining bytes. |
|
| 299 |
+// Possible errors: |
|
| 300 |
+// - ErrShortBytes (too few bytes) |
|
| 301 |
+// - TypeError{} (not a float32)
|
|
| 302 |
+func ReadFloat32Bytes(b []byte) (f float32, o []byte, err error) {
|
|
| 303 |
+ if len(b) < 5 {
|
|
| 304 |
+ err = ErrShortBytes |
|
| 305 |
+ return |
|
| 306 |
+ } |
|
| 307 |
+ |
|
| 308 |
+ if b[0] != mfloat32 {
|
|
| 309 |
+ err = TypeError{Method: Float32Type, Encoded: getType(b[0])}
|
|
| 310 |
+ return |
|
| 311 |
+ } |
|
| 312 |
+ |
|
| 313 |
+ f = math.Float32frombits(getMuint32(b)) |
|
| 314 |
+ o = b[5:] |
|
| 315 |
+ return |
|
| 316 |
+} |
|
| 317 |
+ |
|
| 318 |
+// ReadBoolBytes tries to read a float64 |
|
| 319 |
+// from 'b' and return the value and the remaining bytes. |
|
| 320 |
+// Possible errors: |
|
| 321 |
+// - ErrShortBytes (too few bytes) |
|
| 322 |
+// - TypeError{} (not a bool)
|
|
| 323 |
+func ReadBoolBytes(b []byte) (bool, []byte, error) {
|
|
| 324 |
+ if len(b) < 1 {
|
|
| 325 |
+ return false, b, ErrShortBytes |
|
| 326 |
+ } |
|
| 327 |
+ switch b[0] {
|
|
| 328 |
+ case mtrue: |
|
| 329 |
+ return true, b[1:], nil |
|
| 330 |
+ case mfalse: |
|
| 331 |
+ return false, b[1:], nil |
|
| 332 |
+ default: |
|
| 333 |
+ return false, b, badPrefix(BoolType, b[0]) |
|
| 334 |
+ } |
|
| 335 |
+} |
|
| 336 |
+ |
|
| 337 |
+// ReadInt64Bytes tries to read an int64 |
|
| 338 |
+// from 'b' and return the value and the remaining bytes. |
|
| 339 |
+// Possible errors: |
|
| 340 |
+// - ErrShortBytes (too few bytes) |
|
| 341 |
+// - TypeError (not a int) |
|
| 342 |
+func ReadInt64Bytes(b []byte) (i int64, o []byte, err error) {
|
|
| 343 |
+ l := len(b) |
|
| 344 |
+ if l < 1 {
|
|
| 345 |
+ return 0, nil, ErrShortBytes |
|
| 346 |
+ } |
|
| 347 |
+ |
|
| 348 |
+ lead := b[0] |
|
| 349 |
+ if isfixint(lead) {
|
|
| 350 |
+ i = int64(rfixint(lead)) |
|
| 351 |
+ o = b[1:] |
|
| 352 |
+ return |
|
| 353 |
+ } |
|
| 354 |
+ if isnfixint(lead) {
|
|
| 355 |
+ i = int64(rnfixint(lead)) |
|
| 356 |
+ o = b[1:] |
|
| 357 |
+ return |
|
| 358 |
+ } |
|
| 359 |
+ |
|
| 360 |
+ switch lead {
|
|
| 361 |
+ case mint8: |
|
| 362 |
+ if l < 2 {
|
|
| 363 |
+ err = ErrShortBytes |
|
| 364 |
+ return |
|
| 365 |
+ } |
|
| 366 |
+ i = int64(getMint8(b)) |
|
| 367 |
+ o = b[2:] |
|
| 368 |
+ return |
|
| 369 |
+ |
|
| 370 |
+ case mint16: |
|
| 371 |
+ if l < 3 {
|
|
| 372 |
+ err = ErrShortBytes |
|
| 373 |
+ return |
|
| 374 |
+ } |
|
| 375 |
+ i = int64(getMint16(b)) |
|
| 376 |
+ o = b[3:] |
|
| 377 |
+ return |
|
| 378 |
+ |
|
| 379 |
+ case mint32: |
|
| 380 |
+ if l < 5 {
|
|
| 381 |
+ err = ErrShortBytes |
|
| 382 |
+ return |
|
| 383 |
+ } |
|
| 384 |
+ i = int64(getMint32(b)) |
|
| 385 |
+ o = b[5:] |
|
| 386 |
+ return |
|
| 387 |
+ |
|
| 388 |
+ case mint64: |
|
| 389 |
+ if l < 9 {
|
|
| 390 |
+ err = ErrShortBytes |
|
| 391 |
+ return |
|
| 392 |
+ } |
|
| 393 |
+ i = getMint64(b) |
|
| 394 |
+ o = b[9:] |
|
| 395 |
+ return |
|
| 396 |
+ |
|
| 397 |
+ default: |
|
| 398 |
+ err = badPrefix(IntType, lead) |
|
| 399 |
+ return |
|
| 400 |
+ } |
|
| 401 |
+} |
|
| 402 |
+ |
|
| 403 |
+// ReadInt32Bytes tries to read an int32 |
|
| 404 |
+// from 'b' and return the value and the remaining bytes. |
|
| 405 |
+// Possible errors: |
|
| 406 |
+// - ErrShortBytes (too few bytes) |
|
| 407 |
+// - TypeError{} (not a int)
|
|
| 408 |
+// - IntOverflow{} (value doesn't fit in int32)
|
|
| 409 |
+func ReadInt32Bytes(b []byte) (int32, []byte, error) {
|
|
| 410 |
+ i, o, err := ReadInt64Bytes(b) |
|
| 411 |
+ if i > math.MaxInt32 || i < math.MinInt32 {
|
|
| 412 |
+ return 0, o, IntOverflow{Value: i, FailedBitsize: 32}
|
|
| 413 |
+ } |
|
| 414 |
+ return int32(i), o, err |
|
| 415 |
+} |
|
| 416 |
+ |
|
| 417 |
+// ReadInt16Bytes tries to read an int16 |
|
| 418 |
+// from 'b' and return the value and the remaining bytes. |
|
| 419 |
+// Possible errors: |
|
| 420 |
+// - ErrShortBytes (too few bytes) |
|
| 421 |
+// - TypeError{} (not a int)
|
|
| 422 |
+// - IntOverflow{} (value doesn't fit in int16)
|
|
| 423 |
+func ReadInt16Bytes(b []byte) (int16, []byte, error) {
|
|
| 424 |
+ i, o, err := ReadInt64Bytes(b) |
|
| 425 |
+ if i > math.MaxInt16 || i < math.MinInt16 {
|
|
| 426 |
+ return 0, o, IntOverflow{Value: i, FailedBitsize: 16}
|
|
| 427 |
+ } |
|
| 428 |
+ return int16(i), o, err |
|
| 429 |
+} |
|
| 430 |
+ |
|
| 431 |
+// ReadInt8Bytes tries to read an int16 |
|
| 432 |
+// from 'b' and return the value and the remaining bytes. |
|
| 433 |
+// Possible errors: |
|
| 434 |
+// - ErrShortBytes (too few bytes) |
|
| 435 |
+// - TypeError{} (not a int)
|
|
| 436 |
+// - IntOverflow{} (value doesn't fit in int8)
|
|
| 437 |
+func ReadInt8Bytes(b []byte) (int8, []byte, error) {
|
|
| 438 |
+ i, o, err := ReadInt64Bytes(b) |
|
| 439 |
+ if i > math.MaxInt8 || i < math.MinInt8 {
|
|
| 440 |
+ return 0, o, IntOverflow{Value: i, FailedBitsize: 8}
|
|
| 441 |
+ } |
|
| 442 |
+ return int8(i), o, err |
|
| 443 |
+} |
|
| 444 |
+ |
|
| 445 |
+// ReadIntBytes tries to read an int |
|
| 446 |
+// from 'b' and return the value and the remaining bytes. |
|
| 447 |
+// Possible errors: |
|
| 448 |
+// - ErrShortBytes (too few bytes) |
|
| 449 |
+// - TypeError{} (not a int)
|
|
| 450 |
+// - IntOverflow{} (value doesn't fit in int; 32-bit platforms only)
|
|
| 451 |
+func ReadIntBytes(b []byte) (int, []byte, error) {
|
|
| 452 |
+ if smallint {
|
|
| 453 |
+ i, b, err := ReadInt32Bytes(b) |
|
| 454 |
+ return int(i), b, err |
|
| 455 |
+ } |
|
| 456 |
+ i, b, err := ReadInt64Bytes(b) |
|
| 457 |
+ return int(i), b, err |
|
| 458 |
+} |
|
| 459 |
+ |
|
| 460 |
+// ReadUint64Bytes tries to read a uint64 |
|
| 461 |
+// from 'b' and return the value and the remaining bytes. |
|
| 462 |
+// Possible errors: |
|
| 463 |
+// - ErrShortBytes (too few bytes) |
|
| 464 |
+// - TypeError{} (not a uint)
|
|
| 465 |
+func ReadUint64Bytes(b []byte) (u uint64, o []byte, err error) {
|
|
| 466 |
+ l := len(b) |
|
| 467 |
+ if l < 1 {
|
|
| 468 |
+ return 0, nil, ErrShortBytes |
|
| 469 |
+ } |
|
| 470 |
+ |
|
| 471 |
+ lead := b[0] |
|
| 472 |
+ if isfixint(lead) {
|
|
| 473 |
+ u = uint64(rfixint(lead)) |
|
| 474 |
+ o = b[1:] |
|
| 475 |
+ return |
|
| 476 |
+ } |
|
| 477 |
+ |
|
| 478 |
+ switch lead {
|
|
| 479 |
+ case muint8: |
|
| 480 |
+ if l < 2 {
|
|
| 481 |
+ err = ErrShortBytes |
|
| 482 |
+ return |
|
| 483 |
+ } |
|
| 484 |
+ u = uint64(getMuint8(b)) |
|
| 485 |
+ o = b[2:] |
|
| 486 |
+ return |
|
| 487 |
+ |
|
| 488 |
+ case muint16: |
|
| 489 |
+ if l < 3 {
|
|
| 490 |
+ err = ErrShortBytes |
|
| 491 |
+ return |
|
| 492 |
+ } |
|
| 493 |
+ u = uint64(getMuint16(b)) |
|
| 494 |
+ o = b[3:] |
|
| 495 |
+ return |
|
| 496 |
+ |
|
| 497 |
+ case muint32: |
|
| 498 |
+ if l < 5 {
|
|
| 499 |
+ err = ErrShortBytes |
|
| 500 |
+ return |
|
| 501 |
+ } |
|
| 502 |
+ u = uint64(getMuint32(b)) |
|
| 503 |
+ o = b[5:] |
|
| 504 |
+ return |
|
| 505 |
+ |
|
| 506 |
+ case muint64: |
|
| 507 |
+ if l < 9 {
|
|
| 508 |
+ err = ErrShortBytes |
|
| 509 |
+ return |
|
| 510 |
+ } |
|
| 511 |
+ u = getMuint64(b) |
|
| 512 |
+ o = b[9:] |
|
| 513 |
+ return |
|
| 514 |
+ |
|
| 515 |
+ default: |
|
| 516 |
+ err = badPrefix(UintType, lead) |
|
| 517 |
+ return |
|
| 518 |
+ } |
|
| 519 |
+} |
|
| 520 |
+ |
|
| 521 |
+// ReadUint32Bytes tries to read a uint32 |
|
| 522 |
+// from 'b' and return the value and the remaining bytes. |
|
| 523 |
+// Possible errors: |
|
| 524 |
+// - ErrShortBytes (too few bytes) |
|
| 525 |
+// - TypeError{} (not a uint)
|
|
| 526 |
+// - UintOverflow{} (value too large for uint32)
|
|
| 527 |
+func ReadUint32Bytes(b []byte) (uint32, []byte, error) {
|
|
| 528 |
+ v, o, err := ReadUint64Bytes(b) |
|
| 529 |
+ if v > math.MaxUint32 {
|
|
| 530 |
+ return 0, nil, UintOverflow{Value: v, FailedBitsize: 32}
|
|
| 531 |
+ } |
|
| 532 |
+ return uint32(v), o, err |
|
| 533 |
+} |
|
| 534 |
+ |
|
| 535 |
+// ReadUint16Bytes tries to read a uint16 |
|
| 536 |
+// from 'b' and return the value and the remaining bytes. |
|
| 537 |
+// Possible errors: |
|
| 538 |
+// - ErrShortBytes (too few bytes) |
|
| 539 |
+// - TypeError{} (not a uint)
|
|
| 540 |
+// - UintOverflow{} (value too large for uint16)
|
|
| 541 |
+func ReadUint16Bytes(b []byte) (uint16, []byte, error) {
|
|
| 542 |
+ v, o, err := ReadUint64Bytes(b) |
|
| 543 |
+ if v > math.MaxUint16 {
|
|
| 544 |
+ return 0, nil, UintOverflow{Value: v, FailedBitsize: 16}
|
|
| 545 |
+ } |
|
| 546 |
+ return uint16(v), o, err |
|
| 547 |
+} |
|
| 548 |
+ |
|
| 549 |
+// ReadUint8Bytes tries to read a uint8 |
|
| 550 |
+// from 'b' and return the value and the remaining bytes. |
|
| 551 |
+// Possible errors: |
|
| 552 |
+// - ErrShortBytes (too few bytes) |
|
| 553 |
+// - TypeError{} (not a uint)
|
|
| 554 |
+// - UintOverflow{} (value too large for uint8)
|
|
| 555 |
+func ReadUint8Bytes(b []byte) (uint8, []byte, error) {
|
|
| 556 |
+ v, o, err := ReadUint64Bytes(b) |
|
| 557 |
+ if v > math.MaxUint8 {
|
|
| 558 |
+ return 0, nil, UintOverflow{Value: v, FailedBitsize: 8}
|
|
| 559 |
+ } |
|
| 560 |
+ return uint8(v), o, err |
|
| 561 |
+} |
|
| 562 |
+ |
|
| 563 |
+// ReadUintBytes tries to read a uint |
|
| 564 |
+// from 'b' and return the value and the remaining bytes. |
|
| 565 |
+// Possible errors: |
|
| 566 |
+// - ErrShortBytes (too few bytes) |
|
| 567 |
+// - TypeError{} (not a uint)
|
|
| 568 |
+// - UintOverflow{} (value too large for uint; 32-bit platforms only)
|
|
| 569 |
+func ReadUintBytes(b []byte) (uint, []byte, error) {
|
|
| 570 |
+ if smallint {
|
|
| 571 |
+ u, b, err := ReadUint32Bytes(b) |
|
| 572 |
+ return uint(u), b, err |
|
| 573 |
+ } |
|
| 574 |
+ u, b, err := ReadUint64Bytes(b) |
|
| 575 |
+ return uint(u), b, err |
|
| 576 |
+} |
|
| 577 |
+ |
|
| 578 |
+// ReadByteBytes is analagous to ReadUint8Bytes |
|
| 579 |
+func ReadByteBytes(b []byte) (byte, []byte, error) {
|
|
| 580 |
+ return ReadUint8Bytes(b) |
|
| 581 |
+} |
|
| 582 |
+ |
|
| 583 |
+// ReadBytesBytes reads a 'bin' object |
|
| 584 |
+// from 'b' and returns its vaue and |
|
| 585 |
+// the remaining bytes in 'b'. |
|
| 586 |
+// Possible errors: |
|
| 587 |
+// - ErrShortBytes (too few bytes) |
|
| 588 |
+// - TypeError{} (not a 'bin' object)
|
|
| 589 |
+func ReadBytesBytes(b []byte, scratch []byte) (v []byte, o []byte, err error) {
|
|
| 590 |
+ return readBytesBytes(b, scratch, false) |
|
| 591 |
+} |
|
| 592 |
+ |
|
| 593 |
+func readBytesBytes(b []byte, scratch []byte, zc bool) (v []byte, o []byte, err error) {
|
|
| 594 |
+ l := len(b) |
|
| 595 |
+ if l < 1 {
|
|
| 596 |
+ return nil, nil, ErrShortBytes |
|
| 597 |
+ } |
|
| 598 |
+ |
|
| 599 |
+ lead := b[0] |
|
| 600 |
+ var read int |
|
| 601 |
+ switch lead {
|
|
| 602 |
+ case mbin8: |
|
| 603 |
+ if l < 2 {
|
|
| 604 |
+ err = ErrShortBytes |
|
| 605 |
+ return |
|
| 606 |
+ } |
|
| 607 |
+ |
|
| 608 |
+ read = int(b[1]) |
|
| 609 |
+ b = b[2:] |
|
| 610 |
+ |
|
| 611 |
+ case mbin16: |
|
| 612 |
+ if l < 3 {
|
|
| 613 |
+ err = ErrShortBytes |
|
| 614 |
+ return |
|
| 615 |
+ } |
|
| 616 |
+ read = int(big.Uint16(b[1:])) |
|
| 617 |
+ b = b[3:] |
|
| 618 |
+ |
|
| 619 |
+ case mbin32: |
|
| 620 |
+ if l < 5 {
|
|
| 621 |
+ err = ErrShortBytes |
|
| 622 |
+ return |
|
| 623 |
+ } |
|
| 624 |
+ read = int(big.Uint32(b[1:])) |
|
| 625 |
+ b = b[5:] |
|
| 626 |
+ |
|
| 627 |
+ default: |
|
| 628 |
+ err = badPrefix(BinType, lead) |
|
| 629 |
+ return |
|
| 630 |
+ } |
|
| 631 |
+ |
|
| 632 |
+ if len(b) < read {
|
|
| 633 |
+ err = ErrShortBytes |
|
| 634 |
+ return |
|
| 635 |
+ } |
|
| 636 |
+ |
|
| 637 |
+ // zero-copy |
|
| 638 |
+ if zc {
|
|
| 639 |
+ v = b[0:read] |
|
| 640 |
+ o = b[read:] |
|
| 641 |
+ return |
|
| 642 |
+ } |
|
| 643 |
+ |
|
| 644 |
+ if cap(scratch) >= read {
|
|
| 645 |
+ v = scratch[0:read] |
|
| 646 |
+ } else {
|
|
| 647 |
+ v = make([]byte, read) |
|
| 648 |
+ } |
|
| 649 |
+ |
|
| 650 |
+ o = b[copy(v, b):] |
|
| 651 |
+ return |
|
| 652 |
+} |
|
| 653 |
+ |
|
| 654 |
+// ReadBytesZC extracts the messagepack-encoded |
|
| 655 |
+// binary field without copying. The returned []byte |
|
| 656 |
+// points to the same memory as the input slice. |
|
| 657 |
+// Possible errors: |
|
| 658 |
+// - ErrShortBytes (b not long enough) |
|
| 659 |
+// - TypeError{} (object not 'bin')
|
|
| 660 |
+func ReadBytesZC(b []byte) (v []byte, o []byte, err error) {
|
|
| 661 |
+ return readBytesBytes(b, nil, true) |
|
| 662 |
+} |
|
| 663 |
+ |
|
| 664 |
+func ReadExactBytes(b []byte, into []byte) (o []byte, err error) {
|
|
| 665 |
+ l := len(b) |
|
| 666 |
+ if l < 1 {
|
|
| 667 |
+ err = ErrShortBytes |
|
| 668 |
+ return |
|
| 669 |
+ } |
|
| 670 |
+ |
|
| 671 |
+ lead := b[0] |
|
| 672 |
+ var read uint32 |
|
| 673 |
+ var skip int |
|
| 674 |
+ switch lead {
|
|
| 675 |
+ case mbin8: |
|
| 676 |
+ if l < 2 {
|
|
| 677 |
+ err = ErrShortBytes |
|
| 678 |
+ return |
|
| 679 |
+ } |
|
| 680 |
+ |
|
| 681 |
+ read = uint32(b[1]) |
|
| 682 |
+ skip = 2 |
|
| 683 |
+ |
|
| 684 |
+ case mbin16: |
|
| 685 |
+ if l < 3 {
|
|
| 686 |
+ err = ErrShortBytes |
|
| 687 |
+ return |
|
| 688 |
+ } |
|
| 689 |
+ read = uint32(big.Uint16(b[1:])) |
|
| 690 |
+ skip = 3 |
|
| 691 |
+ |
|
| 692 |
+ case mbin32: |
|
| 693 |
+ if l < 5 {
|
|
| 694 |
+ err = ErrShortBytes |
|
| 695 |
+ return |
|
| 696 |
+ } |
|
| 697 |
+ read = uint32(big.Uint32(b[1:])) |
|
| 698 |
+ skip = 5 |
|
| 699 |
+ |
|
| 700 |
+ default: |
|
| 701 |
+ err = badPrefix(BinType, lead) |
|
| 702 |
+ return |
|
| 703 |
+ } |
|
| 704 |
+ |
|
| 705 |
+ if read != uint32(len(into)) {
|
|
| 706 |
+ err = ArrayError{Wanted: uint32(len(into)), Got: read}
|
|
| 707 |
+ return |
|
| 708 |
+ } |
|
| 709 |
+ |
|
| 710 |
+ o = b[skip+copy(into, b[skip:]):] |
|
| 711 |
+ return |
|
| 712 |
+} |
|
| 713 |
+ |
|
| 714 |
+// ReadStringZC reads a messagepack string field |
|
| 715 |
+// without copying. The returned []byte points |
|
| 716 |
+// to the same memory as the input slice. |
|
| 717 |
+// Possible errors: |
|
| 718 |
+// - ErrShortBytes (b not long enough) |
|
| 719 |
+// - TypeError{} (object not 'str')
|
|
| 720 |
+func ReadStringZC(b []byte) (v []byte, o []byte, err error) {
|
|
| 721 |
+ l := len(b) |
|
| 722 |
+ if l < 1 {
|
|
| 723 |
+ return nil, nil, ErrShortBytes |
|
| 724 |
+ } |
|
| 725 |
+ |
|
| 726 |
+ lead := b[0] |
|
| 727 |
+ var read int |
|
| 728 |
+ |
|
| 729 |
+ if isfixstr(lead) {
|
|
| 730 |
+ read = int(rfixstr(lead)) |
|
| 731 |
+ b = b[1:] |
|
| 732 |
+ } else {
|
|
| 733 |
+ switch lead {
|
|
| 734 |
+ case mstr8: |
|
| 735 |
+ if l < 2 {
|
|
| 736 |
+ err = ErrShortBytes |
|
| 737 |
+ return |
|
| 738 |
+ } |
|
| 739 |
+ read = int(b[1]) |
|
| 740 |
+ b = b[2:] |
|
| 741 |
+ |
|
| 742 |
+ case mstr16: |
|
| 743 |
+ if l < 3 {
|
|
| 744 |
+ err = ErrShortBytes |
|
| 745 |
+ return |
|
| 746 |
+ } |
|
| 747 |
+ read = int(big.Uint16(b[1:])) |
|
| 748 |
+ b = b[3:] |
|
| 749 |
+ |
|
| 750 |
+ case mstr32: |
|
| 751 |
+ if l < 5 {
|
|
| 752 |
+ err = ErrShortBytes |
|
| 753 |
+ return |
|
| 754 |
+ } |
|
| 755 |
+ read = int(big.Uint32(b[1:])) |
|
| 756 |
+ b = b[5:] |
|
| 757 |
+ |
|
| 758 |
+ default: |
|
| 759 |
+ err = TypeError{Method: StrType, Encoded: getType(lead)}
|
|
| 760 |
+ return |
|
| 761 |
+ } |
|
| 762 |
+ } |
|
| 763 |
+ |
|
| 764 |
+ if len(b) < read {
|
|
| 765 |
+ err = ErrShortBytes |
|
| 766 |
+ return |
|
| 767 |
+ } |
|
| 768 |
+ |
|
| 769 |
+ v = b[0:read] |
|
| 770 |
+ o = b[read:] |
|
| 771 |
+ return |
|
| 772 |
+} |
|
| 773 |
+ |
|
| 774 |
+// ReadStringBytes reads a 'str' object |
|
| 775 |
+// from 'b' and returns its value and the |
|
| 776 |
+// remaining bytes in 'b'. |
|
| 777 |
+// Possible errors: |
|
| 778 |
+// - ErrShortBytes (b not long enough) |
|
| 779 |
+// - TypeError{} (not 'str' type)
|
|
| 780 |
+// - InvalidPrefixError |
|
| 781 |
+func ReadStringBytes(b []byte) (string, []byte, error) {
|
|
| 782 |
+ v, o, err := ReadStringZC(b) |
|
| 783 |
+ return string(v), o, err |
|
| 784 |
+} |
|
| 785 |
+ |
|
| 786 |
+// ReadComplex128Bytes reads a complex128 |
|
| 787 |
+// extension object from 'b' and returns the |
|
| 788 |
+// remaining bytes. |
|
| 789 |
+// Possible errors: |
|
| 790 |
+// - ErrShortBytes (not enough bytes in 'b') |
|
| 791 |
+// - TypeError{} (object not a complex128)
|
|
| 792 |
+// - InvalidPrefixError |
|
| 793 |
+// - ExtensionTypeError{} (object an extension of the correct size, but not a complex128)
|
|
| 794 |
+func ReadComplex128Bytes(b []byte) (c complex128, o []byte, err error) {
|
|
| 795 |
+ if len(b) < 18 {
|
|
| 796 |
+ err = ErrShortBytes |
|
| 797 |
+ return |
|
| 798 |
+ } |
|
| 799 |
+ if b[0] != mfixext16 {
|
|
| 800 |
+ err = badPrefix(Complex128Type, b[0]) |
|
| 801 |
+ return |
|
| 802 |
+ } |
|
| 803 |
+ if int8(b[1]) != Complex128Extension {
|
|
| 804 |
+ err = errExt(int8(b[1]), Complex128Extension) |
|
| 805 |
+ return |
|
| 806 |
+ } |
|
| 807 |
+ c = complex(math.Float64frombits(big.Uint64(b[2:])), |
|
| 808 |
+ math.Float64frombits(big.Uint64(b[10:]))) |
|
| 809 |
+ o = b[18:] |
|
| 810 |
+ return |
|
| 811 |
+} |
|
| 812 |
+ |
|
| 813 |
+// ReadComplex64Bytes reads a complex64 |
|
| 814 |
+// extension object from 'b' and returns the |
|
| 815 |
+// remaining bytes. |
|
| 816 |
+// Possible errors: |
|
| 817 |
+// - ErrShortBytes (not enough bytes in 'b') |
|
| 818 |
+// - TypeError{} (object not a complex64)
|
|
| 819 |
+// - ExtensionTypeError{} (object an extension of the correct size, but not a complex64)
|
|
| 820 |
+func ReadComplex64Bytes(b []byte) (c complex64, o []byte, err error) {
|
|
| 821 |
+ if len(b) < 10 {
|
|
| 822 |
+ err = ErrShortBytes |
|
| 823 |
+ return |
|
| 824 |
+ } |
|
| 825 |
+ if b[0] != mfixext8 {
|
|
| 826 |
+ err = badPrefix(Complex64Type, b[0]) |
|
| 827 |
+ return |
|
| 828 |
+ } |
|
| 829 |
+ if b[1] != Complex64Extension {
|
|
| 830 |
+ err = errExt(int8(b[1]), Complex64Extension) |
|
| 831 |
+ return |
|
| 832 |
+ } |
|
| 833 |
+ c = complex(math.Float32frombits(big.Uint32(b[2:])), |
|
| 834 |
+ math.Float32frombits(big.Uint32(b[6:]))) |
|
| 835 |
+ o = b[10:] |
|
| 836 |
+ return |
|
| 837 |
+} |
|
| 838 |
+ |
|
| 839 |
+// ReadTimeBytes reads a time.Time |
|
| 840 |
+// extension object from 'b' and returns the |
|
| 841 |
+// remaining bytes. |
|
| 842 |
+// Possible errors: |
|
| 843 |
+// - ErrShortBytes (not enough bytes in 'b') |
|
| 844 |
+// - TypeError{} (object not a complex64)
|
|
| 845 |
+// - ExtensionTypeError{} (object an extension of the correct size, but not a time.Time)
|
|
| 846 |
+func ReadTimeBytes(b []byte) (t time.Time, o []byte, err error) {
|
|
| 847 |
+ if len(b) < 15 {
|
|
| 848 |
+ err = ErrShortBytes |
|
| 849 |
+ return |
|
| 850 |
+ } |
|
| 851 |
+ if b[0] != mext8 || b[1] != 12 {
|
|
| 852 |
+ err = badPrefix(TimeType, b[0]) |
|
| 853 |
+ return |
|
| 854 |
+ } |
|
| 855 |
+ if int8(b[2]) != TimeExtension {
|
|
| 856 |
+ err = errExt(int8(b[2]), TimeExtension) |
|
| 857 |
+ return |
|
| 858 |
+ } |
|
| 859 |
+ sec, nsec := getUnix(b[3:]) |
|
| 860 |
+ t = time.Unix(sec, int64(nsec)).Local() |
|
| 861 |
+ o = b[15:] |
|
| 862 |
+ return |
|
| 863 |
+} |
|
| 864 |
+ |
|
| 865 |
+// ReadMapStrIntfBytes reads a map[string]interface{}
|
|
| 866 |
+// out of 'b' and returns the map and remaining bytes. |
|
| 867 |
+// If 'old' is non-nil, the values will be read into that map. |
|
| 868 |
+func ReadMapStrIntfBytes(b []byte, old map[string]interface{}) (v map[string]interface{}, o []byte, err error) {
|
|
| 869 |
+ var sz uint32 |
|
| 870 |
+ o = b |
|
| 871 |
+ sz, o, err = ReadMapHeaderBytes(o) |
|
| 872 |
+ |
|
| 873 |
+ if err != nil {
|
|
| 874 |
+ return |
|
| 875 |
+ } |
|
| 876 |
+ |
|
| 877 |
+ if old != nil {
|
|
| 878 |
+ for key := range old {
|
|
| 879 |
+ delete(old, key) |
|
| 880 |
+ } |
|
| 881 |
+ v = old |
|
| 882 |
+ } else {
|
|
| 883 |
+ v = make(map[string]interface{}, int(sz))
|
|
| 884 |
+ } |
|
| 885 |
+ |
|
| 886 |
+ for z := uint32(0); z < sz; z++ {
|
|
| 887 |
+ if len(o) < 1 {
|
|
| 888 |
+ err = ErrShortBytes |
|
| 889 |
+ return |
|
| 890 |
+ } |
|
| 891 |
+ var key []byte |
|
| 892 |
+ key, o, err = ReadMapKeyZC(o) |
|
| 893 |
+ if err != nil {
|
|
| 894 |
+ return |
|
| 895 |
+ } |
|
| 896 |
+ var val interface{}
|
|
| 897 |
+ val, o, err = ReadIntfBytes(o) |
|
| 898 |
+ if err != nil {
|
|
| 899 |
+ return |
|
| 900 |
+ } |
|
| 901 |
+ v[string(key)] = val |
|
| 902 |
+ } |
|
| 903 |
+ return |
|
| 904 |
+} |
|
| 905 |
+ |
|
| 906 |
+// ReadIntfBytes attempts to read |
|
| 907 |
+// the next object out of 'b' as a raw interface{} and
|
|
| 908 |
+// return the remaining bytes. |
|
| 909 |
+func ReadIntfBytes(b []byte) (i interface{}, o []byte, err error) {
|
|
| 910 |
+ if len(b) < 1 {
|
|
| 911 |
+ err = ErrShortBytes |
|
| 912 |
+ return |
|
| 913 |
+ } |
|
| 914 |
+ |
|
| 915 |
+ k := NextType(b) |
|
| 916 |
+ |
|
| 917 |
+ switch k {
|
|
| 918 |
+ case MapType: |
|
| 919 |
+ i, o, err = ReadMapStrIntfBytes(b, nil) |
|
| 920 |
+ return |
|
| 921 |
+ |
|
| 922 |
+ case ArrayType: |
|
| 923 |
+ var sz uint32 |
|
| 924 |
+ sz, b, err = ReadArrayHeaderBytes(b) |
|
| 925 |
+ if err != nil {
|
|
| 926 |
+ return |
|
| 927 |
+ } |
|
| 928 |
+ j := make([]interface{}, int(sz))
|
|
| 929 |
+ i = j |
|
| 930 |
+ for d := range j {
|
|
| 931 |
+ j[d], b, err = ReadIntfBytes(b) |
|
| 932 |
+ if err != nil {
|
|
| 933 |
+ return |
|
| 934 |
+ } |
|
| 935 |
+ } |
|
| 936 |
+ return |
|
| 937 |
+ |
|
| 938 |
+ case Float32Type: |
|
| 939 |
+ i, o, err = ReadFloat32Bytes(b) |
|
| 940 |
+ return |
|
| 941 |
+ |
|
| 942 |
+ case Float64Type: |
|
| 943 |
+ i, o, err = ReadFloat64Bytes(b) |
|
| 944 |
+ return |
|
| 945 |
+ |
|
| 946 |
+ case IntType: |
|
| 947 |
+ i, o, err = ReadInt64Bytes(b) |
|
| 948 |
+ return |
|
| 949 |
+ |
|
| 950 |
+ case UintType: |
|
| 951 |
+ i, o, err = ReadUint64Bytes(b) |
|
| 952 |
+ return |
|
| 953 |
+ |
|
| 954 |
+ case BoolType: |
|
| 955 |
+ i, o, err = ReadBoolBytes(b) |
|
| 956 |
+ return |
|
| 957 |
+ |
|
| 958 |
+ case TimeType: |
|
| 959 |
+ i, o, err = ReadTimeBytes(b) |
|
| 960 |
+ return |
|
| 961 |
+ |
|
| 962 |
+ case Complex64Type: |
|
| 963 |
+ i, o, err = ReadComplex64Bytes(b) |
|
| 964 |
+ return |
|
| 965 |
+ |
|
| 966 |
+ case Complex128Type: |
|
| 967 |
+ i, o, err = ReadComplex128Bytes(b) |
|
| 968 |
+ return |
|
| 969 |
+ |
|
| 970 |
+ case ExtensionType: |
|
| 971 |
+ var t int8 |
|
| 972 |
+ t, err = peekExtension(b) |
|
| 973 |
+ if err != nil {
|
|
| 974 |
+ return |
|
| 975 |
+ } |
|
| 976 |
+ // use a user-defined extension, |
|
| 977 |
+ // if it's been registered |
|
| 978 |
+ f, ok := extensionReg[t] |
|
| 979 |
+ if ok {
|
|
| 980 |
+ e := f() |
|
| 981 |
+ o, err = ReadExtensionBytes(b, e) |
|
| 982 |
+ i = e |
|
| 983 |
+ return |
|
| 984 |
+ } |
|
| 985 |
+ // last resort is a raw extension |
|
| 986 |
+ e := RawExtension{}
|
|
| 987 |
+ e.Type = int8(t) |
|
| 988 |
+ o, err = ReadExtensionBytes(b, &e) |
|
| 989 |
+ i = &e |
|
| 990 |
+ return |
|
| 991 |
+ |
|
| 992 |
+ case NilType: |
|
| 993 |
+ o, err = ReadNilBytes(b) |
|
| 994 |
+ return |
|
| 995 |
+ |
|
| 996 |
+ case BinType: |
|
| 997 |
+ i, o, err = ReadBytesBytes(b, nil) |
|
| 998 |
+ return |
|
| 999 |
+ |
|
| 1000 |
+ case StrType: |
|
| 1001 |
+ i, o, err = ReadStringBytes(b) |
|
| 1002 |
+ return |
|
| 1003 |
+ |
|
| 1004 |
+ default: |
|
| 1005 |
+ err = InvalidPrefixError(b[0]) |
|
| 1006 |
+ return |
|
| 1007 |
+ } |
|
| 1008 |
+} |
|
| 1009 |
+ |
|
| 1010 |
+// Skip skips the next object in 'b' and |
|
| 1011 |
+// returns the remaining bytes. If the object |
|
| 1012 |
+// is a map or array, all of its elements |
|
| 1013 |
+// will be skipped. |
|
| 1014 |
+// Possible Errors: |
|
| 1015 |
+// - ErrShortBytes (not enough bytes in b) |
|
| 1016 |
+// - InvalidPrefixError (bad encoding) |
|
| 1017 |
+func Skip(b []byte) ([]byte, error) {
|
|
| 1018 |
+ sz, asz, err := getSize(b) |
|
| 1019 |
+ if err != nil {
|
|
| 1020 |
+ return b, err |
|
| 1021 |
+ } |
|
| 1022 |
+ if uintptr(len(b)) < sz {
|
|
| 1023 |
+ return b, ErrShortBytes |
|
| 1024 |
+ } |
|
| 1025 |
+ b = b[sz:] |
|
| 1026 |
+ for asz > 0 {
|
|
| 1027 |
+ b, err = Skip(b) |
|
| 1028 |
+ if err != nil {
|
|
| 1029 |
+ return b, err |
|
| 1030 |
+ } |
|
| 1031 |
+ asz-- |
|
| 1032 |
+ } |
|
| 1033 |
+ return b, nil |
|
| 1034 |
+} |
|
| 1035 |
+ |
|
| 1036 |
+// returns (skip N bytes, skip M objects, error) |
|
| 1037 |
+func getSize(b []byte) (uintptr, uintptr, error) {
|
|
| 1038 |
+ l := len(b) |
|
| 1039 |
+ if l == 0 {
|
|
| 1040 |
+ return 0, 0, ErrShortBytes |
|
| 1041 |
+ } |
|
| 1042 |
+ lead := b[0] |
|
| 1043 |
+ spec := &sizes[lead] // get type information |
|
| 1044 |
+ size, mode := spec.size, spec.extra |
|
| 1045 |
+ if size == 0 {
|
|
| 1046 |
+ return 0, 0, InvalidPrefixError(lead) |
|
| 1047 |
+ } |
|
| 1048 |
+ if mode >= 0 { // fixed composites
|
|
| 1049 |
+ return uintptr(size), uintptr(mode), nil |
|
| 1050 |
+ } |
|
| 1051 |
+ if l < int(size) {
|
|
| 1052 |
+ return 0, 0, ErrShortBytes |
|
| 1053 |
+ } |
|
| 1054 |
+ switch mode {
|
|
| 1055 |
+ case extra8: |
|
| 1056 |
+ return uintptr(size) + uintptr(b[1]), 0, nil |
|
| 1057 |
+ case extra16: |
|
| 1058 |
+ return uintptr(size) + uintptr(big.Uint16(b[1:])), 0, nil |
|
| 1059 |
+ case extra32: |
|
| 1060 |
+ return uintptr(size) + uintptr(big.Uint32(b[1:])), 0, nil |
|
| 1061 |
+ case map16v: |
|
| 1062 |
+ return uintptr(size), 2 * uintptr(big.Uint16(b[1:])), nil |
|
| 1063 |
+ case map32v: |
|
| 1064 |
+ return uintptr(size), 2 * uintptr(big.Uint32(b[1:])), nil |
|
| 1065 |
+ case array16v: |
|
| 1066 |
+ return uintptr(size), uintptr(big.Uint16(b[1:])), nil |
|
| 1067 |
+ case array32v: |
|
| 1068 |
+ return uintptr(size), uintptr(big.Uint32(b[1:])), nil |
|
| 1069 |
+ default: |
|
| 1070 |
+ return 0, 0, fatal |
|
| 1071 |
+ } |
|
| 1072 |
+} |
| 0 | 1073 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,38 @@ |
| 0 |
+package msgp |
|
| 1 |
+ |
|
| 2 |
+// The sizes provided |
|
| 3 |
+// are the worst-case |
|
| 4 |
+// encoded sizes for |
|
| 5 |
+// each type. For variable- |
|
| 6 |
+// length types ([]byte, string), |
|
| 7 |
+// the total encoded size is |
|
| 8 |
+// the prefix size plus the |
|
| 9 |
+// length of the object. |
|
| 10 |
+const ( |
|
| 11 |
+ Int64Size = 9 |
|
| 12 |
+ IntSize = Int64Size |
|
| 13 |
+ UintSize = Int64Size |
|
| 14 |
+ Int8Size = 2 |
|
| 15 |
+ Int16Size = 3 |
|
| 16 |
+ Int32Size = 5 |
|
| 17 |
+ Uint8Size = 2 |
|
| 18 |
+ ByteSize = Uint8Size |
|
| 19 |
+ Uint16Size = 3 |
|
| 20 |
+ Uint32Size = 5 |
|
| 21 |
+ Uint64Size = Int64Size |
|
| 22 |
+ Float64Size = 9 |
|
| 23 |
+ Float32Size = 5 |
|
| 24 |
+ Complex64Size = 10 |
|
| 25 |
+ Complex128Size = 18 |
|
| 26 |
+ |
|
| 27 |
+ TimeSize = 15 |
|
| 28 |
+ BoolSize = 1 |
|
| 29 |
+ NilSize = 1 |
|
| 30 |
+ |
|
| 31 |
+ MapHeaderSize = 5 |
|
| 32 |
+ ArrayHeaderSize = 5 |
|
| 33 |
+ |
|
| 34 |
+ BytesPrefixSize = 5 |
|
| 35 |
+ StringPrefixSize = 5 |
|
| 36 |
+ ExtensionPrefixSize = 6 |
|
| 37 |
+) |
| 0 | 38 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,768 @@ |
| 0 |
+package msgp |
|
| 1 |
+ |
|
| 2 |
+import ( |
|
| 3 |
+ "errors" |
|
| 4 |
+ "fmt" |
|
| 5 |
+ "io" |
|
| 6 |
+ "math" |
|
| 7 |
+ "reflect" |
|
| 8 |
+ "sync" |
|
| 9 |
+ "time" |
|
| 10 |
+) |
|
| 11 |
+ |
|
| 12 |
+func abs(i int64) int64 {
|
|
| 13 |
+ if i < 0 {
|
|
| 14 |
+ return -i |
|
| 15 |
+ } |
|
| 16 |
+ return i |
|
| 17 |
+} |
|
| 18 |
+ |
|
| 19 |
+// Sizer is an interface implemented |
|
| 20 |
+// by types that can estimate their |
|
| 21 |
+// size when MessagePack encoded. |
|
| 22 |
+// This interface is optional, but |
|
| 23 |
+// encoding/marshaling implementations |
|
| 24 |
+// may use this as a way to pre-allocate |
|
| 25 |
+// memory for serialization. |
|
| 26 |
+type Sizer interface {
|
|
| 27 |
+ Msgsize() int |
|
| 28 |
+} |
|
| 29 |
+ |
|
| 30 |
+var ( |
|
| 31 |
+ // Nowhere is an io.Writer to nowhere |
|
| 32 |
+ Nowhere io.Writer = nwhere{}
|
|
| 33 |
+ |
|
| 34 |
+ btsType = reflect.TypeOf(([]byte)(nil)) |
|
| 35 |
+ writerPool = sync.Pool{
|
|
| 36 |
+ New: func() interface{} {
|
|
| 37 |
+ return &Writer{buf: make([]byte, 2048)}
|
|
| 38 |
+ }, |
|
| 39 |
+ } |
|
| 40 |
+) |
|
| 41 |
+ |
|
| 42 |
+func popWriter(w io.Writer) *Writer {
|
|
| 43 |
+ wr := writerPool.Get().(*Writer) |
|
| 44 |
+ wr.Reset(w) |
|
| 45 |
+ return wr |
|
| 46 |
+} |
|
| 47 |
+ |
|
| 48 |
+func pushWriter(wr *Writer) {
|
|
| 49 |
+ wr.w = nil |
|
| 50 |
+ wr.wloc = 0 |
|
| 51 |
+ writerPool.Put(wr) |
|
| 52 |
+} |
|
| 53 |
+ |
|
| 54 |
+// freeW frees a writer for use |
|
| 55 |
+// by other processes. It is not necessary |
|
| 56 |
+// to call freeW on a writer. However, maintaining |
|
| 57 |
+// a reference to a *Writer after calling freeW on |
|
| 58 |
+// it will cause undefined behavior. |
|
| 59 |
+func freeW(w *Writer) { pushWriter(w) }
|
|
| 60 |
+ |
|
| 61 |
+// Require ensures that cap(old)-len(old) >= extra |
|
| 62 |
+func Require(old []byte, extra int) []byte {
|
|
| 63 |
+ if cap(old)-len(old) >= extra {
|
|
| 64 |
+ return old |
|
| 65 |
+ } |
|
| 66 |
+ if len(old) == 0 {
|
|
| 67 |
+ return make([]byte, 0, extra) |
|
| 68 |
+ } |
|
| 69 |
+ n := make([]byte, len(old), cap(old)-len(old)+extra) |
|
| 70 |
+ copy(n, old) |
|
| 71 |
+ return n |
|
| 72 |
+} |
|
| 73 |
+ |
|
| 74 |
+// nowhere writer |
|
| 75 |
+type nwhere struct{}
|
|
| 76 |
+ |
|
| 77 |
+func (n nwhere) Write(p []byte) (int, error) { return len(p), nil }
|
|
| 78 |
+ |
|
| 79 |
+// Marshaler is the interface implemented |
|
| 80 |
+// by types that know how to marshal themselves |
|
| 81 |
+// as MessagePack. MarshalMsg appends the marshalled |
|
| 82 |
+// form of the object to the provided |
|
| 83 |
+// byte slice, returning the extended |
|
| 84 |
+// slice and any errors encountered. |
|
| 85 |
+type Marshaler interface {
|
|
| 86 |
+ MarshalMsg([]byte) ([]byte, error) |
|
| 87 |
+} |
|
| 88 |
+ |
|
| 89 |
+// Encodable is the interface implemented |
|
| 90 |
+// by types that know how to write themselves |
|
| 91 |
+// as MessagePack using a *msgp.Writer. |
|
| 92 |
+type Encodable interface {
|
|
| 93 |
+ EncodeMsg(*Writer) error |
|
| 94 |
+} |
|
| 95 |
+ |
|
| 96 |
+// Writer is a buffered writer |
|
| 97 |
+// that can be used to write |
|
| 98 |
+// MessagePack objects to an io.Writer. |
|
| 99 |
+// You must call *Writer.Flush() in order |
|
| 100 |
+// to flush all of the buffered data |
|
| 101 |
+// to the underlying writer. |
|
| 102 |
+type Writer struct {
|
|
| 103 |
+ w io.Writer |
|
| 104 |
+ buf []byte |
|
| 105 |
+ wloc int |
|
| 106 |
+} |
|
| 107 |
+ |
|
| 108 |
+// NewWriter returns a new *Writer. |
|
| 109 |
+func NewWriter(w io.Writer) *Writer {
|
|
| 110 |
+ if wr, ok := w.(*Writer); ok {
|
|
| 111 |
+ return wr |
|
| 112 |
+ } |
|
| 113 |
+ return popWriter(w) |
|
| 114 |
+} |
|
| 115 |
+ |
|
| 116 |
+// NewWriterSize returns a writer with a custom buffer size. |
|
| 117 |
+func NewWriterSize(w io.Writer, sz int) *Writer {
|
|
| 118 |
+ // we must be able to require() 18 |
|
| 119 |
+ // contiguous bytes, so that is the |
|
| 120 |
+ // practical minimum buffer size |
|
| 121 |
+ if sz < 18 {
|
|
| 122 |
+ sz = 18 |
|
| 123 |
+ } |
|
| 124 |
+ |
|
| 125 |
+ return &Writer{
|
|
| 126 |
+ w: w, |
|
| 127 |
+ buf: make([]byte, sz), |
|
| 128 |
+ } |
|
| 129 |
+} |
|
| 130 |
+ |
|
| 131 |
+// Encode encodes an Encodable to an io.Writer. |
|
| 132 |
+func Encode(w io.Writer, e Encodable) error {
|
|
| 133 |
+ wr := NewWriter(w) |
|
| 134 |
+ err := e.EncodeMsg(wr) |
|
| 135 |
+ if err == nil {
|
|
| 136 |
+ err = wr.Flush() |
|
| 137 |
+ } |
|
| 138 |
+ freeW(wr) |
|
| 139 |
+ return err |
|
| 140 |
+} |
|
| 141 |
+ |
|
| 142 |
+func (mw *Writer) flush() error {
|
|
| 143 |
+ if mw.wloc == 0 {
|
|
| 144 |
+ return nil |
|
| 145 |
+ } |
|
| 146 |
+ n, err := mw.w.Write(mw.buf[:mw.wloc]) |
|
| 147 |
+ if err != nil {
|
|
| 148 |
+ if n > 0 {
|
|
| 149 |
+ mw.wloc = copy(mw.buf, mw.buf[n:mw.wloc]) |
|
| 150 |
+ } |
|
| 151 |
+ return err |
|
| 152 |
+ } |
|
| 153 |
+ mw.wloc = 0 |
|
| 154 |
+ return nil |
|
| 155 |
+} |
|
| 156 |
+ |
|
| 157 |
+// Flush flushes all of the buffered |
|
| 158 |
+// data to the underlying writer. |
|
| 159 |
+func (mw *Writer) Flush() error { return mw.flush() }
|
|
| 160 |
+ |
|
| 161 |
+// Buffered returns the number bytes in the write buffer |
|
| 162 |
+func (mw *Writer) Buffered() int { return len(mw.buf) - mw.wloc }
|
|
| 163 |
+ |
|
| 164 |
+func (mw *Writer) avail() int { return len(mw.buf) - mw.wloc }
|
|
| 165 |
+ |
|
| 166 |
+func (mw *Writer) bufsize() int { return len(mw.buf) }
|
|
| 167 |
+ |
|
| 168 |
+// NOTE: this should only be called with |
|
| 169 |
+// a number that is guaranteed to be less than |
|
| 170 |
+// len(mw.buf). typically, it is called with a constant. |
|
| 171 |
+// |
|
| 172 |
+// NOTE: this is a hot code path |
|
| 173 |
+func (mw *Writer) require(n int) (int, error) {
|
|
| 174 |
+ c := len(mw.buf) |
|
| 175 |
+ wl := mw.wloc |
|
| 176 |
+ if c-wl < n {
|
|
| 177 |
+ if err := mw.flush(); err != nil {
|
|
| 178 |
+ return 0, err |
|
| 179 |
+ } |
|
| 180 |
+ wl = mw.wloc |
|
| 181 |
+ } |
|
| 182 |
+ mw.wloc += n |
|
| 183 |
+ return wl, nil |
|
| 184 |
+} |
|
| 185 |
+ |
|
| 186 |
+// push one byte onto the buffer |
|
| 187 |
+// |
|
| 188 |
+// NOTE: this is a hot code path |
|
| 189 |
+func (mw *Writer) push(b byte) error {
|
|
| 190 |
+ if mw.wloc == len(mw.buf) {
|
|
| 191 |
+ if err := mw.flush(); err != nil {
|
|
| 192 |
+ return err |
|
| 193 |
+ } |
|
| 194 |
+ } |
|
| 195 |
+ mw.buf[mw.wloc] = b |
|
| 196 |
+ mw.wloc++ |
|
| 197 |
+ return nil |
|
| 198 |
+} |
|
| 199 |
+ |
|
| 200 |
+func (mw *Writer) prefix8(b byte, u uint8) error {
|
|
| 201 |
+ const need = 2 |
|
| 202 |
+ if len(mw.buf)-mw.wloc < need {
|
|
| 203 |
+ if err := mw.flush(); err != nil {
|
|
| 204 |
+ return err |
|
| 205 |
+ } |
|
| 206 |
+ } |
|
| 207 |
+ prefixu8(mw.buf[mw.wloc:], b, u) |
|
| 208 |
+ mw.wloc += need |
|
| 209 |
+ return nil |
|
| 210 |
+} |
|
| 211 |
+ |
|
| 212 |
+func (mw *Writer) prefix16(b byte, u uint16) error {
|
|
| 213 |
+ const need = 3 |
|
| 214 |
+ if len(mw.buf)-mw.wloc < need {
|
|
| 215 |
+ if err := mw.flush(); err != nil {
|
|
| 216 |
+ return err |
|
| 217 |
+ } |
|
| 218 |
+ } |
|
| 219 |
+ prefixu16(mw.buf[mw.wloc:], b, u) |
|
| 220 |
+ mw.wloc += need |
|
| 221 |
+ return nil |
|
| 222 |
+} |
|
| 223 |
+ |
|
| 224 |
+func (mw *Writer) prefix32(b byte, u uint32) error {
|
|
| 225 |
+ const need = 5 |
|
| 226 |
+ if len(mw.buf)-mw.wloc < need {
|
|
| 227 |
+ if err := mw.flush(); err != nil {
|
|
| 228 |
+ return err |
|
| 229 |
+ } |
|
| 230 |
+ } |
|
| 231 |
+ prefixu32(mw.buf[mw.wloc:], b, u) |
|
| 232 |
+ mw.wloc += need |
|
| 233 |
+ return nil |
|
| 234 |
+} |
|
| 235 |
+ |
|
| 236 |
+func (mw *Writer) prefix64(b byte, u uint64) error {
|
|
| 237 |
+ const need = 9 |
|
| 238 |
+ if len(mw.buf)-mw.wloc < need {
|
|
| 239 |
+ if err := mw.flush(); err != nil {
|
|
| 240 |
+ return err |
|
| 241 |
+ } |
|
| 242 |
+ } |
|
| 243 |
+ prefixu64(mw.buf[mw.wloc:], b, u) |
|
| 244 |
+ mw.wloc += need |
|
| 245 |
+ return nil |
|
| 246 |
+} |
|
| 247 |
+ |
|
| 248 |
+// Write implements io.Writer, and writes |
|
| 249 |
+// data directly to the buffer. |
|
| 250 |
+func (mw *Writer) Write(p []byte) (int, error) {
|
|
| 251 |
+ l := len(p) |
|
| 252 |
+ if mw.avail() < l {
|
|
| 253 |
+ if err := mw.flush(); err != nil {
|
|
| 254 |
+ return 0, err |
|
| 255 |
+ } |
|
| 256 |
+ if l > len(mw.buf) {
|
|
| 257 |
+ return mw.w.Write(p) |
|
| 258 |
+ } |
|
| 259 |
+ } |
|
| 260 |
+ mw.wloc += copy(mw.buf[mw.wloc:], p) |
|
| 261 |
+ return l, nil |
|
| 262 |
+} |
|
| 263 |
+ |
|
| 264 |
+// implements io.WriteString |
|
| 265 |
+func (mw *Writer) writeString(s string) error {
|
|
| 266 |
+ l := len(s) |
|
| 267 |
+ if mw.avail() < l {
|
|
| 268 |
+ if err := mw.flush(); err != nil {
|
|
| 269 |
+ return err |
|
| 270 |
+ } |
|
| 271 |
+ if l > len(mw.buf) {
|
|
| 272 |
+ _, err := io.WriteString(mw.w, s) |
|
| 273 |
+ return err |
|
| 274 |
+ } |
|
| 275 |
+ } |
|
| 276 |
+ mw.wloc += copy(mw.buf[mw.wloc:], s) |
|
| 277 |
+ return nil |
|
| 278 |
+} |
|
| 279 |
+ |
|
| 280 |
+// Reset changes the underlying writer used by the Writer |
|
| 281 |
+func (mw *Writer) Reset(w io.Writer) {
|
|
| 282 |
+ mw.buf = mw.buf[:cap(mw.buf)] |
|
| 283 |
+ mw.w = w |
|
| 284 |
+ mw.wloc = 0 |
|
| 285 |
+} |
|
| 286 |
+ |
|
| 287 |
+// WriteMapHeader writes a map header of the given |
|
| 288 |
+// size to the writer |
|
| 289 |
+func (mw *Writer) WriteMapHeader(sz uint32) error {
|
|
| 290 |
+ switch {
|
|
| 291 |
+ case sz < 16: |
|
| 292 |
+ return mw.push(wfixmap(uint8(sz))) |
|
| 293 |
+ case sz < math.MaxUint16: |
|
| 294 |
+ return mw.prefix16(mmap16, uint16(sz)) |
|
| 295 |
+ default: |
|
| 296 |
+ return mw.prefix32(mmap32, sz) |
|
| 297 |
+ } |
|
| 298 |
+} |
|
| 299 |
+ |
|
| 300 |
+// WriteArrayHeader writes an array header of the |
|
| 301 |
+// given size to the writer |
|
| 302 |
+func (mw *Writer) WriteArrayHeader(sz uint32) error {
|
|
| 303 |
+ switch {
|
|
| 304 |
+ case sz < 16: |
|
| 305 |
+ return mw.push(wfixarray(uint8(sz))) |
|
| 306 |
+ case sz < math.MaxUint16: |
|
| 307 |
+ return mw.prefix16(marray16, uint16(sz)) |
|
| 308 |
+ default: |
|
| 309 |
+ return mw.prefix32(marray32, sz) |
|
| 310 |
+ } |
|
| 311 |
+} |
|
| 312 |
+ |
|
| 313 |
+// WriteNil writes a nil byte to the buffer |
|
| 314 |
+func (mw *Writer) WriteNil() error {
|
|
| 315 |
+ return mw.push(mnil) |
|
| 316 |
+} |
|
| 317 |
+ |
|
| 318 |
+// WriteFloat64 writes a float64 to the writer |
|
| 319 |
+func (mw *Writer) WriteFloat64(f float64) error {
|
|
| 320 |
+ return mw.prefix64(mfloat64, math.Float64bits(f)) |
|
| 321 |
+} |
|
| 322 |
+ |
|
| 323 |
+// WriteFloat32 writes a float32 to the writer |
|
| 324 |
+func (mw *Writer) WriteFloat32(f float32) error {
|
|
| 325 |
+ return mw.prefix32(mfloat32, math.Float32bits(f)) |
|
| 326 |
+} |
|
| 327 |
+ |
|
| 328 |
+// WriteInt64 writes an int64 to the writer |
|
| 329 |
+func (mw *Writer) WriteInt64(i int64) error {
|
|
| 330 |
+ a := abs(i) |
|
| 331 |
+ switch {
|
|
| 332 |
+ case i < 0 && i > -32: |
|
| 333 |
+ return mw.push(wnfixint(int8(i))) |
|
| 334 |
+ case i >= 0 && i < 128: |
|
| 335 |
+ return mw.push(wfixint(uint8(i))) |
|
| 336 |
+ case a < math.MaxInt8: |
|
| 337 |
+ return mw.prefix8(mint8, uint8(i)) |
|
| 338 |
+ case a < math.MaxInt16: |
|
| 339 |
+ return mw.prefix16(mint16, uint16(i)) |
|
| 340 |
+ case a < math.MaxInt32: |
|
| 341 |
+ return mw.prefix32(mint32, uint32(i)) |
|
| 342 |
+ default: |
|
| 343 |
+ return mw.prefix64(mint64, uint64(i)) |
|
| 344 |
+ } |
|
| 345 |
+} |
|
| 346 |
+ |
|
| 347 |
+// WriteInt8 writes an int8 to the writer |
|
| 348 |
+func (mw *Writer) WriteInt8(i int8) error { return mw.WriteInt64(int64(i)) }
|
|
| 349 |
+ |
|
| 350 |
+// WriteInt16 writes an int16 to the writer |
|
| 351 |
+func (mw *Writer) WriteInt16(i int16) error { return mw.WriteInt64(int64(i)) }
|
|
| 352 |
+ |
|
| 353 |
+// WriteInt32 writes an int32 to the writer |
|
| 354 |
+func (mw *Writer) WriteInt32(i int32) error { return mw.WriteInt64(int64(i)) }
|
|
| 355 |
+ |
|
| 356 |
+// WriteInt writes an int to the writer |
|
| 357 |
+func (mw *Writer) WriteInt(i int) error { return mw.WriteInt64(int64(i)) }
|
|
| 358 |
+ |
|
| 359 |
+// WriteUint64 writes a uint64 to the writer |
|
| 360 |
+func (mw *Writer) WriteUint64(u uint64) error {
|
|
| 361 |
+ switch {
|
|
| 362 |
+ case u < (1 << 7): |
|
| 363 |
+ return mw.push(wfixint(uint8(u))) |
|
| 364 |
+ case u < math.MaxUint8: |
|
| 365 |
+ return mw.prefix8(muint8, uint8(u)) |
|
| 366 |
+ case u < math.MaxUint16: |
|
| 367 |
+ return mw.prefix16(muint16, uint16(u)) |
|
| 368 |
+ case u < math.MaxUint32: |
|
| 369 |
+ return mw.prefix32(muint32, uint32(u)) |
|
| 370 |
+ default: |
|
| 371 |
+ return mw.prefix64(muint64, u) |
|
| 372 |
+ } |
|
| 373 |
+} |
|
| 374 |
+ |
|
| 375 |
+// WriteByte is analagous to WriteUint8 |
|
| 376 |
+func (mw *Writer) WriteByte(u byte) error { return mw.WriteUint8(uint8(u)) }
|
|
| 377 |
+ |
|
| 378 |
+// WriteUint8 writes a uint8 to the writer |
|
| 379 |
+func (mw *Writer) WriteUint8(u uint8) error { return mw.WriteUint64(uint64(u)) }
|
|
| 380 |
+ |
|
| 381 |
+// WriteUint16 writes a uint16 to the writer |
|
| 382 |
+func (mw *Writer) WriteUint16(u uint16) error { return mw.WriteUint64(uint64(u)) }
|
|
| 383 |
+ |
|
| 384 |
+// WriteUint32 writes a uint32 to the writer |
|
| 385 |
+func (mw *Writer) WriteUint32(u uint32) error { return mw.WriteUint64(uint64(u)) }
|
|
| 386 |
+ |
|
| 387 |
+// WriteUint writes a uint to the writer |
|
| 388 |
+func (mw *Writer) WriteUint(u uint) error { return mw.WriteUint64(uint64(u)) }
|
|
| 389 |
+ |
|
| 390 |
+// WriteBytes writes binary as 'bin' to the writer |
|
| 391 |
+func (mw *Writer) WriteBytes(b []byte) error {
|
|
| 392 |
+ sz := uint32(len(b)) |
|
| 393 |
+ var err error |
|
| 394 |
+ switch {
|
|
| 395 |
+ case sz < math.MaxUint8: |
|
| 396 |
+ err = mw.prefix8(mbin8, uint8(sz)) |
|
| 397 |
+ case sz < math.MaxUint16: |
|
| 398 |
+ err = mw.prefix16(mbin16, uint16(sz)) |
|
| 399 |
+ default: |
|
| 400 |
+ err = mw.prefix32(mbin32, sz) |
|
| 401 |
+ } |
|
| 402 |
+ if err != nil {
|
|
| 403 |
+ return err |
|
| 404 |
+ } |
|
| 405 |
+ _, err = mw.Write(b) |
|
| 406 |
+ return err |
|
| 407 |
+} |
|
| 408 |
+ |
|
| 409 |
+// WriteBool writes a bool to the writer |
|
| 410 |
+func (mw *Writer) WriteBool(b bool) error {
|
|
| 411 |
+ if b {
|
|
| 412 |
+ return mw.push(mtrue) |
|
| 413 |
+ } |
|
| 414 |
+ return mw.push(mfalse) |
|
| 415 |
+} |
|
| 416 |
+ |
|
| 417 |
+// WriteString writes a messagepack string to the writer. |
|
| 418 |
+// (This is NOT an implementation of io.StringWriter) |
|
| 419 |
+func (mw *Writer) WriteString(s string) error {
|
|
| 420 |
+ sz := uint32(len(s)) |
|
| 421 |
+ var err error |
|
| 422 |
+ switch {
|
|
| 423 |
+ case sz < 32: |
|
| 424 |
+ err = mw.push(wfixstr(uint8(sz))) |
|
| 425 |
+ case sz < math.MaxUint8: |
|
| 426 |
+ err = mw.prefix8(mstr8, uint8(sz)) |
|
| 427 |
+ case sz < math.MaxUint16: |
|
| 428 |
+ err = mw.prefix16(mstr16, uint16(sz)) |
|
| 429 |
+ default: |
|
| 430 |
+ err = mw.prefix32(mstr32, sz) |
|
| 431 |
+ } |
|
| 432 |
+ if err != nil {
|
|
| 433 |
+ return err |
|
| 434 |
+ } |
|
| 435 |
+ return mw.writeString(s) |
|
| 436 |
+} |
|
| 437 |
+ |
|
| 438 |
+// WriteComplex64 writes a complex64 to the writer |
|
| 439 |
+func (mw *Writer) WriteComplex64(f complex64) error {
|
|
| 440 |
+ o, err := mw.require(10) |
|
| 441 |
+ if err != nil {
|
|
| 442 |
+ return err |
|
| 443 |
+ } |
|
| 444 |
+ mw.buf[o] = mfixext8 |
|
| 445 |
+ mw.buf[o+1] = Complex64Extension |
|
| 446 |
+ big.PutUint32(mw.buf[o+2:], math.Float32bits(real(f))) |
|
| 447 |
+ big.PutUint32(mw.buf[o+6:], math.Float32bits(imag(f))) |
|
| 448 |
+ return nil |
|
| 449 |
+} |
|
| 450 |
+ |
|
| 451 |
+// WriteComplex128 writes a complex128 to the writer |
|
| 452 |
+func (mw *Writer) WriteComplex128(f complex128) error {
|
|
| 453 |
+ o, err := mw.require(18) |
|
| 454 |
+ if err != nil {
|
|
| 455 |
+ return err |
|
| 456 |
+ } |
|
| 457 |
+ mw.buf[o] = mfixext16 |
|
| 458 |
+ mw.buf[o+1] = Complex128Extension |
|
| 459 |
+ big.PutUint64(mw.buf[o+2:], math.Float64bits(real(f))) |
|
| 460 |
+ big.PutUint64(mw.buf[o+10:], math.Float64bits(imag(f))) |
|
| 461 |
+ return nil |
|
| 462 |
+} |
|
| 463 |
+ |
|
| 464 |
+// WriteMapStrStr writes a map[string]string to the writer |
|
| 465 |
+func (mw *Writer) WriteMapStrStr(mp map[string]string) (err error) {
|
|
| 466 |
+ err = mw.WriteMapHeader(uint32(len(mp))) |
|
| 467 |
+ if err != nil {
|
|
| 468 |
+ return |
|
| 469 |
+ } |
|
| 470 |
+ for key, val := range mp {
|
|
| 471 |
+ err = mw.WriteString(key) |
|
| 472 |
+ if err != nil {
|
|
| 473 |
+ return |
|
| 474 |
+ } |
|
| 475 |
+ err = mw.WriteString(val) |
|
| 476 |
+ if err != nil {
|
|
| 477 |
+ return |
|
| 478 |
+ } |
|
| 479 |
+ } |
|
| 480 |
+ return nil |
|
| 481 |
+} |
|
| 482 |
+ |
|
| 483 |
+// WriteMapStrIntf writes a map[string]interface to the writer |
|
| 484 |
+func (mw *Writer) WriteMapStrIntf(mp map[string]interface{}) (err error) {
|
|
| 485 |
+ err = mw.WriteMapHeader(uint32(len(mp))) |
|
| 486 |
+ if err != nil {
|
|
| 487 |
+ return |
|
| 488 |
+ } |
|
| 489 |
+ for key, val := range mp {
|
|
| 490 |
+ err = mw.WriteString(key) |
|
| 491 |
+ if err != nil {
|
|
| 492 |
+ return |
|
| 493 |
+ } |
|
| 494 |
+ err = mw.WriteIntf(val) |
|
| 495 |
+ if err != nil {
|
|
| 496 |
+ return |
|
| 497 |
+ } |
|
| 498 |
+ } |
|
| 499 |
+ return |
|
| 500 |
+} |
|
| 501 |
+ |
|
| 502 |
+// WriteTime writes a time.Time object to the wire. |
|
| 503 |
+// |
|
| 504 |
+// Time is encoded as Unix time, which means that |
|
| 505 |
+// location (time zone) data is removed from the object. |
|
| 506 |
+// The encoded object itself is 12 bytes: 8 bytes for |
|
| 507 |
+// a big-endian 64-bit integer denoting seconds |
|
| 508 |
+// elapsed since "zero" Unix time, followed by 4 bytes |
|
| 509 |
+// for a big-endian 32-bit signed integer denoting |
|
| 510 |
+// the nanosecond offset of the time. This encoding |
|
| 511 |
+// is intended to ease portability accross languages. |
|
| 512 |
+// (Note that this is *not* the standard time.Time |
|
| 513 |
+// binary encoding, because its implementation relies |
|
| 514 |
+// heavily on the internal representation used by the |
|
| 515 |
+// time package.) |
|
| 516 |
+func (mw *Writer) WriteTime(t time.Time) error {
|
|
| 517 |
+ t = t.UTC() |
|
| 518 |
+ o, err := mw.require(15) |
|
| 519 |
+ if err != nil {
|
|
| 520 |
+ return err |
|
| 521 |
+ } |
|
| 522 |
+ mw.buf[o] = mext8 |
|
| 523 |
+ mw.buf[o+1] = 12 |
|
| 524 |
+ mw.buf[o+2] = TimeExtension |
|
| 525 |
+ putUnix(mw.buf[o+3:], t.Unix(), int32(t.Nanosecond())) |
|
| 526 |
+ return nil |
|
| 527 |
+} |
|
| 528 |
+ |
|
| 529 |
+// WriteIntf writes the concrete type of 'v'. |
|
| 530 |
+// WriteIntf will error if 'v' is not one of the following: |
|
| 531 |
+// - A bool, float, string, []byte, int, uint, or complex |
|
| 532 |
+// - A map of supported types (with string keys) |
|
| 533 |
+// - An array or slice of supported types |
|
| 534 |
+// - A pointer to a supported type |
|
| 535 |
+// - A type that satisfies the msgp.Encodable interface |
|
| 536 |
+// - A type that satisfies the msgp.Extension interface |
|
| 537 |
+func (mw *Writer) WriteIntf(v interface{}) error {
|
|
| 538 |
+ if v == nil {
|
|
| 539 |
+ return mw.WriteNil() |
|
| 540 |
+ } |
|
| 541 |
+ switch v := v.(type) {
|
|
| 542 |
+ |
|
| 543 |
+ // preferred interfaces |
|
| 544 |
+ |
|
| 545 |
+ case Encodable: |
|
| 546 |
+ return v.EncodeMsg(mw) |
|
| 547 |
+ case Extension: |
|
| 548 |
+ return mw.WriteExtension(v) |
|
| 549 |
+ |
|
| 550 |
+ // concrete types |
|
| 551 |
+ |
|
| 552 |
+ case bool: |
|
| 553 |
+ return mw.WriteBool(v) |
|
| 554 |
+ case float32: |
|
| 555 |
+ return mw.WriteFloat32(v) |
|
| 556 |
+ case float64: |
|
| 557 |
+ return mw.WriteFloat64(v) |
|
| 558 |
+ case complex64: |
|
| 559 |
+ return mw.WriteComplex64(v) |
|
| 560 |
+ case complex128: |
|
| 561 |
+ return mw.WriteComplex128(v) |
|
| 562 |
+ case uint8: |
|
| 563 |
+ return mw.WriteUint8(v) |
|
| 564 |
+ case uint16: |
|
| 565 |
+ return mw.WriteUint16(v) |
|
| 566 |
+ case uint32: |
|
| 567 |
+ return mw.WriteUint32(v) |
|
| 568 |
+ case uint64: |
|
| 569 |
+ return mw.WriteUint64(v) |
|
| 570 |
+ case uint: |
|
| 571 |
+ return mw.WriteUint(v) |
|
| 572 |
+ case int8: |
|
| 573 |
+ return mw.WriteInt8(v) |
|
| 574 |
+ case int16: |
|
| 575 |
+ return mw.WriteInt16(v) |
|
| 576 |
+ case int32: |
|
| 577 |
+ return mw.WriteInt32(v) |
|
| 578 |
+ case int64: |
|
| 579 |
+ return mw.WriteInt64(v) |
|
| 580 |
+ case int: |
|
| 581 |
+ return mw.WriteInt(v) |
|
| 582 |
+ case string: |
|
| 583 |
+ return mw.WriteString(v) |
|
| 584 |
+ case []byte: |
|
| 585 |
+ return mw.WriteBytes(v) |
|
| 586 |
+ case map[string]string: |
|
| 587 |
+ return mw.WriteMapStrStr(v) |
|
| 588 |
+ case map[string]interface{}:
|
|
| 589 |
+ return mw.WriteMapStrIntf(v) |
|
| 590 |
+ case time.Time: |
|
| 591 |
+ return mw.WriteTime(v) |
|
| 592 |
+ } |
|
| 593 |
+ |
|
| 594 |
+ val := reflect.ValueOf(v) |
|
| 595 |
+ if !isSupported(val.Kind()) || !val.IsValid() {
|
|
| 596 |
+ return fmt.Errorf("msgp: type %s not supported", val)
|
|
| 597 |
+ } |
|
| 598 |
+ |
|
| 599 |
+ switch val.Kind() {
|
|
| 600 |
+ case reflect.Ptr: |
|
| 601 |
+ if val.IsNil() {
|
|
| 602 |
+ return mw.WriteNil() |
|
| 603 |
+ } |
|
| 604 |
+ return mw.WriteIntf(val.Elem().Interface()) |
|
| 605 |
+ case reflect.Slice: |
|
| 606 |
+ return mw.writeSlice(val) |
|
| 607 |
+ case reflect.Map: |
|
| 608 |
+ return mw.writeMap(val) |
|
| 609 |
+ } |
|
| 610 |
+ return &ErrUnsupportedType{val.Type()}
|
|
| 611 |
+} |
|
| 612 |
+ |
|
| 613 |
+func (mw *Writer) writeMap(v reflect.Value) (err error) {
|
|
| 614 |
+ if v.Elem().Kind() != reflect.String {
|
|
| 615 |
+ return errors.New("msgp: map keys must be strings")
|
|
| 616 |
+ } |
|
| 617 |
+ ks := v.MapKeys() |
|
| 618 |
+ err = mw.WriteMapHeader(uint32(len(ks))) |
|
| 619 |
+ if err != nil {
|
|
| 620 |
+ return |
|
| 621 |
+ } |
|
| 622 |
+ for _, key := range ks {
|
|
| 623 |
+ val := v.MapIndex(key) |
|
| 624 |
+ err = mw.WriteString(key.String()) |
|
| 625 |
+ if err != nil {
|
|
| 626 |
+ return |
|
| 627 |
+ } |
|
| 628 |
+ err = mw.WriteIntf(val.Interface()) |
|
| 629 |
+ if err != nil {
|
|
| 630 |
+ return |
|
| 631 |
+ } |
|
| 632 |
+ } |
|
| 633 |
+ return |
|
| 634 |
+} |
|
| 635 |
+ |
|
| 636 |
+func (mw *Writer) writeSlice(v reflect.Value) (err error) {
|
|
| 637 |
+ // is []byte |
|
| 638 |
+ if v.Type().ConvertibleTo(btsType) {
|
|
| 639 |
+ return mw.WriteBytes(v.Bytes()) |
|
| 640 |
+ } |
|
| 641 |
+ |
|
| 642 |
+ sz := uint32(v.Len()) |
|
| 643 |
+ err = mw.WriteArrayHeader(sz) |
|
| 644 |
+ if err != nil {
|
|
| 645 |
+ return |
|
| 646 |
+ } |
|
| 647 |
+ for i := uint32(0); i < sz; i++ {
|
|
| 648 |
+ err = mw.WriteIntf(v.Index(int(i)).Interface()) |
|
| 649 |
+ if err != nil {
|
|
| 650 |
+ return |
|
| 651 |
+ } |
|
| 652 |
+ } |
|
| 653 |
+ return |
|
| 654 |
+} |
|
| 655 |
+ |
|
| 656 |
+func (mw *Writer) writeStruct(v reflect.Value) error {
|
|
| 657 |
+ if enc, ok := v.Interface().(Encodable); ok {
|
|
| 658 |
+ return enc.EncodeMsg(mw) |
|
| 659 |
+ } |
|
| 660 |
+ return fmt.Errorf("msgp: unsupported type: %s", v.Type())
|
|
| 661 |
+} |
|
| 662 |
+ |
|
| 663 |
+func (mw *Writer) writeVal(v reflect.Value) error {
|
|
| 664 |
+ if !isSupported(v.Kind()) {
|
|
| 665 |
+ return fmt.Errorf("msgp: msgp/enc: type %q not supported", v.Type())
|
|
| 666 |
+ } |
|
| 667 |
+ |
|
| 668 |
+ // shortcut for nil values |
|
| 669 |
+ if v.IsNil() {
|
|
| 670 |
+ return mw.WriteNil() |
|
| 671 |
+ } |
|
| 672 |
+ switch v.Kind() {
|
|
| 673 |
+ case reflect.Bool: |
|
| 674 |
+ return mw.WriteBool(v.Bool()) |
|
| 675 |
+ |
|
| 676 |
+ case reflect.Float32, reflect.Float64: |
|
| 677 |
+ return mw.WriteFloat64(v.Float()) |
|
| 678 |
+ |
|
| 679 |
+ case reflect.Complex64, reflect.Complex128: |
|
| 680 |
+ return mw.WriteComplex128(v.Complex()) |
|
| 681 |
+ |
|
| 682 |
+ case reflect.Int, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int8: |
|
| 683 |
+ return mw.WriteInt64(v.Int()) |
|
| 684 |
+ |
|
| 685 |
+ case reflect.Interface, reflect.Ptr: |
|
| 686 |
+ if v.IsNil() {
|
|
| 687 |
+ mw.WriteNil() |
|
| 688 |
+ } |
|
| 689 |
+ return mw.writeVal(v.Elem()) |
|
| 690 |
+ |
|
| 691 |
+ case reflect.Map: |
|
| 692 |
+ return mw.writeMap(v) |
|
| 693 |
+ |
|
| 694 |
+ case reflect.Uint, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint8: |
|
| 695 |
+ return mw.WriteUint64(v.Uint()) |
|
| 696 |
+ |
|
| 697 |
+ case reflect.String: |
|
| 698 |
+ return mw.WriteString(v.String()) |
|
| 699 |
+ |
|
| 700 |
+ case reflect.Slice, reflect.Array: |
|
| 701 |
+ return mw.writeSlice(v) |
|
| 702 |
+ |
|
| 703 |
+ case reflect.Struct: |
|
| 704 |
+ return mw.writeStruct(v) |
|
| 705 |
+ |
|
| 706 |
+ } |
|
| 707 |
+ return fmt.Errorf("msgp: msgp/enc: type %q not supported", v.Type())
|
|
| 708 |
+} |
|
| 709 |
+ |
|
| 710 |
+// is the reflect.Kind encodable? |
|
| 711 |
+func isSupported(k reflect.Kind) bool {
|
|
| 712 |
+ switch k {
|
|
| 713 |
+ case reflect.Func, reflect.Chan, reflect.Invalid, reflect.UnsafePointer: |
|
| 714 |
+ return false |
|
| 715 |
+ default: |
|
| 716 |
+ return true |
|
| 717 |
+ } |
|
| 718 |
+} |
|
| 719 |
+ |
|
| 720 |
+// GuessSize guesses the size of the underlying |
|
| 721 |
+// value of 'i'. If the underlying value is not |
|
| 722 |
+// a simple builtin (or []byte), GuessSize defaults |
|
| 723 |
+// to 512. |
|
| 724 |
+func GuessSize(i interface{}) int {
|
|
| 725 |
+ if i == nil {
|
|
| 726 |
+ return NilSize |
|
| 727 |
+ } |
|
| 728 |
+ |
|
| 729 |
+ switch i := i.(type) {
|
|
| 730 |
+ case Sizer: |
|
| 731 |
+ return i.Msgsize() |
|
| 732 |
+ case Extension: |
|
| 733 |
+ return ExtensionPrefixSize + i.Len() |
|
| 734 |
+ case float64: |
|
| 735 |
+ return Float64Size |
|
| 736 |
+ case float32: |
|
| 737 |
+ return Float32Size |
|
| 738 |
+ case uint8, uint16, uint32, uint64, uint: |
|
| 739 |
+ return UintSize |
|
| 740 |
+ case int8, int16, int32, int64, int: |
|
| 741 |
+ return IntSize |
|
| 742 |
+ case []byte: |
|
| 743 |
+ return BytesPrefixSize + len(i) |
|
| 744 |
+ case string: |
|
| 745 |
+ return StringPrefixSize + len(i) |
|
| 746 |
+ case complex64: |
|
| 747 |
+ return Complex64Size |
|
| 748 |
+ case complex128: |
|
| 749 |
+ return Complex128Size |
|
| 750 |
+ case bool: |
|
| 751 |
+ return BoolSize |
|
| 752 |
+ case map[string]interface{}:
|
|
| 753 |
+ s := MapHeaderSize |
|
| 754 |
+ for key, val := range i {
|
|
| 755 |
+ s += StringPrefixSize + len(key) + GuessSize(val) |
|
| 756 |
+ } |
|
| 757 |
+ return s |
|
| 758 |
+ case map[string]string: |
|
| 759 |
+ s := MapHeaderSize |
|
| 760 |
+ for key, val := range i {
|
|
| 761 |
+ s += 2*StringPrefixSize + len(key) + len(val) |
|
| 762 |
+ } |
|
| 763 |
+ return s |
|
| 764 |
+ default: |
|
| 765 |
+ return 512 |
|
| 766 |
+ } |
|
| 767 |
+} |
| 0 | 768 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,369 @@ |
| 0 |
+package msgp |
|
| 1 |
+ |
|
| 2 |
+import ( |
|
| 3 |
+ "math" |
|
| 4 |
+ "reflect" |
|
| 5 |
+ "time" |
|
| 6 |
+) |
|
| 7 |
+ |
|
| 8 |
+// ensure 'sz' extra bytes in 'b' btw len(b) and cap(b) |
|
| 9 |
+func ensure(b []byte, sz int) ([]byte, int) {
|
|
| 10 |
+ l := len(b) |
|
| 11 |
+ c := cap(b) |
|
| 12 |
+ if c-l < sz {
|
|
| 13 |
+ o := make([]byte, (2*c)+sz) // exponential growth |
|
| 14 |
+ n := copy(o, b) |
|
| 15 |
+ return o[:n+sz], n |
|
| 16 |
+ } |
|
| 17 |
+ return b[:l+sz], l |
|
| 18 |
+} |
|
| 19 |
+ |
|
| 20 |
+// AppendMapHeader appends a map header with the |
|
| 21 |
+// given size to the slice |
|
| 22 |
+func AppendMapHeader(b []byte, sz uint32) []byte {
|
|
| 23 |
+ switch {
|
|
| 24 |
+ case sz < 16: |
|
| 25 |
+ return append(b, wfixmap(uint8(sz))) |
|
| 26 |
+ |
|
| 27 |
+ case sz < math.MaxUint16: |
|
| 28 |
+ o, n := ensure(b, 3) |
|
| 29 |
+ prefixu16(o[n:], mmap16, uint16(sz)) |
|
| 30 |
+ return o |
|
| 31 |
+ |
|
| 32 |
+ default: |
|
| 33 |
+ o, n := ensure(b, 5) |
|
| 34 |
+ prefixu32(o[n:], mmap32, sz) |
|
| 35 |
+ return o |
|
| 36 |
+ } |
|
| 37 |
+} |
|
| 38 |
+ |
|
| 39 |
+// AppendArrayHeader appends an array header with |
|
| 40 |
+// the given size to the slice |
|
| 41 |
+func AppendArrayHeader(b []byte, sz uint32) []byte {
|
|
| 42 |
+ switch {
|
|
| 43 |
+ case sz < 16: |
|
| 44 |
+ return append(b, wfixarray(uint8(sz))) |
|
| 45 |
+ |
|
| 46 |
+ case sz < math.MaxUint16: |
|
| 47 |
+ o, n := ensure(b, 3) |
|
| 48 |
+ prefixu16(o[n:], marray16, uint16(sz)) |
|
| 49 |
+ return o |
|
| 50 |
+ |
|
| 51 |
+ default: |
|
| 52 |
+ o, n := ensure(b, 5) |
|
| 53 |
+ prefixu32(o[n:], marray32, sz) |
|
| 54 |
+ return o |
|
| 55 |
+ } |
|
| 56 |
+} |
|
| 57 |
+ |
|
| 58 |
+// AppendNil appends a 'nil' byte to the slice |
|
| 59 |
+func AppendNil(b []byte) []byte { return append(b, mnil) }
|
|
| 60 |
+ |
|
| 61 |
+// AppendFloat64 appends a float64 to the slice |
|
| 62 |
+func AppendFloat64(b []byte, f float64) []byte {
|
|
| 63 |
+ o, n := ensure(b, Float64Size) |
|
| 64 |
+ prefixu64(o[n:], mfloat64, math.Float64bits(f)) |
|
| 65 |
+ return o |
|
| 66 |
+} |
|
| 67 |
+ |
|
| 68 |
+// AppendFloat32 appends a float32 to the slice |
|
| 69 |
+func AppendFloat32(b []byte, f float32) []byte {
|
|
| 70 |
+ o, n := ensure(b, Float32Size) |
|
| 71 |
+ prefixu32(o[n:], mfloat32, math.Float32bits(f)) |
|
| 72 |
+ return o |
|
| 73 |
+} |
|
| 74 |
+ |
|
| 75 |
+// AppendInt64 appends an int64 to the slice |
|
| 76 |
+func AppendInt64(b []byte, i int64) []byte {
|
|
| 77 |
+ a := abs(i) |
|
| 78 |
+ switch {
|
|
| 79 |
+ case i < 0 && i > -32: |
|
| 80 |
+ return append(b, wnfixint(int8(i))) |
|
| 81 |
+ |
|
| 82 |
+ case i >= 0 && i < 128: |
|
| 83 |
+ return append(b, wfixint(uint8(i))) |
|
| 84 |
+ |
|
| 85 |
+ case a < math.MaxInt8: |
|
| 86 |
+ o, n := ensure(b, 2) |
|
| 87 |
+ putMint8(o[n:], int8(i)) |
|
| 88 |
+ return o |
|
| 89 |
+ |
|
| 90 |
+ case a < math.MaxInt16: |
|
| 91 |
+ o, n := ensure(b, 3) |
|
| 92 |
+ putMint16(o[n:], int16(i)) |
|
| 93 |
+ return o |
|
| 94 |
+ |
|
| 95 |
+ case a < math.MaxInt32: |
|
| 96 |
+ o, n := ensure(b, 5) |
|
| 97 |
+ putMint32(o[n:], int32(i)) |
|
| 98 |
+ return o |
|
| 99 |
+ |
|
| 100 |
+ default: |
|
| 101 |
+ o, n := ensure(b, 9) |
|
| 102 |
+ putMint64(o[n:], i) |
|
| 103 |
+ return o |
|
| 104 |
+ } |
|
| 105 |
+} |
|
| 106 |
+ |
|
| 107 |
+// AppendInt appends an int to the slice |
|
| 108 |
+func AppendInt(b []byte, i int) []byte { return AppendInt64(b, int64(i)) }
|
|
| 109 |
+ |
|
| 110 |
+// AppendInt8 appends an int8 to the slice |
|
| 111 |
+func AppendInt8(b []byte, i int8) []byte { return AppendInt64(b, int64(i)) }
|
|
| 112 |
+ |
|
| 113 |
+// AppendInt16 appends an int16 to the slice |
|
| 114 |
+func AppendInt16(b []byte, i int16) []byte { return AppendInt64(b, int64(i)) }
|
|
| 115 |
+ |
|
| 116 |
+// AppendInt32 appends an int32 to the slice |
|
| 117 |
+func AppendInt32(b []byte, i int32) []byte { return AppendInt64(b, int64(i)) }
|
|
| 118 |
+ |
|
| 119 |
+// AppendUint64 appends a uint64 to the slice |
|
| 120 |
+func AppendUint64(b []byte, u uint64) []byte {
|
|
| 121 |
+ switch {
|
|
| 122 |
+ case u < (1 << 7): |
|
| 123 |
+ return append(b, wfixint(uint8(u))) |
|
| 124 |
+ |
|
| 125 |
+ case u < math.MaxUint8: |
|
| 126 |
+ o, n := ensure(b, 2) |
|
| 127 |
+ putMuint8(o[n:], uint8(u)) |
|
| 128 |
+ return o |
|
| 129 |
+ |
|
| 130 |
+ case u < math.MaxUint16: |
|
| 131 |
+ o, n := ensure(b, 3) |
|
| 132 |
+ putMuint16(o[n:], uint16(u)) |
|
| 133 |
+ return o |
|
| 134 |
+ |
|
| 135 |
+ case u < math.MaxUint32: |
|
| 136 |
+ o, n := ensure(b, 5) |
|
| 137 |
+ putMuint32(o[n:], uint32(u)) |
|
| 138 |
+ return o |
|
| 139 |
+ |
|
| 140 |
+ default: |
|
| 141 |
+ o, n := ensure(b, 9) |
|
| 142 |
+ putMuint64(o[n:], u) |
|
| 143 |
+ return o |
|
| 144 |
+ |
|
| 145 |
+ } |
|
| 146 |
+} |
|
| 147 |
+ |
|
| 148 |
+// AppendUint appends a uint to the slice |
|
| 149 |
+func AppendUint(b []byte, u uint) []byte { return AppendUint64(b, uint64(u)) }
|
|
| 150 |
+ |
|
| 151 |
+// AppendUint8 appends a uint8 to the slice |
|
| 152 |
+func AppendUint8(b []byte, u uint8) []byte { return AppendUint64(b, uint64(u)) }
|
|
| 153 |
+ |
|
| 154 |
+// AppendByte is analagous to AppendUint8 |
|
| 155 |
+func AppendByte(b []byte, u byte) []byte { return AppendUint8(b, uint8(u)) }
|
|
| 156 |
+ |
|
| 157 |
+// AppendUint16 appends a uint16 to the slice |
|
| 158 |
+func AppendUint16(b []byte, u uint16) []byte { return AppendUint64(b, uint64(u)) }
|
|
| 159 |
+ |
|
| 160 |
+// AppendUint32 appends a uint32 to the slice |
|
| 161 |
+func AppendUint32(b []byte, u uint32) []byte { return AppendUint64(b, uint64(u)) }
|
|
| 162 |
+ |
|
| 163 |
+// AppendBytes appends bytes to the slice as MessagePack 'bin' data |
|
| 164 |
+func AppendBytes(b []byte, bts []byte) []byte {
|
|
| 165 |
+ sz := len(bts) |
|
| 166 |
+ var o []byte |
|
| 167 |
+ var n int |
|
| 168 |
+ switch {
|
|
| 169 |
+ case sz < math.MaxUint8: |
|
| 170 |
+ o, n = ensure(b, 2+sz) |
|
| 171 |
+ prefixu8(o[n:], mbin8, uint8(sz)) |
|
| 172 |
+ n += 2 |
|
| 173 |
+ case sz < math.MaxUint16: |
|
| 174 |
+ o, n = ensure(b, 3+sz) |
|
| 175 |
+ prefixu16(o[n:], mbin16, uint16(sz)) |
|
| 176 |
+ n += 3 |
|
| 177 |
+ default: |
|
| 178 |
+ o, n = ensure(b, 5+sz) |
|
| 179 |
+ prefixu32(o[n:], mbin32, uint32(sz)) |
|
| 180 |
+ n += 5 |
|
| 181 |
+ } |
|
| 182 |
+ return o[:n+copy(o[n:], bts)] |
|
| 183 |
+} |
|
| 184 |
+ |
|
| 185 |
+// AppendBool appends a bool to the slice |
|
| 186 |
+func AppendBool(b []byte, t bool) []byte {
|
|
| 187 |
+ if t {
|
|
| 188 |
+ return append(b, mtrue) |
|
| 189 |
+ } |
|
| 190 |
+ return append(b, mfalse) |
|
| 191 |
+} |
|
| 192 |
+ |
|
| 193 |
+// AppendString appends a string as a MessagePack 'str' to the slice |
|
| 194 |
+func AppendString(b []byte, s string) []byte {
|
|
| 195 |
+ sz := len(s) |
|
| 196 |
+ var n int |
|
| 197 |
+ var o []byte |
|
| 198 |
+ switch {
|
|
| 199 |
+ case sz < 32: |
|
| 200 |
+ o, n = ensure(b, 1+sz) |
|
| 201 |
+ o[n] = wfixstr(uint8(sz)) |
|
| 202 |
+ n++ |
|
| 203 |
+ case sz < math.MaxUint8: |
|
| 204 |
+ o, n = ensure(b, 2+sz) |
|
| 205 |
+ prefixu8(o[n:], mstr8, uint8(sz)) |
|
| 206 |
+ n += 2 |
|
| 207 |
+ case sz < math.MaxUint16: |
|
| 208 |
+ o, n = ensure(b, 3+sz) |
|
| 209 |
+ prefixu16(o[n:], mstr16, uint16(sz)) |
|
| 210 |
+ n += 3 |
|
| 211 |
+ default: |
|
| 212 |
+ o, n = ensure(b, 5+sz) |
|
| 213 |
+ prefixu32(o[n:], mstr32, uint32(sz)) |
|
| 214 |
+ n += 5 |
|
| 215 |
+ } |
|
| 216 |
+ return o[:n+copy(o[n:], s)] |
|
| 217 |
+} |
|
| 218 |
+ |
|
| 219 |
+// AppendComplex64 appends a complex64 to the slice as a MessagePack extension |
|
| 220 |
+func AppendComplex64(b []byte, c complex64) []byte {
|
|
| 221 |
+ o, n := ensure(b, Complex64Size) |
|
| 222 |
+ o[n] = mfixext8 |
|
| 223 |
+ o[n+1] = Complex64Extension |
|
| 224 |
+ big.PutUint32(o[n+2:], math.Float32bits(real(c))) |
|
| 225 |
+ big.PutUint32(o[n+6:], math.Float32bits(imag(c))) |
|
| 226 |
+ return o |
|
| 227 |
+} |
|
| 228 |
+ |
|
| 229 |
+// AppendComplex128 appends a complex128 to the slice as a MessagePack extension |
|
| 230 |
+func AppendComplex128(b []byte, c complex128) []byte {
|
|
| 231 |
+ o, n := ensure(b, Complex128Size) |
|
| 232 |
+ o[n] = mfixext16 |
|
| 233 |
+ o[n+1] = Complex128Extension |
|
| 234 |
+ big.PutUint64(o[n+2:], math.Float64bits(real(c))) |
|
| 235 |
+ big.PutUint64(o[n+10:], math.Float64bits(imag(c))) |
|
| 236 |
+ return o |
|
| 237 |
+} |
|
| 238 |
+ |
|
| 239 |
+// AppendTime appends a time.Time to the slice as a MessagePack extension |
|
| 240 |
+func AppendTime(b []byte, t time.Time) []byte {
|
|
| 241 |
+ o, n := ensure(b, TimeSize) |
|
| 242 |
+ t = t.UTC() |
|
| 243 |
+ o[n] = mext8 |
|
| 244 |
+ o[n+1] = 12 |
|
| 245 |
+ o[n+2] = TimeExtension |
|
| 246 |
+ putUnix(o[n+3:], t.Unix(), int32(t.Nanosecond())) |
|
| 247 |
+ return o |
|
| 248 |
+} |
|
| 249 |
+ |
|
| 250 |
+// AppendMapStrStr appends a map[string]string to the slice |
|
| 251 |
+// as a MessagePack map with 'str'-type keys and values |
|
| 252 |
+func AppendMapStrStr(b []byte, m map[string]string) []byte {
|
|
| 253 |
+ sz := uint32(len(m)) |
|
| 254 |
+ b = AppendMapHeader(b, sz) |
|
| 255 |
+ for key, val := range m {
|
|
| 256 |
+ b = AppendString(b, key) |
|
| 257 |
+ b = AppendString(b, val) |
|
| 258 |
+ } |
|
| 259 |
+ return b |
|
| 260 |
+} |
|
| 261 |
+ |
|
| 262 |
+// AppendMapStrIntf appends a map[string]interface{} to the slice
|
|
| 263 |
+// as a MessagePack map with 'str'-type keys. |
|
| 264 |
+func AppendMapStrIntf(b []byte, m map[string]interface{}) ([]byte, error) {
|
|
| 265 |
+ sz := uint32(len(m)) |
|
| 266 |
+ b = AppendMapHeader(b, sz) |
|
| 267 |
+ var err error |
|
| 268 |
+ for key, val := range m {
|
|
| 269 |
+ b = AppendString(b, key) |
|
| 270 |
+ b, err = AppendIntf(b, val) |
|
| 271 |
+ if err != nil {
|
|
| 272 |
+ return b, err |
|
| 273 |
+ } |
|
| 274 |
+ } |
|
| 275 |
+ return b, nil |
|
| 276 |
+} |
|
| 277 |
+ |
|
| 278 |
+// AppendIntf appends the concrete type of 'i' to the |
|
| 279 |
+// provided []byte. 'i' must be one of the following: |
|
| 280 |
+// - 'nil' |
|
| 281 |
+// - A bool, float, string, []byte, int, uint, or complex |
|
| 282 |
+// - A map[string]interface{} or map[string]string
|
|
| 283 |
+// - A []T, where T is another supported type |
|
| 284 |
+// - A *T, where T is another supported type |
|
| 285 |
+// - A type that satisfieds the msgp.Marshaler interface |
|
| 286 |
+// - A type that satisfies the msgp.Extension interface |
|
| 287 |
+func AppendIntf(b []byte, i interface{}) ([]byte, error) {
|
|
| 288 |
+ if i == nil {
|
|
| 289 |
+ return AppendNil(b), nil |
|
| 290 |
+ } |
|
| 291 |
+ |
|
| 292 |
+ // all the concrete types |
|
| 293 |
+ // for which we have methods |
|
| 294 |
+ switch i := i.(type) {
|
|
| 295 |
+ case Marshaler: |
|
| 296 |
+ return i.MarshalMsg(b) |
|
| 297 |
+ case Extension: |
|
| 298 |
+ return AppendExtension(b, i) |
|
| 299 |
+ case bool: |
|
| 300 |
+ return AppendBool(b, i), nil |
|
| 301 |
+ case float32: |
|
| 302 |
+ return AppendFloat32(b, i), nil |
|
| 303 |
+ case float64: |
|
| 304 |
+ return AppendFloat64(b, i), nil |
|
| 305 |
+ case complex64: |
|
| 306 |
+ return AppendComplex64(b, i), nil |
|
| 307 |
+ case complex128: |
|
| 308 |
+ return AppendComplex128(b, i), nil |
|
| 309 |
+ case string: |
|
| 310 |
+ return AppendString(b, i), nil |
|
| 311 |
+ case []byte: |
|
| 312 |
+ return AppendBytes(b, i), nil |
|
| 313 |
+ case int8: |
|
| 314 |
+ return AppendInt8(b, i), nil |
|
| 315 |
+ case int16: |
|
| 316 |
+ return AppendInt16(b, i), nil |
|
| 317 |
+ case int32: |
|
| 318 |
+ return AppendInt32(b, i), nil |
|
| 319 |
+ case int64: |
|
| 320 |
+ return AppendInt64(b, i), nil |
|
| 321 |
+ case int: |
|
| 322 |
+ return AppendInt64(b, int64(i)), nil |
|
| 323 |
+ case uint: |
|
| 324 |
+ return AppendUint64(b, uint64(i)), nil |
|
| 325 |
+ case uint8: |
|
| 326 |
+ return AppendUint8(b, i), nil |
|
| 327 |
+ case uint16: |
|
| 328 |
+ return AppendUint16(b, i), nil |
|
| 329 |
+ case uint32: |
|
| 330 |
+ return AppendUint32(b, i), nil |
|
| 331 |
+ case uint64: |
|
| 332 |
+ return AppendUint64(b, i), nil |
|
| 333 |
+ case time.Time: |
|
| 334 |
+ return AppendTime(b, i), nil |
|
| 335 |
+ case map[string]interface{}:
|
|
| 336 |
+ return AppendMapStrIntf(b, i) |
|
| 337 |
+ case map[string]string: |
|
| 338 |
+ return AppendMapStrStr(b, i), nil |
|
| 339 |
+ case []interface{}:
|
|
| 340 |
+ b = AppendArrayHeader(b, uint32(len(i))) |
|
| 341 |
+ var err error |
|
| 342 |
+ for _, k := range i {
|
|
| 343 |
+ b, err = AppendIntf(b, k) |
|
| 344 |
+ if err != nil {
|
|
| 345 |
+ return b, err |
|
| 346 |
+ } |
|
| 347 |
+ } |
|
| 348 |
+ return b, nil |
|
| 349 |
+ } |
|
| 350 |
+ |
|
| 351 |
+ var err error |
|
| 352 |
+ v := reflect.ValueOf(i) |
|
| 353 |
+ switch v.Kind() {
|
|
| 354 |
+ case reflect.Array, reflect.Slice: |
|
| 355 |
+ l := v.Len() |
|
| 356 |
+ b = AppendArrayHeader(b, uint32(l)) |
|
| 357 |
+ for i := 0; i < l; i++ {
|
|
| 358 |
+ b, err = AppendIntf(b, v.Index(i).Interface()) |
|
| 359 |
+ if err != nil {
|
|
| 360 |
+ return b, err |
|
| 361 |
+ } |
|
| 362 |
+ } |
|
| 363 |
+ return b, nil |
|
| 364 |
+ |
|
| 365 |
+ default: |
|
| 366 |
+ return b, &ErrUnsupportedType{T: v.Type()}
|
|
| 367 |
+ } |
|
| 368 |
+} |