vendor: Update everything

GitHub-Pull-Request: https://github.com/syncthing/syncthing/pull/4620
This commit is contained in:
Jakob Borg
2017-12-29 11:38:00 +00:00
parent 1296a22069
commit c24bf7ea55
1070 changed files with 294926 additions and 488191 deletions
+201
View File
@@ -0,0 +1,201 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
+105
View File
@@ -0,0 +1,105 @@
// Package bytefmt contains helper methods and constants for converting to and from a human-readable byte format.
//
// bytefmt.ByteSize(100.5*bytefmt.MEGABYTE) // "100.5M"
// bytefmt.ByteSize(uint64(1024)) // "1K"
//
package bytefmt
import (
"errors"
"fmt"
"regexp"
"strconv"
"strings"
)
const (
BYTE = 1.0
KILOBYTE = 1024 * BYTE
MEGABYTE = 1024 * KILOBYTE
GIGABYTE = 1024 * MEGABYTE
TERABYTE = 1024 * GIGABYTE
)
var bytesPattern *regexp.Regexp = regexp.MustCompile(`(?i)^(-?\d+(?:\.\d+)?)([KMGT]i?B?|B)$`)
var invalidByteQuantityError = errors.New("Byte quantity must be a positive integer with a unit of measurement like M, MB, MiB, G, GiB, or GB")
// ByteSize returns a human-readable byte string of the form 10M, 12.5K, and so forth. The following units are available:
// T: Terabyte
// G: Gigabyte
// M: Megabyte
// K: Kilobyte
// B: Byte
// The unit that results in the smallest number greater than or equal to 1 is always chosen.
func ByteSize(bytes uint64) string {
unit := ""
value := float32(bytes)
switch {
case bytes >= TERABYTE:
unit = "T"
value = value / TERABYTE
case bytes >= GIGABYTE:
unit = "G"
value = value / GIGABYTE
case bytes >= MEGABYTE:
unit = "M"
value = value / MEGABYTE
case bytes >= KILOBYTE:
unit = "K"
value = value / KILOBYTE
case bytes >= BYTE:
unit = "B"
case bytes == 0:
return "0"
}
stringValue := fmt.Sprintf("%.1f", value)
stringValue = strings.TrimSuffix(stringValue, ".0")
return fmt.Sprintf("%s%s", stringValue, unit)
}
// ToMegabytes parses a string formatted by ByteSize as megabytes.
func ToMegabytes(s string) (uint64, error) {
bytes, err := ToBytes(s)
if err != nil {
return 0, err
}
return bytes / MEGABYTE, nil
}
// ToBytes parses a string formatted by ByteSize as bytes. Note binary-prefixed and SI prefixed units both mean a base-2 units
// KB = K = KiB = 1024
// MB = M = MiB = 1024 * K
// GB = G = GiB = 1024 * M
// TB = T = TiB = 1024 * G
func ToBytes(s string) (uint64, error) {
parts := bytesPattern.FindStringSubmatch(strings.TrimSpace(s))
if len(parts) < 3 {
return 0, invalidByteQuantityError
}
value, err := strconv.ParseFloat(parts[1], 64)
if err != nil || value <= 0 {
return 0, invalidByteQuantityError
}
var bytes uint64
unit := strings.ToUpper(parts[2])
switch unit[:1] {
case "T":
bytes = uint64(value * TERABYTE)
case "G":
bytes = uint64(value * GIGABYTE)
case "M":
bytes = uint64(value * MEGABYTE)
case "K":
bytes = uint64(value * KILOBYTE)
case "B":
bytes = uint64(value * BYTE)
}
return bytes, nil
}
+1
View File
@@ -0,0 +1 @@
package bytefmt // import "code.cloudfoundry.org/bytefmt"
+33 -35
View File
@@ -14,7 +14,9 @@ const (
Size = 4
)
type digest struct {
// Adler32 is a digest which satisfies the rollinghash.Hash32 interface.
// It implements the adler32 algorithm https://en.wikipedia.org/wiki/Adler-32
type Adler32 struct {
a, b uint32
// window is treated like a circular buffer, where the oldest element
@@ -26,44 +28,43 @@ type digest struct {
vanilla hash.Hash32
}
// Reset resets the Hash to its initial state.
func (d *digest) Reset() {
d.window = d.window[:0] // Reset the size but don't reallocate
// Reset resets the digest to its initial state.
func (d *Adler32) Reset() {
d.window = d.window[:1] // Reset the size but don't reallocate
d.window[0] = 0
d.a = 1
d.b = 0
d.oldest = 0
}
// New returns a new rollinghash.Hash32 computing the rolling Adler-32
// checksum. The window is copied from the last Write(). This window is
// only used to determine which is the oldest element (leaving the
// window). The calls to Roll() do not recompute the whole checksum.
func New() rollinghash.Hash32 {
return &digest{
// New returns a new Adler32 digest
func New() *Adler32 {
return &Adler32{
a: 1,
b: 0,
window: make([]byte, 0),
window: make([]byte, 1, rollinghash.DefaultWindowCap),
oldest: 0,
vanilla: vanilla.New(),
}
}
// Size returns the number of bytes Sum will return.
func (d *digest) Size() int { return Size }
// Size is 4 bytes
func (d *Adler32) Size() int { return Size }
// BlockSize returns the hash's underlying block size.
// The Write method must be able to accept any amount
// of data, but it may operate more efficiently if all
// writes are a multiple of the block size.
func (d *digest) BlockSize() int { return 1 }
// BlockSize is 1 byte
func (d *Adler32) BlockSize() int { return 1 }
// Write (via the embedded io.Writer interface) adds more data to the
// running hash. It never returns an error.
func (d *digest) Write(p []byte) (int, error) {
// Write (re)initializes the rolling window with the input byte slice and
// adds its data to the digest.
func (d *Adler32) Write(p []byte) (int, error) {
// Copy the window, avoiding allocations where possible
if len(d.window) != len(p) {
if cap(d.window) >= len(p) {
d.window = d.window[:len(p)]
l := len(p)
if l == 0 {
l = 1
}
if len(d.window) != l {
if cap(d.window) >= l {
d.window = d.window[:l]
} else {
d.window = make([]byte, len(p))
}
@@ -79,23 +80,20 @@ func (d *digest) Write(p []byte) (int, error) {
return len(d.window), nil
}
func (d *digest) Sum32() uint32 {
// Sum32 returns the hash as a uint32
func (d *Adler32) Sum32() uint32 {
return d.b<<16 | d.a
}
func (d *digest) Sum(b []byte) []byte {
// Sum returns the hash as a byte slice
func (d *Adler32) Sum(b []byte) []byte {
v := d.Sum32()
return append(b, byte(v>>24), byte(v>>16), byte(v>>8), byte(v))
}
// Roll updates the checksum of the window from the leaving byte and the
// entering byte. See
// http://stackoverflow.com/questions/40985080/why-does-my-rolling-adler32-checksum-not-work-in-go-modulo-arithmetic
func (d *digest) Roll(b byte) {
if len(d.window) == 0 {
d.window = make([]byte, 1)
d.window[0] = b
}
// Roll updates the checksum of the window from the entering byte. You
// MUST initialize a window with Write() before calling this method.
func (d *Adler32) Roll(b byte) {
// extract the entering/leaving bytes and update the circular buffer.
enter := uint32(b)
leave := uint32(d.window[d.oldest])
@@ -105,7 +103,7 @@ func (d *digest) Roll(b byte) {
d.oldest = 0
}
// compute
// See http://stackoverflow.com/questions/40985080/why-does-my-rolling-adler32-checksum-not-work-in-go-modulo-arithmetic
d.a = (d.a + Mod + enter - leave) % Mod
d.b = (d.b + (d.n*leave/Mod+1)*Mod + d.a - (d.n * leave) - 1) % Mod
}
+103
View File
@@ -0,0 +1,103 @@
// Package rollinghash/bozo32 is a wrong implementation of the rabinkarp
// checksum. In practice, it works very well and exhibits all the
// properties wanted from a rolling checksum, so after realising that this
// code did not implement the rabinkarp checksum as described in the
// original paper, it was renamed from rabinkarp32 to bozo32 and kept
// in this package.
package bozo32
import rollinghash "github.com/chmduquesne/rollinghash"
// The size of the checksum.
const Size = 4
// Bozo32 is a digest which satisfies the rollinghash.Hash32 interface.
type Bozo32 struct {
a uint32
h uint32
aPowerN uint32
// window is treated like a circular buffer, where the oldest element
// is indicated by d.oldest
window []byte
oldest int
}
// Reset resets the Hash to its initial state.
func (d *Bozo32) Reset() {
d.h = 0
d.aPowerN = 1
d.window = nil
d.oldest = 0
}
func NewFromInt(a uint32) *Bozo32 {
return &Bozo32{
a: a,
h: 0,
aPowerN: 1,
window: make([]byte, 1, rollinghash.DefaultWindowCap),
oldest: 0,
}
}
func New() *Bozo32 {
return NewFromInt(65521) // largest prime fitting in 16 bits
}
// Size is 4 bytes
func (d *Bozo32) Size() int { return Size }
// BlockSize is 1 byte
func (d *Bozo32) BlockSize() int { return 1 }
// Write (re)initializes the rolling window with the input byte slice and
// adds its data to the digest. It never returns an error.
func (d *Bozo32) Write(data []byte) (int, error) {
// Copy the window
l := len(data)
if l == 0 {
l = 1
}
if len(d.window) >= l {
d.window = d.window[:l]
} else {
d.window = make([]byte, l)
}
copy(d.window, data)
for _, c := range d.window {
d.h *= d.a
d.h += uint32(c)
d.aPowerN *= d.a
}
return len(d.window), nil
}
// Sum32 returns the hash as a uint32
func (d *Bozo32) Sum32() uint32 {
return d.h
}
// Sum returns the hash as byte slice
func (d *Bozo32) Sum(b []byte) []byte {
v := d.Sum32()
return append(b, byte(v>>24), byte(v>>16), byte(v>>8), byte(v))
}
// Roll updates the checksum of the window from the entering byte. You
// MUST initialize a window with Write() before calling this method.
func (d *Bozo32) Roll(c byte) {
// extract the entering/leaving bytes and update the circular buffer.
enter := uint32(c)
leave := uint32(d.window[d.oldest])
d.window[d.oldest] = c
l := len(d.window)
d.oldest += 1
if d.oldest >= l {
d.oldest = 0
}
d.h = d.h*d.a + enter - leave*d.aPowerN
}
+58 -86
View File
@@ -3,69 +3,25 @@
package buzhash32
import rollinghash "github.com/chmduquesne/rollinghash"
import (
"math/rand"
// 256 random integers generated with a dummy python script
var DefaultHash = [256]uint32{
0xa5659a00, 0x2dbfda02, 0xac29a407, 0xce942c08, 0x48513609,
0x325f158, 0xb54e5e13, 0xa9063618, 0xa5793419, 0x554b081a,
0xe5643dac, 0xfb50e41c, 0x2b31661d, 0x335da61f, 0xe702f7b0,
0xe31c1424, 0x6dfed825, 0xd30cf628, 0xba626a2a, 0x74b9c22b,
0xa5d1942d, 0xf364ae2f, 0x70d2e84c, 0x190ad208, 0x92e3b740,
0xd7e9f435, 0x15763836, 0x930ecab4, 0x641ea65e, 0xc0b2eb0a,
0x2675e03e, 0x1a24c63f, 0xeddbcbb7, 0x3ea42bb2, 0x815f5849,
0xa55c284b, 0xbb30964c, 0x6f7acc4e, 0x74538a50, 0x66df9652,
0x2bae8454, 0xfe9d8055, 0x8c866fd4, 0x82f0a63d, 0x8f26365e,
0xe66c3460, 0x6423266, 0x60696abc, 0xf75de6d, 0xd20c86e,
0x69f8c6f, 0x8ac0f470, 0x273aab68, 0x4e044c74, 0xb2ec7875,
0xf642d676, 0xd719e877, 0xee557e78, 0xdd20be7a, 0xd252707e,
0xfa507a7f, 0xee537683, 0x6aac7684, 0x340e3485, 0x1c291288,
0xab89c8c, 0xbe6e6c8d, 0xf99cf2f7, 0x69c65890, 0xd3757491,
0xfeb63895, 0x67067a96, 0xa0089b19, 0x6c449898, 0x4eca749a,
0x1101229b, 0x6b86d29d, 0x9c21be9e, 0xc5904933, 0xe1e820a3,
0x6bd524a6, 0xd4695ea7, 0xc3d007e0, 0xbed8e4a9, 0x1c49d8af,
0xedbae4b1, 0x1d2af6b4, 0x79526b9, 0xbc1d5abb, 0x6a2eb8bc,
0x611b3695, 0x745c3cc4, 0x81005276, 0x5f442c8, 0x42dc30ca,
0x55e460cb, 0x47648cc, 0x20da7122, 0xc4eedccd, 0xc21c14d0,
0x27b5dfa9, 0x7e961fce, 0x8d0296d6, 0xce3684d7, 0x28e96da,
0xedf7dcdc, 0x6817a0df, 0x51caae0, 0x8f226e1, 0xa1a00ce3,
0xf811c6e5, 0x13e96ee6, 0xd4d4e4d1, 0xab160ee9, 0xb2cf06ea,
0xf4ab6eb, 0x998f56f1, 0x16974cf2, 0xd42438f5, 0xe00ba6f7,
0xbf01b8f8, 0x7a8a00f9, 0xdded6a7f, 0xb0ce58fd, 0xe5d81901,
0xcc823b03, 0xc962e704, 0x2b4aff05, 0x5bcb7181, 0xe7207108,
0xf3c93109, 0x1ffb650a, 0x37a31ad7, 0xfe27322d, 0x15b16d11,
0x51a70512, 0xb579d92e, 0x53658284, 0x91fedb1b, 0x2ef0b122,
0x93966523, 0xfa66af26, 0xa7fac32b, 0x7a81692c, 0x4f8d7f2e,
0xf9875730, 0xa5ab2331, 0x79db8333, 0x8be32937, 0xf900af39,
0xd09d4f3a, 0x9b22053d, 0xd2053e1c, 0xd0deaa35, 0x4a975740,
0xcb3706e0, 0x40aea6cd, 0x769fdd44, 0x7e3e4947, 0xc20ac949,
0x3788c34b, 0x9b23f74c, 0xb33e441d, 0x705d8a8d, 0x6a5e3a84,
0xb4f955e3, 0xf681a155, 0x7dec1b56, 0x7bf5df58, 0xd3fa255a,
0x3797c15c, 0xbf511562, 0xb048d65, 0xcd04f367, 0xae3a8368,
0x769c856d, 0xc7bb9d6f, 0xe43e1f71, 0xa24de03e, 0x7f8cb376,
0x618b778, 0x19e02f33, 0x2f810eea, 0x2b1ce595, 0x4f2f7180,
0x72903140, 0x26a44584, 0x6af97e96, 0xb08acb86, 0x4d25cd41,
0x1d74fd89, 0xe0f5b277, 0xbad158c, 0x5fed3b8d, 0x68b26794,
0xcbe58795, 0xc1180797, 0xa1352399, 0x71dacd9c, 0x42b5549a,
0xbf5371a0, 0x7ed41fa1, 0x6fe29a3, 0xa779fba5, 0x48a095a7,
0xc2cad5a8, 0x7d7f15a9, 0xccd195aa, 0x2a9047ac, 0x3ec66ef2,
0x252743ae, 0xdd8827af, 0x85fc5055, 0xb9d5c7b2, 0x5a224fb4,
0xec26e7b6, 0xe4d8f7b7, 0x6e5aa58d, 0xeff753b9, 0x6c391fbb,
0x989f65bc, 0x2fe4a7c1, 0x9d1d9bc3, 0xa09aadc6, 0x2df33fc8,
0x5ec27933, 0x5e7f41cb, 0xb920f7cd, 0xc1a603ce, 0xf0888fcf,
0xdc4ad1d1, 0x34b3dbd4, 0x170981d5, 0x22e5b5d6, 0x13049bd7,
0xf12a8b95, 0xff7e87d9, 0xabb74b84, 0x215cff4f, 0xaf24f7dc,
0xc87461d, 0x41a55e0, 0xfde9b9e1, 0x1d1956fb, 0x13d60de4,
0x435f93e5, 0xe0ab5de6, 0x5c1d3fe7, 0x411a1fe8, 0x55e102a9,
0x3d9b07eb, 0xdd6b8dee, 0x741293f3, 0xa5b10ca9, 0x5abad5fd,
0x22372f55,
rollinghash "github.com/chmduquesne/rollinghash"
)
var defaultHashes [256]uint32
func init() {
defaultHashes = GenerateHashes(1)
}
// The size of the checksum.
const Size = 4
// digest represents the partial evaluation of a checksum.
type digest struct {
// Buzhash32 is a digest which satisfies the rollinghash.Hash32 interface.
// It implements the cyclic polynomial algorithm
// https://en.wikipedia.org/wiki/Rolling_hash#Cyclic_polynomial
type Buzhash32 struct {
sum uint32
nRotate uint
nRotateComplement uint // redundant, but pre-computed to spare an operation
@@ -78,44 +34,62 @@ type digest struct {
}
// Reset resets the Hash to its initial state.
func (d *digest) Reset() {
func (d *Buzhash32) Reset() {
d.window = d.window[:0]
d.oldest = 0
d.sum = 0
}
func New() rollinghash.Hash32 {
return NewFromUint32Array(DefaultHash)
// GenerateHashes generates a list of hashes to use with buzhash
func GenerateHashes(seed int64) (res [256]uint32) {
random := rand.New(rand.NewSource(seed))
used := make(map[uint32]bool)
for i, _ := range res {
x := uint32(random.Int63())
for used[x] {
x = uint32(random.Int63())
}
used[x] = true
res[i] = x
}
return res
}
// New returns a buzhash based on a list of hashes provided by a call to
// GenerateHashes, seeded with the default value 1.
func New() *Buzhash32 {
return NewFromUint32Array(defaultHashes)
}
// NewFromUint32Array returns a buzhash based on the provided table uint32 values.
func NewFromUint32Array(b [256]uint32) rollinghash.Hash32 {
return &digest{
func NewFromUint32Array(b [256]uint32) *Buzhash32 {
return &Buzhash32{
sum: 0,
window: make([]byte, 0),
window: make([]byte, 1, rollinghash.DefaultWindowCap),
oldest: 0,
bytehash: b,
}
}
// Size returns the number of bytes Sum will return.
func (d *digest) Size() int { return Size }
// Size is 4 bytes
func (d *Buzhash32) Size() int { return Size }
// BlockSize returns the hash's underlying block size.
// The Write method must be able to accept any amount
// of data, but it may operate more efficiently if all
// writes are a multiple of the block size.
func (d *digest) BlockSize() int { return 1 }
// BlockSize is 1 byte
func (d *Buzhash32) BlockSize() int { return 1 }
// Write (via the embedded io.Writer interface) adds more data to the
// running hash. It never returns an error.
func (d *digest) Write(data []byte) (int, error) {
// Write (re)initializes the rolling window with the input byte slice and
// adds its data to the digest.
func (d *Buzhash32) Write(data []byte) (int, error) {
// Copy the window, avoiding allocations where possible
if len(d.window) != len(data) {
if cap(d.window) >= len(data) {
d.window = d.window[:len(data)]
l := len(data)
if l == 0 {
l = 1
}
if len(d.window) != l {
if cap(d.window) >= l {
d.window = d.window[:l]
} else {
d.window = make([]byte, len(data))
d.window = make([]byte, l)
}
}
copy(d.window, data)
@@ -129,22 +103,20 @@ func (d *digest) Write(data []byte) (int, error) {
return len(d.window), nil
}
func (d *digest) Sum32() uint32 {
// Sum32 returns the hash as a uint32
func (d *Buzhash32) Sum32() uint32 {
return d.sum
}
func (d *digest) Sum(b []byte) []byte {
// Sum returns the hash as byte slice
func (d *Buzhash32) Sum(b []byte) []byte {
v := d.Sum32()
return append(b, byte(v>>24), byte(v>>16), byte(v>>8), byte(v))
}
// Roll updates the checksum of the window from the leaving byte and the
// entering byte.
func (d *digest) Roll(c byte) {
if len(d.window) == 0 {
d.window = make([]byte, 1)
d.window[0] = c
}
// Roll updates the checksum of the window from the entering byte. You
// MUST initialize a window with Write() before calling this method.
func (d *Buzhash32) Roll(c byte) {
// extract the entering/leaving bytes and update the circular buffer.
hn := d.bytehash[int(c)]
h0 := d.bytehash[int(d.window[d.oldest])]
+59 -121
View File
@@ -3,103 +3,25 @@
package buzhash64
import rollinghash "github.com/chmduquesne/rollinghash"
import (
"math/rand"
// 256 random integers generated with a dummy python script
var DefaultHash = [256]uint64{
0xd6923700885676e1, 0x2ef758a165917c6c, 0xcac8db9a800db08f,
0x91dfa96019476e5f, 0x61ad4b5c6ec62e4b, 0xbabfc786038a37cb,
0xb68fe9816c09bb98, 0x6dae71ffcf505baf, 0x8f1d5ac180423f59,
0x2ddcaf458c114dae, 0x2975abd372acbb39, 0x620f80a1e7fb8ca0,
0xf8d9b75b40d1fdda, 0x81bff1a297143fab, 0x81935f4d4c31ae6e,
0xf4e0765a732a3a36, 0x0cded3fd708f0f14, 0xa89cb64087b25da9,
0xa69372234eb0602d, 0x773a079265484e2d, 0x8dbc0985c9c4e1cb,
0x000a09a5bc2c80b0, 0xdcaa87a327cead66, 0xd26eaa01fb42ef69,
0x34411456e2c244d7, 0x1082e6fb20af4bea, 0x1e00897e330f3832,
0x4253bef8099f370d, 0x890ce98ec0e8a69c, 0x89eb60e611308754,
0xb39c22caeb5444f1, 0x3e841276d561b022, 0x45292a4e1aaeb117,
0x1a4b1f1d7aeb46d1, 0x7016fc7d7b3114a6, 0x4fc9ea1dfd505a34,
0x97b6013b3739d65e, 0x7fcc6abfae8eb598, 0xff8ec196383c66f2,
0x87ca90161ecaf261, 0xc27ac70e06c9caa3, 0x42c4d7617c362ede,
0xb38656002f3984f0, 0x0520f83a5be24d68, 0x097cdf0f89aa5ad6,
0xcc2c65d8ab0e1e32, 0x8c8ebfd12b2c4fa9, 0x9e99c42db2e8be1d,
0x7bcef376a9003964, 0xbd9bc65dbfebce71, 0xd47a52cea9f0bc02,
0xeadb465977d2d8ca, 0x43065df5caca1a4b, 0x82f5ae94dd2cc349,
0xc4e362ab8614dd84, 0xc8922bf4a4bebf05, 0xb1719f57f9a1ed23,
0xe93a41737e8094ac, 0x33e611a02d4abc93, 0x1dcdb2d07ea310bc,
0xf7a85d96655b03ef, 0x60aafabd410c3180, 0x18c401b08a67ffeb,
0xc1eed3417948c90f, 0x525bfe6ad095d998, 0x2a97938c7fd244c2,
0xbb75ef8569ba728c, 0x53f47ee01b7d1915, 0x51025252faf2890e,
0xf6bd601ee7ad2608, 0x06a07a64f7afbffa, 0x224f41d09b13aed5,
0x9f80d30ece1bcd5c, 0x6ce1076c6780de0c, 0xfd123415c8262763,
0x0d5a643d04d9f438, 0xb92e476b8a36d170, 0x0f533c6c9f196cce,
0x0071ebbeb03d43af, 0x00dcbdee475f482d, 0x3339362a5b7c099c,
0x2f957910672cf39e, 0xd69554bbea71bb60, 0x635dd0f5801c9d13,
0x9832470506cba5cd, 0x77625064508cebba, 0xf428e6bfb38a5d01,
0x4a086e0cf23ab715, 0xb958fe962ca69576, 0x5d0ab146601ee29f,
0x90f0042e06fcc096, 0xba69eaa94dd5cbcc, 0xa821915b9a5fa628,
0xea4f4c03801babed, 0xbc7d5f845d913103, 0xe3cc105d6e4a11ea,
0x251f29b1422b1af5, 0xd700ffdb510d7634, 0x3002ebfda5cc4592,
0xf5614fc379a46223, 0x02cb3e88a92ab123, 0x4dab9392f9075ca5,
0xc8d8c5b39eb3e593, 0x7d6545c168d526df, 0x3cd78f7794445ee4,
0x24e2a4f47772f09a, 0x43be5ca35c81d4ec, 0x77583ba052e5b605,
0x92e07779ea9ccd7f, 0xb9dc8617c0a14ea8, 0x8a2821cb56440f77,
0x15f29e095f8b279e, 0x75c12968e423728c, 0x98cfdf60152b8d2f,
0x3b5a8db5cf80bd68, 0x2356e64e821e3ac4, 0x320b7aef2daff0d4,
0xbae4290e875658bf, 0x3b569a663e0b2445, 0xc494ce552c404288,
0x37a905ddeb550d88, 0x2333bcdc81c0c5c3, 0x8d2682d13259af0c,
0x5ad34026f7e9b8f4, 0x081970325f7f949d, 0xbcf17bf08e61ef19,
0xb3e5da3782fd7f03, 0x8ed53c8ec27635e1, 0x79fca624a1e73b7c,
0xdc9bdb3be0b69b20, 0xc119a348042544cd, 0x1c2408e49ed2a747,
0xe85f0237669d180d, 0x4508bcebda7465f9, 0x5af245c13d3a8ef7,
0xbb8bb6b61f021ed0, 0x48eaa45234935f75, 0x2f78f8fb1695eb65,
0x5dd1e1c8c20a1b76, 0x2f74a22a3159ec45, 0xc64f9c864dfb98cf,
0xf928618091913d32, 0xec08db6828a11873, 0x029ba990fa5cdba6,
0x94b870390499d9ba, 0x1086685fce933b2c, 0x6065be1f390c003a,
0x0f46e9a9d5197803, 0x42833f7327727669, 0xdda6c27eb0d682b3,
0x5ec3a67f39a77d05, 0x818f5646400a80ec, 0xe45c502c1b655c1b,
0xd56ddb4fddd63c56, 0x7ebc81bd9fd90fd1, 0x4f6c111625fb5c8e,
0x6c0fc5f0487dc6ee, 0xc57a12a7159119ed, 0x526bc3b3aadd9dd6,
0xe89f8367962fe1ea, 0x72bac3c1c99d1845, 0x6f56a75582ae96b9,
0x7d23f484a9a317f1, 0xe876956fd23c9f95, 0xdd6411629a0dab0a,
0x827046f4383dad03, 0x36aa4c0e807f9a6d, 0xcfe6ae3f86224a12,
0x84802ff4baf0e073, 0x19d786fe8a6eecd6, 0x38e9f4a7a4ce611a,
0x5442a62e65063565, 0x6a6780a6d0257b82, 0x39af9a8cf5786bd7,
0xe65d071b8fb1c8ee, 0xa63ebe71ad620e4f, 0xdfaaadf4584a0b68,
0x7bb8f20bd9681981, 0xbfa8bbaae1c5db8b, 0xae3a8b06f286932a,
0xe92a89eebe1f3292, 0xf11e1c10444edbd2, 0xaf8308bd4915c7f3,
0x8a1338317833acdc, 0xcec67d8359c7f0e8, 0x3f66a4906e23838a,
0x9e959f9b1c22fef3, 0x8b5404e71735a246, 0xcbddfc7a87347d03,
0x7a0d9bd544622f25, 0x3a78e12aab2f532f, 0xddf89b2aecd51922,
0x38f7465f6d416db4, 0x4349369edbf8ea2a, 0x5e4d38719ad9d621,
0x0ec281878dddca6a, 0x1c92cae74d6b897a, 0xa0c7c7149a8a76b3,
0xc469dca35bf1cb2a, 0x6a902e29fcf0ecd4, 0x8c455620d8f5df32,
0x0b435e9d1c207663, 0x51299e4c5ccbfbd2, 0x365add776bcad536,
0x957aa2746c2bd41e, 0x414ec15efe36e3a1, 0x6faed19dc4940f61,
0x6766d7072a6e1d87, 0x3c01b82ebdff7a2d, 0xbbbe879684ec244c,
0xa425c502184dc5b4, 0x02d77f005bb369ad, 0xb56546c281f8c88f,
0xb49a866ea16fc9e9, 0x93ee62b3965991ec, 0xf03d0958eb9664a9,
0x7e57cce4c6c8d5ab, 0x6ae6f4180ea9c5b1, 0xc45fdb113dfba663,
0x7892fabea1c2d876, 0x7b39106ce2f6d405, 0x12332253ddcff808,
0x877af9766d5147c4, 0xbbfe3ac2eb6e9d3f, 0xd298d13ac6c3c8c4,
0x142bc26ad3606528, 0xb0665de1231f2938, 0xf68498ac39f406ec,
0xc68379a33b570cfe, 0xb43cfe7fcd5d6688, 0x0e18e07f10ee779c,
0xa021ffa7e745086d, 0xa113db9a2c6bdb43, 0xa00e360382ecd221,
0x192dc98cbd494a06, 0xb0c9f52cf0252d86, 0x3efb668bcba50726,
0x114c30f72555d676, 0x99259c3011e85910, 0x5e6c7d80d32133ec,
0xfa445c39db50cb51, 0x14f1d142aac12947, 0x04dcb1a831c0e97a,
0x3102eda0466cb1d7, 0xc57ea8effb8c20f5, 0xa3641775b56361af,
0xaf9608c03cc46398, 0x023b9055ff80b8dc, 0x91965be76eddb8f0,
0xdcdffd182d67712f, 0xe8bf232ef77feef7, 0x0cc8d45930eb0846,
0xef2d62d35924c29a, 0x8a68c569490911e2, 0xc44a865ef922d723,
0xc942fc5e5c343766,
"github.com/chmduquesne/rollinghash"
)
var defaultHashes [256]uint64
func init() {
defaultHashes = GenerateHashes(1)
}
// The size of the checksum.
const Size = 8
// digest represents the partial evaluation of a checksum.
type digest struct {
// Buzhash64 is a digest which satisfies the rollinghash.Hash64 interface.
// It implements the cyclic polynomial algorithm
// https://en.wikipedia.org/wiki/Rolling_hash#Cyclic_polynomial
type Buzhash64 struct {
sum uint64
nRotate uint
nRotateComplement uint // redundant, but pre-computed to spare an operation
@@ -112,44 +34,62 @@ type digest struct {
}
// Reset resets the Hash to its initial state.
func (d *digest) Reset() {
func (d *Buzhash64) Reset() {
d.window = d.window[:0]
d.oldest = 0
d.sum = 0
}
func New() rollinghash.Hash64 {
return NewFromUint64Array(DefaultHash)
// GenerateHashes generates a list of hashes to use with buzhash
func GenerateHashes(seed int64) (res [256]uint64) {
random := rand.New(rand.NewSource(seed))
used := make(map[uint64]bool)
for i, _ := range res {
x := uint64(random.Int63())
for used[x] {
x = uint64(random.Int63())
}
used[x] = true
res[i] = x
}
return res
}
// NewFromUint32Array returns a buzhash based on the provided table uint32 values.
func NewFromUint64Array(b [256]uint64) rollinghash.Hash64 {
return &digest{
// New returns a buzhash based on a list of hashes provided by a call to
// GenerateHashes, seeded with the default value 1.
func New() *Buzhash64 {
return NewFromUint64Array(defaultHashes)
}
// NewFromUint64Array returns a buzhash based on the provided table uint64 values.
func NewFromUint64Array(b [256]uint64) *Buzhash64 {
return &Buzhash64{
sum: 0,
window: make([]byte, 0),
window: make([]byte, 1, rollinghash.DefaultWindowCap),
oldest: 0,
bytehash: b,
}
}
// Size returns the number of bytes Sum will return.
func (d *digest) Size() int { return Size }
// Size is 8 bytes
func (d *Buzhash64) Size() int { return Size }
// BlockSize returns the hash's underlying block size.
// The Write method must be able to accept any amount
// of data, but it may operate more efficiently if all
// writes are a multiple of the block size.
func (d *digest) BlockSize() int { return 1 }
// BlockSize is 1 byte
func (d *Buzhash64) BlockSize() int { return 1 }
// Write (via the embedded io.Writer interface) adds more data to the
// running hash. It never returns an error.
func (d *digest) Write(data []byte) (int, error) {
// Write (re)initializes the rolling window with the input byte slice and
// adds its data to the digest.
func (d *Buzhash64) Write(data []byte) (int, error) {
// Copy the window, avoiding allocations where possible
if len(d.window) != len(data) {
if cap(d.window) >= len(data) {
d.window = d.window[:len(data)]
l := len(data)
if l == 0 {
l = 1
}
if len(d.window) != l {
if cap(d.window) >= l {
d.window = d.window[:l]
} else {
d.window = make([]byte, len(data))
d.window = make([]byte, l)
}
}
copy(d.window, data)
@@ -163,22 +103,20 @@ func (d *digest) Write(data []byte) (int, error) {
return len(d.window), nil
}
func (d *digest) Sum64() uint64 {
// Sum64 returns the hash as a uint64
func (d *Buzhash64) Sum64() uint64 {
return d.sum
}
func (d *digest) Sum(b []byte) []byte {
// Sum returns the hash as a byte slice
func (d *Buzhash64) Sum(b []byte) []byte {
v := d.Sum64()
return append(b, byte(v>>56), byte(v>>48), byte(v>>40), byte(v>>32), byte(v>>24), byte(v>>16), byte(v>>8), byte(v))
}
// Roll updates the checksum of the window from the leaving byte and the
// entering byte.
func (d *digest) Roll(c byte) {
if len(d.window) == 0 {
d.window = make([]byte, 1)
d.window[0] = c
}
// Roll updates the checksum of the window from the entering byte. You
// MUST initialize a window with Write() before calling this method.
func (d *Buzhash64) Roll(c byte) {
// extract the entering/leaving bytes and update the circular buffer.
hn := d.bytehash[int(c)]
h0 := d.bytehash[int(d.window[d.oldest])]
-89
View File
@@ -1,89 +0,0 @@
// Package rollinghash/rabinkarp32 implements a particular case of
// rabin-karp where the modulus is 0xffffffff (32 bits of '1')
package rabinkarp32
import rollinghash "github.com/chmduquesne/rollinghash"
// The size of a rabinkarp32 checksum.
const Size = 4
// digest represents the partial evaluation of a checksum.
type digest struct {
a uint32
h uint32
aPowerN uint32
// window is treated like a circular buffer, where the oldest element
// is indicated by d.oldest
window []byte
oldest int
}
// Reset resets the Hash to its initial state.
func (d *digest) Reset() {
d.h = 0
d.aPowerN = 1
d.window = nil
d.oldest = 0
}
func NewFromInt(a uint32) rollinghash.Hash32 {
return &digest{a: a, h: 0, aPowerN: 1, window: nil, oldest: 0}
}
func New() rollinghash.Hash32 {
return NewFromInt(65521) // largest prime fitting in 16 bits
}
// Size returns the number of bytes Sum will return.
func (d *digest) Size() int { return Size }
// BlockSize returns the hash's underlying block size.
// The Write method must be able to accept any amount
// of data, but it may operate more efficiently if all
// writes are a multiple of the block size.
func (d *digest) BlockSize() int { return 1 }
// Write (via the embedded io.Writer interface) adds more data to the
// running hash. It never returns an error.
func (d *digest) Write(data []byte) (int, error) {
// Copy the window
d.window = make([]byte, len(data))
copy(d.window, data)
for _, c := range d.window {
d.h *= d.a
d.h += uint32(c)
d.aPowerN *= d.a
}
return len(d.window), nil
}
func (d *digest) Sum32() uint32 {
return d.h
}
func (d *digest) Sum(b []byte) []byte {
v := d.Sum32()
return append(b, byte(v>>24), byte(v>>16), byte(v>>8), byte(v))
}
// Roll updates the checksum of the window from the leaving byte and the
// entering byte.
func (d *digest) Roll(c byte) {
if len(d.window) == 0 {
d.window = make([]byte, 1)
d.window[0] = c
}
// extract the entering/leaving bytes and update the circular buffer.
enter := uint32(c)
leave := uint32(d.window[d.oldest])
d.window[d.oldest] = c
l := len(d.window)
d.oldest += 1
if d.oldest >= l {
d.oldest = 0
}
d.h = d.h*d.a + enter - leave*d.aPowerN
}
+318
View File
@@ -0,0 +1,318 @@
// Copyright (c) 2014, Alexander Neumann <alexander@bumpern.de>
// Copyright (c) 2017, Christophe-Marie Duquesne <chmd@chmd.fr>
//
// This file was adapted from restic https://github.com/restic/chunker
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package rabinkarp64
import (
"encoding/binary"
"errors"
"fmt"
"io"
"math/rand"
"strconv"
)
// Pol is a polynomial from F_2[X].
type Pol uint64
// Add returns x+y.
func (x Pol) Add(y Pol) Pol {
r := Pol(uint64(x) ^ uint64(y))
return r
}
// mulOverflows returns true if the multiplication would overflow uint64.
// Code by Rob Pike, see
// https://groups.google.com/d/msg/golang-nuts/h5oSN5t3Au4/KaNQREhZh0QJ
func mulOverflows(a, b Pol) bool {
if a <= 1 || b <= 1 {
return false
}
c := a.mul(b)
d := c.Div(b)
if d != a {
return true
}
return false
}
func (x Pol) mul(y Pol) Pol {
if x == 0 || y == 0 {
return 0
}
var res Pol
for i := 0; i <= y.Deg(); i++ {
if (y & (1 << uint(i))) > 0 {
res = res.Add(x << uint(i))
}
}
return res
}
// Mul returns x*y. When an overflow occurs, Mul panics.
func (x Pol) Mul(y Pol) Pol {
if mulOverflows(x, y) {
panic("multiplication would overflow uint64")
}
return x.mul(y)
}
// Deg returns the degree of the polynomial x. If x is zero, -1 is returned.
func (x Pol) Deg() int {
// the degree of 0 is -1
if x == 0 {
return -1
}
// see https://graphics.stanford.edu/~seander/bithacks.html#IntegerLog
r := 0
if uint64(x)&0xffffffff00000000 > 0 {
x >>= 32
r |= 32
}
if uint64(x)&0xffff0000 > 0 {
x >>= 16
r |= 16
}
if uint64(x)&0xff00 > 0 {
x >>= 8
r |= 8
}
if uint64(x)&0xf0 > 0 {
x >>= 4
r |= 4
}
if uint64(x)&0xc > 0 {
x >>= 2
r |= 2
}
if uint64(x)&0x2 > 0 {
x >>= 1
r |= 1
}
return r
}
// String returns the coefficients in hex.
func (x Pol) String() string {
return "0x" + strconv.FormatUint(uint64(x), 16)
}
// Expand returns the string representation of the polynomial x.
func (x Pol) Expand() string {
if x == 0 {
return "0"
}
s := ""
for i := x.Deg(); i > 1; i-- {
if x&(1<<uint(i)) > 0 {
s += fmt.Sprintf("+x^%d", i)
}
}
if x&2 > 0 {
s += "+x"
}
if x&1 > 0 {
s += "+1"
}
return s[1:]
}
// DivMod returns x / d = q, and remainder r,
// see https://en.wikipedia.org/wiki/Division_algorithm
func (x Pol) DivMod(d Pol) (Pol, Pol) {
if x == 0 {
return 0, 0
}
if d == 0 {
panic("division by zero")
}
D := d.Deg()
diff := x.Deg() - D
if diff < 0 {
return 0, x
}
var q Pol
for diff >= 0 {
m := d << uint(diff)
q |= (1 << uint(diff))
x = x.Add(m)
diff = x.Deg() - D
}
return q, x
}
// Div returns the integer division result x / d.
func (x Pol) Div(d Pol) Pol {
q, _ := x.DivMod(d)
return q
}
// Mod returns the remainder of x / d
func (x Pol) Mod(d Pol) Pol {
_, r := x.DivMod(d)
return r
}
// I really dislike having a function that does not terminate, so specify a
// really large upper bound for finding a new irreducible polynomial, and
// return an error when no irreducible polynomial has been found within
// randPolMaxTries.
const randPolMaxTries = 1e6
// RandomPolynomial returns a new random irreducible polynomial
// of degree 53 using the input seed as a source.
// It is equivalent to calling DerivePolynomial(rand.Reader).
func RandomPolynomial(seed int64) (Pol, error) {
return DerivePolynomial(rand.New(rand.NewSource(seed)))
}
// DerivePolynomial returns an irreducible polynomial of degree 53
// (largest prime number below 64-8) by reading bytes from source.
// There are (2^53-2/53) irreducible polynomials of degree 53 in
// F_2[X], c.f. Michael O. Rabin (1981): "Fingerprinting by Random
// Polynomials", page 4. If no polynomial could be found in one
// million tries, an error is returned.
func DerivePolynomial(source io.Reader) (Pol, error) {
for i := 0; i < randPolMaxTries; i++ {
var f Pol
// choose polynomial at (pseudo)random
err := binary.Read(source, binary.LittleEndian, &f)
if err != nil {
return 0, err
}
// mask away bits above bit 53
f &= Pol((1 << 54) - 1)
// set highest and lowest bit so that the degree is 53 and the
// polynomial is not trivially reducible
f |= (1 << 53) | 1
// test if f is irreducible
if f.Irreducible() {
return f, nil
}
}
// If this is reached, we haven't found an irreducible polynomial in
// randPolMaxTries. This error is very unlikely to occur.
return 0, errors.New("unable to find new random irreducible polynomial")
}
// GCD computes the Greatest Common Divisor x and f.
func (x Pol) GCD(f Pol) Pol {
if f == 0 {
return x
}
if x == 0 {
return f
}
if x.Deg() < f.Deg() {
x, f = f, x
}
return f.GCD(x.Mod(f))
}
// Irreducible returns true iff x is irreducible over F_2. This function
// uses Ben Or's reducibility test.
//
// For details see "Tests and Constructions of Irreducible Polynomials over
// Finite Fields".
func (x Pol) Irreducible() bool {
for i := 1; i <= x.Deg()/2; i++ {
if x.GCD(qp(uint(i), x)) != 1 {
return false
}
}
return true
}
// MulMod computes x*f mod g
func (x Pol) MulMod(f, g Pol) Pol {
if x == 0 || f == 0 {
return 0
}
var res Pol
for i := 0; i <= f.Deg(); i++ {
if (f & (1 << uint(i))) > 0 {
a := x
for j := 0; j < i; j++ {
a = a.Mul(2).Mod(g)
}
res = res.Add(a).Mod(g)
}
}
return res
}
// qp computes the polynomial (x^(2^p)-x) mod g. This is needed for the
// reducibility test.
func qp(p uint, g Pol) Pol {
num := (1 << p)
i := 1
// start with x
res := Pol(2)
for i < num {
// repeatedly square res
res = res.MulMod(res, g)
i *= 2
}
// add x
return res.Add(2).Mod(g)
}
+224
View File
@@ -0,0 +1,224 @@
// Copyright (c) 2014, Alexander Neumann <alexander@bumpern.de>
// Copyright (c) 2017, Christophe-Marie Duquesne <chmd@chmd.fr>
//
// This file was adapted from restic https://github.com/restic/chunker
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package rabinkarp64
import (
"sync"
"github.com/chmduquesne/rollinghash"
)
const Size = 8
type tables struct {
out [256]Pol
mod [256]Pol
}
// tables are cacheable for a given pol and windowsize
type index struct {
pol Pol
windowsize int
}
type RabinKarp64 struct {
pol Pol
tables *tables
polShift uint
value Pol
// window is treated like a circular buffer, where the oldest element
// is indicated by d.oldest
window []byte
oldest int
}
// cache precomputed tables, these are read-only anyway
var cache struct {
// For a given polynom and a given window size, we get a table
entries map[index]*tables
sync.Mutex
}
func init() {
cache.entries = make(map[index]*tables)
}
func (d *RabinKarp64) buildTables() {
windowsize := len(d.window)
idx := index{d.pol, windowsize}
cache.Lock()
t, ok := cache.entries[idx]
cache.Unlock()
if ok {
d.tables = t
return
}
t = &tables{}
// calculate table for sliding out bytes. The byte to slide out is used as
// the index for the table, the value contains the following:
// out_table[b] = Hash(b || 0 || ... || 0)
// \ windowsize-1 zero bytes /
// To slide out byte b_0 for window size w with known hash
// H := H(b_0 || ... || b_w), it is sufficient to add out_table[b_0]:
// H(b_0 || ... || b_w) + H(b_0 || 0 || ... || 0)
// = H(b_0 + b_0 || b_1 + 0 || ... || b_w + 0)
// = H( 0 || b_1 || ... || b_w)
//
// Afterwards a new byte can be shifted in.
for b := 0; b < 256; b++ {
var h Pol
h <<= 8
h |= Pol(b)
h = h.Mod(d.pol)
for i := 0; i < windowsize-1; i++ {
h <<= 8
h |= Pol(0)
h = h.Mod(d.pol)
}
t.out[b] = h
}
// calculate table for reduction mod Polynomial
k := d.pol.Deg()
for b := 0; b < 256; b++ {
// mod_table[b] = A | B, where A = (b(x) * x^k mod pol) and B = b(x) * x^k
//
// The 8 bits above deg(Polynomial) determine what happens next and so
// these bits are used as a lookup to this table. The value is split in
// two parts: Part A contains the result of the modulus operation, part
// B is used to cancel out the 8 top bits so that one XOR operation is
// enough to reduce modulo Polynomial
t.mod[b] = Pol(uint64(b)<<uint(k)).Mod(d.pol) | (Pol(b) << uint(k))
}
d.tables = t
cache.Lock()
cache.entries[idx] = d.tables
cache.Unlock()
}
// NewFromPol returns a RabinKarp64 digest from a polynomial over GF(2).
// It is assumed that the input polynomial is irreducible. You can obtain
// such a polynomial using the RandomPolynomial function.
func NewFromPol(p Pol) *RabinKarp64 {
res := &RabinKarp64{
pol: p,
tables: nil,
polShift: uint(p.Deg() - 8),
value: 0,
window: make([]byte, 0, rollinghash.DefaultWindowCap),
oldest: 0,
}
return res
}
// New returns a RabinKarp64 digest from the default polynomial obtained
// when using RandomPolynomial with the seed 1.
func New() *RabinKarp64 {
p, err := RandomPolynomial(1)
if err != nil {
panic(err)
}
return NewFromPol(p)
}
// Reset resets the running hash to its initial state
func (d *RabinKarp64) Reset() {
d.tables = nil
d.value = 0
d.window = d.window[:1]
d.window[0] = 0
d.oldest = 0
}
// Size is 8 bytes
func (d *RabinKarp64) Size() int { return Size }
// BlockSize is 1 byte
func (d *RabinKarp64) BlockSize() int { return 1 }
// Write (re)initializes the rolling window with the input byte slice and
// adds its data to the digest. It never returns an error.
func (d *RabinKarp64) Write(data []byte) (int, error) {
// Copy the window
l := len(data)
if l == 0 {
l = 1
}
if len(d.window) >= l {
d.window = d.window[:l]
} else {
d.window = make([]byte, l)
}
copy(d.window, data)
for _, b := range d.window {
d.value <<= 8
d.value |= Pol(b)
d.value = d.value.Mod(d.pol)
}
d.buildTables()
return len(d.window), nil
}
// Sum64 returns the hash as a uint64
func (d *RabinKarp64) Sum64() uint64 {
return uint64(d.value)
}
// Sum returns the hash as byte slice
func (d *RabinKarp64) Sum(b []byte) []byte {
v := d.Sum64()
return append(b, byte(v>>56), byte(v>>48), byte(v>>40), byte(v>>32), byte(v>>24), byte(v>>16), byte(v>>8), byte(v))
}
// Roll updates the checksum of the window from the entering byte. You
// MUST initialize a window with Write() before calling this method.
func (d *RabinKarp64) Roll(c byte) {
// extract the entering/leaving bytes and update the circular buffer.
enter := c
leave := uint64(d.window[d.oldest])
d.window[d.oldest] = c
d.oldest += 1
if d.oldest >= len(d.window) {
d.oldest = 0
}
d.value ^= d.tables.out[leave]
index := byte(d.value >> d.polShift)
d.value <<= 8
d.value |= Pol(enter)
d.value ^= d.tables.mod[index]
}
+126
View File
@@ -0,0 +1,126 @@
package main
import (
"flag"
"fmt"
"io"
"log"
"os"
"time"
"code.cloudfoundry.org/bytefmt"
//rollsum "github.com/chmduquesne/rollinghash/adler32"
//rollsum "github.com/chmduquesne/rollinghash/buzhash32"
rollsum "github.com/chmduquesne/rollinghash/buzhash64"
//rollsum "github.com/chmduquesne/rollinghash/bozo32"
)
const (
KiB = 1024
MiB = 1024 * KiB
GiB = 1024 * MiB
clearscreen = "\033[2J\033[1;1H"
clearline = "\x1b[2K"
)
func genMasks() (res []uint64) {
res = make([]uint64, 64)
ones := ^uint64(0) // 0xffffffffffffffff
for i := 0; i < 64; i++ {
res[i] = ones >> uint(63-i)
}
return
}
func hash2uint64(s []byte) (res uint64) {
for _, b := range s {
res <<= 8
res |= uint64(b)
}
return
}
func main() {
dostats := flag.Bool("stats", false, "Do some stats about the rolling sum")
size := flag.String("size", "256M", "How much data to read")
flag.Parse()
fileSize, err := bytefmt.ToBytes(*size)
if err != nil {
log.Fatal(err)
}
bufsize := 16 * MiB
rbuf := make([]byte, bufsize)
hbuf := make([]byte, 0, 8)
t := time.Now()
f, err := os.Open("/dev/urandom")
if err != nil {
log.Fatal(err)
}
defer func() {
if err := f.Close(); err != nil {
log.Fatal(err)
}
}()
io.ReadFull(f, rbuf)
roll := rollsum.New()
roll.Write(rbuf[:64])
masks := genMasks()
hits := make(map[uint64]uint64)
for _, m := range masks {
hits[m] = 0
}
n := uint64(0)
k := 0
for n < fileSize {
if k >= bufsize {
status := fmt.Sprintf("Byte count: %s", bytefmt.ByteSize(n))
if *dostats {
fmt.Printf(clearscreen)
fmt.Println(status)
for i, m := range masks {
frequency := "NaN"
if hits[m] != 0 {
frequency = bytefmt.ByteSize(n / hits[m])
}
fmt.Printf("0x%016x (%02d bits): every %s\n", m, i+1, frequency)
}
} else {
fmt.Printf(clearline)
fmt.Printf(status)
fmt.Printf("\r")
}
_, err := io.ReadFull(f, rbuf)
if err != nil {
panic(err)
}
k = 0
}
roll.Roll(rbuf[k])
if *dostats {
s := hash2uint64(roll.Sum(hbuf))
for _, m := range masks {
if s&m == m {
hits[m] += 1
} else {
break
}
}
}
k++
n++
}
duration := time.Since(t)
fmt.Printf("Rolled %s of data in %v (%s/s).\n",
bytefmt.ByteSize(n),
duration,
bytefmt.ByteSize(n*1e9/uint64(duration)),
)
}
+12 -4
View File
@@ -7,11 +7,19 @@ package rollinghash
import "hash"
// DefaultWindowCap is the default capacity of the internal window of a
// new Hash.
const DefaultWindowCap = 64
// A Roller is a type that has the method Roll. Roll updates the hash of a
// rolling window from just the entering byte. You MUST call Write()
// BEFORE using this method and provide it with an initial window of size
// at least 1 byte. You can then call this method for every new byte
// entering the window. The byte leaving the window is automatically
// computed from a copy of the window internally kept in the checksum.
// This window is updated along with the internal state of the checksum
// every time Roll() is called.
type Roller interface {
// Roll updates the hash of a rolling window from the entering byte.
// A copy of the window is internally kept from the last Write().
// This copy is updated along with the internal state of the checksum
// in order to determine the new hash very quickly.
Roll(b byte)
}
+13 -28
View File
@@ -301,7 +301,6 @@ func (t *Tree) Delete(k interface{} /*K*/) (ok bool) {
pi = i + 1
p = x
q = x.x[pi].ch
ok = false
continue
case *d:
t.extract(x, i)
@@ -547,12 +546,13 @@ func (t *Tree) Set(k interface{} /*K*/, v interface{} /*V*/) {
if ok {
switch x := q.(type) {
case *x:
i++
if x.c > 2*kx {
x, i = t.splitX(p, x, pi, i)
}
pi = i + 1
pi = i
p = x
q = x.x[i+1].ch
q = x.x[i].ch
continue
case *d:
x.d[i].v = v
@@ -614,12 +614,13 @@ func (t *Tree) Put(k interface{} /*K*/, upd func(oldV interface{} /*V*/, exists
if ok {
switch x := q.(type) {
case *x:
i++
if x.c > 2*kx {
x, i = t.splitX(p, x, pi, i)
}
pi = i + 1
pi = i
p = x
q = x.x[i+1].ch
q = x.x[i].ch
continue
case *d:
oldV = x.d[i].v
@@ -701,36 +702,20 @@ func (t *Tree) splitX(p *x, q *x, pi int, i int) (*x, int) {
r.c = kx
if pi >= 0 {
p.insert(pi, q.x[kx].k, r)
q.x[kx].k = zk
for i := range q.x[kx+1:] {
q.x[kx+i+1] = zxe
}
switch {
case i < kx:
return q, i
case i == kx:
return p, pi
default: // i > kx
return r, i - kx - 1
}
} else {
t.r = newX(q).insert(0, q.x[kx].k, r)
}
nr := newX(q).insert(0, q.x[kx].k, r)
t.r = nr
q.x[kx].k = zk
for i := range q.x[kx+1:] {
q.x[kx+i+1] = zxe
}
switch {
case i < kx:
return q, i
case i == kx:
return nr, 0
default: // i > kx
return r, i - kx - 1
if i > kx {
q = r
i -= kx + 1
}
return q, i
}
func (t *Tree) underflow(p *x, q *d, pi int) {
+30 -49
View File
@@ -76,7 +76,7 @@ type (
//
// However, once an Enumerator returns io.EOF to signal "no more
// items", it does no more attempt to "resync" on tree mutation(s). In
// other words, io.EOF from an Enumaretor is "sticky" (idempotent).
// other words, io.EOF from an Enumerator is "sticky" (idempotent).
Enumerator struct {
err error
hit bool
@@ -450,7 +450,7 @@ func (t *Tree) overflow(p *x, q *d, pi, i int, k int, v int) {
t.ver++
l, r := p.siblings(pi)
if l != nil && l.c < 2*kd {
if l != nil && l.c < 2*kd && i != 0 {
l.mvL(q, 1)
t.insert(q, i-1, k, v)
p.x[pi-1].k = q.d[0].k
@@ -473,9 +473,9 @@ func (t *Tree) overflow(p *x, q *d, pi, i int, k int, v int) {
t.split(p, q, pi, i, k, v)
}
// Seek returns an Enumerator positioned on a an item such that k >= item's
// key. ok reports if k == item.key The Enumerator's position is possibly
// after the last item in the tree.
// Seek returns an Enumerator positioned on an item such that k >= item's key.
// ok reports if k == item.key The Enumerator's position is possibly after the
// last item in the tree.
func (t *Tree) Seek(k int) (e *Enumerator, ok bool) {
q := t.r
if q == nil {
@@ -547,12 +547,13 @@ func (t *Tree) Set(k int, v int) {
if ok {
switch x := q.(type) {
case *x:
i++
if x.c > 2*kx {
x, i = t.splitX(p, x, pi, i)
}
pi = i + 1
pi = i
p = x
q = x.x[i+1].ch
q = x.x[i].ch
continue
case *d:
x.d[i].v = v
@@ -614,12 +615,13 @@ func (t *Tree) Put(k int, upd func(oldV int, exists bool) (newV int, write bool)
if ok {
switch x := q.(type) {
case *x:
i++
if x.c > 2*kx {
x, i = t.splitX(p, x, pi, i)
}
pi = i + 1
pi = i
p = x
q = x.x[i+1].ch
q = x.x[i].ch
continue
case *d:
oldV = x.d[i].v
@@ -701,36 +703,20 @@ func (t *Tree) splitX(p *x, q *x, pi int, i int) (*x, int) {
r.c = kx
if pi >= 0 {
p.insert(pi, q.x[kx].k, r)
q.x[kx].k = zk
for i := range q.x[kx+1:] {
q.x[kx+i+1] = zxe
}
switch {
case i < kx:
return q, i
case i == kx:
return p, pi
default: // i > kx
return r, i - kx - 1
}
} else {
t.r = newX(q).insert(0, q.x[kx].k, r)
}
nr := newX(q).insert(0, q.x[kx].k, r)
t.r = nr
q.x[kx].k = zk
for i := range q.x[kx+1:] {
q.x[kx+i+1] = zxe
}
switch {
case i < kx:
return q, i
case i == kx:
return nr, 0
default: // i > kx
return r, i - kx - 1
if i > kx {
q = r
i -= kx + 1
}
return q, i
}
func (t *Tree) underflow(p *x, q *d, pi int) {
@@ -826,13 +812,7 @@ func (e *Enumerator) Next() (k int, v int, err error) {
}
if e.ver != e.t.ver {
f, hit := e.t.Seek(e.k)
if !e.hit && hit {
if err = f.next(); err != nil {
return
}
}
f, _ := e.t.Seek(e.k)
*e = *f
f.Close()
}
@@ -849,7 +829,7 @@ func (e *Enumerator) Next() (k int, v int, err error) {
i := e.q.d[e.i]
k, v = i.k, i.v
e.k, e.hit = k, false
e.k, e.hit = k, true
e.next()
return
}
@@ -880,13 +860,7 @@ func (e *Enumerator) Prev() (k int, v int, err error) {
}
if e.ver != e.t.ver {
f, hit := e.t.Seek(e.k)
if !e.hit && hit {
if err = f.prev(); err != nil {
return
}
}
f, _ := e.t.Seek(e.k)
*e = *f
f.Close()
}
@@ -895,15 +869,22 @@ func (e *Enumerator) Prev() (k int, v int, err error) {
return
}
if !e.hit {
// move to previous because Seek overshoots if there's no hit
if err = e.prev(); err != nil {
return
}
}
if e.i >= e.q.c {
if err = e.next(); err != nil {
if err = e.prev(); err != nil {
return
}
}
i := e.q.d[e.i]
k, v = i.k, i.v
e.k, e.hit = k, false
e.k, e.hit = k, true
e.prev()
return
}
+2
View File
@@ -190,7 +190,9 @@ func TempFile(dir, prefix, suffix string) (f *os.File, err error) {
f, err = os.OpenFile(name, os.O_RDWR|os.O_CREATE|os.O_EXCL, 0600)
if os.IsExist(err) {
if nconflict++; nconflict > 10 {
randmu.Lock()
rand = reseed()
randmu.Unlock()
}
continue
}
+27
View File
@@ -0,0 +1,27 @@
Copyright (c) 2014 The golex Authors. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the names of the authors nor the names of the
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+410
View File
@@ -0,0 +1,410 @@
// Copyright (c) 2015 The golex Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package lex
import (
"bytes"
"fmt"
"go/token"
"io"
"os"
)
// BOM handling modes which can be set by the BOMMode Option. Default is BOMIgnoreFirst.
const (
BOMError = iota // BOM is an error anywhere.
BOMIgnoreFirst // Skip BOM if at beginning, report as error if anywhere else.
BOMPassAll // No special handling of BOM.
BOMPassFirst // No special handling of BOM if at beginning, report as error if anywhere else.
)
const (
NonASCII = 0x80 // DefaultRuneClass returns NonASCII for non ASCII runes.
RuneEOF = -1 // Distinct from any valid Unicode rune value.
)
// DefaultRuneClass returns the character class of r. If r is an ASCII code
// then its class equals the ASCII code. Any other rune is of class NonASCII.
//
// DefaultRuneClass is the default implementation Lexer will use to convert
// runes (21 bit entities) to scanner classes (8 bit entities).
//
// Non ASCII aware lexical analyzers will typically use their own
// categorization function. To assign such custom function use the RuneClass
// option.
func DefaultRuneClass(r rune) int {
if r >= 0 && r < 0x80 {
return int(r)
}
return NonASCII
}
// Char represents a rune and its position.
type Char struct {
Rune rune
pos int32
}
// NewChar returns a new Char value.
func NewChar(pos token.Pos, r rune) Char { return Char{pos: int32(pos), Rune: r} }
// IsValid reports whether c is not a zero Char.
func (c Char) IsValid() bool { return c.Pos().IsValid() }
// Pos returns the token.Pos associated with c.
func (c Char) Pos() token.Pos { return token.Pos(c.pos) }
// CharReader is a RuneReader providing additionally explicit position
// information by returning a Char instead of a rune as its first result.
type CharReader interface {
ReadChar() (c Char, size int, err error)
}
// Lexer suports golex[0] generated lexical analyzers.
type Lexer struct {
File *token.File // The *token.File passed to New.
First Char // First remembers the lookahead char when Rule0 was invoked.
Last Char // Last remembers the last Char returned by Next.
Prev Char // Prev remembers the Char previous to Last.
bomMode int // See the BOM* constants.
bytesBuf bytes.Buffer // Used by TokenBytes.
charSrc CharReader // Lexer alternative input.
classf func(rune) int //
errorf func(token.Pos, string) //
lookahead Char // Lookahead if non zero.
mark int // Longest match marker.
off int // Used for File.AddLine.
src io.RuneReader // Lexer input.
tokenBuf []Char // Lexeme collector.
ungetBuf []Char // Unget buffer.
}
// New returns a new *Lexer. The result can be amended using opts.
//
// Non Unicode Input
//
// To consume sources in other encodings and still have exact position
// information, pass an io.RuneReader which returns the next input character
// reencoded as an Unicode rune but returns the size (number of bytes used to
// encode it) of the original character, not the size of its UTF-8
// representation after converted to an Unicode rune. Size is the second
// returned value of io.RuneReader.ReadRune method[4].
//
// When src optionally implements CharReader its ReadChar method is used
// instead of io.ReadRune.
func New(file *token.File, src io.RuneReader, opts ...Option) (*Lexer, error) {
r := &Lexer{
File: file,
bomMode: BOMIgnoreFirst,
classf: DefaultRuneClass,
src: src,
}
if x, ok := src.(CharReader); ok {
r.charSrc = x
}
r.errorf = r.defaultErrorf
for _, o := range opts {
if err := o(r); err != nil {
return nil, err
}
}
return r, nil
}
// Abort handles the situation when the scanner does not successfully recognize
// any token or when an attempt to find the longest match "overruns" from an
// accepting state only to never reach an accepting state again. In the first
// case the scanner was never in an accepting state since last call to Rule0
// and then (true, previousLookahead rune) is returned, effectively consuming a
// single Char token, avoiding scanner stall. Otherwise there was at least one
// accepting scanner state marked using Mark. In this case Abort rollbacks the
// lexer state to the marked state and returns (false, 0). The scanner must
// then execute a prescribed goto statement. For example:
//
// %yyc c
// %yyn c = l.Next()
// %yym l.Mark()
//
// %{
// package foo
//
// import (...)
//
// type lexer struct {
// *lex.Lexer
// ...
// }
//
// func newLexer(...) *lexer {
// return &lexer{
// lex.NewLexer(...),
// ...
// }
// }
//
// func (l *lexer) scan() int {
// c := l.Enter()
// %}
//
// ... more lex defintions
//
// %%
//
// c = l.Rule0()
//
// ... lex rules
//
// %%
//
// if c, ok := l.Abort(); ok {
// return c
// }
//
// goto yyAction
// }
func (l *Lexer) Abort() (int, bool) {
if l.mark >= 0 {
if len(l.tokenBuf) > l.mark {
l.Unget(l.lookahead)
for i := len(l.tokenBuf) - 1; i >= l.mark; i-- {
l.Unget(l.tokenBuf[i])
}
}
l.tokenBuf = l.tokenBuf[:l.mark]
return 0, false
}
switch n := len(l.tokenBuf); n {
case 0: // [] z
c := l.lookahead
l.Next()
return int(c.Rune), true
case 1: // [a] z
return int(l.tokenBuf[0].Rune), true
default: // [a, b, ...], z
c := l.tokenBuf[0] // a
l.Unget(l.lookahead) // z
for i := n - 1; i > 1; i-- {
l.Unget(l.tokenBuf[i]) // ...
}
l.lookahead = l.tokenBuf[1] // b
l.tokenBuf = l.tokenBuf[:1]
return int(c.Rune), true
}
}
func (l *Lexer) class() int { return l.classf(l.lookahead.Rune) }
func (l *Lexer) defaultErrorf(pos token.Pos, msg string) {
l.Error(fmt.Sprintf("%v: %v", l.File.Position(pos), msg))
}
// Enter ensures the lexer has a valid lookahead Char and returns its class.
// Typical use in an .l file
//
// func (l *lexer) scan() lex.Char {
// c := l.Enter()
// ...
func (l *Lexer) Enter() int {
if !l.lookahead.IsValid() {
l.Next()
}
return l.class()
}
// Error Implements yyLexer[2] by printing the msg to stderr.
func (l *Lexer) Error(msg string) {
fmt.Fprintf(os.Stderr, "%s\n", msg)
}
// Lookahead returns the current lookahead.
func (l *Lexer) Lookahead() Char {
if !l.lookahead.IsValid() {
l.Next()
}
return l.lookahead
}
// Mark records the current state of scanner as accepting. It implements the
// golex macro %yym. Typical usage in an .l file:
//
// %yym l.Mark()
func (l *Lexer) Mark() { l.mark = len(l.tokenBuf) }
func (l *Lexer) next() int {
const bom = '\ufeff'
if c := l.lookahead; c.IsValid() {
l.tokenBuf = append(l.tokenBuf, c)
}
if n := len(l.ungetBuf); n != 0 {
l.lookahead = l.ungetBuf[n-1]
l.ungetBuf = l.ungetBuf[:n-1]
return l.class()
}
if l.src == nil {
return RuneEOF
}
var r rune
var sz int
var err error
var pos token.Pos
var c Char
again:
off0 := l.off
switch cs := l.charSrc; {
case cs != nil:
c, sz, err = cs.ReadChar()
r = c.Rune
pos = c.Pos()
default:
r, sz, err = l.src.ReadRune()
pos = l.File.Pos(l.off)
}
l.off += sz
if err != nil {
l.src = nil
r = RuneEOF
if err != io.EOF {
l.errorf(pos, err.Error())
}
}
if r == bom {
switch l.bomMode {
default:
fallthrough
case BOMIgnoreFirst:
if off0 != 0 {
l.errorf(pos, "unicode (UTF-8) BOM in middle of file")
}
goto again
case BOMPassAll:
// nop
case BOMPassFirst:
if off0 != 0 {
l.errorf(pos, "unicode (UTF-8) BOM in middle of file")
goto again
}
case BOMError:
switch {
case off0 == 0:
l.errorf(pos, "unicode (UTF-8) BOM at beginnig of file")
default:
l.errorf(pos, "unicode (UTF-8) BOM in middle of file")
}
goto again
}
}
l.lookahead = NewChar(pos, r)
if r == '\n' {
l.File.AddLine(l.off)
}
return l.class()
}
// Next advances the scanner for one rune and returns the respective character
// class of the new lookahead. Typical usage in an .l file:
//
// %yyn c = l.Next()
func (l *Lexer) Next() int {
l.Prev = l.Last
r := l.next()
l.Last = l.lookahead
return r
}
// Offset returns the current reading offset of the lexer's source.
func (l *Lexer) Offset() int { return l.off }
// Rule0 initializes the scanner state before the attempt to recognize a token
// starts. The token collecting buffer is cleared. Rule0 records the current
// lookahead in l.First and returns its class. Typical usage in an .l file:
//
// ... lex definitions
//
// %%
//
// c := l.Rule0()
//
// first-pattern-regexp
func (l *Lexer) Rule0() int {
if !l.lookahead.IsValid() {
l.Next()
}
l.First = l.lookahead
l.mark = -1
if len(l.tokenBuf) > 1<<18 { //DONE constant tuned
l.tokenBuf = nil
} else {
l.tokenBuf = l.tokenBuf[:0]
}
return l.class()
}
// Token returns the currently collected token chars. The result is R/O.
func (l *Lexer) Token() []Char { return l.tokenBuf }
// TokenBytes returns the UTF-8 encoding of Token. If builder is not nil then
// it's called instead to build the encoded token byte value into the buffer
// passed to it.
//
// The Result is R/O.
func (l *Lexer) TokenBytes(builder func(*bytes.Buffer)) []byte {
if len(l.bytesBuf.Bytes()) < 1<<18 { //DONE constant tuned
l.bytesBuf.Reset()
} else {
l.bytesBuf = bytes.Buffer{}
}
switch {
case builder != nil:
builder(&l.bytesBuf)
default:
for _, c := range l.Token() {
l.bytesBuf.WriteRune(c.Rune)
}
}
return l.bytesBuf.Bytes()
}
// Unget unreads all chars in c.
func (l *Lexer) Unget(c ...Char) {
l.ungetBuf = append(l.ungetBuf, c...)
l.lookahead = Char{} // Must invalidate lookahead.
}
// Option is a function which can be passed as an optional argument to New.
type Option func(*Lexer) error
// BOMMode option selects how the lexer handles BOMs. See the BOM* constants for details.
func BOMMode(mode int) Option {
return func(l *Lexer) error {
l.bomMode = mode
return nil
}
}
// ErrorFunc option sets a function called when an, for example I/O error,
// occurs. The default is to call Error with the position and message already
// formated as a string.
func ErrorFunc(f func(token.Pos, string)) Option {
return func(l *Lexer) error {
l.errorf = f
return nil
}
}
// RuneClass option sets the function used to convert runes to character
// classes.
func RuneClass(f func(rune) int) Option {
return func(l *Lexer) error {
l.classf = f
return nil
}
}
+40
View File
@@ -0,0 +1,40 @@
// Copyright (c) 2015 The golex Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package lex is a Unicode-friendly run time library for golex[0] generated
// lexical analyzers[1].
//
// Changelog
//
// 2015-04-08: Initial release.
//
// Character classes
//
// Golex internally handles only 8 bit "characters". Many Unicode-aware
// tokenizers do not actually need to recognize every Unicode rune, but only
// some particular partitions/subsets. Like, for example, a particular Unicode
// category, say upper case letters: Lu.
//
// The idea is to convert all runes in a particular set as a single 8 bit
// character allocated outside the ASCII range of codes. The token value, a
// string of runes and their exact positions is collected as usual (see the
// Token and TokenBytes method), but the tokenizer DFA is simpler (and thus
// smaller and perhaps also faster) when this technique is used. In the example
// program (see below), recognizing (and skipping) white space, integer
// literals, one keyword and Go identifiers requires only an 8 state DFA[5].
//
// To provide the conversion from runes to character classes, "install" your
// converting function using the RuneClass option.
//
// References
//
// -
//
// [0]: http://godoc.org/github.com/cznic/golex
// [1]: http://en.wikipedia.org/wiki/Lexical_analysis
// [2]: http://golang.org/cmd/yacc/
// [3]: https://github.com/cznic/golex/blob/master/lex/example.l
// [4]: http://golang.org/pkg/io/#RuneReader
// [5]: https://github.com/cznic/golex/blob/master/lex/dfa
package lex
+36 -4
View File
@@ -124,11 +124,23 @@ func (f *mem) Truncate(size int64) (err error) {
}
first := size >> f.pgBits
if size&int64(f.pgMask) != 0 {
if po := size & int64(f.pgMask); po != 0 {
if p := f.m[first]; p != nil {
b := (*p)[po:]
for i := range b {
b[i] = 0
}
}
first++
}
last := f.size >> f.pgBits
if f.size&int64(f.pgMask) != 0 {
if po := f.size & int64(f.pgMask); po != 0 {
if p := f.m[last]; p != nil {
b := (*p)[po:]
for i := range b {
b[i] = 0
}
}
last++
}
for ; first <= last; first++ {
@@ -143,6 +155,10 @@ func (f *mem) Truncate(size int64) (err error) {
}
func (f *mem) WriteAt(b []byte, off int64) (n int, err error) {
if len(b) == 0 {
return 0, nil
}
pi := off >> f.pgBits
po := int(off) & f.pgMask
n = len(b)
@@ -319,11 +335,23 @@ func (f *file) Truncate(size int64) (err error) {
}
first := size >> f.pgBits
if size&int64(f.pgMask) != 0 {
if po := size & int64(f.pgMask); po != 0 {
if p := f.m[first]; p != nil {
b := p[po:]
for i := range b {
b[i] = 0
}
}
first++
}
last := f.size >> f.pgBits
if f.size&int64(f.pgMask) != 0 {
if po := f.size & int64(f.pgMask); po != 0 {
if p := f.m[last]; p != nil {
b := p[po:]
for i := range b {
b[i] = 0
}
}
last++
}
for ; first <= last; first++ {
@@ -349,6 +377,10 @@ func (f *file) Truncate(size int64) (err error) {
}
func (f *file) WriteAt(b []byte, off int64) (n int, err error) {
if len(b) == 0 {
return 0, nil
}
pi := off >> f.pgBits
po := int(off) & f.pgMask
n = len(b)
+277
View File
@@ -7,6 +7,13 @@
//
// Release history and compatibility issues
//
// 2017-10-14: New variadic functions for Max/Min. Ex:
// func MaxVal(val int, vals ...int) int {
// func MinVal(val int, vals ...int) int {
// func MaxByteVal(val byte, vals ...byte) byte {
// func MinByteVal(val byte, vals ...byte) byte {
// ...
//
// 2016-10-10: New functions QuadPolyDiscriminant and QuadPolyFactors.
//
// 2013-12-13: The following functions have been REMOVED
@@ -631,6 +638,33 @@ func Min(a, b int) int {
return b
}
// MaxVal returns the largest argument passed.
func MaxVal(val int, vals ...int) int {
res := val
for _, v := range vals {
if v > res {
res = v
}
}
return res
}
// MinVal returns the smallest argument passed.
func MinVal(val int, vals ...int) int {
res := val
for _, v := range vals {
if v < res {
res = v
}
}
return res
}
// Clamp returns a value restricted between lo and hi.
func Clamp(v, lo, hi int) int {
return Min(Max(v, lo), hi)
}
// UMax returns the larger of a and b.
func UMax(a, b uint) uint {
if a > b {
@@ -649,6 +683,33 @@ func UMin(a, b uint) uint {
return b
}
// UMaxVal returns the largest argument passed.
func UMaxVal(val uint, vals ...uint) uint {
res := val
for _, v := range vals {
if v > res {
res = v
}
}
return res
}
// UMinVal returns the smallest argument passed.
func UMinVal(val uint, vals ...uint) uint {
res := val
for _, v := range vals {
if v < res {
res = v
}
}
return res
}
// UClamp returns a value restricted between lo and hi.
func UClamp(v, lo, hi uint) uint {
return UMin(UMax(v, lo), hi)
}
// MaxByte returns the larger of a and b.
func MaxByte(a, b byte) byte {
if a > b {
@@ -667,6 +728,33 @@ func MinByte(a, b byte) byte {
return b
}
// MaxByteVal returns the largest argument passed.
func MaxByteVal(val byte, vals ...byte) byte {
res := val
for _, v := range vals {
if v > res {
res = v
}
}
return res
}
// MinByteVal returns the smallest argument passed.
func MinByteVal(val byte, vals ...byte) byte {
res := val
for _, v := range vals {
if v < res {
res = v
}
}
return res
}
// ClampByte returns a value restricted between lo and hi.
func ClampByte(v, lo, hi byte) byte {
return MinByte(MaxByte(v, lo), hi)
}
// MaxInt8 returns the larger of a and b.
func MaxInt8(a, b int8) int8 {
if a > b {
@@ -685,6 +773,33 @@ func MinInt8(a, b int8) int8 {
return b
}
// MaxInt8Val returns the largest argument passed.
func MaxInt8Val(val int8, vals ...int8) int8 {
res := val
for _, v := range vals {
if v > res {
res = v
}
}
return res
}
// MinInt8Val returns the smallest argument passed.
func MinInt8Val(val int8, vals ...int8) int8 {
res := val
for _, v := range vals {
if v < res {
res = v
}
}
return res
}
// ClampInt8 returns a value restricted between lo and hi.
func ClampInt8(v, lo, hi int8) int8 {
return MinInt8(MaxInt8(v, lo), hi)
}
// MaxUint16 returns the larger of a and b.
func MaxUint16(a, b uint16) uint16 {
if a > b {
@@ -703,6 +818,33 @@ func MinUint16(a, b uint16) uint16 {
return b
}
// MaxUint16Val returns the largest argument passed.
func MaxUint16Val(val uint16, vals ...uint16) uint16 {
res := val
for _, v := range vals {
if v > res {
res = v
}
}
return res
}
// MinUint16Val returns the smallest argument passed.
func MinUint16Val(val uint16, vals ...uint16) uint16 {
res := val
for _, v := range vals {
if v < res {
res = v
}
}
return res
}
// ClampUint16 returns a value restricted between lo and hi.
func ClampUint16(v, lo, hi uint16) uint16 {
return MinUint16(MaxUint16(v, lo), hi)
}
// MaxInt16 returns the larger of a and b.
func MaxInt16(a, b int16) int16 {
if a > b {
@@ -721,6 +863,33 @@ func MinInt16(a, b int16) int16 {
return b
}
// MaxInt16Val returns the largest argument passed.
func MaxInt16Val(val int16, vals ...int16) int16 {
res := val
for _, v := range vals {
if v > res {
res = v
}
}
return res
}
// MinInt16Val returns the smallest argument passed.
func MinInt16Val(val int16, vals ...int16) int16 {
res := val
for _, v := range vals {
if v < res {
res = v
}
}
return res
}
// ClampInt16 returns a value restricted between lo and hi.
func ClampInt16(v, lo, hi int16) int16 {
return MinInt16(MaxInt16(v, lo), hi)
}
// MaxUint32 returns the larger of a and b.
func MaxUint32(a, b uint32) uint32 {
if a > b {
@@ -739,6 +908,33 @@ func MinUint32(a, b uint32) uint32 {
return b
}
// MaxUint32Val returns the largest argument passed.
func MaxUint32Val(val uint32, vals ...uint32) uint32 {
res := val
for _, v := range vals {
if v > res {
res = v
}
}
return res
}
// MinUint32Val returns the smallest argument passed.
func MinUint32Val(val uint32, vals ...uint32) uint32 {
res := val
for _, v := range vals {
if v < res {
res = v
}
}
return res
}
// ClampUint32 returns a value restricted between lo and hi.
func ClampUint32(v, lo, hi uint32) uint32 {
return MinUint32(MaxUint32(v, lo), hi)
}
// MaxInt32 returns the larger of a and b.
func MaxInt32(a, b int32) int32 {
if a > b {
@@ -757,6 +953,33 @@ func MinInt32(a, b int32) int32 {
return b
}
// MaxInt32Val returns the largest argument passed.
func MaxInt32Val(val int32, vals ...int32) int32 {
res := val
for _, v := range vals {
if v > res {
res = v
}
}
return res
}
// MinInt32Val returns the smallest argument passed.
func MinInt32Val(val int32, vals ...int32) int32 {
res := val
for _, v := range vals {
if v < res {
res = v
}
}
return res
}
// ClampInt32 returns a value restricted between lo and hi.
func ClampInt32(v, lo, hi int32) int32 {
return MinInt32(MaxInt32(v, lo), hi)
}
// MaxUint64 returns the larger of a and b.
func MaxUint64(a, b uint64) uint64 {
if a > b {
@@ -775,6 +998,33 @@ func MinUint64(a, b uint64) uint64 {
return b
}
// MaxUint64Val returns the largest argument passed.
func MaxUint64Val(val uint64, vals ...uint64) uint64 {
res := val
for _, v := range vals {
if v > res {
res = v
}
}
return res
}
// MinUint64Val returns the smallest argument passed.
func MinUint64Val(val uint64, vals ...uint64) uint64 {
res := val
for _, v := range vals {
if v < res {
res = v
}
}
return res
}
// ClampUint64 returns a value restricted between lo and hi.
func ClampUint64(v, lo, hi uint64) uint64 {
return MinUint64(MaxUint64(v, lo), hi)
}
// MaxInt64 returns the larger of a and b.
func MaxInt64(a, b int64) int64 {
if a > b {
@@ -793,6 +1043,33 @@ func MinInt64(a, b int64) int64 {
return b
}
// MaxInt64Val returns the largest argument passed.
func MaxInt64Val(val int64, vals ...int64) int64 {
res := val
for _, v := range vals {
if v > res {
res = v
}
}
return res
}
// MinInt64Val returns the smallest argument passed.
func MinInt64Val(val int64, vals ...int64) int64 {
res := val
for _, v := range vals {
if v < res {
res = v
}
}
return res
}
// ClampInt64 returns a value restricted between lo and hi.
func ClampInt64(v, lo, hi int64) int64 {
return MinInt64(MaxInt64(v, lo), hi)
}
// ToBase produces n in base b. For example
//
// ToBase(2047, 22) -> [1, 5, 4]
+1 -1
View File
@@ -146,7 +146,7 @@ It is conjectured that every odd d ∊ N divides infinitely many Mersenne number
The returned n should be the exponent of smallest such Mn.
NOTE: The computation of n from a given d performs roughly in O(n). It is
thus highly recomended to use the 'max' argument to limit the "searched"
thus highly recommended to use the 'max' argument to limit the "searched"
exponent upper bound as appropriate. Otherwise the computation can take a long
time as a large factor can be a divisor of a Mn with exponent above the uint32
limits.
-2
View File
@@ -270,7 +270,6 @@ func (t *tree) extract(q *d, i int) { // (r []interface{}) {
}
q.d[q.c] = zde // GC
t.c--
return
}
func (t *tree) find(q interface{}, k []interface{}) (i int, ok bool) {
@@ -491,7 +490,6 @@ func (t *tree) Set(k []interface{}, v []interface{}) {
z := t.insert(&d{}, 0, k, v)
t.r, t.first, t.last = z, z, z
return
}
func (t *tree) split(p *x, q *d, pi, i int, k []interface{}, v []interface{}) {
+21
View File
@@ -53,6 +53,7 @@ var builtin = map[string]struct {
"second": {builtinSecond, 1, 1, true, false},
"seconds": {builtinSeconds, 1, 1, true, false},
"since": {builtinSince, 1, 1, false, false},
"sleep": {builtinSleep, 1, 1, false, false},
"sum": {builtinSum, 1, 1, false, true},
"timeIn": {builtinTimeIn, 2, 2, true, false},
"weekday": {builtinWeekday, 1, 1, true, false},
@@ -873,6 +874,26 @@ func builtinSince(arg []interface{}, ctx map[interface{}]interface{}) (v interfa
}
}
func builtinSleep(arg []interface{}, ctx map[interface{}]interface{}) (v interface{}, err error) {
switch x := arg[0].(type) {
case nil:
return nil, nil
case time.Duration:
time.Sleep(x)
return nil, nil
case idealInt:
v := time.Second * time.Duration(int64(x))
time.Sleep(v)
return nil, nil
case int64:
v := time.Second * time.Duration(x)
time.Sleep(v)
return nil, nil
default:
return nil, invArg(x, "sleep")
}
}
func builtinSum(arg []interface{}, ctx map[interface{}]interface{}) (v interface{}, err error) {
if _, ok := ctx["$agg0"]; ok {
return
+16 -5
View File
@@ -213,12 +213,14 @@
// newline = . // the Unicode code point U+000A
// unicode_char = . // an arbitrary Unicode code point except newline
// ascii_letter = "a" … "z" | "A" … "Z" .
// unicode_letter = . // Unicode category L.
// unicode_digit = . // Unocode category D.
//
// Letters and digits
//
// The underscore character _ (U+005F) is considered a letter.
//
// letter = ascii_letter | "_" .
// letter = ascii_letter | unicode_letter | "_" .
// decimal_digit = "0" … "9" .
// octal_digit = "0" … "7" .
// hex_digit = "0" … "9" | "A" … "F" | "a" … "f" .
@@ -262,7 +264,7 @@
// identifier is a sequence of one or more letters and digits. The first
// character in an identifier must be a letter.
//
// identifier = letter { letter | decimal_digit } .
// identifier = letter { letter | decimal_digit | unicode_digit } .
//
// For example
//
@@ -1089,7 +1091,7 @@
//
// - Rational values are comparable and ordered, in the usual way.
//
// - String values are comparable and ordered, lexically byte-wise.
// - String and Blob values are comparable and ordered, lexically byte-wise.
//
// - Time values are comparable and ordered.
//
@@ -1738,7 +1740,7 @@
// The result can be filtered using a WhereClause and orderd by the OrderBy
// clause.
//
// SelectStmt = "SELECT" [ "DISTINCT" ] ( "*" | FieldList ) "FROM" RecordSetList
// SelectStmt = "SELECT" [ "DISTINCT" ] ( "*" | FieldList ) [ "FROM" RecordSetList ]
// [ JoinClause ] [ WhereClause ] [ GroupByClause ] [ OrderBy ] [ Limit ] [ Offset ].
//
// JoinClause = ( "LEFT" | "RIGHT" | "FULL" ) [ "OUTER" ] "JOIN" RecordSet "ON" Expression .
@@ -1878,7 +1880,16 @@
// It is an error if the expression evaluates to a non null value of non bool
// type.
//
// WhereClause = "WHERE" Expression .
// Another form of the WHERE clause is an existence predicate of a
// parenthesized select statement. The EXISTS form evaluates to true if the
// parenthesized SELECT statement produces a non empty record set. The NOT
// EXISTS form evaluates to true if the parenthesized SELECT statement produces
// an empty record set. The parenthesized SELECT statement is evaluated only
// once (TODO issue #159).
//
// WhereClause = "WHERE" Expression
// | "WHERE" "EXISTS" "(" SelectStmt ")"
// | "WHERE" "NOT" "EXISTS" "(" SelectStmt ")" .
//
// Recordset grouping
//
+44 -4
View File
@@ -375,10 +375,8 @@ func driverQuery(db *driverDB, ctx *TCtx, list List, args []driver.Value) (drive
switch n := len(rss); n {
case 0:
return nil, errNoResult
case 1:
return newdriverRows(rss[len(rss)-1]), nil
default:
return nil, fmt.Errorf("query produced %d result sets, expected only one", n)
return newDriverMultiRows(rss), nil
}
}
@@ -469,7 +467,7 @@ func (r *driverRows) Next(dest []driver.Value) error {
switch v := xi.(type) {
case nil, int64, float64, bool, []byte, time.Time:
dest[i] = v
case complex64, complex128, *big.Int, *big.Rat:
case complex64, complex128, *big.Int, *big.Rat, idealComplex:
var buf bytes.Buffer
fmt.Fprintf(&buf, "%v", v)
dest[i] = buf.Bytes()
@@ -495,6 +493,12 @@ func (r *driverRows) Next(dest []driver.Value) error {
dest[i] = int64(v)
case string:
dest[i] = []byte(v)
case idealInt:
dest[i] = int64(v)
case idealUint:
dest[i] = int64(v)
case idealFloat:
dest[i] = float64(v)
default:
return fmt.Errorf("internal error 004")
}
@@ -508,6 +512,42 @@ func (r *driverRows) Next(dest []driver.Value) error {
}
}
type driverMultiRows struct {
rs []Recordset
pos int
active *driverRows
}
func newDriverMultiRows(rs []Recordset) *driverMultiRows {
return &driverMultiRows{
rs: rs,
active: newdriverRows(rs[0]),
}
}
func (r *driverMultiRows) Columns() []string {
return r.active.Columns()
}
func (r *driverMultiRows) Close() error {
return r.active.Close()
}
func (r *driverMultiRows) HasNextResultSet() bool {
return r.pos+1 < len(r.rs)
}
func (r *driverMultiRows) NextResultSet() error {
if r.HasNextResultSet() {
r.active.Close()
r.pos++
r.active = newdriverRows(r.rs[r.pos])
return nil
}
return io.EOF
}
func (r *driverMultiRows) Next(dest []driver.Value) error {
return r.active.Next(dest)
}
// driverStmt is a prepared statement. It is bound to a driverConn and not used
// by multiple goroutines concurrently.
type driverStmt struct {
+140
View File
@@ -0,0 +1,140 @@
// +build go1.8
package ql
import (
"context"
"database/sql/driver"
"fmt"
"strconv"
"strings"
)
const prefix = "$"
func (c *driverConn) ExecContext(ctx context.Context, query string, args []driver.NamedValue) (driver.Result, error) {
query, vals, err := replaceNamed(query, args)
if err != nil {
return nil, err
}
return c.Exec(query, vals)
}
func replaceNamed(query string, args []driver.NamedValue) (string, []driver.Value, error) {
toks, err := tokenize(query)
if err != nil {
return "", nil, err
}
a := make([]driver.Value, len(args))
m := map[string]int{}
for _, v := range args {
m[v.Name] = v.Ordinal
a[v.Ordinal-1] = v.Value
}
for i, v := range toks {
if len(v) > 1 && strings.HasPrefix(v, prefix) {
if v[1] >= '1' && v[1] <= '9' {
continue
}
nm := v[1:]
k, ok := m[nm]
if !ok {
return query, nil, fmt.Errorf("unknown named parameter %s", nm)
}
toks[i] = fmt.Sprintf("$%d", k)
}
}
return strings.Join(toks, " "), a, nil
}
func (c *driverConn) QueryContext(ctx context.Context, query string, args []driver.NamedValue) (driver.Rows, error) {
query, vals, err := replaceNamed(query, args)
if err != nil {
return nil, err
}
return c.Query(query, vals)
}
func (c *driverConn) PrepareContext(ctx context.Context, query string) (driver.Stmt, error) {
query, err := filterNamedArgs(query)
if err != nil {
return nil, err
}
return c.Prepare(query)
}
func filterNamedArgs(query string) (string, error) {
toks, err := tokenize(query)
if err != nil {
return "", err
}
n := 0
for _, v := range toks {
if len(v) > 1 && strings.HasPrefix(v, prefix) && v[1] >= '1' && v[1] <= '9' {
m, err := strconv.ParseUint(v[1:], 10, 31)
if err != nil {
return "", err
}
if int(m) > n {
n = int(m)
}
}
}
for i, v := range toks {
if len(v) > 1 && strings.HasPrefix(v, prefix) {
if v[1] >= '1' && v[1] <= '9' {
continue
}
n++
toks[i] = fmt.Sprintf("$%d", n)
}
}
return strings.Join(toks, " "), nil
}
func (s *driverStmt) ExecContext(ctx context.Context, args []driver.NamedValue) (driver.Result, error) {
a := make([]driver.Value, len(args))
for k, v := range args {
a[k] = v.Value
}
return s.Exec(a)
}
func (s *driverStmt) QueryContext(ctx context.Context, args []driver.NamedValue) (driver.Rows, error) {
a := make([]driver.Value, len(args))
for k, v := range args {
a[k] = v.Value
}
return s.Query(a)
}
func tokenize(s string) (r []string, _ error) {
lx, err := newLexer(s)
if err != nil {
return nil, err
}
var lval yySymType
for lx.Lex(&lval) != 0 {
s := string(lx.TokenBytes(nil))
if s != "" {
switch s[len(s)-1] {
case '"':
s = "\"" + s
case '`':
s = "`" + s
}
}
r = append(r, s)
}
return r, nil
}
+43
View File
@@ -5,6 +5,7 @@
package ql
import (
"bytes"
"fmt"
"math/big"
"regexp"
@@ -779,6 +780,13 @@ func (o *binaryOperation) eval(execCtx *execCtx, ctx map[interface{}]interface{}
default:
return invOp2(x, y, op)
}
case []byte:
switch y := b.(type) {
case []byte:
return bytes.Equal(x, y), nil
default:
return invOp2(x, y, op)
}
default:
return invOp2(a, b, op)
}
@@ -930,6 +938,13 @@ func (o *binaryOperation) eval(execCtx *execCtx, ctx map[interface{}]interface{}
default:
return invOp2(x, y, op)
}
case []byte:
switch y := b.(type) {
case []byte:
return bytes.Compare(x, y) < 0, nil
default:
return invOp2(x, y, op)
}
default:
return invOp2(a, b, op)
}
@@ -1081,6 +1096,13 @@ func (o *binaryOperation) eval(execCtx *execCtx, ctx map[interface{}]interface{}
default:
return invOp2(x, y, op)
}
case []byte:
switch y := b.(type) {
case []byte:
return bytes.Compare(x, y) <= 0, nil
default:
return invOp2(x, y, op)
}
default:
return invOp2(a, b, op)
}
@@ -1232,6 +1254,13 @@ func (o *binaryOperation) eval(execCtx *execCtx, ctx map[interface{}]interface{}
default:
return invOp2(x, y, op)
}
case []byte:
switch y := b.(type) {
case []byte:
return bytes.Compare(x, y) >= 0, nil
default:
return invOp2(x, y, op)
}
default:
return invOp2(a, b, op)
}
@@ -1403,6 +1432,13 @@ func (o *binaryOperation) eval(execCtx *execCtx, ctx map[interface{}]interface{}
default:
return invOp2(x, y, op)
}
case []byte:
switch y := b.(type) {
case []byte:
return !bytes.Equal(x, y), nil
default:
return invOp2(x, y, op)
}
default:
return invOp2(a, b, op)
}
@@ -1574,6 +1610,13 @@ func (o *binaryOperation) eval(execCtx *execCtx, ctx map[interface{}]interface{}
default:
return invOp2(x, y, op)
}
case []byte:
switch y := b.(type) {
case []byte:
return bytes.Equal(x, y), nil
default:
return invOp2(x, y, op)
}
default:
return invOp2(a, b, op)
}
+154
View File
@@ -0,0 +1,154 @@
// Copyright 2017 The ql Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package ql
import (
"fmt"
"go/scanner"
"go/token"
"math"
"strconv"
"strings"
"unicode"
"github.com/cznic/golex/lex"
)
const (
ccEOF = iota + 0x80
ccLetter
ccDigit
ccOther
)
func runeClass(r rune) int {
switch {
case r == lex.RuneEOF:
return ccEOF
case r < 0x80:
return int(r)
case unicode.IsLetter(r):
return ccLetter
case unicode.IsDigit(r):
return ccDigit
default:
return ccOther
}
}
type lexer struct {
*lex.Lexer
agg []bool
col int
errs scanner.ErrorList
expr expression
file *token.File
inj int
line int
list []stmt
params int
root bool
sc int
}
func newLexer(src string) (*lexer, error) {
fset := token.NewFileSet()
file := fset.AddFile("", -1, len(src))
l := &lexer{
file: file,
}
l0, err := lex.New(
file,
strings.NewReader(src),
lex.ErrorFunc(func(pos token.Pos, msg string) {
l.errPos(pos, msg)
}),
lex.RuneClass(runeClass),
lex.BOMMode(lex.BOMIgnoreFirst),
)
if err != nil {
return nil, err
}
l.Lexer = l0
return l, nil
}
func (l *lexer) errPos(pos token.Pos, format string, arg ...interface{}) {
l.errs.Add(l.file.Position(pos), fmt.Sprintf(format, arg...))
}
func (l *lexer) err(s string, arg ...interface{}) {
l.errPos(l.Last.Pos(), s, arg...)
}
// Implements yyLexer.
func (l *lexer) Error(s string) {
l.err(s)
}
func (l *lexer) int(lval *yySymType, im bool) int {
val := l.TokenBytes(nil)
if im {
val = val[:len(val)-1]
}
n, err := strconv.ParseUint(string(val), 0, 64)
if err != nil {
l.err("integer literal: %v", err)
return int(unicode.ReplacementChar)
}
if im {
lval.item = idealComplex(complex(0, float64(n)))
return imaginaryLit
}
switch {
case n < math.MaxInt64:
lval.item = idealInt(n)
default:
lval.item = idealUint(n)
}
return intLit
}
func (l *lexer) float(lval *yySymType, im bool) int {
val := l.TokenBytes(nil)
if im {
val = val[:len(val)-1]
}
n, err := strconv.ParseFloat(string(val), 64)
if err != nil {
l.err("float literal: %v", err)
return int(unicode.ReplacementChar)
}
if im {
lval.item = idealComplex(complex(0, n))
return imaginaryLit
}
lval.item = idealFloat(n)
return floatLit
}
func (l *lexer) str(lval *yySymType, pref string) int {
val := l.TokenBytes(nil)
l.sc = 0
s := pref + string(val)
s, err := strconv.Unquote(s)
if err != nil {
l.err("string literal: %v", err)
return int(unicode.ReplacementChar)
}
lval.item = s
return stringLit
}
func (l *lexer) npos() (line, col int) {
pos := l.file.Position(l.Last.Pos())
return pos.Line, pos.Column
}
+8 -3
View File
@@ -11,6 +11,7 @@ import (
"fmt"
"io"
"math/big"
"sync"
"time"
)
@@ -247,6 +248,7 @@ type mem struct {
recycler []int
tnl int
rollback *undos
mu sync.RWMutex
}
func newMemStorage() (s *mem, err error) {
@@ -278,10 +280,13 @@ func (s *mem) newUndo(tag int, h int64, data []interface{}) {
func (s *mem) Acid() bool { return false }
func (s *mem) Close() (err error) {
s.mu.Lock()
defer s.mu.Unlock()
if s.tnl != 0 {
return fmt.Errorf("cannot close DB while open transaction exist")
}
*s = mem{}
s.data, s.recycler, s.rollback = nil, nil, nil
s.id, s.tnl = 0, 0
return
}
@@ -453,6 +458,8 @@ func (s *mem) Create(data ...interface{}) (h int64, err error) {
}
func (s *mem) Read(dst []interface{}, h int64, cols ...*col) (data []interface{}, err error) {
s.mu.RLock()
defer s.mu.RUnlock()
if i := int(h); i != 0 && i < len(s.data) {
d := s.clone(s.data[h]...)
if cols == nil {
@@ -822,7 +829,6 @@ func (t *xtree) extract(q *xd, i int) { // (r int64) {
}
q.xd[q.c] = zxde // GC
t.c--
return
}
func (t *xtree) find(q interface{}, k indexKey) (i int, ok bool) {
@@ -1043,7 +1049,6 @@ func (t *xtree) Set(k indexKey, v int) {
z := t.insert(&xd{}, 0, k, v)
t.r, t.first, t.last = z, z, z
return
}
func (t *xtree) split(p *xx, q *xd, pi, i int, k indexKey, v int) {
+1053 -1006
View File
File diff suppressed because it is too large Load Diff
+32 -3
View File
@@ -49,6 +49,7 @@ var (
_ plan = (*selectFieldsDefaultPlan)(nil)
_ plan = (*selectFieldsGroupPlan)(nil)
_ plan = (*selectIndexDefaultPlan)(nil)
_ plan = (*selectDummyPlan)(nil)
_ plan = (*sysColumnDefaultPlan)(nil)
_ plan = (*sysIndexDefaultPlan)(nil)
_ plan = (*sysTableDefaultPlan)(nil)
@@ -1379,9 +1380,7 @@ func (r *explainDefaultPlan) do(ctx *execCtx, f func(id interface{}, data []inte
return nil
}
func (r *explainDefaultPlan) explain(w strutil.Formatter) {
return
}
func (r *explainDefaultPlan) explain(w strutil.Formatter) {}
func (r *explainDefaultPlan) fieldNames() []string {
return []string{""}
@@ -2798,3 +2797,33 @@ func (r *fullJoinDefaultPlan) do(ctx *execCtx, f func(id interface{}, data []int
}
}
}
type selectDummyPlan struct {
flds []*fld
}
func (r *selectDummyPlan) hasID() bool { return true }
func (r *selectDummyPlan) explain(w strutil.Formatter) {
w.Format("┌Selects values from dummy table\n└Output field names %v\n", qnames(r.fieldNames()))
}
func (r *selectDummyPlan) fieldNames() []string { return make([]string, len(r.flds)) }
func (r *selectDummyPlan) filter(expr expression) (plan, []string, error) {
return nil, nil, nil
}
func (r *selectDummyPlan) do(ctx *execCtx, f func(id interface{}, data []interface{}) (bool, error)) (err error) {
m := map[interface{}]interface{}{}
data := []interface{}{}
for _, v := range r.flds {
rst, err := v.expr.eval(ctx, m)
if err != nil {
return err
}
data = append(data, rst)
}
_, err = f(nil, data)
return
}
+100 -24
View File
@@ -330,8 +330,21 @@ func (r *orderByRset) plan(ctx *execCtx) (plan, error) {
}
type whereRset struct {
expr expression
src plan
expr expression
src plan
sel *selectStmt
exists bool
}
func (r *whereRset) String() string {
if r.sel != nil {
s := ""
if !r.exists {
s += " NOT "
}
return fmt.Sprintf("%s EXISTS ( %s )", s, strings.TrimSuffix(r.sel.String(), ";"))
}
return r.expr.String()
}
func (r *whereRset) planBinOp(x *binaryOperation) (plan, error) {
@@ -514,6 +527,44 @@ func (r *whereRset) planUnaryOp(x *unaryOperation) (plan, error) {
}
func (r *whereRset) plan(ctx *execCtx) (plan, error) {
o := r.src
if r.sel != nil {
var exists bool
ctx.mu.RLock()
m, ok := ctx.cache[r.sel]
ctx.mu.RUnlock()
if ok {
exists = m.(bool)
} else {
p, err := r.sel.plan(ctx)
if err != nil {
return nil, err
}
err = p.do(ctx, func(i interface{}, data []interface{}) (bool, error) {
if len(data) > 0 {
exists = true
}
return false, nil
})
if err != nil {
return nil, err
}
ctx.mu.Lock()
ctx.cache[r.sel] = true
ctx.mu.Unlock()
}
if r.exists == exists {
return o, nil
}
return &nullPlan{fields: o.fieldNames()}, nil
}
return r.planExpr(ctx)
}
func (r *whereRset) planExpr(ctx *execCtx) (plan, error) {
if r.expr == nil {
return &nullPlan{}, nil
}
expr, err := r.expr.clone(ctx.arg)
if err != nil {
return nil, err
@@ -567,6 +618,10 @@ type selectRset struct {
}
func (r *selectRset) plan(ctx *execCtx) (plan, error) {
if r.src == nil {
return nil, nil
}
var flds2 []*fld
if len(r.flds) != 0 {
m := map[string]struct{}{}
@@ -703,8 +758,7 @@ func findCol(cols []*col, name string) (c *col) {
}
func (f *col) clone() *col {
var r col
r = *f
r := *f
r.constraint = f.constraint.clone()
if f.dflt != nil {
r.dflt, _ = r.dflt.clone(nil)
@@ -795,7 +849,7 @@ func newDB(store storage) (db *DB, err error) {
return
}
ctx := &execCtx{db: db0}
ctx := newExecCtx(db0, nil)
for _, t := range db0.root.tables {
if err := t.constraintsAndDefaults(ctx); err != nil {
return nil, err
@@ -893,7 +947,7 @@ func newDB(store storage) (db *DB, err error) {
func (db *DB) deleteIndex2ByIndexName(nm string) error {
for _, s := range deleteIndex2ByIndexName.l {
if _, err := s.exec(&execCtx{db: db, arg: []interface{}{nm}}); err != nil {
if _, err := s.exec(newExecCtx(db, []interface{}{nm})); err != nil {
return err
}
}
@@ -902,7 +956,7 @@ func (db *DB) deleteIndex2ByIndexName(nm string) error {
func (db *DB) deleteIndex2ByTableName(nm string) error {
for _, s := range deleteIndex2ByTableName.l {
if _, err := s.exec(&execCtx{db: db, arg: []interface{}{nm}}); err != nil {
if _, err := s.exec(newExecCtx(db, []interface{}{nm})); err != nil {
return err
}
}
@@ -931,7 +985,7 @@ func (db *DB) createIndex2() error {
expr := "id()"
if i != 0 {
expr = t.cols[i-1].name
expr = t.cols0[i-1].name
}
if err := db.insertIndex2(t.name, index.name, []string{expr}, index.unique, true, index.xroot); err != nil {
@@ -1036,29 +1090,41 @@ func (db *DB) run(ctx *TCtx, ql string, arg ...interface{}) (rs []Recordset, ind
//
// Compile is safe for concurrent use by multiple goroutines.
func Compile(src string) (List, error) {
l := newLexer(src)
l, err := newLexer(src)
if err != nil {
return List{}, err
}
if yyParse(l) != 0 {
return List{}, l.errs[0]
return List{}, l.errs
}
return List{l.list, l.params}, nil
}
func compileExpr(src string) (expression, error) {
l := newLexer(src)
l, err := newLexer(src)
if err != nil {
return nil, err
}
l.inj = parseExpression
if yyParse(l) != 0 {
return nil, l.errs[0]
return nil, l.errs
}
return l.expr, nil
}
func compile(src string) (List, error) {
l := newLexer(src)
l, err := newLexer(src)
if err != nil {
return List{}, err
}
l.root = true
if yyParse(l) != 0 {
return List{}, l.errs[0]
return List{}, l.errs
}
return List{l.list, l.params}, nil
@@ -1263,7 +1329,7 @@ func (db *DB) run1(pc *TCtx, s stmt, arg ...interface{}) (rs Recordset, tnla, tn
db.rwmu.RLock() // can safely grab before Unlock
db.muUnlock()
defer db.rwmu.RUnlock()
rs, err = s.exec(&execCtx{db, arg}) // R/O tctx
rs, err = s.exec(newExecCtx(db, arg)) // R/O tctx
return rs, tnla, tnlb, err
}
default: // case true:
@@ -1345,7 +1411,7 @@ func (db *DB) run1(pc *TCtx, s stmt, arg ...interface{}) (rs Recordset, tnla, tn
db.muUnlock() // must Unlock before RLock
db.rwmu.RLock()
defer db.rwmu.RUnlock()
rs, err = s.exec(&execCtx{db, arg})
rs, err = s.exec(newExecCtx(db, arg))
return rs, tnla, tnlb, err
}
@@ -1355,7 +1421,7 @@ func (db *DB) run1(pc *TCtx, s stmt, arg ...interface{}) (rs Recordset, tnla, tn
return nil, tnla, tnlb, fmt.Errorf("invalid passed transaction context")
}
rs, err = s.exec(&execCtx{db, arg})
rs, err = s.exec(newExecCtx(db, arg))
return rs, tnla, tnlb, err
}
}
@@ -1523,13 +1589,13 @@ func (db *DB) info() (r *DbInfo, err error) {
ti := TableInfo{Name: nm}
m := map[string]*ColumnInfo{}
if hasColumn2 {
rs, err := selectColumn2.l[0].exec(&execCtx{db: db, arg: []interface{}{nm}})
rs, err := selectColumn2.l[0].exec(newExecCtx(db, []interface{}{nm}))
if err != nil {
return nil, err
}
if err := rs.(recordset).do(
&execCtx{db: db, arg: []interface{}{nm}},
newExecCtx(db, []interface{}{nm}),
func(id interface{}, data []interface{}) (bool, error) {
ci := &ColumnInfo{NotNull: data[1].(bool), Constraint: data[2].(string), Default: data[3].(string)}
m[data[0].(string)] = ci
@@ -1609,7 +1675,15 @@ type joinRset struct {
on expression
}
func (r *joinRset) isZero() bool {
return len(r.sources) == 0 && r.typ == 0 && r.on == nil
}
func (r *joinRset) String() string {
if r.isZero() {
return ""
}
a := make([]string, len(r.sources))
for i, pair0 := range r.sources {
pair := pair0.([]interface{})
@@ -1652,6 +1726,9 @@ func (r *joinRset) String() string {
}
func (r *joinRset) plan(ctx *execCtx) (plan, error) {
if r.isZero() {
return nil, nil
}
rsets := make([]plan, len(r.sources))
names := make([]string, len(r.sources))
var err error
@@ -1699,19 +1776,18 @@ func (r *joinRset) plan(ctx *execCtx) (plan, error) {
if f != "" && nm != "" {
f = fmt.Sprintf("%s.%s", nm, f)
}
if nm == "" {
f = ""
}
fields = append(fields, f)
}
}
rsets[i] = q
}
if len(rsets) == 1 {
switch len(rsets) {
case 0:
return nil, nil
case 1:
return rsets[0], nil
}
right := len(rsets[len(rsets)-1].fieldNames())
switch r.typ {
case crossJoin:
+156 -38
View File
@@ -58,6 +58,7 @@ import (
"log"
"os"
"regexp"
"runtime"
"sort"
"strings"
"time"
@@ -84,22 +85,66 @@ func main() {
}
}
func do() (err error) {
oDB := flag.String("db", "ql.db", "The DB file to open. It'll be created if missing.")
oFlds := flag.Bool("fld", false, "Show recordset's field names.")
oSchema := flag.String("schema", "", "If non empty, show the CREATE statements of matching tables and exit.")
oTables := flag.String("tables", "", "If non empty, list matching table names and exit.")
oTime := flag.Bool("t", false, "Measure and report time to execute the statement(s) including DB create/open/close.")
type config struct {
db string
flds bool
schema string
tables string
time bool
help bool
interactive bool
}
func (c *config) parse() {
db := flag.String("db", "ql.db", "The DB file to open. It'll be created if missing.")
flds := flag.Bool("fld", false, "Show recordset's field names.")
schema := flag.String("schema", "", "If non empty, show the CREATE statements of matching tables and exit.")
tables := flag.String("tables", "", "If non empty, list matching table names and exit.")
time := flag.Bool("t", false, "Measure and report time to execute the statement(s) including DB create/open/close.")
help := flag.Bool("h", false, "Shows this help text.")
interactive := flag.Bool("i", false, "runs in interactive mode")
flag.Parse()
c.flds = *flds
c.db = *db
c.schema = *schema
c.tables = *tables
c.time = *time
c.help = *help
c.interactive = *interactive
}
t0 := time.Now()
if *oTime {
defer func() {
fmt.Fprintf(os.Stderr, "%s\n", time.Since(t0))
}()
func do() (err error) {
cfg := &config{}
cfg.parse()
if cfg.help {
flag.PrintDefaults()
return nil
}
if flag.NArg() == 0 && !cfg.interactive {
db, err := ql.OpenFile(*oDB, &ql.Options{CanCreate: true})
// Somehow we expect input to the ql tool.
// This will block trying to read input from stdin
b, err := ioutil.ReadAll(os.Stdin)
if err != nil || len(b) == 0 {
flag.PrintDefaults()
return nil
}
db, err := ql.OpenFile(cfg.db, &ql.Options{CanCreate: true})
if err != nil {
return err
}
defer func() {
ec := db.Close()
switch {
case ec != nil && err != nil:
log.Println(ec)
case ec != nil:
err = ec
}
}()
return run(cfg, bufio.NewWriter(os.Stdout), string(b), db)
}
db, err := ql.OpenFile(cfg.db, &ql.Options{CanCreate: true})
if err != nil {
return err
}
@@ -113,8 +158,85 @@ func do() (err error) {
err = ec
}
}()
r := bufio.NewReader(os.Stdin)
o := bufio.NewWriter(os.Stdout)
if cfg.interactive {
for {
o.WriteString("ql> ")
o.Flush()
src, err := readSrc(cfg.interactive, r)
if err != nil {
return err
}
err = run(cfg, o, src, db)
if err != nil {
fmt.Fprintln(o, err)
o.Flush()
}
}
return nil
}
src, err := readSrc(cfg.interactive, r)
if err != nil {
return err
}
return run(cfg, o, src, db)
}
if pat := *oSchema; pat != "" {
func readSrc(i bool, in *bufio.Reader) (string, error) {
if i {
return in.ReadString('\n')
}
var src string
switch n := flag.NArg(); n {
case 0:
b, err := ioutil.ReadAll(in)
if err != nil {
return "", err
}
src = string(b)
default:
a := make([]string, n)
for i := range a {
a[i] = flag.Arg(i)
}
src = strings.Join(a, " ")
}
return src, nil
}
func run(cfg *config, o *bufio.Writer, src string, db *ql.DB) (err error) {
defer o.Flush()
if cfg.interactive {
src = strings.TrimSpace(src)
if strings.HasPrefix(src, "\\") ||
strings.HasPrefix(src, ".") {
switch src {
case "\\clear", ".clear":
switch runtime.GOOS {
case "darwin", "linux":
fmt.Fprintln(o, "\033[H\033[2J")
default:
fmt.Fprintln(o, "clear not supported in this system")
}
return nil
case "\\q", "\\exit", ".q", ".exit":
// we make sure to close the database before exiting
db.Close()
os.Exit(1)
}
}
}
t0 := time.Now()
if cfg.time {
defer func() {
fmt.Fprintf(os.Stderr, "%s\n", time.Since(t0))
}()
}
if pat := cfg.schema; pat != "" {
re, err := regexp.Compile(pat)
if err != nil {
return err
@@ -139,12 +261,12 @@ func do() (err error) {
}
sort.Strings(r)
if len(r) != 0 {
fmt.Println(strings.Join(r, "\n"))
fmt.Fprintln(o, strings.Join(r, "\n"))
}
return nil
}
if pat := *oTables; pat != "" {
if pat := cfg.tables; pat != "" {
re, err := regexp.Compile(pat)
if err != nil {
return err
@@ -165,29 +287,18 @@ func do() (err error) {
}
sort.Strings(r)
if len(r) != 0 {
fmt.Println(strings.Join(r, "\n"))
fmt.Fprintln(o, strings.Join(r, "\n"))
}
return nil
}
var src string
switch n := flag.NArg(); n {
case 0:
b, err := ioutil.ReadAll(bufio.NewReader(os.Stdin))
if err != nil {
return err
}
src = strings.TrimSpace(src)
src = string(b)
default:
a := make([]string, n)
for i := range a {
a[i] = flag.Arg(i)
}
src = strings.Join(a, " ")
commit := "COMMIT;"
if !strings.HasSuffix(src, ";") {
commit = "; " + commit
}
src = "BEGIN TRANSACTION; " + src + "; COMMIT;"
src = "BEGIN TRANSACTION; " + src + commit
l, err := ql.Compile(src)
if err != nil {
log.Println(src)
@@ -206,14 +317,21 @@ func do() (err error) {
switch {
case l.IsExplainStmt():
return rs[len(rs)-1].Do(*oFlds, func(data []interface{}) (bool, error) {
fmt.Println(data[0])
return rs[len(rs)-1].Do(cfg.flds, func(data []interface{}) (bool, error) {
fmt.Fprintln(o, data[0])
return true, nil
})
default:
return rs[len(rs)-1].Do(*oFlds, func(data []interface{}) (bool, error) {
fmt.Println(str(data))
return true, nil
})
for _, rst := range rs {
err = rst.Do(cfg.flds, func(data []interface{}) (bool, error) {
fmt.Fprintln(o, str(data))
return true, nil
})
o.Flush()
if err != nil {
return
}
}
return
}
}
+2764 -2098
View File
File diff suppressed because it is too large Load Diff
+38 -15
View File
@@ -9,6 +9,8 @@ import (
"fmt"
"strings"
"sync"
"github.com/cznic/strutil"
)
@@ -121,8 +123,18 @@ type stmt interface {
}
type execCtx struct { //LATER +shared temp
db *DB
arg []interface{}
db *DB
arg []interface{}
cache map[interface{}]interface{}
mu sync.RWMutex
}
func newExecCtx(db *DB, arg []interface{}) *execCtx {
return &execCtx{
db: db,
arg: arg,
cache: make(map[interface{}]interface{}),
}
}
type explainStmt struct {
@@ -571,7 +583,7 @@ func (s *alterTableDropColumnStmt) exec(ctx *execCtx) (Recordset, error) {
}
if _, ok := ctx.db.root.tables["__Column2"]; ok {
if _, err := deleteColumn2.l[0].exec(&execCtx{db: ctx.db, arg: []interface{}{s.tableName, c.name}}); err != nil {
if _, err := deleteColumn2.l[0].exec(newExecCtx(ctx.db, []interface{}{s.tableName, c.name})); err != nil {
return nil, err
}
}
@@ -680,7 +692,7 @@ func (s *alterTableAddStmt) exec(ctx *execCtx) (Recordset, error) {
if c.constraint != nil || c.dflt != nil {
for _, s := range createColumn2.l {
_, err := s.exec(&execCtx{db: ctx.db})
_, err := s.exec(newExecCtx(ctx.db, nil))
if err != nil {
return nil, err
}
@@ -693,7 +705,7 @@ func (s *alterTableAddStmt) exec(ctx *execCtx) (Recordset, error) {
if e := c.dflt; e != nil {
d = e.String()
}
if _, err := insertColumn2.l[0].exec(&execCtx{db: ctx.db, arg: []interface{}{s.tableName, c.name, notNull, co, d}}); err != nil {
if _, err := insertColumn2.l[0].exec(newExecCtx(ctx.db, []interface{}{s.tableName, c.name, notNull, co, d})); err != nil {
return nil, err
}
}
@@ -750,11 +762,16 @@ func (s *selectStmt) String() string {
}
b.WriteString(" " + strings.Join(a, ", "))
}
b.WriteString(" FROM ")
b.WriteString(s.from.String())
if s.from != nil {
if !s.from.isZero() {
b.WriteString(" FROM ")
b.WriteString(s.from.String())
}
}
if s.where != nil {
b.WriteString(" WHERE ")
b.WriteString(s.where.expr.String())
b.WriteString(s.where.String())
}
if s.group != nil {
b.WriteString(" GROUP BY ")
@@ -777,13 +794,19 @@ func (s *selectStmt) String() string {
}
func (s *selectStmt) plan(ctx *execCtx) (plan, error) { //LATER overlapping goroutines/pipelines
r, err := s.from.plan(ctx)
if err != nil {
return nil, err
var r plan
var err error
if s.from != nil {
r, err = s.from.plan(ctx)
if err != nil {
return nil, err
}
}
if r == nil {
return &selectDummyPlan{flds: s.flds}, nil
}
if w := s.where; w != nil {
if r, err = (&whereRset{expr: w.expr, src: r}).plan(ctx); err != nil {
if r, err = (&whereRset{expr: w.expr, src: r, sel: w.sel, exists: w.exists}).plan(ctx); err != nil {
return nil, err
}
}
@@ -1234,7 +1257,7 @@ func (s *createTableStmt) exec(ctx *execCtx) (_ Recordset, err error) {
if c.constraint != nil || c.dflt != nil {
if mustCreateColumn2 {
for _, stmt := range createColumn2.l {
_, err := stmt.exec(&execCtx{db: ctx.db})
_, err := stmt.exec(newExecCtx(ctx.db, nil))
if err != nil {
return nil, err
}
@@ -1250,7 +1273,7 @@ func (s *createTableStmt) exec(ctx *execCtx) (_ Recordset, err error) {
if e := c.dflt; e != nil {
d = e.String()
}
if _, err := insertColumn2.l[0].exec(&execCtx{db: ctx.db, arg: []interface{}{s.tableName, c.name, notNull, co, d}}); err != nil {
if _, err := insertColumn2.l[0].exec(newExecCtx(ctx.db, []interface{}{s.tableName, c.name, notNull, co, d})); err != nil {
return nil, err
}
}
+8 -4
View File
@@ -153,7 +153,7 @@ func (t *table) constraintsAndDefaults(ctx *execCtx) error {
constraints := make([]*constraint, len(cols))
defaults := make([]expression, len(cols))
arg := []interface{}{t.name}
rs, err := selectColumn2.l[0].exec(&execCtx{db: ctx.db, arg: arg})
rs, err := selectColumn2.l[0].exec(newExecCtx(ctx.db, arg))
if err != nil {
return err
}
@@ -161,7 +161,7 @@ func (t *table) constraintsAndDefaults(ctx *execCtx) error {
var rows [][]interface{}
ok = false
if err := rs.(recordset).do(
&execCtx{db: ctx.db, arg: arg},
newExecCtx(ctx.db, arg),
func(id interface{}, data []interface{}) (more bool, err error) {
rows = append(rows, data)
return true, nil
@@ -330,7 +330,7 @@ func (t *table) findIndexByColName(name string) (*col, *indexedCol) {
continue
}
if c := t.cols[i-1]; c.name == name {
if c := t.cols0[i-1]; c.name == name {
return c, v
}
}
@@ -784,7 +784,11 @@ func (t *table) row(ctx *execCtx, h int64) (int64, []interface{}, error) {
return -1, nil, err
}
return rec[1].(int64), rec[2:], nil
id := rec[1].(int64)
for i, c := range t.cols {
rec[i] = rec[c.index+2]
}
return id, rec[:len(t.cols)], nil
}
// storage fields
+14 -1
View File
@@ -397,7 +397,7 @@ func (d *GoDict) S(id int) (s string, ok bool) {
// to a string slice over an unreferenced biger underlying string keeps the biger one
// in memory anyway - it can't be GCed.
func StrPack(s string) string {
return string([]byte(s))
return string([]byte(s)) // T(U(T)) intentional.
}
// JoinFields returns strings in flds joined by sep. Flds may contain arbitrary
@@ -665,6 +665,19 @@ func Gopath() string {
}
}
// Homepath returns the user's home directory path.
func Homepath() string {
// go1.8: https://github.com/golang/go/blob/74628a8b9f102bddd5078ee426efe0fd57033115/doc/code.html#L122
switch runtime.GOOS {
case "plan9":
return os.Getenv("home")
case "windows":
return os.Getenv("USERPROFILE")
default:
return os.Getenv("HOME")
}
}
// ImportPath returns the import path of the caller or an error, if any.
func ImportPath() (string, error) {
_, file, _, ok := runtime.Caller(1)
+3
View File
@@ -155,6 +155,9 @@ func (d *Diff) diff(aVal, bVal reflect.Value, path Path) bool {
for i := 0; i < typ.NumField(); i++ {
index := []int{i}
field := typ.FieldByIndex(index)
if field.Tag.Get("testdiff") == "ignore" { // skip fields marked to be ignored
continue
}
localPath := append(localPath, StructField(field.Name))
aI := unsafeReflectValue(aVal.FieldByIndex(index))
bI := unsafeReflectValue(bVal.FieldByIndex(index))
-3
View File
@@ -1,3 +0,0 @@
._*
*.js
*.js.map
-8
View File
@@ -1,8 +0,0 @@
Walter Schulze <awalterschulze@gmail.com> Walter Schulze <walter@vastech.co.za>
Walter Schulze <awalterschulze@gmail.com> <walter@vastech.co.za>
Walter Schulze <awalterschulze@gmail.com> awalterschulze <awalterschulze@gmail.com>
Walter Schulze <awalterschulze@gmail.com> awalterschulze@gmail.com <awalterschulze@gmail.com>
John Tuley <john@tuley.org> <jtuley@pivotal.io>
Anton Povarov <anton.povarov@gmail.com> <antoxa@corp.badoo.com>
Denis Smirnov <denis.smirnov.91@gmail.com> dennwc
DongYun Kang <ceram1000@gmail.com> <ceram1000@gmail.com>
-20
View File
@@ -1,20 +0,0 @@
env:
- PROTOBUF_VERSION=2.6.1
- PROTOBUF_VERSION=3.0.2
- PROTOBUF_VERSION=3.3.0
before_install:
- ./install-protobuf.sh
- PATH=/home/travis/bin:$PATH protoc --version
script:
- PATH=/home/travis/bin:$PATH make buildserverall
- echo $TRAVIS_GO_VERSION
- if [ "$TRAVIS_GO_VERSION" == 1.8 ] && [[ "$PROTOBUF_VERSION" == 3.3.0 ]]; then ! git status --porcelain | read || (git status; git diff; exit 1); fi
language: go
go:
- 1.7.1
- 1.8
-14
View File
@@ -1,14 +0,0 @@
# This is the official list of GoGo authors for copyright purposes.
# This file is distinct from the CONTRIBUTORS file, which
# lists people. For example, employees are listed in CONTRIBUTORS,
# but not in AUTHORS, because the employer holds the copyright.
# Names should be added to this file as one of
# Organization's name
# Individual's name <submission email address>
# Individual's name <submission email address> <email2> <emailN>
# Please keep the list sorted.
Vastech SA (PTY) LTD
Walter Schulze <awalterschulze@gmail.com>
-19
View File
@@ -1,19 +0,0 @@
Anton Povarov <anton.povarov@gmail.com>
Brian Goff <cpuguy83@gmail.com>
Clayton Coleman <ccoleman@redhat.com>
Denis Smirnov <denis.smirnov.91@gmail.com>
DongYun Kang <ceram1000@gmail.com>
Dwayne Schultz <dschultz@pivotal.io>
Georg Apitz <gapitz@pivotal.io>
Gustav Paul <gustav.paul@gmail.com>
Johan Brandhorst <johan.brandhorst@gmail.com>
John Shahid <jvshahid@gmail.com>
John Tuley <john@tuley.org>
Laurent <laurent@adyoulike.com>
Patrick Lee <patrick@dropbox.com>
Sergio Arbeo <serabe@gmail.com>
Stephen J Day <stephen.day@docker.com>
Tamir Duberstein <tamird@gmail.com>
Todd Eisenberger <teisenberger@dropbox.com>
Tormod Erevik Lea <tormodlea@gmail.com>
Walter Schulze <awalterschulze@gmail.com>
-5
View File
@@ -1,5 +0,0 @@
The contributors to the Go protobuf repository:
# This source code was written by the Go contributors.
# The master list of contributors is in the main Go distribution,
# visible at http://tip.golang.org/CONTRIBUTORS.
-154
View File
@@ -1,154 +0,0 @@
# Protocol Buffers for Go with Gadgets
#
# Copyright (c) 2013, The GoGo Authors. All rights reserved.
# http://github.com/gogo/protobuf
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following disclaimer
# in the documentation and/or other materials provided with the
# distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
GO_VERSION:=$(shell go version)
.PHONY: nuke regenerate tests clean install gofmt vet contributors
all: clean install regenerate install tests errcheck vet
buildserverall: clean install regenerate install tests vet js
install:
go install ./proto
go install ./gogoproto
go install ./jsonpb
go install ./protoc-gen-gogo
go install ./protoc-gen-gofast
go install ./protoc-gen-gogofast
go install ./protoc-gen-gogofaster
go install ./protoc-gen-gogoslick
go install ./protoc-gen-gostring
go install ./protoc-min-version
go install ./protoc-gen-combo
go install ./gogoreplace
clean:
go clean ./...
nuke:
go clean -i ./...
gofmt:
gofmt -l -s -w .
regenerate:
make -C protoc-gen-gogo/descriptor regenerate
make -C protoc-gen-gogo/plugin regenerate
make -C protoc-gen-gogo/testdata regenerate
make -C gogoproto regenerate
make -C proto/testdata regenerate
make -C jsonpb/jsonpb_test_proto regenerate
make -C _conformance regenerate
make -C types regenerate
make -C test regenerate
make -C test/example regenerate
make -C test/unrecognized regenerate
make -C test/group regenerate
make -C test/unrecognizedgroup regenerate
make -C test/enumstringer regenerate
make -C test/unmarshalmerge regenerate
make -C test/moredefaults regenerate
make -C test/issue8 regenerate
make -C test/enumprefix regenerate
make -C test/enumcustomname regenerate
make -C test/packed regenerate
make -C test/protosize regenerate
make -C test/tags regenerate
make -C test/oneof regenerate
make -C test/oneof3 regenerate
make -C test/theproto3 regenerate
make -C test/mapsproto2 regenerate
make -C test/issue42order regenerate
make -C proto generate-test-pbs
make -C test/importdedup regenerate
make -C test/custombytesnonstruct regenerate
make -C test/required regenerate
make -C test/casttype regenerate
make -C test/castvalue regenerate
make -C vanity/test regenerate
make -C test/sizeunderscore regenerate
make -C test/issue34 regenerate
make -C test/empty-issue70 regenerate
make -C test/indeximport-issue72 regenerate
make -C test/fuzztests regenerate
make -C test/oneofembed regenerate
make -C test/asymetric-issue125 regenerate
make -C test/filedotname regenerate
make -C test/nopackage regenerate
make -C test/types regenerate
make -C test/proto3extension regenerate
make -C test/stdtypes regenerate
make -C test/data regenerate
make -C test/typedecl regenerate
make -C test/issue260 regenerate
make -C test/issue261 regenerate
make -C test/issue262 regenerate
make -C test/enumdecl regenerate
make -C test/typedecl_all regenerate
make -C test/enumdecl_all regenerate
make gofmt
tests:
go build ./test/enumprefix
go test ./...
vet:
go vet ./...
go tool vet --shadow .
errcheck:
go get github.com/kisielk/errcheck
errcheck ./test/...
drone:
sudo apt-get install protobuf-compiler
(cd $(GOPATH)/src/github.com/gogo/protobuf && make buildserverall)
testall:
go get -u github.com/golang/protobuf/proto
make -C protoc-gen-gogo/testdata test
make -C vanity/test test
make -C test/registration test
make tests
bench:
(cd test/mixbench && go build .)
(cd test/mixbench && ./mixbench)
contributors:
git log --format='%aN <%aE>' | sort -fu > CONTRIBUTORS
js:
ifeq (go1.8, $(findstring go1.8, $(GO_VERSION)))
go get github.com/gopherjs/gopherjs
gopherjs build github.com/gogo/protobuf/protoc-gen-gogo
endif
update:
(cd protobuf && make update)
-258
View File
@@ -1,258 +0,0 @@
GoGoProtobuf http://github.com/gogo/protobuf extends
GoProtobuf http://github.com/golang/protobuf
# Go support for Protocol Buffers
Google's data interchange format.
Copyright 2010 The Go Authors.
https://github.com/golang/protobuf
This package and the code it generates requires at least Go 1.4.
This software implements Go bindings for protocol buffers. For
information about protocol buffers themselves, see
https://developers.google.com/protocol-buffers/
## Installation ##
To use this software, you must:
- Install the standard C++ implementation of protocol buffers from
https://developers.google.com/protocol-buffers/
- Of course, install the Go compiler and tools from
https://golang.org/
See
https://golang.org/doc/install
for details or, if you are using gccgo, follow the instructions at
https://golang.org/doc/install/gccgo
- Grab the code from the repository and install the proto package.
The simplest way is to run `go get -u github.com/golang/protobuf/protoc-gen-go`.
The compiler plugin, protoc-gen-go, will be installed in $GOBIN,
defaulting to $GOPATH/bin. It must be in your $PATH for the protocol
compiler, protoc, to find it.
This software has two parts: a 'protocol compiler plugin' that
generates Go source files that, once compiled, can access and manage
protocol buffers; and a library that implements run-time support for
encoding (marshaling), decoding (unmarshaling), and accessing protocol
buffers.
There is support for gRPC in Go using protocol buffers.
See the note at the bottom of this file for details.
There are no insertion points in the plugin.
GoGoProtobuf provides extensions for protocol buffers and GoProtobuf
see http://github.com/gogo/protobuf/gogoproto/doc.go
## Using protocol buffers with Go ##
Once the software is installed, there are two steps to using it.
First you must compile the protocol buffer definitions and then import
them, with the support library, into your program.
To compile the protocol buffer definition, run protoc with the --gogo_out
parameter set to the directory you want to output the Go code to.
protoc --gogo_out=. *.proto
The generated files will be suffixed .pb.go. See the Test code below
for an example using such a file.
The package comment for the proto library contains text describing
the interface provided in Go for protocol buffers. Here is an edited
version.
If you are using any gogo.proto extensions you will need to specify the
proto_path to include the descriptor.proto and gogo.proto.
gogo.proto is located in github.com/gogo/protobuf/gogoproto
This should be fine, since your import is the same.
descriptor.proto is located in either github.com/gogo/protobuf/protobuf
or code.google.com/p/protobuf/trunk/src/
Its import is google/protobuf/descriptor.proto so it might need some help.
protoc --gogo_out=. -I=.:github.com/gogo/protobuf/protobuf *.proto
==========
The proto package converts data structures to and from the
wire format of protocol buffers. It works in concert with the
Go source code generated for .proto files by the protocol compiler.
A summary of the properties of the protocol buffer interface
for a protocol buffer variable v:
- Names are turned from camel_case to CamelCase for export.
- There are no methods on v to set fields; just treat
them as structure fields.
- There are getters that return a field's value if set,
and return the field's default value if unset.
The getters work even if the receiver is a nil message.
- The zero value for a struct is its correct initialization state.
All desired fields must be set before marshaling.
- A Reset() method will restore a protobuf struct to its zero state.
- Non-repeated fields are pointers to the values; nil means unset.
That is, optional or required field int32 f becomes F *int32.
- Repeated fields are slices.
- Helper functions are available to aid the setting of fields.
Helpers for getting values are superseded by the
GetFoo methods and their use is deprecated.
msg.Foo = proto.String("hello") // set field
- Constants are defined to hold the default values of all fields that
have them. They have the form Default_StructName_FieldName.
Because the getter methods handle defaulted values,
direct use of these constants should be rare.
- Enums are given type names and maps from names to values.
Enum values are prefixed with the enum's type name. Enum types have
a String method, and a Enum method to assist in message construction.
- Nested groups and enums have type names prefixed with the name of
the surrounding message type.
- Extensions are given descriptor names that start with E_,
followed by an underscore-delimited list of the nested messages
that contain it (if any) followed by the CamelCased name of the
extension field itself. HasExtension, ClearExtension, GetExtension
and SetExtension are functions for manipulating extensions.
- Oneof field sets are given a single field in their message,
with distinguished wrapper types for each possible field value.
- Marshal and Unmarshal are functions to encode and decode the wire format.
When the .proto file specifies `syntax="proto3"`, there are some differences:
- Non-repeated fields of non-message type are values instead of pointers.
- Getters are only generated for message and oneof fields.
- Enum types do not get an Enum method.
Consider file test.proto, containing
```proto
package example;
enum FOO { X = 17; };
message Test {
required string label = 1;
optional int32 type = 2 [default=77];
repeated int64 reps = 3;
optional group OptionalGroup = 4 {
required string RequiredField = 5;
}
}
```
To create and play with a Test object from the example package,
```go
package main
import (
"log"
"github.com/gogo/protobuf/proto"
"path/to/example"
)
func main() {
test := &example.Test {
Label: proto.String("hello"),
Type: proto.Int32(17),
Reps: []int64{1, 2, 3},
Optionalgroup: &example.Test_OptionalGroup {
RequiredField: proto.String("good bye"),
},
}
data, err := proto.Marshal(test)
if err != nil {
log.Fatal("marshaling error: ", err)
}
newTest := &example.Test{}
err = proto.Unmarshal(data, newTest)
if err != nil {
log.Fatal("unmarshaling error: ", err)
}
// Now test and newTest contain the same data.
if test.GetLabel() != newTest.GetLabel() {
log.Fatalf("data mismatch %q != %q", test.GetLabel(), newTest.GetLabel())
}
// etc.
}
```
## Parameters ##
To pass extra parameters to the plugin, use a comma-separated
parameter list separated from the output directory by a colon:
protoc --gogo_out=plugins=grpc,import_path=mypackage:. *.proto
- `import_prefix=xxx` - a prefix that is added onto the beginning of
all imports. Useful for things like generating protos in a
subdirectory, or regenerating vendored protobufs in-place.
- `import_path=foo/bar` - used as the package if no input files
declare `go_package`. If it contains slashes, everything up to the
rightmost slash is ignored.
- `plugins=plugin1+plugin2` - specifies the list of sub-plugins to
load. The only plugin in this repo is `grpc`.
- `Mfoo/bar.proto=quux/shme` - declares that foo/bar.proto is
associated with Go package quux/shme. This is subject to the
import_prefix parameter.
## gRPC Support ##
If a proto file specifies RPC services, protoc-gen-go can be instructed to
generate code compatible with gRPC (http://www.grpc.io/). To do this, pass
the `plugins` parameter to protoc-gen-go; the usual way is to insert it into
the --go_out argument to protoc:
protoc --gogo_out=plugins=grpc:. *.proto
## Compatibility ##
The library and the generated code are expected to be stable over time.
However, we reserve the right to make breaking changes without notice for the
following reasons:
- Security. A security issue in the specification or implementation may come to
light whose resolution requires breaking compatibility. We reserve the right
to address such security issues.
- Unspecified behavior. There are some aspects of the Protocol Buffers
specification that are undefined. Programs that depend on such unspecified
behavior may break in future releases.
- Specification errors or changes. If it becomes necessary to address an
inconsistency, incompleteness, or change in the Protocol Buffers
specification, resolving the issue could affect the meaning or legality of
existing programs. We reserve the right to address such issues, including
updating the implementations.
- Bugs. If the library has a bug that violates the specification, a program
that depends on the buggy behavior may break if the bug is fixed. We reserve
the right to fix such bugs.
- Adding methods or fields to generated structs. These may conflict with field
names that already exist in a schema, causing applications to break. When the
code generator encounters a field in the schema that would collide with a
generated field or method name, the code generator will append an underscore
to the generated field or method name.
- Adding, removing, or changing methods or fields in generated structs that
start with `XXX`. These parts of the generated code are exported out of
necessity, but should not be considered part of the public API.
- Adding, removing, or changing unexported symbols in generated code.
Any breaking changes outside of these will be announced 6 months in advance to
protobuf@googlegroups.com.
You should, whenever possible, use generated code created by the `protoc-gen-go`
tool built at the same commit as the `proto` package. The `proto` package
declares package-level constants in the form `ProtoPackageIsVersionX`.
Application code and generated code may depend on one of these constants to
ensure that compilation will fail if the available version of the proto library
is too old. Whenever we make a change to the generated code that requires newer
library support, in the same commit we will increment the version number of the
generated code and declare a new package-level constant whose name incorporates
the latest version number. Removing a compatibility constant is considered a
breaking change and would be subject to the announcement policy stated above.
## Plugins ##
The `protoc-gen-go/generator` package exposes a plugin interface,
which is used by the gRPC code generation. This interface is not
supported and is subject to incompatible changes without notice.
-118
View File
@@ -1,118 +0,0 @@
# Protocol Buffers for Go with Gadgets
[![Build Status](https://travis-ci.org/gogo/protobuf.svg?branch=master)](https://travis-ci.org/gogo/protobuf)
gogoprotobuf is a fork of <a href="https://github.com/golang/protobuf">golang/protobuf</a> with extra code generation features.
This code generation is used to achieve:
- fast marshalling and unmarshalling
- more canonical Go structures
- goprotobuf compatibility
- less typing by optionally generating extra helper code
- peace of mind by optionally generating test and benchmark code
- other serialization formats
Keeping track of how up to date gogoprotobuf is relative to golang/protobuf is done in this
<a href="https://github.com/gogo/protobuf/issues/191">issue</a>
## Users
These projects use gogoprotobuf:
- <a href="http://godoc.org/github.com/coreos/etcd">etcd</a> - <a href="https://blog.gopheracademy.com/advent-2015/etcd-distributed-key-value-store-with-grpc-http2/">blog</a> - <a href="https://github.com/coreos/etcd/blob/master/etcdserver/etcdserverpb/etcdserver.proto">sample proto file</a>
- <a href="https://www.spacemonkey.com/">spacemonkey</a> - <a href="https://www.spacemonkey.com/blog/posts/go-space-monkey">blog</a>
- <a href="http://badoo.com">badoo</a> - <a href="https://github.com/badoo/lsd/blob/32061f501c5eca9c76c596d790b450501ba27b2f/proto/lsd.proto">sample proto file</a>
- <a href="https://github.com/mesos/mesos-go">mesos-go</a> - <a href="https://github.com/mesos/mesos-go/blob/f9e5fb7c2f50ab5f23299f26b6b07c5d6afdd252/api/v0/mesosproto/authentication.proto">sample proto file</a>
- <a href="https://github.com/mozilla-services/heka">heka</a> - <a href="https://github.com/mozilla-services/heka/commit/eb72fbf7d2d28249fbaf8d8dc6607f4eb6f03351">the switch from golang/protobuf to gogo/protobuf when it was still on code.google.com</a>
- <a href="https://github.com/cockroachdb/cockroach">cockroachdb</a> - <a href="https://github.com/cockroachdb/cockroach/blob/651d54d393e391a30154e9117ab4b18d9ee6d845/roachpb/metadata.proto">sample proto file</a>
- <a href="https://github.com/jbenet/go-ipfs">go-ipfs</a> - <a href="https://github.com/ipfs/go-ipfs/blob/2b6da0c024f28abeb16947fb452787196a6b56a2/merkledag/pb/merkledag.proto">sample proto file</a>
- <a href="https://github.com/philhofer/rkive">rkive-go</a> - <a href="https://github.com/philhofer/rkive/blob/e5dd884d3ea07b341321073882ae28aa16dd11be/rpbc/riak_dt.proto">sample proto file</a>
- <a href="https://www.dropbox.com">dropbox</a>
- <a href="https://srclib.org/">srclib</a> - <a href="https://github.com/sourcegraph/srclib/blob/6538858f0c410cac5c63440317b8d009e889d3fb/graph/def.proto">sample proto file</a>
- <a href="http://www.adyoulike.com/">adyoulike</a>
- <a href="http://www.cloudfoundry.org/">cloudfoundry</a> - <a href="https://github.com/cloudfoundry/bbs/blob/d673710b8c4211037805129944ee4c5373d6588a/models/events.proto">sample proto file</a>
- <a href="http://kubernetes.io/">kubernetes</a> - <a href="https://github.com/kubernetes/kubernetes/tree/88d8628137f94ee816aaa6606ae8cd045dee0bff/cmd/libs/go2idl">go2idl built on top of gogoprotobuf</a>
- <a href="https://dgraph.io/">dgraph</a> - <a href="https://github.com/dgraph-io/dgraph/releases/tag/v0.4.3">release notes</a> - <a href="https://discuss.dgraph.io/t/gogoprotobuf-is-extremely-fast/639">benchmarks</a></a>
- <a href="https://github.com/centrifugal/centrifugo">centrifugo</a> - <a href="https://forum.golangbridge.org/t/centrifugo-real-time-messaging-websocket-or-sockjs-server-v1-5-0-released/2861">release notes</a> - <a href="https://medium.com/@fzambia/centrifugo-protobuf-inside-json-outside-21d39bdabd68#.o3icmgjqd">blog</a>
- <a href="https://github.com/docker/swarmkit">docker swarmkit</a> - <a href="https://github.com/docker/swarmkit/blob/63600e01af3b8da2a0ed1c9fa6e1ae4299d75edb/api/objects.proto">sample proto file</a>
- <a href="https://nats.io/">nats.io</a> - <a href="https://github.com/nats-io/go-nats-streaming/blob/master/pb/protocol.proto">go-nats-streaming</a>
- <a href="https://github.com/pingcap/tidb">tidb</a> - Communication between <a href="https://github.com/pingcap/tipb/blob/master/generate-go.sh#L4">tidb</a> and <a href="https://github.com/pingcap/kvproto/blob/master/generate_go.sh#L3">tikv</a>
- <a href="https://github.com/AsynkronIT/protoactor-go">protoactor-go</a> - <a href="https://github.com/AsynkronIT/protoactor-go/blob/dev/protobuf/protoc-gen-protoactor/main.go">vanity command</a> that also generates actors from service definitions
- <a href="https://containerd.io/">containerd</a> - <a href="https://github.com/containerd/containerd/tree/master/cmd/protoc-gen-gogoctrd">vanity command with custom field names</a> that conforms to the golang convention.
Please lets us know if you are using gogoprotobuf by posting on our <a href="https://groups.google.com/forum/#!topic/gogoprotobuf/Brw76BxmFpQ">GoogleGroup</a>.
### Mentioned
- <a href="http://www.slideshare.net/albertstrasheim/serialization-in-go">Cloudflare - go serialization talk - Albert Strasheim</a>
- <a href="http://gophercon.sourcegraph.com/post/83747547505/writing-a-high-performance-database-in-go">gophercon</a>
- <a href="https://github.com/alecthomas/go_serialization_benchmarks">alecthomas' go serialization benchmarks</a>
## Getting Started
There are several ways to use gogoprotobuf, but for all you need to install go and protoc.
After that you can choose:
- Speed
- More Speed and more generated code
- Most Speed and most customization
### Installation
To install it, you must first have Go (at least version 1.6.3) installed (see [http://golang.org/doc/install](http://golang.org/doc/install)). Go 1.7.1 and 1.8 are continuously tested.
Next, install the standard protocol buffer implementation from [https://github.com/google/protobuf](https://github.com/google/protobuf).
Most versions from 2.3.1 should not give any problems, but 2.6.1, 3.0.2 and 3.3.0 are continuously tested.
### Speed
Install the protoc-gen-gofast binary
go get github.com/gogo/protobuf/protoc-gen-gofast
Use it to generate faster marshaling and unmarshaling go code for your protocol buffers.
protoc --gofast_out=. myproto.proto
This does not allow you to use any of the other gogoprotobuf [extensions](https://github.com/gogo/protobuf/blob/master/extensions.md).
### More Speed and more generated code
Fields without pointers cause less time in the garbage collector.
More code generation results in more convenient methods.
Other binaries are also included:
protoc-gen-gogofast (same as gofast, but imports gogoprotobuf)
protoc-gen-gogofaster (same as gogofast, without XXX_unrecognized, less pointer fields)
protoc-gen-gogoslick (same as gogofaster, but with generated string, gostring and equal methods)
Installing any of these binaries is easy. Simply run:
go get github.com/gogo/protobuf/proto
go get github.com/gogo/protobuf/{binary}
go get github.com/gogo/protobuf/gogoproto
These binaries allow you to using gogoprotobuf [extensions](https://github.com/gogo/protobuf/blob/master/extensions.md).
### Most Speed and most customization
Customizing the fields of the messages to be the fields that you actually want to use removes the need to copy between the structs you use and structs you use to serialize.
gogoprotobuf also offers more serialization formats and generation of tests and even more methods.
Please visit the [extensions](https://github.com/gogo/protobuf/blob/master/extensions.md) page for more documentation.
Install protoc-gen-gogo:
go get github.com/gogo/protobuf/proto
go get github.com/gogo/protobuf/jsonpb
go get github.com/gogo/protobuf/protoc-gen-gogo
go get github.com/gogo/protobuf/gogoproto
## GRPC
It works the same as golang/protobuf, simply specify the plugin.
Here is an example using gofast:
protoc --gofast_out=plugins=grpc:. my.proto
-40
View File
@@ -1,40 +0,0 @@
# Go support for Protocol Buffers - Google's data interchange format
#
# Copyright 2016 The Go Authors. All rights reserved.
# https://github.com/golang/protobuf
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following disclaimer
# in the documentation and/or other materials provided with the
# distribution.
# * Neither the name of Google Inc. nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
regenerate:
protoc-min-version --version="3.0.0" --proto_path=$(GOPATH)/src:$(GOPATH)/src/github.com/gogo/protobuf/protobuf:. --gogo_out=\
Mgoogle/protobuf/any.proto=github.com/gogo/protobuf/types,\
Mgoogle/protobuf/duration.proto=github.com/gogo/protobuf/types,\
Mgoogle/protobuf/struct.proto=github.com/gogo/protobuf/types,\
Mgoogle/protobuf/timestamp.proto=github.com/gogo/protobuf/types,\
Mgoogle/protobuf/wrappers.proto=github.com/gogo/protobuf/types,\
Mgoogle/protobuf/field_mask.proto=github.com/gogo/protobuf/types\
:. conformance_proto/conformance.proto
-161
View File
@@ -1,161 +0,0 @@
// Go support for Protocol Buffers - Google's data interchange format
//
// Copyright 2016 The Go Authors. All rights reserved.
// https://github.com/golang/protobuf
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// conformance implements the conformance test subprocess protocol as
// documented in conformance.proto.
package main
import (
"encoding/binary"
"fmt"
"io"
"os"
pb "github.com/gogo/protobuf/_conformance/conformance_proto"
"github.com/gogo/protobuf/jsonpb"
"github.com/gogo/protobuf/proto"
)
func main() {
var sizeBuf [4]byte
inbuf := make([]byte, 0, 4096)
outbuf := proto.NewBuffer(nil)
for {
if _, err := io.ReadFull(os.Stdin, sizeBuf[:]); err == io.EOF {
break
} else if err != nil {
fmt.Fprintln(os.Stderr, "go conformance: read request:", err)
os.Exit(1)
}
size := binary.LittleEndian.Uint32(sizeBuf[:])
if int(size) > cap(inbuf) {
inbuf = make([]byte, size)
}
inbuf = inbuf[:size]
if _, err := io.ReadFull(os.Stdin, inbuf); err != nil {
fmt.Fprintln(os.Stderr, "go conformance: read request:", err)
os.Exit(1)
}
req := new(pb.ConformanceRequest)
if err := proto.Unmarshal(inbuf, req); err != nil {
fmt.Fprintln(os.Stderr, "go conformance: parse request:", err)
os.Exit(1)
}
res := handle(req)
if err := outbuf.Marshal(res); err != nil {
fmt.Fprintln(os.Stderr, "go conformance: marshal response:", err)
os.Exit(1)
}
binary.LittleEndian.PutUint32(sizeBuf[:], uint32(len(outbuf.Bytes())))
if _, err := os.Stdout.Write(sizeBuf[:]); err != nil {
fmt.Fprintln(os.Stderr, "go conformance: write response:", err)
os.Exit(1)
}
if _, err := os.Stdout.Write(outbuf.Bytes()); err != nil {
fmt.Fprintln(os.Stderr, "go conformance: write response:", err)
os.Exit(1)
}
outbuf.Reset()
}
}
var jsonMarshaler = jsonpb.Marshaler{
OrigName: true,
}
func handle(req *pb.ConformanceRequest) *pb.ConformanceResponse {
var err error
var msg pb.TestAllTypes
switch p := req.Payload.(type) {
case *pb.ConformanceRequest_ProtobufPayload:
err = proto.Unmarshal(p.ProtobufPayload, &msg)
case *pb.ConformanceRequest_JsonPayload:
err = jsonpb.UnmarshalString(p.JsonPayload, &msg)
if err != nil && err.Error() == "unmarshaling Any not supported yet" {
return &pb.ConformanceResponse{
Result: &pb.ConformanceResponse_Skipped{
Skipped: err.Error(),
},
}
}
default:
return &pb.ConformanceResponse{
Result: &pb.ConformanceResponse_RuntimeError{
RuntimeError: "unknown request payload type",
},
}
}
if err != nil {
return &pb.ConformanceResponse{
Result: &pb.ConformanceResponse_ParseError{
ParseError: err.Error(),
},
}
}
switch req.RequestedOutputFormat {
case pb.WireFormat_PROTOBUF:
p, err := proto.Marshal(&msg)
if err != nil {
return &pb.ConformanceResponse{
Result: &pb.ConformanceResponse_SerializeError{
SerializeError: err.Error(),
},
}
}
return &pb.ConformanceResponse{
Result: &pb.ConformanceResponse_ProtobufPayload{
ProtobufPayload: p,
},
}
case pb.WireFormat_JSON:
p, err := jsonMarshaler.MarshalToString(&msg)
if err != nil {
return &pb.ConformanceResponse{
Result: &pb.ConformanceResponse_SerializeError{
SerializeError: err.Error(),
},
}
}
return &pb.ConformanceResponse{
Result: &pb.ConformanceResponse_JsonPayload{
JsonPayload: p,
},
}
default:
return &pb.ConformanceResponse{
Result: &pb.ConformanceResponse_RuntimeError{
RuntimeError: "unknown output format",
},
}
}
}
File diff suppressed because it is too large Load Diff
@@ -1,285 +0,0 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
syntax = "proto3";
package conformance;
option java_package = "com.google.protobuf.conformance";
import "google/protobuf/any.proto";
import "google/protobuf/duration.proto";
import "google/protobuf/field_mask.proto";
import "google/protobuf/struct.proto";
import "google/protobuf/timestamp.proto";
import "google/protobuf/wrappers.proto";
// This defines the conformance testing protocol. This protocol exists between
// the conformance test suite itself and the code being tested. For each test,
// the suite will send a ConformanceRequest message and expect a
// ConformanceResponse message.
//
// You can either run the tests in two different ways:
//
// 1. in-process (using the interface in conformance_test.h).
//
// 2. as a sub-process communicating over a pipe. Information about how to
// do this is in conformance_test_runner.cc.
//
// Pros/cons of the two approaches:
//
// - running as a sub-process is much simpler for languages other than C/C++.
//
// - running as a sub-process may be more tricky in unusual environments like
// iOS apps, where fork/stdin/stdout are not available.
enum WireFormat {
UNSPECIFIED = 0;
PROTOBUF = 1;
JSON = 2;
}
// Represents a single test case's input. The testee should:
//
// 1. parse this proto (which should always succeed)
// 2. parse the protobuf or JSON payload in "payload" (which may fail)
// 3. if the parse succeeded, serialize the message in the requested format.
message ConformanceRequest {
// The payload (whether protobuf of JSON) is always for a TestAllTypes proto
// (see below).
oneof payload {
bytes protobuf_payload = 1;
string json_payload = 2;
}
// Which format should the testee serialize its message to?
WireFormat requested_output_format = 3;
}
// Represents a single test case's output.
message ConformanceResponse {
oneof result {
// This string should be set to indicate parsing failed. The string can
// provide more information about the parse error if it is available.
//
// Setting this string does not necessarily mean the testee failed the
// test. Some of the test cases are intentionally invalid input.
string parse_error = 1;
// If the input was successfully parsed but errors occurred when
// serializing it to the requested output format, set the error message in
// this field.
string serialize_error = 6;
// This should be set if some other error occurred. This will always
// indicate that the test failed. The string can provide more information
// about the failure.
string runtime_error = 2;
// If the input was successfully parsed and the requested output was
// protobuf, serialize it to protobuf and set it in this field.
bytes protobuf_payload = 3;
// If the input was successfully parsed and the requested output was JSON,
// serialize to JSON and set it in this field.
string json_payload = 4;
// For when the testee skipped the test, likely because a certain feature
// wasn't supported, like JSON input/output.
string skipped = 5;
}
}
// This proto includes every type of field in both singular and repeated
// forms.
message TestAllTypes {
message NestedMessage {
int32 a = 1;
TestAllTypes corecursive = 2;
}
enum NestedEnum {
FOO = 0;
BAR = 1;
BAZ = 2;
NEG = -1; // Intentionally negative.
}
// Singular
int32 optional_int32 = 1;
int64 optional_int64 = 2;
uint32 optional_uint32 = 3;
uint64 optional_uint64 = 4;
sint32 optional_sint32 = 5;
sint64 optional_sint64 = 6;
fixed32 optional_fixed32 = 7;
fixed64 optional_fixed64 = 8;
sfixed32 optional_sfixed32 = 9;
sfixed64 optional_sfixed64 = 10;
float optional_float = 11;
double optional_double = 12;
bool optional_bool = 13;
string optional_string = 14;
bytes optional_bytes = 15;
NestedMessage optional_nested_message = 18;
ForeignMessage optional_foreign_message = 19;
NestedEnum optional_nested_enum = 21;
ForeignEnum optional_foreign_enum = 22;
string optional_string_piece = 24 [ctype=STRING_PIECE];
string optional_cord = 25 [ctype=CORD];
TestAllTypes recursive_message = 27;
// Repeated
repeated int32 repeated_int32 = 31;
repeated int64 repeated_int64 = 32;
repeated uint32 repeated_uint32 = 33;
repeated uint64 repeated_uint64 = 34;
repeated sint32 repeated_sint32 = 35;
repeated sint64 repeated_sint64 = 36;
repeated fixed32 repeated_fixed32 = 37;
repeated fixed64 repeated_fixed64 = 38;
repeated sfixed32 repeated_sfixed32 = 39;
repeated sfixed64 repeated_sfixed64 = 40;
repeated float repeated_float = 41;
repeated double repeated_double = 42;
repeated bool repeated_bool = 43;
repeated string repeated_string = 44;
repeated bytes repeated_bytes = 45;
repeated NestedMessage repeated_nested_message = 48;
repeated ForeignMessage repeated_foreign_message = 49;
repeated NestedEnum repeated_nested_enum = 51;
repeated ForeignEnum repeated_foreign_enum = 52;
repeated string repeated_string_piece = 54 [ctype=STRING_PIECE];
repeated string repeated_cord = 55 [ctype=CORD];
// Map
map < int32, int32> map_int32_int32 = 56;
map < int64, int64> map_int64_int64 = 57;
map < uint32, uint32> map_uint32_uint32 = 58;
map < uint64, uint64> map_uint64_uint64 = 59;
map < sint32, sint32> map_sint32_sint32 = 60;
map < sint64, sint64> map_sint64_sint64 = 61;
map < fixed32, fixed32> map_fixed32_fixed32 = 62;
map < fixed64, fixed64> map_fixed64_fixed64 = 63;
map <sfixed32, sfixed32> map_sfixed32_sfixed32 = 64;
map <sfixed64, sfixed64> map_sfixed64_sfixed64 = 65;
map < int32, float> map_int32_float = 66;
map < int32, double> map_int32_double = 67;
map < bool, bool> map_bool_bool = 68;
map < string, string> map_string_string = 69;
map < string, bytes> map_string_bytes = 70;
map < string, NestedMessage> map_string_nested_message = 71;
map < string, ForeignMessage> map_string_foreign_message = 72;
map < string, NestedEnum> map_string_nested_enum = 73;
map < string, ForeignEnum> map_string_foreign_enum = 74;
oneof oneof_field {
uint32 oneof_uint32 = 111;
NestedMessage oneof_nested_message = 112;
string oneof_string = 113;
bytes oneof_bytes = 114;
bool oneof_bool = 115;
uint64 oneof_uint64 = 116;
float oneof_float = 117;
double oneof_double = 118;
NestedEnum oneof_enum = 119;
}
// Well-known types
google.protobuf.BoolValue optional_bool_wrapper = 201;
google.protobuf.Int32Value optional_int32_wrapper = 202;
google.protobuf.Int64Value optional_int64_wrapper = 203;
google.protobuf.UInt32Value optional_uint32_wrapper = 204;
google.protobuf.UInt64Value optional_uint64_wrapper = 205;
google.protobuf.FloatValue optional_float_wrapper = 206;
google.protobuf.DoubleValue optional_double_wrapper = 207;
google.protobuf.StringValue optional_string_wrapper = 208;
google.protobuf.BytesValue optional_bytes_wrapper = 209;
repeated google.protobuf.BoolValue repeated_bool_wrapper = 211;
repeated google.protobuf.Int32Value repeated_int32_wrapper = 212;
repeated google.protobuf.Int64Value repeated_int64_wrapper = 213;
repeated google.protobuf.UInt32Value repeated_uint32_wrapper = 214;
repeated google.protobuf.UInt64Value repeated_uint64_wrapper = 215;
repeated google.protobuf.FloatValue repeated_float_wrapper = 216;
repeated google.protobuf.DoubleValue repeated_double_wrapper = 217;
repeated google.protobuf.StringValue repeated_string_wrapper = 218;
repeated google.protobuf.BytesValue repeated_bytes_wrapper = 219;
google.protobuf.Duration optional_duration = 301;
google.protobuf.Timestamp optional_timestamp = 302;
google.protobuf.FieldMask optional_field_mask = 303;
google.protobuf.Struct optional_struct = 304;
google.protobuf.Any optional_any = 305;
google.protobuf.Value optional_value = 306;
repeated google.protobuf.Duration repeated_duration = 311;
repeated google.protobuf.Timestamp repeated_timestamp = 312;
repeated google.protobuf.FieldMask repeated_fieldmask = 313;
repeated google.protobuf.Struct repeated_struct = 324;
repeated google.protobuf.Any repeated_any = 315;
repeated google.protobuf.Value repeated_value = 316;
// Test field-name-to-JSON-name convention.
// (protobuf says names can be any valid C/C++ identifier.)
int32 fieldname1 = 401;
int32 field_name2 = 402;
int32 _field_name3 = 403;
int32 field__name4_ = 404;
int32 field0name5 = 405;
int32 field_0_name6 = 406;
int32 fieldName7 = 407;
int32 FieldName8 = 408;
int32 field_Name9 = 409;
int32 Field_Name10 = 410;
int32 FIELD_NAME11 = 411;
int32 FIELD_name12 = 412;
int32 __field_name13 = 413;
int32 __Field_name14 = 414;
int32 field__name15 = 415;
int32 field__Name16 = 416;
int32 field_name17__ = 417;
int32 Field_name18__ = 418;
}
message ForeignMessage {
int32 c = 1;
}
enum ForeignEnum {
FOREIGN_FOO = 0;
FOREIGN_BAR = 1;
FOREIGN_BAZ = 2;
}
-190
View File
@@ -1,190 +0,0 @@
# Benchmarks
## How to reproduce
For a comparison run:
make bench
followed by [benchcmp](http://code.google.com/p/go/source/browse/misc/benchcmp benchcmp) on the resulting files:
$GOROOT/misc/benchcmp $GOPATH/src/github.com/gogo/protobuf/test/mixbench/marshal.txt $GOPATH/src/github.com/gogo/protobuf/test/mixbench/marshaler.txt
$GOROOT/misc/benchcmp $GOPATH/src/github.com/gogo/protobuf/test/mixbench/unmarshal.txt $GOPATH/src/github.com/gogo/protobuf/test/mixbench/unmarshaler.txt
Benchmarks ran on Revision: 11c56be39364
June 2013
Processor 2,66 GHz Intel Core i7
Memory 8 GB 1067 MHz DDR3
## Marshaler
<table>
<tr><td>benchmark</td><td>old ns/op</td><td>new ns/op</td><td>delta</td></tr>
<tr><td>BenchmarkNidOptNativeProtoMarshal</td><td>2656</td><td>889</td><td>-66.53%</td></tr>
<tr><td>BenchmarkNinOptNativeProtoMarshal</td><td>2651</td><td>1015</td><td>-61.71%</td></tr>
<tr><td>BenchmarkNidRepNativeProtoMarshal</td><td>42661</td><td>12519</td><td>-70.65%</td></tr>
<tr><td>BenchmarkNinRepNativeProtoMarshal</td><td>42306</td><td>12354</td><td>-70.80%</td></tr>
<tr><td>BenchmarkNidRepPackedNativeProtoMarshal</td><td>34148</td><td>11902</td><td>-65.15%</td></tr>
<tr><td>BenchmarkNinRepPackedNativeProtoMarshal</td><td>33375</td><td>11969</td><td>-64.14%</td></tr>
<tr><td>BenchmarkNidOptStructProtoMarshal</td><td>7148</td><td>3727</td><td>-47.86%</td></tr>
<tr><td>BenchmarkNinOptStructProtoMarshal</td><td>6956</td><td>3481</td><td>-49.96%</td></tr>
<tr><td>BenchmarkNidRepStructProtoMarshal</td><td>46551</td><td>19492</td><td>-58.13%</td></tr>
<tr><td>BenchmarkNinRepStructProtoMarshal</td><td>46715</td><td>19043</td><td>-59.24%</td></tr>
<tr><td>BenchmarkNidEmbeddedStructProtoMarshal</td><td>5231</td><td>2050</td><td>-60.81%</td></tr>
<tr><td>BenchmarkNinEmbeddedStructProtoMarshal</td><td>4665</td><td>2000</td><td>-57.13%</td></tr>
<tr><td>BenchmarkNidNestedStructProtoMarshal</td><td>181106</td><td>103604</td><td>-42.79%</td></tr>
<tr><td>BenchmarkNinNestedStructProtoMarshal</td><td>182053</td><td>102069</td><td>-43.93%</td></tr>
<tr><td>BenchmarkNidOptCustomProtoMarshal</td><td>1209</td><td>310</td><td>-74.36%</td></tr>
<tr><td>BenchmarkNinOptCustomProtoMarshal</td><td>1435</td><td>277</td><td>-80.70%</td></tr>
<tr><td>BenchmarkNidRepCustomProtoMarshal</td><td>4126</td><td>763</td><td>-81.51%</td></tr>
<tr><td>BenchmarkNinRepCustomProtoMarshal</td><td>3972</td><td>769</td><td>-80.64%</td></tr>
<tr><td>BenchmarkNinOptNativeUnionProtoMarshal</td><td>973</td><td>303</td><td>-68.86%</td></tr>
<tr><td>BenchmarkNinOptStructUnionProtoMarshal</td><td>1536</td><td>521</td><td>-66.08%</td></tr>
<tr><td>BenchmarkNinEmbeddedStructUnionProtoMarshal</td><td>2327</td><td>884</td><td>-62.01%</td></tr>
<tr><td>BenchmarkNinNestedStructUnionProtoMarshal</td><td>2070</td><td>743</td><td>-64.11%</td></tr>
<tr><td>BenchmarkTreeProtoMarshal</td><td>1554</td><td>838</td><td>-46.07%</td></tr>
<tr><td>BenchmarkOrBranchProtoMarshal</td><td>3156</td><td>2012</td><td>-36.25%</td></tr>
<tr><td>BenchmarkAndBranchProtoMarshal</td><td>3183</td><td>1996</td><td>-37.29%</td></tr>
<tr><td>BenchmarkLeafProtoMarshal</td><td>965</td><td>606</td><td>-37.20%</td></tr>
<tr><td>BenchmarkDeepTreeProtoMarshal</td><td>2316</td><td>1283</td><td>-44.60%</td></tr>
<tr><td>BenchmarkADeepBranchProtoMarshal</td><td>2719</td><td>1492</td><td>-45.13%</td></tr>
<tr><td>BenchmarkAndDeepBranchProtoMarshal</td><td>4663</td><td>2922</td><td>-37.34%</td></tr>
<tr><td>BenchmarkDeepLeafProtoMarshal</td><td>1849</td><td>1016</td><td>-45.05%</td></tr>
<tr><td>BenchmarkNilProtoMarshal</td><td>439</td><td>76</td><td>-82.53%</td></tr>
<tr><td>BenchmarkNidOptEnumProtoMarshal</td><td>514</td><td>152</td><td>-70.43%</td></tr>
<tr><td>BenchmarkNinOptEnumProtoMarshal</td><td>550</td><td>158</td><td>-71.27%</td></tr>
<tr><td>BenchmarkNidRepEnumProtoMarshal</td><td>647</td><td>207</td><td>-68.01%</td></tr>
<tr><td>BenchmarkNinRepEnumProtoMarshal</td><td>662</td><td>213</td><td>-67.82%</td></tr>
<tr><td>BenchmarkTimerProtoMarshal</td><td>934</td><td>271</td><td>-70.99%</td></tr>
<tr><td>BenchmarkMyExtendableProtoMarshal</td><td>608</td><td>185</td><td>-69.57%</td></tr>
<tr><td>BenchmarkOtherExtenableProtoMarshal</td><td>1112</td><td>332</td><td>-70.14%</td></tr>
</table>
<table>
<tr><td>benchmark</td><td>old MB/s</td><td>new MB/s</td><td>speedup</td></tr>
<tr><td>BenchmarkNidOptNativeProtoMarshal</td><td>126.86</td><td>378.86</td><td>2.99x</td></tr>
<tr><td>BenchmarkNinOptNativeProtoMarshal</td><td>114.27</td><td>298.42</td><td>2.61x</td></tr>
<tr><td>BenchmarkNidRepNativeProtoMarshal</td><td>164.25</td><td>561.20</td><td>3.42x</td></tr>
<tr><td>BenchmarkNinRepNativeProtoMarshal</td><td>166.10</td><td>568.23</td><td>3.42x</td></tr>
<tr><td>BenchmarkNidRepPackedNativeProtoMarshal</td><td>99.10</td><td>283.97</td><td>2.87x</td></tr>
<tr><td>BenchmarkNinRepPackedNativeProtoMarshal</td><td>101.30</td><td>282.31</td><td>2.79x</td></tr>
<tr><td>BenchmarkNidOptStructProtoMarshal</td><td>176.83</td><td>339.07</td><td>1.92x</td></tr>
<tr><td>BenchmarkNinOptStructProtoMarshal</td><td>163.59</td><td>326.57</td><td>2.00x</td></tr>
<tr><td>BenchmarkNidRepStructProtoMarshal</td><td>178.84</td><td>427.49</td><td>2.39x</td></tr>
<tr><td>BenchmarkNinRepStructProtoMarshal</td><td>178.70</td><td>437.69</td><td>2.45x</td></tr>
<tr><td>BenchmarkNidEmbeddedStructProtoMarshal</td><td>124.24</td><td>317.56</td><td>2.56x</td></tr>
<tr><td>BenchmarkNinEmbeddedStructProtoMarshal</td><td>132.03</td><td>307.99</td><td>2.33x</td></tr>
<tr><td>BenchmarkNidNestedStructProtoMarshal</td><td>192.91</td><td>337.86</td><td>1.75x</td></tr>
<tr><td>BenchmarkNinNestedStructProtoMarshal</td><td>192.44</td><td>344.45</td><td>1.79x</td></tr>
<tr><td>BenchmarkNidOptCustomProtoMarshal</td><td>29.77</td><td>116.03</td><td>3.90x</td></tr>
<tr><td>BenchmarkNinOptCustomProtoMarshal</td><td>22.29</td><td>115.38</td><td>5.18x</td></tr>
<tr><td>BenchmarkNidRepCustomProtoMarshal</td><td>35.14</td><td>189.80</td><td>5.40x</td></tr>
<tr><td>BenchmarkNinRepCustomProtoMarshal</td><td>36.50</td><td>188.40</td><td>5.16x</td></tr>
<tr><td>BenchmarkNinOptNativeUnionProtoMarshal</td><td>32.87</td><td>105.39</td><td>3.21x</td></tr>
<tr><td>BenchmarkNinOptStructUnionProtoMarshal</td><td>66.40</td><td>195.76</td><td>2.95x</td></tr>
<tr><td>BenchmarkNinEmbeddedStructUnionProtoMarshal</td><td>93.24</td><td>245.26</td><td>2.63x</td></tr>
<tr><td>BenchmarkNinNestedStructUnionProtoMarshal</td><td>57.49</td><td>160.06</td><td>2.78x</td></tr>
<tr><td>BenchmarkTreeProtoMarshal</td><td>137.64</td><td>255.12</td><td>1.85x</td></tr>
<tr><td>BenchmarkOrBranchProtoMarshal</td><td>137.80</td><td>216.10</td><td>1.57x</td></tr>
<tr><td>BenchmarkAndBranchProtoMarshal</td><td>136.64</td><td>217.89</td><td>1.59x</td></tr>
<tr><td>BenchmarkLeafProtoMarshal</td><td>214.48</td><td>341.53</td><td>1.59x</td></tr>
<tr><td>BenchmarkDeepTreeProtoMarshal</td><td>95.85</td><td>173.03</td><td>1.81x</td></tr>
<tr><td>BenchmarkADeepBranchProtoMarshal</td><td>82.73</td><td>150.78</td><td>1.82x</td></tr>
<tr><td>BenchmarkAndDeepBranchProtoMarshal</td><td>96.72</td><td>153.98</td><td>1.59x</td></tr>
<tr><td>BenchmarkDeepLeafProtoMarshal</td><td>117.34</td><td>213.41</td><td>1.82x</td></tr>
<tr><td>BenchmarkNidOptEnumProtoMarshal</td><td>3.89</td><td>13.16</td><td>3.38x</td></tr>
<tr><td>BenchmarkNinOptEnumProtoMarshal</td><td>1.82</td><td>6.30</td><td>3.46x</td></tr>
<tr><td>BenchmarkNidRepEnumProtoMarshal</td><td>12.36</td><td>38.50</td><td>3.11x</td></tr>
<tr><td>BenchmarkNinRepEnumProtoMarshal</td><td>12.08</td><td>37.53</td><td>3.11x</td></tr>
<tr><td>BenchmarkTimerProtoMarshal</td><td>73.81</td><td>253.87</td><td>3.44x</td></tr>
<tr><td>BenchmarkMyExtendableProtoMarshal</td><td>13.15</td><td>43.08</td><td>3.28x</td></tr>
<tr><td>BenchmarkOtherExtenableProtoMarshal</td><td>24.28</td><td>81.09</td><td>3.34x</td></tr>
</table>
## Unmarshaler
<table>
<tr><td>benchmark</td><td>old ns/op</td><td>new ns/op</td><td>delta</td></tr>
<tr><td>BenchmarkNidOptNativeProtoUnmarshal</td><td>2521</td><td>1006</td><td>-60.10%</td></tr>
<tr><td>BenchmarkNinOptNativeProtoUnmarshal</td><td>2529</td><td>1750</td><td>-30.80%</td></tr>
<tr><td>BenchmarkNidRepNativeProtoUnmarshal</td><td>49067</td><td>35299</td><td>-28.06%</td></tr>
<tr><td>BenchmarkNinRepNativeProtoUnmarshal</td><td>47990</td><td>35456</td><td>-26.12%</td></tr>
<tr><td>BenchmarkNidRepPackedNativeProtoUnmarshal</td><td>26456</td><td>23950</td><td>-9.47%</td></tr>
<tr><td>BenchmarkNinRepPackedNativeProtoUnmarshal</td><td>26499</td><td>24037</td><td>-9.29%</td></tr>
<tr><td>BenchmarkNidOptStructProtoUnmarshal</td><td>6803</td><td>3873</td><td>-43.07%</td></tr>
<tr><td>BenchmarkNinOptStructProtoUnmarshal</td><td>6786</td><td>4154</td><td>-38.79%</td></tr>
<tr><td>BenchmarkNidRepStructProtoUnmarshal</td><td>56276</td><td>31970</td><td>-43.19%</td></tr>
<tr><td>BenchmarkNinRepStructProtoUnmarshal</td><td>48750</td><td>31832</td><td>-34.70%</td></tr>
<tr><td>BenchmarkNidEmbeddedStructProtoUnmarshal</td><td>4556</td><td>1973</td><td>-56.69%</td></tr>
<tr><td>BenchmarkNinEmbeddedStructProtoUnmarshal</td><td>4485</td><td>1975</td><td>-55.96%</td></tr>
<tr><td>BenchmarkNidNestedStructProtoUnmarshal</td><td>223395</td><td>135844</td><td>-39.19%</td></tr>
<tr><td>BenchmarkNinNestedStructProtoUnmarshal</td><td>226446</td><td>134022</td><td>-40.82%</td></tr>
<tr><td>BenchmarkNidOptCustomProtoUnmarshal</td><td>1859</td><td>300</td><td>-83.86%</td></tr>
<tr><td>BenchmarkNinOptCustomProtoUnmarshal</td><td>1486</td><td>402</td><td>-72.95%</td></tr>
<tr><td>BenchmarkNidRepCustomProtoUnmarshal</td><td>8229</td><td>1669</td><td>-79.72%</td></tr>
<tr><td>BenchmarkNinRepCustomProtoUnmarshal</td><td>8253</td><td>1649</td><td>-80.02%</td></tr>
<tr><td>BenchmarkNinOptNativeUnionProtoUnmarshal</td><td>840</td><td>307</td><td>-63.45%</td></tr>
<tr><td>BenchmarkNinOptStructUnionProtoUnmarshal</td><td>1395</td><td>639</td><td>-54.19%</td></tr>
<tr><td>BenchmarkNinEmbeddedStructUnionProtoUnmarshal</td><td>2297</td><td>1167</td><td>-49.19%</td></tr>
<tr><td>BenchmarkNinNestedStructUnionProtoUnmarshal</td><td>1820</td><td>889</td><td>-51.15%</td></tr>
<tr><td>BenchmarkTreeProtoUnmarshal</td><td>1521</td><td>720</td><td>-52.66%</td></tr>
<tr><td>BenchmarkOrBranchProtoUnmarshal</td><td>2669</td><td>1385</td><td>-48.11%</td></tr>
<tr><td>BenchmarkAndBranchProtoUnmarshal</td><td>2667</td><td>1420</td><td>-46.76%</td></tr>
<tr><td>BenchmarkLeafProtoUnmarshal</td><td>1171</td><td>584</td><td>-50.13%</td></tr>
<tr><td>BenchmarkDeepTreeProtoUnmarshal</td><td>2065</td><td>1081</td><td>-47.65%</td></tr>
<tr><td>BenchmarkADeepBranchProtoUnmarshal</td><td>2695</td><td>1178</td><td>-56.29%</td></tr>
<tr><td>BenchmarkAndDeepBranchProtoUnmarshal</td><td>4055</td><td>1918</td><td>-52.70%</td></tr>
<tr><td>BenchmarkDeepLeafProtoUnmarshal</td><td>1758</td><td>865</td><td>-50.80%</td></tr>
<tr><td>BenchmarkNilProtoUnmarshal</td><td>564</td><td>63</td><td>-88.79%</td></tr>
<tr><td>BenchmarkNidOptEnumProtoUnmarshal</td><td>762</td><td>73</td><td>-90.34%</td></tr>
<tr><td>BenchmarkNinOptEnumProtoUnmarshal</td><td>764</td><td>163</td><td>-78.66%</td></tr>
<tr><td>BenchmarkNidRepEnumProtoUnmarshal</td><td>1078</td><td>447</td><td>-58.53%</td></tr>
<tr><td>BenchmarkNinRepEnumProtoUnmarshal</td><td>1071</td><td>479</td><td>-55.28%</td></tr>
<tr><td>BenchmarkTimerProtoUnmarshal</td><td>1128</td><td>362</td><td>-67.91%</td></tr>
<tr><td>BenchmarkMyExtendableProtoUnmarshal</td><td>808</td><td>217</td><td>-73.14%</td></tr>
<tr><td>BenchmarkOtherExtenableProtoUnmarshal</td><td>1233</td><td>517</td><td>-58.07%</td></tr>
</table>
<table>
<tr><td>benchmark</td><td>old MB/s</td><td>new MB/s</td><td>speedup</td></tr>
<tr><td>BenchmarkNidOptNativeProtoUnmarshal</td><td>133.67</td><td>334.98</td><td>2.51x</td></tr>
<tr><td>BenchmarkNinOptNativeProtoUnmarshal</td><td>119.77</td><td>173.08</td><td>1.45x</td></tr>
<tr><td>BenchmarkNidRepNativeProtoUnmarshal</td><td>143.23</td><td>199.12</td><td>1.39x</td></tr>
<tr><td>BenchmarkNinRepNativeProtoUnmarshal</td><td>146.07</td><td>198.16</td><td>1.36x</td></tr>
<tr><td>BenchmarkNidRepPackedNativeProtoUnmarshal</td><td>127.80</td><td>141.04</td><td>1.10x</td></tr>
<tr><td>BenchmarkNinRepPackedNativeProtoUnmarshal</td><td>127.55</td><td>140.78</td><td>1.10x</td></tr>
<tr><td>BenchmarkNidOptStructProtoUnmarshal</td><td>185.79</td><td>326.31</td><td>1.76x</td></tr>
<tr><td>BenchmarkNinOptStructProtoUnmarshal</td><td>167.68</td><td>273.66</td><td>1.63x</td></tr>
<tr><td>BenchmarkNidRepStructProtoUnmarshal</td><td>147.88</td><td>260.39</td><td>1.76x</td></tr>
<tr><td>BenchmarkNinRepStructProtoUnmarshal</td><td>171.20</td><td>261.97</td><td>1.53x</td></tr>
<tr><td>BenchmarkNidEmbeddedStructProtoUnmarshal</td><td>142.86</td><td>329.42</td><td>2.31x</td></tr>
<tr><td>BenchmarkNinEmbeddedStructProtoUnmarshal</td><td>137.33</td><td>311.83</td><td>2.27x</td></tr>
<tr><td>BenchmarkNidNestedStructProtoUnmarshal</td><td>154.97</td><td>259.47</td><td>1.67x</td></tr>
<tr><td>BenchmarkNinNestedStructProtoUnmarshal</td><td>154.32</td><td>258.42</td><td>1.67x</td></tr>
<tr><td>BenchmarkNidOptCustomProtoUnmarshal</td><td>19.36</td><td>119.66</td><td>6.18x</td></tr>
<tr><td>BenchmarkNinOptCustomProtoUnmarshal</td><td>21.52</td><td>79.50</td><td>3.69x</td></tr>
<tr><td>BenchmarkNidRepCustomProtoUnmarshal</td><td>17.62</td><td>86.86</td><td>4.93x</td></tr>
<tr><td>BenchmarkNinRepCustomProtoUnmarshal</td><td>17.57</td><td>87.92</td><td>5.00x</td></tr>
<tr><td>BenchmarkNinOptNativeUnionProtoUnmarshal</td><td>38.07</td><td>104.12</td><td>2.73x</td></tr>
<tr><td>BenchmarkNinOptStructUnionProtoUnmarshal</td><td>73.08</td><td>159.54</td><td>2.18x</td></tr>
<tr><td>BenchmarkNinEmbeddedStructUnionProtoUnmarshal</td><td>94.00</td><td>185.92</td><td>1.98x</td></tr>
<tr><td>BenchmarkNinNestedStructUnionProtoUnmarshal</td><td>65.35</td><td>133.75</td><td>2.05x</td></tr>
<tr><td>BenchmarkTreeProtoUnmarshal</td><td>141.28</td><td>297.13</td><td>2.10x</td></tr>
<tr><td>BenchmarkOrBranchProtoUnmarshal</td><td>162.56</td><td>313.96</td><td>1.93x</td></tr>
<tr><td>BenchmarkAndBranchProtoUnmarshal</td><td>163.06</td><td>306.15</td><td>1.88x</td></tr>
<tr><td>BenchmarkLeafProtoUnmarshal</td><td>176.72</td><td>354.19</td><td>2.00x</td></tr>
<tr><td>BenchmarkDeepTreeProtoUnmarshal</td><td>107.50</td><td>205.30</td><td>1.91x</td></tr>
<tr><td>BenchmarkADeepBranchProtoUnmarshal</td><td>83.48</td><td>190.88</td><td>2.29x</td></tr>
<tr><td>BenchmarkAndDeepBranchProtoUnmarshal</td><td>110.97</td><td>234.60</td><td>2.11x</td></tr>
<tr><td>BenchmarkDeepLeafProtoUnmarshal</td><td>123.40</td><td>250.73</td><td>2.03x</td></tr>
<tr><td>BenchmarkNidOptEnumProtoUnmarshal</td><td>2.62</td><td>27.16</td><td>10.37x</td></tr>
<tr><td>BenchmarkNinOptEnumProtoUnmarshal</td><td>1.31</td><td>6.11</td><td>4.66x</td></tr>
<tr><td>BenchmarkNidRepEnumProtoUnmarshal</td><td>7.42</td><td>17.88</td><td>2.41x</td></tr>
<tr><td>BenchmarkNinRepEnumProtoUnmarshal</td><td>7.47</td><td>16.69</td><td>2.23x</td></tr>
<tr><td>BenchmarkTimerProtoUnmarshal</td><td>61.12</td><td>190.34</td><td>3.11x</td></tr>
<tr><td>BenchmarkMyExtendableProtoUnmarshal</td><td>9.90</td><td>36.71</td><td>3.71x</td></tr>
<tr><td>BenchmarkOtherExtenableProtoUnmarshal</td><td>21.90</td><td>52.13</td><td>2.38x</td></tr>
</table>
-54
View File
@@ -1,54 +0,0 @@
// Protocol Buffers for Go with Gadgets
//
// Copyright (c) 2015, The GoGo Authors. All rights reserved.
// http://github.com/gogo/protobuf
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package codec
import (
"github.com/gogo/protobuf/test"
"math/rand"
"testing"
"time"
)
func TestCodec(t *testing.T) {
r := rand.New(rand.NewSource(time.Now().UnixNano()))
in := test.NewPopulatedNinOptStruct(r, true)
c := New(r.Intn(1024))
data, err := c.Marshal(in)
if err != nil {
t.Fatal(err)
}
out := &test.NinOptStruct{}
err = c.Unmarshal(data, out)
if err != nil {
t.Fatal(err)
}
if err := in.VerboseEqual(out); err != nil {
t.Fatal(err)
}
}
-68
View File
@@ -1,68 +0,0 @@
# Custom types
Custom types is a gogo protobuf extensions that allows for using a custom
struct type to decorate the underlying structure of the protocol message.
# How to use
## Defining the protobuf message
```proto
message CustomType {
optional ProtoType Field = 1 [(gogoproto.customtype) = "T"];
}
message ProtoType {
optional string Field = 1;
}
```
or alternatively you can declare the field type in the protocol message to be
`bytes`:
```proto
message BytesCustomType {
optional bytes Field = 1 [(gogoproto.customtype) = "T"];
}
```
The downside of using `bytes` is that it makes it harder to generate protobuf
code in other languages. In either case, it is the user responsibility to
ensure that the custom type marshals and unmarshals to the expected wire
format. That is, in the first example, gogo protobuf will not attempt to ensure
that the wire format of `ProtoType` and `T` are wire compatible.
## Custom type method signatures
The custom type must define the following methods with the given
signatures. Assuming the custom type is called `T`:
```go
func (t T) Marshal() ([]byte, error) {}
func (t *T) MarshalTo(data []byte) (n int, err error) {}
func (t *T) Unmarshal(data []byte) error {}
func (t T) MarshalJSON() ([]byte, error) {}
func (t *T) UnmarshalJSON(data []byte) error {}
// only required if the compare option is set
func (t T) Compare(other T) int {}
// only required if the equal option is set
func (t T) Equal(other T) bool {}
// only required if populate option is set
func NewPopulatedT(r randyThetest) *T {}
```
Check [t.go](test/t.go) for a full example
# Warnings and issues
`Warning about customtype: It is your responsibility to test all cases of your marshaling, unmarshaling and size methods implemented for your custom type.`
Issues with customtype include:
* <a href="https://github.com/gogo/protobuf/issues/199">A Bytes method is not allowed.<a/>
* <a href="https://github.com/gogo/protobuf/issues/132">Defining a customtype as a fake proto message is broken.</a>
* <a href="https://github.com/gogo/protobuf/issues/147">proto.Clone is broken.</a>
* <a href="https://github.com/gogo/protobuf/issues/125">Using a proto message as a customtype is not allowed.</a>
* <a href="https://github.com/gogo/protobuf/issues/200">cusomtype of type map can not UnmarshalText</a>
* <a href="https://github.com/gogo/protobuf/issues/201">customtype of type struct cannot jsonpb unmarshal</a>
-162
View File
@@ -1,162 +0,0 @@
# gogoprotobuf Extensions
Here is an [example.proto](https://github.com/gogo/protobuf/blob/master/test/example/example.proto) which uses most of the gogoprotobuf code generation plugins.
Please also look at the example [Makefile](https://github.com/gogo/protobuf/blob/master/test/example/Makefile) which shows how to specify the `descriptor.proto` and `gogo.proto` in your proto_path
The documentation at [http://godoc.org/github.com/gogo/protobuf/gogoproto](http://godoc.org/github.com/gogo/protobuf/gogoproto) describes the extensions made to goprotobuf in more detail.
Also see [http://godoc.org/github.com/gogo/protobuf/plugin/](http://godoc.org/github.com/gogo/protobuf/plugin/) for documentation of each of the extensions which have their own plugins.
# Fast Marshalling and Unmarshalling
Generating a `Marshal`, `MarshalTo`, `Size` (or `ProtoSize`) and `Unmarshal` method for a struct results in faster marshalling and unmarshalling than when using reflect.
See [BenchComparison](https://github.com/gogo/protobuf/blob/master/bench.md) for a comparison between reflect and generated code used for marshalling and unmarshalling.
<table>
<tr><td><b>Name</b></td><td><b>Option</b></td><td><b>Type</b></td><td><b>Description</b></td><td><b>Default</b></td></tr>
<tr><td><a href="http://godoc.org/github.com/gogo/protobuf/plugin/marshalto">marshaler</a></td><td>Message</td><td>bool</td><td>if true, a Marshal and MarshalTo method is generated for the specific message</td><td>false</td></tr>
<tr><td><a href="http://godoc.org/github.com/gogo/protobuf/plugin/size">sizer</a></td><td>Message</td><td>bool</td><td>if true, a Size method is generated for the specific message</td><td>false</td></tr>
<tr><td><a href="http://godoc.org/github.com/gogo/protobuf/plugin/unmarshal">unmarshaler</a></td><td> Message </td><td> bool </td><td> if true, an Unmarshal method is generated for the specific message </td><td> false</td></tr>
<tr><td><a href="http://godoc.org/github.com/gogo/protobuf/plugin/size">protosizer</a></td><td>Message</td><td>bool</td><td>if true, a ProtoSize method is generated for the specific message</td><td>false</td></tr>
<tr><td><a href="http://godoc.org/github.com/gogo/protobuf/plugin/marshalto"> unsafe_marshaler</a> </td><td> Message </td><td> bool </td><td> if true, a Marshal and MarshalTo method is generated for the specific message. The generated code uses the unsafe package and is not compatible with big endian CPUs. </td><td> false</td></tr>
<tr><td><a href="http://godoc.org/github.com/gogo/protobuf/plugin/unmarshal">unsafe_unmarshaler</a></td><td> Message </td><td> bool </td><td> if true, an Unmarshal method is generated for the specific message. The generated code uses the unsafe package and is not compatible with big endian CPUs. </td><td> false</td></tr>
<tr><td><a href="http://godoc.org/github.com/gogo/protobuf/plugin/marshalto">stable_marshaler</a></td><td> Message </td><td> bool </td><td> if true, a Marshal and MarshalTo method is generated for the specific message, but unlike marshaler the output is guaranteed to be deterministic, at the sacrifice of some speed</td><td> false </td></tr>
<tr><td>typedecl (beta)</td><td> Message </td><td> bool </td><td> if false, type declaration of the message is excluded from the generated output. Requires the marshaler and unmarshaler to be generated.</td><td> true </td></tr>
</table>
# More Canonical Go Structures
Lots of times working with a goprotobuf struct will lead you to a place where you create another struct that is easier to work with and then have a function to copy the values between the two structs.
You might also find that basic structs that started their life as part of an API need to be sent over the wire. With gob, you could just send it. With goprotobuf, you need to make a new struct.
`gogoprotobuf` tries to fix these problems with the nullable, embed, customtype, customname, casttype, castkey and castvalue field extensions.
<table>
<tr><td><b>Name</b></td><td><b>Option</b></td><td><b>Type</b></td><td><b>Description</b></td><td><b>Default</b></td></tr>
<tr><td><a href="http://godoc.org/github.com/gogo/protobuf/gogoproto">nullable</a></td><td> Field </td><td> bool </td><td> if false, a field is generated without a pointer (see warning below). </td><td> true </td></tr>
<tr><td><a href="http://godoc.org/github.com/gogo/protobuf/gogoproto">embed</a></td><td> Field </td><td> bool </td><td> if true, the field is generated as an embedded field. </td><td> false </td></tr>
<tr><td><a href="http://godoc.org/github.com/gogo/protobuf/gogoproto">customtype</a> </td><td> Field </td><td> string </td><td> It works with the Marshal and Unmarshal methods, to allow you to have your own types in your struct, but marshal to bytes. For example, custom.Uuid or custom.Fixed128. For more information please refer to the <a href="custom_types.md">CustomTypes</a> document </td><td> goprotobuf type </td></tr>
<tr><td><a href="http://godoc.org/github.com/gogo/protobuf/gogoproto"> customname</a> (beta) </td><td> Field </td><td> string </td><td> Changes the generated fieldname. This is especially useful when generated methods conflict with fieldnames. </td><td> goprotobuf field name </td></tr>
<tr><td><a href="http://godoc.org/github.com/gogo/protobuf/gogoproto"> casttype</a> (beta) </td><td> Field </td><td> string </td><td> Changes the generated field type. It assumes that this type is castable to the original goprotobuf field type. It currently does not support maps, structs or enums. </td><td> goprotobuf field type </td></tr>
<tr><td><a href="http://godoc.org/github.com/gogo/protobuf/gogoproto"> castkey </a> (beta) </td><td> Field </td><td> string </td><td> Changes the generated fieldtype for a map key. All generated code assumes that this type is castable to the protocol buffer field type. Only supported on maps. </td><td> goprotobuf field type </td></tr>
<tr><td><a href="http://godoc.org/github.com/gogo/protobuf/gogoproto"> castvalue </a> (beta) </td><td> Field </td><td> string </td><td> Changes the generated fieldtype for a map value. All generated code assumes that this type is castable to the protocol buffer field type. Only supported on maps. </td><td> goprotobuf field type </td></tr>
<tr><td>enum_customname (beta)</td><td> Enum </td><td> string </td><td>Sets the type name of an enum. If goproto_enum_prefix is enabled, this value will be used as a prefix when generating enum values.</td><td>goprotobuf enum type name. Helps with golint issues.</td></tr>
<tr><td>enumdecl (beta)</td><td> Enum </td><td> bool </td><td> if false, type declaration of the enum is excluded from the generated output. Requires the marshaler and unmarshaler to be generated. </td><td> true </td></tr>
<tr><td>enumvalue_customname (beta) </td><td> Enum Value </td><td> string </td><td>Changes the generated enum name. Helps with golint issues.</td><td>goprotobuf enum value name</td></tr>
<tr><td><a href="https://github.com/gogo/protobuf/blob/master/test/types/types.proto">stdtime</a></td><td> Timestamp Field </td><td> bool </td><td>Changes the Well Known Timestamp Type to time.Time</td><td>Timestamp</td></tr>
<tr><td><a href="https://github.com/gogo/protobuf/blob/master/test/types/types.proto">stdduration</a></td><td> Duration Field </td><td> bool </td><td>Changes the Well Known Duration Type to time.Duration</td><td>Duration</td></tr>
</table>
`Warning about nullable: according to the Protocol Buffer specification, you should be able to tell whether a field is set or unset. With the option nullable=false this feature is lost, since your non-nullable fields will always be set.`
# Goprotobuf Compatibility
Gogoprotobuf is compatible with Goprotobuf, because it is compatible with protocol buffers (see the section on tests below).
Gogoprotobuf generates the same code as goprotobuf if no extensions are used.
The enumprefix, getters and stringer extensions can be used to remove some of the unnecessary code generated by goprotobuf.
<table>
<tr><td><b>Name</b></td><td><b>Option</b></td><td><b>Type</b></td><td><b>Description</b></td><td><b>Default</b></td></tr>
<tr><td> gogoproto_import </td><td> File </td><td> bool </td><td> if false, the generated code imports github.com/golang/protobuf/proto instead of github.com/gogo/protobuf/proto. </td><td> true </td></tr>
<tr><td> goproto_enum_prefix </td><td> Enum </td><td> bool </td><td> if false, generates the enum constant names without the messagetype prefix </td><td> true </td></tr>
<tr><td> goproto_getters </td><td> Message </td><td> bool </td><td> if false, the message is generated without get methods, this is useful when you would rather want to use face </td><td> true </td></tr>
<tr><td> goproto_stringer </td><td> Message </td><td> bool </td><td> if false, the message is generated without the default string method, this is useful for rather using stringer </td><td> true </td></tr>
<tr><td> goproto_enum_stringer (experimental) </td><td> Enum </td><td> bool </td><td> if false, the enum is generated without the default string method, this is useful for rather using enum_stringer </td><td> true </td></tr>
<tr><td> goproto_extensions_map (beta) </td><td> Message </td><td> bool </td><td> if false, the extensions field is generated as type []byte instead of type map[int32]proto.Extension </td><td> true </td></tr>
<tr><td> goproto_unrecognized (beta) </td><td> Message </td><td> bool </td><td>if false, XXX_unrecognized field is not generated. This is useful to reduce GC pressure at the cost of losing information about unrecognized fields. </td><td> true </td></tr>
<tr><td> goproto_registration (beta) </td><td> File </td><td> bool </td><td>if true, the generated files will register all messages and types against both gogo/protobuf and golang/protobuf. This is necessary when using third-party packages which read registrations from golang/protobuf (such as the grpc-gateway). </td><td> false </td></tr>
</table>
# Less Typing
The Protocol Buffer language is very parseable and extra code can be easily generated for structures.
Helper methods, functions and interfaces can be generated by triggering certain extensions like gostring.
<table>
<tr><td><b>Name</b></td><td><b>Option</b></td><td><b>Type</b></td><td><b>Description</b></td><td><b>Default</b></td></tr>
<tr><td><a href="http://godoc.org/github.com/gogo/protobuf/plugin/gostring">gostring</a></td><td> Message </td><td> bool </td><td> if true, a `GoString` method is generated. This returns a string representing valid go code to reproduce the current state of the struct. </td><td> false </td></tr>
<tr><td><a href="http://godoc.org/github.com/gogo/protobuf/plugin/union"> onlyone</a> (deprecated) </td><td> Message </td><td> bool </td><td> if true, all fields must be nullable and only one of the fields may be set, like a union. Two methods are generated: `GetValue() interface{}` and `SetValue(v interface{}) (set bool)`. These provide easier interaction with a union. </td><td> false </td></tr>
<tr><td><a href="http://godoc.org/github.com/gogo/protobuf/plugin/equal"> equal</a></td><td> Message </td><td> bool </td><td> if true, an Equal method is generated </td><td> false </td></tr>
<tr><td><a href="http://godoc.org/github.com/gogo/protobuf/plugin/compare"> compare</a></td><td> Message </td><td> bool </td><td> if true, a Compare method is generated. This is very useful for quickly implementing sort on a list of protobuf structs </td><td> false </td></tr>
<tr><td><a href="http://godoc.org/github.com/gogo/protobuf/plugin/equal"> verbose_equal</a> </td><td> Message </td><td> bool </td><td> if true, a verbose equal method is generated for the message. This returns an error which describes the exact element which is not equal to the exact element in the other struct. </td><td> false </td></tr>
<tr><td><a href="http://godoc.org/github.com/gogo/protobuf/plugin/stringer"> stringer</a> </td><td> Message </td><td> bool </td><td> if true, a String method is generated for the message. </td><td> false </td></tr>
<tr><td><a href="http://godoc.org/github.com/gogo/protobuf/plugin/face">face</a> </td><td> Message </td><td> bool </td><td> if true, a function will be generated which can convert a structure which satisfies an interface (face) to the specified structure. This interface contains getters for each of the fields in the struct. The specified struct is also generated with the getters. This allows it to satisfy its own face. </td><td> false </td></tr>
<tr><td><a href="http://godoc.org/github.com/gogo/protobuf/plugin/description"> description</a> (beta) </td><td> Message </td><td> bool </td><td> if true, a Description method is generated for the message. </td><td> false </td></tr>
<tr><td> <a href="http://godoc.org/github.com/gogo/protobuf/plugin/populate"> populate</a> </td><td> Message </td><td> bool </td><td> if true, a `NewPopulated<MessageName>` function is generated. This is necessary for generated tests. </td><td> false </td></tr>
<tr><td><a href="http://godoc.org/github.com/gogo/protobuf/plugin/enumstringer"> enum_stringer</a> (experimental) </td><td> Enum </td><td> bool </td><td> if true, a String method is generated for an Enum </td><td> false </td></tr>
</table>
Issues with Compare include:
* <a href="https://github.com/gogo/protobuf/issues/221">Oneof is not supported yet</a>
* <a href="https://github.com/gogo/protobuf/issues/230">Not all Well Known Types are supported yet</a>
* <a href="https://github.com/gogo/protobuf/issues/231">Maps are not supported</a>
#Peace of Mind
Test and Benchmark generation is done with the following extensions:
<table>
<tr><td><a href="http://godoc.org/github.com/gogo/protobuf/plugin/testgen">testgen</a> </td><td> Message </td><td> bool </td><td> if true, tests are generated for proto, json and prototext marshalling as well as for some of the other enabled plugins </td><td> false </td></tr>
<tr><td> benchgen </td><td> Message </td><td> bool </td><td> if true, benchmarks are generated for proto, json and prototext marshalling as well as for some of the other enabled plugins </td><td> false </td></tr>
</table>
# More Serialization Formats
Other serialization formats like xml and json typically use reflect to marshal and unmarshal structured data. Manipulating these structs into something other than the default Go requires editing tags. The following extensions provide ways of editing these tags for the generated protobuf structs.
<table>
<tr><td><a href="https://github.com/gogo/protobuf/blob/master/test/tags/tags.proto">jsontag</a> (beta) </td><td> Field </td><td> string </td><td> if set, the json tag value between the double quotes is replaced with this string </td><td> fieldname </td></tr>
<tr><td><a href="https://github.com/gogo/protobuf/blob/master/test/tags/tags.proto">moretags</a> (beta) </td><td> Field </td><td> string </td><td> if set, this string is appended to the tag string </td><td> empty </td></tr>
</table>
<a href="https://groups.google.com/forum/#!topic/gogoprotobuf/xmFnqAS6MIc">Here is a longer explanation of jsontag and moretags</a>
# File Options
Each of the boolean message and enum extensions also have a file extension:
* `marshaler_all`
* `sizer_all`
* `protosizer_all`
* `unmarshaler_all`
* `unsafe_marshaler_all`
* `unsafe_unmarshaler_all`
* `stable_marshaler_all`
* `goproto_enum_prefix_all`
* `goproto_getters_all`
* `goproto_stringer_all`
* `goproto_enum_stringer_all`
* `goproto_extensions_map_all`
* `goproto_unrecognized_all`
* `gostring_all`
* `onlyone_all`
* `equal_all`
* `compare_all`
* `verbose_equal_all`
* `stringer_all`
* `enum_stringer_all`
* `face_all`
* `description_all`
* `populate_all`
* `testgen_all`
* `benchgen_all`
* `enumdecl_all`
* `typedecl_all`
Each of these are the same as their Message Option counterparts, except they apply to all messages in the file. Their Message option counterparts can also be used to overwrite their effect.
# Tests
* The normal barrage of tests are run with: `make tests`
* A few weird tests: `make testall`
* Tests for compatibility with [golang/protobuf](https://github.com/golang/protobuf) are handled by a different project [harmonytests](https://github.com/gogo/harmonytests), since it requires goprotobuf.
* Cross version tests are made with [Travis CI](https://travis-ci.org/gogo/protobuf).
* GRPC Tests are also handled by a different project [grpctests](https://github.com/gogo/grpctests), since it depends on a lot of grpc libraries.
* Thanks to [go-fuzz](https://github.com/dvyukov/go-fuzz/) we have proper [fuzztests](https://github.com/gogo/fuzztests).
-37
View File
@@ -1,37 +0,0 @@
# Protocol Buffers for Go with Gadgets
#
# Copyright (c) 2013, The GoGo Authors. All rights reserved.
# http://github.com/gogo/protobuf
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following disclaimer
# in the documentation and/or other materials provided with the
# distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
regenerate:
go install github.com/gogo/protobuf/protoc-gen-gogo
protoc --gogo_out=Mgoogle/protobuf/descriptor.proto=github.com/gogo/protobuf/protoc-gen-gogo/descriptor:. --proto_path=../../../../:../protobuf/:. *.proto
restore:
cp gogo.pb.golden gogo.pb.go
preserve:
cp gogo.pb.go gogo.pb.golden
+78 -77
View File
@@ -723,81 +723,82 @@ func init() {
func init() { proto.RegisterFile("gogo.proto", fileDescriptorGogo) }
var fileDescriptorGogo = []byte{
// 1201 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x98, 0xcb, 0x6f, 0x1c, 0x45,
0x13, 0xc0, 0xf5, 0xe9, 0x73, 0x64, 0x6f, 0xf9, 0x85, 0xd7, 0xc6, 0x84, 0x08, 0x44, 0x72, 0xe3,
0xe4, 0x9c, 0x22, 0x94, 0xb6, 0x22, 0xcb, 0xb1, 0x1c, 0x2b, 0x11, 0x06, 0x63, 0xe2, 0x00, 0xe2,
0xb0, 0x9a, 0xdd, 0x6d, 0x4f, 0x06, 0x66, 0xa6, 0x87, 0x99, 0x9e, 0x28, 0xce, 0x0d, 0x85, 0x87,
0x10, 0xe2, 0x8d, 0x04, 0x09, 0x49, 0x80, 0x03, 0xef, 0x67, 0x78, 0x1f, 0xb9, 0xf0, 0xb8, 0xf2,
0x3f, 0x70, 0x01, 0xcc, 0xdb, 0x37, 0x5f, 0x50, 0xcd, 0x56, 0xcd, 0xf6, 0xac, 0x57, 0xea, 0xde,
0xdb, 0xec, 0xba, 0x7f, 0xbf, 0xad, 0xa9, 0x9a, 0xae, 0xea, 0x31, 0x80, 0xaf, 0x7c, 0x35, 0x97,
0xa4, 0x4a, 0xab, 0x7a, 0x0d, 0xaf, 0x8b, 0xcb, 0x03, 0x07, 0x7d, 0xa5, 0xfc, 0x50, 0x1e, 0x2e,
0x3e, 0x35, 0xf3, 0xcd, 0xc3, 0x6d, 0x99, 0xb5, 0xd2, 0x20, 0xd1, 0x2a, 0xed, 0x2c, 0x16, 0x77,
0xc1, 0x34, 0x2d, 0x6e, 0xc8, 0x38, 0x8f, 0x1a, 0x49, 0x2a, 0x37, 0x83, 0xf3, 0xf5, 0x5b, 0xe6,
0x3a, 0xe4, 0x1c, 0x93, 0x73, 0xcb, 0x71, 0x1e, 0xdd, 0x9d, 0xe8, 0x40, 0xc5, 0xd9, 0xfe, 0xeb,
0x3f, 0xff, 0xff, 0xe0, 0xff, 0x6e, 0x1f, 0x59, 0x9f, 0x22, 0x14, 0xff, 0xb6, 0x56, 0x80, 0x62,
0x1d, 0x6e, 0xac, 0xf8, 0x32, 0x9d, 0x06, 0xb1, 0x2f, 0x53, 0x8b, 0xf1, 0x3b, 0x32, 0x4e, 0x1b,
0xc6, 0x7b, 0x09, 0x15, 0x4b, 0x30, 0x3e, 0x88, 0xeb, 0x7b, 0x72, 0x8d, 0x49, 0x53, 0xb2, 0x02,
0x93, 0x85, 0xa4, 0x95, 0x67, 0x5a, 0x45, 0xb1, 0x17, 0x49, 0x8b, 0xe6, 0x87, 0x42, 0x53, 0x5b,
0x9f, 0x40, 0x6c, 0xa9, 0xa4, 0x84, 0x80, 0x11, 0xfc, 0xa6, 0x2d, 0x5b, 0xa1, 0xc5, 0xf0, 0x23,
0x05, 0x52, 0xae, 0x17, 0x67, 0x60, 0x06, 0xaf, 0xcf, 0x79, 0x61, 0x2e, 0xcd, 0x48, 0x0e, 0xf5,
0xf5, 0x9c, 0xc1, 0x65, 0x2c, 0xfb, 0xe9, 0xe2, 0x50, 0x11, 0xce, 0x74, 0x29, 0x30, 0x62, 0x32,
0xaa, 0xe8, 0x4b, 0xad, 0x65, 0x9a, 0x35, 0xbc, 0xb0, 0x5f, 0x78, 0x27, 0x82, 0xb0, 0x34, 0x5e,
0xda, 0xae, 0x56, 0x71, 0xa5, 0x43, 0x2e, 0x86, 0xa1, 0xd8, 0x80, 0x9b, 0xfa, 0x3c, 0x15, 0x0e,
0xce, 0xcb, 0xe4, 0x9c, 0xd9, 0xf3, 0x64, 0xa0, 0x76, 0x0d, 0xf8, 0xfb, 0xb2, 0x96, 0x0e, 0xce,
0xd7, 0xc8, 0x59, 0x27, 0x96, 0x4b, 0x8a, 0xc6, 0x53, 0x30, 0x75, 0x4e, 0xa6, 0x4d, 0x95, 0xc9,
0x86, 0x7c, 0x24, 0xf7, 0x42, 0x07, 0xdd, 0x15, 0xd2, 0x4d, 0x12, 0xb8, 0x8c, 0x1c, 0xba, 0x8e,
0xc2, 0xc8, 0xa6, 0xd7, 0x92, 0x0e, 0x8a, 0xab, 0xa4, 0x18, 0xc6, 0xf5, 0x88, 0x2e, 0xc2, 0x98,
0xaf, 0x3a, 0xb7, 0xe4, 0x80, 0x5f, 0x23, 0x7c, 0x94, 0x19, 0x52, 0x24, 0x2a, 0xc9, 0x43, 0x4f,
0xbb, 0x44, 0xf0, 0x3a, 0x2b, 0x98, 0x21, 0xc5, 0x00, 0x69, 0x7d, 0x83, 0x15, 0x99, 0x91, 0xcf,
0x05, 0x18, 0x55, 0x71, 0xb8, 0xa5, 0x62, 0x97, 0x20, 0xde, 0x24, 0x03, 0x10, 0x82, 0x82, 0x79,
0xa8, 0xb9, 0x16, 0xe2, 0xad, 0x6d, 0xde, 0x1e, 0x5c, 0x81, 0x15, 0x98, 0xe4, 0x06, 0x15, 0xa8,
0xd8, 0x41, 0xf1, 0x36, 0x29, 0x26, 0x0c, 0x8c, 0x6e, 0x43, 0xcb, 0x4c, 0xfb, 0xd2, 0x45, 0xf2,
0x0e, 0xdf, 0x06, 0x21, 0x94, 0xca, 0xa6, 0x8c, 0x5b, 0x67, 0xdd, 0x0c, 0xef, 0x72, 0x2a, 0x99,
0x41, 0xc5, 0x12, 0x8c, 0x47, 0x5e, 0x9a, 0x9d, 0xf5, 0x42, 0xa7, 0x72, 0xbc, 0x47, 0x8e, 0xb1,
0x12, 0xa2, 0x8c, 0xe4, 0xf1, 0x20, 0x9a, 0xf7, 0x39, 0x23, 0x06, 0x46, 0x5b, 0x2f, 0xd3, 0x5e,
0x33, 0x94, 0x8d, 0x41, 0x6c, 0x1f, 0xf0, 0xd6, 0xeb, 0xb0, 0xab, 0xa6, 0x71, 0x1e, 0x6a, 0x59,
0x70, 0xc1, 0x49, 0xf3, 0x21, 0x57, 0xba, 0x00, 0x10, 0x7e, 0x00, 0x6e, 0xee, 0x3b, 0x26, 0x1c,
0x64, 0x1f, 0x91, 0x6c, 0xb6, 0xcf, 0xa8, 0xa0, 0x96, 0x30, 0xa8, 0xf2, 0x63, 0x6e, 0x09, 0xb2,
0xc7, 0xb5, 0x06, 0x33, 0x79, 0x9c, 0x79, 0x9b, 0x83, 0x65, 0xed, 0x13, 0xce, 0x5a, 0x87, 0xad,
0x64, 0xed, 0x34, 0xcc, 0x92, 0x71, 0xb0, 0xba, 0x7e, 0xca, 0x8d, 0xb5, 0x43, 0x6f, 0x54, 0xab,
0xfb, 0x20, 0x1c, 0x28, 0xd3, 0x79, 0x5e, 0xcb, 0x38, 0x43, 0xa6, 0x11, 0x79, 0x89, 0x83, 0xf9,
0x3a, 0x99, 0xb9, 0xe3, 0x2f, 0x97, 0x82, 0x55, 0x2f, 0x41, 0xf9, 0xfd, 0xb0, 0x9f, 0xe5, 0x79,
0x9c, 0xca, 0x96, 0xf2, 0xe3, 0xe0, 0x82, 0x6c, 0x3b, 0xa8, 0x3f, 0xeb, 0x29, 0xd5, 0x86, 0x81,
0xa3, 0xf9, 0x24, 0xdc, 0x50, 0x9e, 0x55, 0x1a, 0x41, 0x94, 0xa8, 0x54, 0x5b, 0x8c, 0x9f, 0x73,
0xa5, 0x4a, 0xee, 0x64, 0x81, 0x89, 0x65, 0x98, 0x28, 0x3e, 0xba, 0x3e, 0x92, 0x5f, 0x90, 0x68,
0xbc, 0x4b, 0x51, 0xe3, 0x68, 0xa9, 0x28, 0xf1, 0x52, 0x97, 0xfe, 0xf7, 0x25, 0x37, 0x0e, 0x42,
0xa8, 0x71, 0xe8, 0xad, 0x44, 0xe2, 0xb4, 0x77, 0x30, 0x7c, 0xc5, 0x8d, 0x83, 0x19, 0x52, 0xf0,
0x81, 0xc1, 0x41, 0xf1, 0x35, 0x2b, 0x98, 0x41, 0xc5, 0x3d, 0xdd, 0x41, 0x9b, 0x4a, 0x3f, 0xc8,
0x74, 0xea, 0xe1, 0x6a, 0x8b, 0xea, 0x9b, 0xed, 0xea, 0x21, 0x6c, 0xdd, 0x40, 0xc5, 0x29, 0x98,
0xec, 0x39, 0x62, 0xd4, 0x6f, 0xdb, 0x63, 0x5b, 0x95, 0x59, 0xe6, 0xf9, 0xa5, 0xf0, 0xd1, 0x1d,
0x6a, 0x46, 0xd5, 0x13, 0x86, 0xb8, 0x13, 0xeb, 0x5e, 0x3d, 0x07, 0xd8, 0x65, 0x17, 0x77, 0xca,
0xd2, 0x57, 0x8e, 0x01, 0xe2, 0x04, 0x8c, 0x57, 0xce, 0x00, 0x76, 0xd5, 0x63, 0xa4, 0x1a, 0x33,
0x8f, 0x00, 0xe2, 0x08, 0x0c, 0xe1, 0x3c, 0xb7, 0xe3, 0x8f, 0x13, 0x5e, 0x2c, 0x17, 0xc7, 0x60,
0x84, 0xe7, 0xb8, 0x1d, 0x7d, 0x82, 0xd0, 0x12, 0x41, 0x9c, 0x67, 0xb8, 0x1d, 0x7f, 0x92, 0x71,
0x46, 0x10, 0x77, 0x4f, 0xe1, 0xb7, 0x4f, 0x0f, 0x51, 0x1f, 0xe6, 0xdc, 0xcd, 0xc3, 0x30, 0x0d,
0x6f, 0x3b, 0xfd, 0x14, 0xfd, 0x38, 0x13, 0xe2, 0x0e, 0xd8, 0xe7, 0x98, 0xf0, 0x67, 0x08, 0xed,
0xac, 0x17, 0x4b, 0x30, 0x6a, 0x0c, 0x6c, 0x3b, 0xfe, 0x2c, 0xe1, 0x26, 0x85, 0xa1, 0xd3, 0xc0,
0xb6, 0x0b, 0x9e, 0xe3, 0xd0, 0x89, 0xc0, 0xb4, 0xf1, 0xac, 0xb6, 0xd3, 0xcf, 0x73, 0xd6, 0x19,
0x11, 0x0b, 0x50, 0x2b, 0xfb, 0xaf, 0x9d, 0x7f, 0x81, 0xf8, 0x2e, 0x83, 0x19, 0x30, 0xfa, 0xbf,
0x5d, 0xf1, 0x22, 0x67, 0xc0, 0xa0, 0x70, 0x1b, 0xf5, 0xce, 0x74, 0xbb, 0xe9, 0x25, 0xde, 0x46,
0x3d, 0x23, 0x1d, 0xab, 0x59, 0xb4, 0x41, 0xbb, 0xe2, 0x65, 0xae, 0x66, 0xb1, 0x1e, 0xc3, 0xe8,
0x1d, 0x92, 0x76, 0xc7, 0x2b, 0x1c, 0x46, 0xcf, 0x8c, 0x14, 0x6b, 0x50, 0xdf, 0x3b, 0x20, 0xed,
0xbe, 0x57, 0xc9, 0x37, 0xb5, 0x67, 0x3e, 0x8a, 0xfb, 0x60, 0xb6, 0xff, 0x70, 0xb4, 0x5b, 0x2f,
0xed, 0xf4, 0xbc, 0xce, 0x98, 0xb3, 0x51, 0x9c, 0xee, 0x76, 0x59, 0x73, 0x30, 0xda, 0xb5, 0x97,
0x77, 0xaa, 0x8d, 0xd6, 0x9c, 0x8b, 0x62, 0x11, 0xa0, 0x3b, 0x93, 0xec, 0xae, 0x2b, 0xe4, 0x32,
0x20, 0xdc, 0x1a, 0x34, 0x92, 0xec, 0xfc, 0x55, 0xde, 0x1a, 0x44, 0xe0, 0xd6, 0xe0, 0x69, 0x64,
0xa7, 0xaf, 0xf1, 0xd6, 0x60, 0x44, 0xcc, 0xc3, 0x48, 0x9c, 0x87, 0x21, 0x3e, 0x5b, 0xf5, 0x5b,
0xfb, 0x8c, 0x1b, 0x19, 0xb6, 0x19, 0xfe, 0x65, 0x97, 0x60, 0x06, 0xc4, 0x11, 0xd8, 0x27, 0xa3,
0xa6, 0x6c, 0xdb, 0xc8, 0x5f, 0x77, 0xb9, 0x9f, 0xe0, 0x6a, 0xb1, 0x00, 0xd0, 0x79, 0x99, 0xc6,
0x28, 0x6c, 0xec, 0x6f, 0xbb, 0x9d, 0xf7, 0x7a, 0x03, 0xe9, 0x0a, 0x8a, 0xb7, 0x71, 0x8b, 0x60,
0xbb, 0x2a, 0x28, 0x5e, 0xc0, 0x8f, 0xc2, 0xf0, 0x43, 0x99, 0x8a, 0xb5, 0xe7, 0xdb, 0xe8, 0xdf,
0x89, 0xe6, 0xf5, 0x98, 0xb0, 0x48, 0xa5, 0x52, 0x7b, 0x7e, 0x66, 0x63, 0xff, 0x20, 0xb6, 0x04,
0x10, 0x6e, 0x79, 0x99, 0x76, 0xb9, 0xef, 0x3f, 0x19, 0x66, 0x00, 0x83, 0xc6, 0xeb, 0x87, 0xe5,
0x96, 0x8d, 0xfd, 0x8b, 0x83, 0xa6, 0xf5, 0xe2, 0x18, 0xd4, 0xf0, 0xb2, 0xf8, 0x3f, 0x84, 0x0d,
0xfe, 0x9b, 0xe0, 0x2e, 0x81, 0xbf, 0x9c, 0xe9, 0xb6, 0x0e, 0xec, 0xc9, 0xfe, 0x87, 0x2a, 0xcd,
0xeb, 0xc5, 0x22, 0x8c, 0x66, 0xba, 0xdd, 0xce, 0xe9, 0x44, 0x63, 0xc1, 0xff, 0xdd, 0x2d, 0x5f,
0x72, 0x4b, 0xe6, 0xf8, 0x21, 0x98, 0x6e, 0xa9, 0xa8, 0x17, 0x3c, 0x0e, 0x2b, 0x6a, 0x45, 0xad,
0x15, 0xbb, 0xe8, 0xbf, 0x00, 0x00, 0x00, 0xff, 0xff, 0x0a, 0x9c, 0xec, 0xd8, 0x50, 0x13, 0x00,
0x00,
// 1220 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x98, 0x4b, 0x6f, 0x1c, 0x45,
0x10, 0x80, 0x85, 0x48, 0x14, 0x6f, 0xd9, 0x8e, 0xf1, 0xda, 0x98, 0x10, 0x81, 0x08, 0x9c, 0x38,
0xd9, 0xa7, 0x08, 0xa5, 0xad, 0xc8, 0x72, 0x2c, 0xc7, 0x4a, 0x84, 0xc1, 0x98, 0x38, 0xbc, 0x0e,
0xab, 0xd9, 0xdd, 0xf6, 0x78, 0x60, 0x66, 0x7a, 0x98, 0xe9, 0x89, 0xe2, 0xdc, 0x50, 0x78, 0x08,
0x21, 0xde, 0x48, 0x90, 0x90, 0x04, 0x38, 0xf0, 0x7e, 0x86, 0xf7, 0x91, 0x0b, 0x8f, 0x2b, 0xff,
0x81, 0x0b, 0x60, 0xde, 0xbe, 0xf9, 0x82, 0x6a, 0xb6, 0x6a, 0xb6, 0x67, 0xbd, 0x52, 0xf7, 0xde,
0xc6, 0xeb, 0xfe, 0xbe, 0xad, 0xa9, 0x9a, 0xae, 0xea, 0x59, 0x00, 0x5f, 0xf9, 0x6a, 0x3a, 0x49,
0x95, 0x56, 0xf5, 0x1a, 0x5e, 0x17, 0x97, 0x07, 0x0f, 0xf9, 0x4a, 0xf9, 0xa1, 0x9c, 0x29, 0xfe,
0x6a, 0xe6, 0xeb, 0x33, 0x6d, 0x99, 0xb5, 0xd2, 0x20, 0xd1, 0x2a, 0xed, 0x2c, 0x16, 0x77, 0xc1,
0x04, 0x2d, 0x6e, 0xc8, 0x38, 0x8f, 0x1a, 0x49, 0x2a, 0xd7, 0x83, 0xb3, 0xf5, 0x9b, 0xa6, 0x3b,
0xe4, 0x34, 0x93, 0xd3, 0x8b, 0x71, 0x1e, 0xdd, 0x9d, 0xe8, 0x40, 0xc5, 0xd9, 0x81, 0xab, 0xbf,
0x5c, 0x7b, 0xe8, 0x9a, 0xdb, 0x87, 0x56, 0xc7, 0x09, 0xc5, 0xff, 0xad, 0x14, 0xa0, 0x58, 0x85,
0xeb, 0x2b, 0xbe, 0x4c, 0xa7, 0x41, 0xec, 0xcb, 0xd4, 0x62, 0xfc, 0x9e, 0x8c, 0x13, 0x86, 0xf1,
0x5e, 0x42, 0xc5, 0x02, 0x8c, 0x0e, 0xe2, 0xfa, 0x81, 0x5c, 0x23, 0xd2, 0x94, 0x2c, 0xc1, 0x58,
0x21, 0x69, 0xe5, 0x99, 0x56, 0x51, 0xec, 0x45, 0xd2, 0xa2, 0xf9, 0xb1, 0xd0, 0xd4, 0x56, 0xf7,
0x23, 0xb6, 0x50, 0x52, 0x42, 0xc0, 0x10, 0x7e, 0xd2, 0x96, 0xad, 0xd0, 0x62, 0xf8, 0x89, 0x02,
0x29, 0xd7, 0x8b, 0xd3, 0x30, 0x89, 0xd7, 0x67, 0xbc, 0x30, 0x97, 0x66, 0x24, 0xb7, 0xf6, 0xf5,
0x9c, 0xc6, 0x65, 0x2c, 0xfb, 0xf9, 0xfc, 0x9e, 0x22, 0x9c, 0x89, 0x52, 0x60, 0xc4, 0x64, 0x54,
0xd1, 0x97, 0x5a, 0xcb, 0x34, 0x6b, 0x78, 0x61, 0xbf, 0xf0, 0x8e, 0x07, 0x61, 0x69, 0xbc, 0xb0,
0x55, 0xad, 0xe2, 0x52, 0x87, 0x9c, 0x0f, 0x43, 0xb1, 0x06, 0x37, 0xf4, 0x79, 0x2a, 0x1c, 0x9c,
0x17, 0xc9, 0x39, 0xb9, 0xeb, 0xc9, 0x40, 0xed, 0x0a, 0xf0, 0xe7, 0x65, 0x2d, 0x1d, 0x9c, 0xaf,
0x93, 0xb3, 0x4e, 0x2c, 0x97, 0x14, 0x8d, 0x27, 0x61, 0xfc, 0x8c, 0x4c, 0x9b, 0x2a, 0x93, 0x0d,
0xf9, 0x68, 0xee, 0x85, 0x0e, 0xba, 0x4b, 0xa4, 0x1b, 0x23, 0x70, 0x11, 0x39, 0x74, 0x1d, 0x81,
0xa1, 0x75, 0xaf, 0x25, 0x1d, 0x14, 0x97, 0x49, 0xb1, 0x0f, 0xd7, 0x23, 0x3a, 0x0f, 0x23, 0xbe,
0xea, 0xdc, 0x92, 0x03, 0x7e, 0x85, 0xf0, 0x61, 0x66, 0x48, 0x91, 0xa8, 0x24, 0x0f, 0x3d, 0xed,
0x12, 0xc1, 0x1b, 0xac, 0x60, 0x86, 0x14, 0x03, 0xa4, 0xf5, 0x4d, 0x56, 0x64, 0x46, 0x3e, 0xe7,
0x60, 0x58, 0xc5, 0xe1, 0xa6, 0x8a, 0x5d, 0x82, 0x78, 0x8b, 0x0c, 0x40, 0x08, 0x0a, 0x66, 0xa1,
0xe6, 0x5a, 0x88, 0xb7, 0xb7, 0x78, 0x7b, 0x70, 0x05, 0x96, 0x60, 0x8c, 0x1b, 0x54, 0xa0, 0x62,
0x07, 0xc5, 0x3b, 0xa4, 0xd8, 0x6f, 0x60, 0x74, 0x1b, 0x5a, 0x66, 0xda, 0x97, 0x2e, 0x92, 0x77,
0xf9, 0x36, 0x08, 0xa1, 0x54, 0x36, 0x65, 0xdc, 0xda, 0x70, 0x33, 0xbc, 0xc7, 0xa9, 0x64, 0x06,
0x15, 0x0b, 0x30, 0x1a, 0x79, 0x69, 0xb6, 0xe1, 0x85, 0x4e, 0xe5, 0x78, 0x9f, 0x1c, 0x23, 0x25,
0x44, 0x19, 0xc9, 0xe3, 0x41, 0x34, 0x1f, 0x70, 0x46, 0x0c, 0x8c, 0xb6, 0x5e, 0xa6, 0xbd, 0x66,
0x28, 0x1b, 0x83, 0xd8, 0x3e, 0xe4, 0xad, 0xd7, 0x61, 0x97, 0x4d, 0xe3, 0x2c, 0xd4, 0xb2, 0xe0,
0x9c, 0x93, 0xe6, 0x23, 0xae, 0x74, 0x01, 0x20, 0xfc, 0x00, 0xdc, 0xd8, 0x77, 0x4c, 0x38, 0xc8,
0x3e, 0x26, 0xd9, 0x54, 0x9f, 0x51, 0x41, 0x2d, 0x61, 0x50, 0xe5, 0x27, 0xdc, 0x12, 0x64, 0x8f,
0x6b, 0x05, 0x26, 0xf3, 0x38, 0xf3, 0xd6, 0x07, 0xcb, 0xda, 0xa7, 0x9c, 0xb5, 0x0e, 0x5b, 0xc9,
0xda, 0x29, 0x98, 0x22, 0xe3, 0x60, 0x75, 0xfd, 0x8c, 0x1b, 0x6b, 0x87, 0x5e, 0xab, 0x56, 0xf7,
0x21, 0x38, 0x58, 0xa6, 0xf3, 0xac, 0x96, 0x71, 0x86, 0x4c, 0x23, 0xf2, 0x12, 0x07, 0xf3, 0x55,
0x32, 0x73, 0xc7, 0x5f, 0x2c, 0x05, 0xcb, 0x5e, 0x82, 0xf2, 0xfb, 0xe1, 0x00, 0xcb, 0xf3, 0x38,
0x95, 0x2d, 0xe5, 0xc7, 0xc1, 0x39, 0xd9, 0x76, 0x50, 0x7f, 0xde, 0x53, 0xaa, 0x35, 0x03, 0x47,
0xf3, 0x09, 0xb8, 0xae, 0x3c, 0xab, 0x34, 0x82, 0x28, 0x51, 0xa9, 0xb6, 0x18, 0xbf, 0xe0, 0x4a,
0x95, 0xdc, 0x89, 0x02, 0x13, 0x8b, 0xb0, 0xbf, 0xf8, 0xd3, 0xf5, 0x91, 0xfc, 0x92, 0x44, 0xa3,
0x5d, 0x8a, 0x1a, 0x47, 0x4b, 0x45, 0x89, 0x97, 0xba, 0xf4, 0xbf, 0xaf, 0xb8, 0x71, 0x10, 0x42,
0x8d, 0x43, 0x6f, 0x26, 0x12, 0xa7, 0xbd, 0x83, 0xe1, 0x6b, 0x6e, 0x1c, 0xcc, 0x90, 0x82, 0x0f,
0x0c, 0x0e, 0x8a, 0x6f, 0x58, 0xc1, 0x0c, 0x2a, 0xee, 0xe9, 0x0e, 0xda, 0x54, 0xfa, 0x41, 0xa6,
0x53, 0x0f, 0x57, 0x5b, 0x54, 0xdf, 0x6e, 0x55, 0x0f, 0x61, 0xab, 0x06, 0x2a, 0x4e, 0xc2, 0x58,
0xcf, 0x11, 0xa3, 0x7e, 0xcb, 0x2e, 0xdb, 0xb2, 0xcc, 0x32, 0xcf, 0x2f, 0x85, 0x8f, 0x6d, 0x53,
0x33, 0xaa, 0x9e, 0x30, 0xc4, 0x9d, 0x58, 0xf7, 0xea, 0x39, 0xc0, 0x2e, 0x3b, 0xbf, 0x5d, 0x96,
0xbe, 0x72, 0x0c, 0x10, 0xc7, 0x61, 0xb4, 0x72, 0x06, 0xb0, 0xab, 0x1e, 0x27, 0xd5, 0x88, 0x79,
0x04, 0x10, 0x87, 0x61, 0x0f, 0xce, 0x73, 0x3b, 0xfe, 0x04, 0xe1, 0xc5, 0x72, 0x71, 0x14, 0x86,
0x78, 0x8e, 0xdb, 0xd1, 0x27, 0x09, 0x2d, 0x11, 0xc4, 0x79, 0x86, 0xdb, 0xf1, 0xa7, 0x18, 0x67,
0x04, 0x71, 0xf7, 0x14, 0x7e, 0xf7, 0xcc, 0x1e, 0xea, 0xc3, 0x9c, 0xbb, 0x59, 0xd8, 0x47, 0xc3,
0xdb, 0x4e, 0x3f, 0x4d, 0x5f, 0xce, 0x84, 0xb8, 0x03, 0xf6, 0x3a, 0x26, 0xfc, 0x59, 0x42, 0x3b,
0xeb, 0xc5, 0x02, 0x0c, 0x1b, 0x03, 0xdb, 0x8e, 0x3f, 0x47, 0xb8, 0x49, 0x61, 0xe8, 0x34, 0xb0,
0xed, 0x82, 0xe7, 0x39, 0x74, 0x22, 0x30, 0x6d, 0x3c, 0xab, 0xed, 0xf4, 0x0b, 0x9c, 0x75, 0x46,
0xc4, 0x1c, 0xd4, 0xca, 0xfe, 0x6b, 0xe7, 0x5f, 0x24, 0xbe, 0xcb, 0x60, 0x06, 0x8c, 0xfe, 0x6f,
0x57, 0xbc, 0xc4, 0x19, 0x30, 0x28, 0xdc, 0x46, 0xbd, 0x33, 0xdd, 0x6e, 0x7a, 0x99, 0xb7, 0x51,
0xcf, 0x48, 0xc7, 0x6a, 0x16, 0x6d, 0xd0, 0xae, 0x78, 0x85, 0xab, 0x59, 0xac, 0xc7, 0x30, 0x7a,
0x87, 0xa4, 0xdd, 0xf1, 0x2a, 0x87, 0xd1, 0x33, 0x23, 0xc5, 0x0a, 0xd4, 0x77, 0x0f, 0x48, 0xbb,
0xef, 0x35, 0xf2, 0x8d, 0xef, 0x9a, 0x8f, 0xe2, 0x3e, 0x98, 0xea, 0x3f, 0x1c, 0xed, 0xd6, 0x0b,
0xdb, 0x3d, 0xaf, 0x33, 0xe6, 0x6c, 0x14, 0xa7, 0xba, 0x5d, 0xd6, 0x1c, 0x8c, 0x76, 0xed, 0xc5,
0xed, 0x6a, 0xa3, 0x35, 0xe7, 0xa2, 0x98, 0x07, 0xe8, 0xce, 0x24, 0xbb, 0xeb, 0x12, 0xb9, 0x0c,
0x08, 0xb7, 0x06, 0x8d, 0x24, 0x3b, 0x7f, 0x99, 0xb7, 0x06, 0x11, 0xb8, 0x35, 0x78, 0x1a, 0xd9,
0xe9, 0x2b, 0xbc, 0x35, 0x18, 0x11, 0xb3, 0x30, 0x14, 0xe7, 0x61, 0x88, 0xcf, 0x56, 0xfd, 0xe6,
0x3e, 0xe3, 0x46, 0x86, 0x6d, 0x86, 0x7f, 0xdd, 0x21, 0x98, 0x01, 0x71, 0x18, 0xf6, 0xca, 0xa8,
0x29, 0xdb, 0x36, 0xf2, 0xb7, 0x1d, 0xee, 0x27, 0xb8, 0x5a, 0xcc, 0x01, 0x74, 0x5e, 0xa6, 0x31,
0x0a, 0x1b, 0xfb, 0xfb, 0x4e, 0xe7, 0xbd, 0xde, 0x40, 0xba, 0x82, 0xe2, 0x6d, 0xdc, 0x22, 0xd8,
0xaa, 0x0a, 0x8a, 0x17, 0xf0, 0x23, 0xb0, 0xef, 0xe1, 0x4c, 0xc5, 0xda, 0xf3, 0x6d, 0xf4, 0x1f,
0x44, 0xf3, 0x7a, 0x4c, 0x58, 0xa4, 0x52, 0xa9, 0x3d, 0x3f, 0xb3, 0xb1, 0x7f, 0x12, 0x5b, 0x02,
0x08, 0xb7, 0xbc, 0x4c, 0xbb, 0xdc, 0xf7, 0x5f, 0x0c, 0x33, 0x80, 0x41, 0xe3, 0xf5, 0x23, 0x72,
0xd3, 0xc6, 0xfe, 0xcd, 0x41, 0xd3, 0x7a, 0x71, 0x14, 0x6a, 0x78, 0x59, 0xfc, 0x0e, 0x61, 0x83,
0xff, 0x21, 0xb8, 0x4b, 0xe0, 0x37, 0x67, 0xba, 0xad, 0x03, 0x7b, 0xb2, 0xff, 0xa5, 0x4a, 0xf3,
0x7a, 0x31, 0x0f, 0xc3, 0x99, 0x6e, 0xb7, 0x73, 0x3a, 0xd1, 0x58, 0xf0, 0xff, 0x76, 0xca, 0x97,
0xdc, 0x92, 0x39, 0xb6, 0x08, 0x13, 0x2d, 0x15, 0xf5, 0x82, 0xc7, 0x60, 0x49, 0x2d, 0xa9, 0x95,
0x62, 0x17, 0x3d, 0x78, 0x9b, 0x1f, 0xe8, 0x8d, 0xbc, 0x39, 0xdd, 0x52, 0xd1, 0x0c, 0x1e, 0x35,
0xbb, 0xbf, 0xa0, 0x95, 0x07, 0xcf, 0xff, 0x03, 0x00, 0x00, 0xff, 0xff, 0xed, 0x5f, 0x6c, 0x20,
0x74, 0x13, 0x00, 0x00,
}
-45
View File
@@ -1,45 +0,0 @@
// Code generated by protoc-gen-go.
// source: gogo.proto
// DO NOT EDIT!
package gogoproto
import proto "github.com/gogo/protobuf/proto"
import json "encoding/json"
import math "math"
import google_protobuf "github.com/gogo/protobuf/protoc-gen-gogo/descriptor"
// Reference proto, json, and math imports to suppress error if they are not otherwise used.
var _ = proto.Marshal
var _ = &json.SyntaxError{}
var _ = math.Inf
var E_Nullable = &proto.ExtensionDesc{
ExtendedType: (*google_protobuf.FieldOptions)(nil),
ExtensionType: (*bool)(nil),
Field: 51235,
Name: "gogoproto.nullable",
Tag: "varint,51235,opt,name=nullable",
}
var E_Embed = &proto.ExtensionDesc{
ExtendedType: (*google_protobuf.FieldOptions)(nil),
ExtensionType: (*bool)(nil),
Field: 51236,
Name: "gogoproto.embed",
Tag: "varint,51236,opt,name=embed",
}
var E_Customtype = &proto.ExtensionDesc{
ExtendedType: (*google_protobuf.FieldOptions)(nil),
ExtensionType: (*string)(nil),
Field: 51237,
Name: "gogoproto.customtype",
Tag: "bytes,51237,opt,name=customtype",
}
func init() {
proto.RegisterExtension(E_Nullable)
proto.RegisterExtension(E_Embed)
proto.RegisterExtension(E_Customtype)
}
-132
View File
@@ -1,132 +0,0 @@
// Protocol Buffers for Go with Gadgets
//
// Copyright (c) 2013, The GoGo Authors. All rights reserved.
// http://github.com/gogo/protobuf
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
syntax = "proto2";
package gogoproto;
import "google/protobuf/descriptor.proto";
option java_package = "com.google.protobuf";
option java_outer_classname = "GoGoProtos";
extend google.protobuf.EnumOptions {
optional bool goproto_enum_prefix = 62001;
optional bool goproto_enum_stringer = 62021;
optional bool enum_stringer = 62022;
optional string enum_customname = 62023;
optional bool enumdecl = 62024;
}
extend google.protobuf.EnumValueOptions {
optional string enumvalue_customname = 66001;
}
extend google.protobuf.FileOptions {
optional bool goproto_getters_all = 63001;
optional bool goproto_enum_prefix_all = 63002;
optional bool goproto_stringer_all = 63003;
optional bool verbose_equal_all = 63004;
optional bool face_all = 63005;
optional bool gostring_all = 63006;
optional bool populate_all = 63007;
optional bool stringer_all = 63008;
optional bool onlyone_all = 63009;
optional bool equal_all = 63013;
optional bool description_all = 63014;
optional bool testgen_all = 63015;
optional bool benchgen_all = 63016;
optional bool marshaler_all = 63017;
optional bool unmarshaler_all = 63018;
optional bool stable_marshaler_all = 63019;
optional bool sizer_all = 63020;
optional bool goproto_enum_stringer_all = 63021;
optional bool enum_stringer_all = 63022;
optional bool unsafe_marshaler_all = 63023;
optional bool unsafe_unmarshaler_all = 63024;
optional bool goproto_extensions_map_all = 63025;
optional bool goproto_unrecognized_all = 63026;
optional bool gogoproto_import = 63027;
optional bool protosizer_all = 63028;
optional bool compare_all = 63029;
optional bool typedecl_all = 63030;
optional bool enumdecl_all = 63031;
optional bool goproto_registration = 63032;
}
extend google.protobuf.MessageOptions {
optional bool goproto_getters = 64001;
optional bool goproto_stringer = 64003;
optional bool verbose_equal = 64004;
optional bool face = 64005;
optional bool gostring = 64006;
optional bool populate = 64007;
optional bool stringer = 67008;
optional bool onlyone = 64009;
optional bool equal = 64013;
optional bool description = 64014;
optional bool testgen = 64015;
optional bool benchgen = 64016;
optional bool marshaler = 64017;
optional bool unmarshaler = 64018;
optional bool stable_marshaler = 64019;
optional bool sizer = 64020;
optional bool unsafe_marshaler = 64023;
optional bool unsafe_unmarshaler = 64024;
optional bool goproto_extensions_map = 64025;
optional bool goproto_unrecognized = 64026;
optional bool protosizer = 64028;
optional bool compare = 64029;
optional bool typedecl = 64030;
}
extend google.protobuf.FieldOptions {
optional bool nullable = 65001;
optional bool embed = 65002;
optional string customtype = 65003;
optional string customname = 65004;
optional string jsontag = 65005;
optional string moretags = 65006;
optional string casttype = 65007;
optional string castkey = 65008;
optional string castvalue = 65009;
optional bool stdtime = 65010;
optional bool stdduration = 65011;
}
-32
View File
@@ -1,32 +0,0 @@
#!/usr/bin/env bash
set -ex
die() {
echo "$@" >&2
exit 1
}
cd /home/travis
case "$PROTOBUF_VERSION" in
2*)
basename=protobuf-$PROTOBUF_VERSION
wget https://github.com/google/protobuf/releases/download/v$PROTOBUF_VERSION/$basename.tar.gz
tar xzf $basename.tar.gz
cd protobuf-$PROTOBUF_VERSION
./configure --prefix=/home/travis && make -j2 && make install
;;
3*)
basename=protoc-$PROTOBUF_VERSION-linux-x86_64
wget https://github.com/google/protobuf/releases/download/v$PROTOBUF_VERSION/$basename.zip
unzip $basename.zip
;;
*)
die "unknown protobuf version: $PROTOBUF_VERSION"
;;
esac
-221
View File
@@ -1,221 +0,0 @@
// Protocol Buffers for Go with Gadgets
//
// Copyright (c) 2013, The GoGo Authors. All rights reserved.
// http://github.com/gogo/protobuf
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package io_test
import (
"bytes"
"encoding/binary"
"github.com/gogo/protobuf/io"
"github.com/gogo/protobuf/test"
goio "io"
"math/rand"
"testing"
"time"
)
func iotest(writer io.WriteCloser, reader io.ReadCloser) error {
size := 1000
msgs := make([]*test.NinOptNative, size)
r := rand.New(rand.NewSource(time.Now().UnixNano()))
for i := range msgs {
msgs[i] = test.NewPopulatedNinOptNative(r, true)
//issue 31
if i == 5 {
msgs[i] = &test.NinOptNative{}
}
//issue 31
if i == 999 {
msgs[i] = &test.NinOptNative{}
}
err := writer.WriteMsg(msgs[i])
if err != nil {
return err
}
}
if err := writer.Close(); err != nil {
return err
}
i := 0
for {
msg := &test.NinOptNative{}
if err := reader.ReadMsg(msg); err != nil {
if err == goio.EOF {
break
}
return err
}
if err := msg.VerboseEqual(msgs[i]); err != nil {
return err
}
i++
}
if i != size {
panic("not enough messages read")
}
if err := reader.Close(); err != nil {
return err
}
return nil
}
type buffer struct {
*bytes.Buffer
closed bool
}
func (this *buffer) Close() error {
this.closed = true
return nil
}
func newBuffer() *buffer {
return &buffer{bytes.NewBuffer(nil), false}
}
func TestBigUint32Normal(t *testing.T) {
buf := newBuffer()
writer := io.NewUint32DelimitedWriter(buf, binary.BigEndian)
reader := io.NewUint32DelimitedReader(buf, binary.BigEndian, 1024*1024)
if err := iotest(writer, reader); err != nil {
t.Error(err)
}
if !buf.closed {
t.Fatalf("did not close buffer")
}
}
func TestBigUint32MaxSize(t *testing.T) {
buf := newBuffer()
writer := io.NewUint32DelimitedWriter(buf, binary.BigEndian)
reader := io.NewUint32DelimitedReader(buf, binary.BigEndian, 20)
if err := iotest(writer, reader); err != goio.ErrShortBuffer {
t.Error(err)
} else {
t.Logf("%s", err)
}
}
func TestLittleUint32Normal(t *testing.T) {
buf := newBuffer()
writer := io.NewUint32DelimitedWriter(buf, binary.LittleEndian)
reader := io.NewUint32DelimitedReader(buf, binary.LittleEndian, 1024*1024)
if err := iotest(writer, reader); err != nil {
t.Error(err)
}
if !buf.closed {
t.Fatalf("did not close buffer")
}
}
func TestLittleUint32MaxSize(t *testing.T) {
buf := newBuffer()
writer := io.NewUint32DelimitedWriter(buf, binary.LittleEndian)
reader := io.NewUint32DelimitedReader(buf, binary.LittleEndian, 20)
if err := iotest(writer, reader); err != goio.ErrShortBuffer {
t.Error(err)
} else {
t.Logf("%s", err)
}
}
func TestVarintNormal(t *testing.T) {
buf := newBuffer()
writer := io.NewDelimitedWriter(buf)
reader := io.NewDelimitedReader(buf, 1024*1024)
if err := iotest(writer, reader); err != nil {
t.Error(err)
}
if !buf.closed {
t.Fatalf("did not close buffer")
}
}
func TestVarintNoClose(t *testing.T) {
buf := bytes.NewBuffer(nil)
writer := io.NewDelimitedWriter(buf)
reader := io.NewDelimitedReader(buf, 1024*1024)
if err := iotest(writer, reader); err != nil {
t.Error(err)
}
}
//issue 32
func TestVarintMaxSize(t *testing.T) {
buf := newBuffer()
writer := io.NewDelimitedWriter(buf)
reader := io.NewDelimitedReader(buf, 20)
if err := iotest(writer, reader); err != goio.ErrShortBuffer {
t.Error(err)
} else {
t.Logf("%s", err)
}
}
func TestVarintError(t *testing.T) {
buf := newBuffer()
buf.Write([]byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f})
reader := io.NewDelimitedReader(buf, 1024*1024)
msg := &test.NinOptNative{}
err := reader.ReadMsg(msg)
if err == nil {
t.Fatalf("Expected error")
}
}
func TestFull(t *testing.T) {
buf := newBuffer()
writer := io.NewFullWriter(buf)
reader := io.NewFullReader(buf, 1024*1024)
r := rand.New(rand.NewSource(time.Now().UnixNano()))
msgIn := test.NewPopulatedNinOptNative(r, true)
if err := writer.WriteMsg(msgIn); err != nil {
panic(err)
}
if err := writer.Close(); err != nil {
panic(err)
}
msgOut := &test.NinOptNative{}
if err := reader.ReadMsg(msgOut); err != nil {
panic(err)
}
if err := msgIn.VerboseEqual(msgOut); err != nil {
panic(err)
}
if err := reader.ReadMsg(msgOut); err != nil {
if err != goio.EOF {
panic(err)
}
}
if err := reader.Close(); err != nil {
panic(err)
}
if !buf.closed {
t.Fatalf("did not close buffer")
}
}
-38
View File
@@ -1,38 +0,0 @@
package io_test
import (
"encoding/binary"
"io/ioutil"
"math/rand"
"testing"
"time"
"github.com/gogo/protobuf/test"
example "github.com/gogo/protobuf/test/example"
"github.com/gogo/protobuf/io"
)
func BenchmarkUint32DelimWriterMarshaller(b *testing.B) {
w := io.NewUint32DelimitedWriter(ioutil.Discard, binary.BigEndian)
r := rand.New(rand.NewSource(time.Now().UnixNano()))
msg := example.NewPopulatedA(r, true)
for i := 0; i < b.N; i++ {
if err := w.WriteMsg(msg); err != nil {
b.Fatal(err)
}
}
}
func BenchmarkUint32DelimWriterFallback(b *testing.B) {
w := io.NewUint32DelimitedWriter(ioutil.Discard, binary.BigEndian)
r := rand.New(rand.NewSource(time.Now().UnixNano()))
msg := test.NewPopulatedNinOptNative(r, true)
for i := 0; i < b.N; i++ {
if err := w.WriteMsg(msg); err != nil {
b.Fatal(err)
}
}
}
+171 -90
View File
@@ -44,6 +44,7 @@ import (
"errors"
"fmt"
"io"
"math"
"reflect"
"sort"
"strconv"
@@ -71,6 +72,31 @@ type Marshaler struct {
// Whether to use the original (.proto) name for fields.
OrigName bool
// A custom URL resolver to use when marshaling Any messages to JSON.
// If unset, the default resolution strategy is to extract the
// fully-qualified type name from the type URL and pass that to
// proto.MessageType(string).
AnyResolver AnyResolver
}
// AnyResolver takes a type URL, present in an Any message, and resolves it into
// an instance of the associated message.
type AnyResolver interface {
Resolve(typeUrl string) (proto.Message, error)
}
func defaultResolveAny(typeUrl string) (proto.Message, error) {
// Only the part of typeUrl after the last slash is relevant.
mname := typeUrl
if slash := strings.LastIndex(mname, "/"); slash >= 0 {
mname = mname[slash+1:]
}
mt := proto.MessageType(mname)
if mt == nil {
return nil, fmt.Errorf("unknown message type %q", mname)
}
return reflect.New(mt.Elem()).Interface().(proto.Message), nil
}
// JSONPBMarshaler is implemented by protobuf messages that customize the
@@ -106,6 +132,12 @@ func (m *Marshaler) MarshalToString(pb proto.Message) (string, error) {
type int32Slice []int32
var nonFinite = map[string]float64{
`"NaN"`: math.NaN(),
`"Infinity"`: math.Inf(1),
`"-Infinity"`: math.Inf(-1),
}
// For sorting extensions ids to ensure stable output.
func (s int32Slice) Len() int { return len(s) }
func (s int32Slice) Less(i, j int) bool { return s[i] < s[j] }
@@ -122,6 +154,22 @@ func (m *Marshaler) marshalObject(out *errWriter, v proto.Message, indent, typeU
if err != nil {
return err
}
if typeURL != "" {
// we are marshaling this object to an Any type
var js map[string]*json.RawMessage
if err = json.Unmarshal(b, &js); err != nil {
return fmt.Errorf("type %T produced invalid JSON: %v", v, err)
}
turl, err := json.Marshal(typeURL)
if err != nil {
return fmt.Errorf("failed to marshal type URL %q to JSON: %v", typeURL, err)
}
js["@type"] = (*json.RawMessage)(&turl)
if b, err = json.Marshal(js); err != nil {
return err
}
}
out.write(string(b))
return out.err
}
@@ -204,6 +252,11 @@ func (m *Marshaler) marshalObject(out *errWriter, v proto.Message, indent, typeU
continue
}
//this is not a protobuf field
if valueField.Tag.Get("protobuf") == "" && valueField.Tag.Get("protobuf_oneof") == "" {
continue
}
// IsNil will panic on most value kinds.
switch value.Kind() {
case reflect.Chan, reflect.Func, reflect.Interface:
@@ -336,16 +389,17 @@ func (m *Marshaler) marshalAny(out *errWriter, any proto.Message, indent string)
turl := v.Field(0).String()
val := v.Field(1).Bytes()
// Only the part of type_url after the last slash is relevant.
mname := turl
if slash := strings.LastIndex(mname, "/"); slash >= 0 {
mname = mname[slash+1:]
var msg proto.Message
var err error
if m.AnyResolver != nil {
msg, err = m.AnyResolver.Resolve(turl)
} else {
msg, err = defaultResolveAny(turl)
}
mt := proto.MessageType(mname)
if mt == nil {
return fmt.Errorf("unknown message type %q", mname)
if err != nil {
return err
}
msg := reflect.New(mt.Elem()).Interface().(proto.Message)
if err := proto.Unmarshal(val, msg); err != nil {
return err
}
@@ -606,6 +660,24 @@ func (m *Marshaler) marshalValue(out *errWriter, prop *proto.Properties, v refle
return out.err
}
// Handle non-finite floats, e.g. NaN, Infinity and -Infinity.
if v.Kind() == reflect.Float32 || v.Kind() == reflect.Float64 {
f := v.Float()
var sval string
switch {
case math.IsInf(f, 1):
sval = `"Infinity"`
case math.IsInf(f, -1):
sval = `"-Infinity"`
case math.IsNaN(f):
sval = `"NaN"`
}
if sval != "" {
out.write(sval)
return out.err
}
}
// Default handling defers to the encoding/json library.
b, err := json.Marshal(v.Interface())
if err != nil {
@@ -628,6 +700,12 @@ type Unmarshaler struct {
// Whether to allow messages to contain unknown fields, as opposed to
// failing to unmarshal.
AllowUnknownFields bool
// A custom URL resolver to use when unmarshaling Any messages from JSON.
// If unset, the default resolution strategy is to extract the
// fully-qualified type name from the type URL and pass that to
// proto.MessageType(string).
AnyResolver AnyResolver
}
// UnmarshalNext unmarshals the next protocol buffer from a JSON object stream.
@@ -677,7 +755,14 @@ func (u *Unmarshaler) unmarshalValue(target reflect.Value, inputValue json.RawMe
// Allocate memory for pointer fields.
if targetType.Kind() == reflect.Ptr {
// If input value is "null" and target is a pointer type, then the field should be treated as not set
// UNLESS the target is structpb.Value, in which case it should be set to structpb.NullValue.
_, isJSONPBUnmarshaler := target.Interface().(JSONPBUnmarshaler)
if string(inputValue) == "null" && targetType != reflect.TypeOf(&types.Value{}) && !isJSONPBUnmarshaler {
return nil
}
target.Set(reflect.New(targetType.Elem()))
return u.unmarshalValue(target.Elem(), inputValue, prop)
}
@@ -685,87 +770,82 @@ func (u *Unmarshaler) unmarshalValue(target reflect.Value, inputValue json.RawMe
return jsu.UnmarshalJSONPB(u, []byte(inputValue))
}
// Handle well-known types.
// Handle well-known types that are not pointers.
if w, ok := target.Addr().Interface().(isWkt); ok {
switch w.XXX_WellKnownType() {
case "DoubleValue", "FloatValue", "Int64Value", "UInt64Value",
"Int32Value", "UInt32Value", "BoolValue", "StringValue", "BytesValue":
// "Wrappers use the same representation in JSON
// as the wrapped primitive type, except that null is allowed."
// encoding/json will turn JSON `null` into Go `nil`,
// so we don't have to do any extra work.
return u.unmarshalValue(target.Field(0), inputValue, prop)
case "Any":
var jsonFields map[string]json.RawMessage
// Use json.RawMessage pointer type instead of value to support pre-1.8 version.
// 1.8 changed RawMessage.MarshalJSON from pointer type to value type, see
// https://github.com/golang/go/issues/14493
var jsonFields map[string]*json.RawMessage
if err := json.Unmarshal(inputValue, &jsonFields); err != nil {
return err
}
val, ok := jsonFields["@type"]
if !ok {
if !ok || val == nil {
return errors.New("Any JSON doesn't have '@type'")
}
var turl string
if err := json.Unmarshal([]byte(val), &turl); err != nil {
return fmt.Errorf("can't unmarshal Any's '@type': %q", val)
if err := json.Unmarshal([]byte(*val), &turl); err != nil {
return fmt.Errorf("can't unmarshal Any's '@type': %q", *val)
}
target.Field(0).SetString(turl)
mname := turl
if slash := strings.LastIndex(mname, "/"); slash >= 0 {
mname = mname[slash+1:]
var m proto.Message
var err error
if u.AnyResolver != nil {
m, err = u.AnyResolver.Resolve(turl)
} else {
m, err = defaultResolveAny(turl)
}
mt := proto.MessageType(mname)
if mt == nil {
return fmt.Errorf("unknown message type %q", mname)
if err != nil {
return err
}
m := reflect.New(mt.Elem()).Interface().(proto.Message)
if _, ok := m.(isWkt); ok {
val, ok := jsonFields["value"]
if !ok {
return errors.New("Any JSON doesn't have 'value'")
}
if err := u.unmarshalValue(reflect.ValueOf(m).Elem(), val, nil); err != nil {
return fmt.Errorf("can't unmarshal Any's WKT: %v", err)
if err = u.unmarshalValue(reflect.ValueOf(m).Elem(), *val, nil); err != nil {
return fmt.Errorf("can't unmarshal Any nested proto %T: %v", m, err)
}
} else {
delete(jsonFields, "@type")
nestedProto, err := json.Marshal(jsonFields)
if err != nil {
return fmt.Errorf("can't generate JSON for Any's nested proto to be unmarshaled: %v", err)
nestedProto, uerr := json.Marshal(jsonFields)
if uerr != nil {
return fmt.Errorf("can't generate JSON for Any's nested proto to be unmarshaled: %v", uerr)
}
if err = u.unmarshalValue(reflect.ValueOf(m).Elem(), nestedProto, nil); err != nil {
return fmt.Errorf("can't unmarshal nested Any proto: %v", err)
return fmt.Errorf("can't unmarshal Any nested proto %T: %v", m, err)
}
}
b, err := proto.Marshal(m)
if err != nil {
return fmt.Errorf("can't marshal proto into Any.Value: %v", err)
return fmt.Errorf("can't marshal proto %T into Any.Value: %v", m, err)
}
target.Field(1).SetBytes(b)
return nil
case "Duration":
ivStr := string(inputValue)
if ivStr == "null" {
target.Field(0).SetInt(0)
target.Field(1).SetInt(0)
return nil
}
unq, err := strconv.Unquote(ivStr)
unq, err := strconv.Unquote(string(inputValue))
if err != nil {
return err
}
d, err := time.ParseDuration(unq)
if err != nil {
return fmt.Errorf("bad Duration: %v", err)
}
ns := d.Nanoseconds()
s := ns / 1e9
ns %= 1e9
@@ -773,29 +853,20 @@ func (u *Unmarshaler) unmarshalValue(target reflect.Value, inputValue json.RawMe
target.Field(1).SetInt(ns)
return nil
case "Timestamp":
ivStr := string(inputValue)
if ivStr == "null" {
target.Field(0).SetInt(0)
target.Field(1).SetInt(0)
return nil
}
unq, err := strconv.Unquote(ivStr)
unq, err := strconv.Unquote(string(inputValue))
if err != nil {
return err
}
t, err := time.Parse(time.RFC3339Nano, unq)
if err != nil {
return fmt.Errorf("bad Timestamp: %v", err)
}
target.Field(0).SetInt(int64(t.Unix()))
target.Field(0).SetInt(t.Unix())
target.Field(1).SetInt(int64(t.Nanosecond()))
return nil
case "Struct":
if string(inputValue) == "null" {
// Interpret a null struct as empty.
return nil
}
var m map[string]json.RawMessage
if err := json.Unmarshal(inputValue, &m); err != nil {
return fmt.Errorf("bad StructValue: %v", err)
@@ -810,14 +881,11 @@ func (u *Unmarshaler) unmarshalValue(target reflect.Value, inputValue json.RawMe
}
return nil
case "ListValue":
if string(inputValue) == "null" {
// Interpret a null ListValue as empty.
return nil
}
var s []json.RawMessage
if err := json.Unmarshal(inputValue, &s); err != nil {
return fmt.Errorf("bad ListValue: %v", err)
}
target.Field(0).Set(reflect.ValueOf(make([]*types.Value, len(s), len(s))))
for i, sv := range s {
if err := u.unmarshalValue(target.Field(0).Index(i), sv, prop); err != nil {
@@ -899,7 +967,7 @@ func (u *Unmarshaler) unmarshalValue(target reflect.Value, inputValue json.RawMe
// Handle nested messages.
if targetType.Kind() == reflect.Struct {
if target.CanAddr() {
if prop != nil && len(prop.CustomType) > 0 && target.CanAddr() {
if m, ok := target.Addr().Interface().(interface {
UnmarshalJSON([]byte) error
}); ok {
@@ -1026,11 +1094,13 @@ func (u *Unmarshaler) unmarshalValue(target reflect.Value, inputValue json.RawMe
if err := json.Unmarshal(inputValue, &slc); err != nil {
return err
}
len := len(slc)
target.Set(reflect.MakeSlice(targetType, len, len))
for i := 0; i < len; i++ {
if err := u.unmarshalValue(target.Index(i), slc[i], prop); err != nil {
return err
if slc != nil {
l := len(slc)
target.Set(reflect.MakeSlice(targetType, l, l))
for i := 0; i < l; i++ {
if err := u.unmarshalValue(target.Index(i), slc[i], prop); err != nil {
return err
}
}
}
return nil
@@ -1042,37 +1112,39 @@ func (u *Unmarshaler) unmarshalValue(target reflect.Value, inputValue json.RawMe
if err := json.Unmarshal(inputValue, &mp); err != nil {
return err
}
target.Set(reflect.MakeMap(targetType))
var keyprop, valprop *proto.Properties
if prop != nil {
// These could still be nil if the protobuf metadata is broken somehow.
// TODO: This won't work because the fields are unexported.
// We should probably just reparse them.
//keyprop, valprop = prop.mkeyprop, prop.mvalprop
}
for ks, raw := range mp {
// Unmarshal map key. The core json library already decoded the key into a
// string, so we handle that specially. Other types were quoted post-serialization.
var k reflect.Value
if targetType.Key().Kind() == reflect.String {
k = reflect.ValueOf(ks)
} else {
k = reflect.New(targetType.Key()).Elem()
if err := u.unmarshalValue(k, json.RawMessage(ks), keyprop); err != nil {
if mp != nil {
target.Set(reflect.MakeMap(targetType))
var keyprop, valprop *proto.Properties
if prop != nil {
// These could still be nil if the protobuf metadata is broken somehow.
// TODO: This won't work because the fields are unexported.
// We should probably just reparse them.
//keyprop, valprop = prop.mkeyprop, prop.mvalprop
}
for ks, raw := range mp {
// Unmarshal map key. The core json library already decoded the key into a
// string, so we handle that specially. Other types were quoted post-serialization.
var k reflect.Value
if targetType.Key().Kind() == reflect.String {
k = reflect.ValueOf(ks)
} else {
k = reflect.New(targetType.Key()).Elem()
if err := u.unmarshalValue(k, json.RawMessage(ks), keyprop); err != nil {
return err
}
}
if !k.Type().AssignableTo(targetType.Key()) {
k = k.Convert(targetType.Key())
}
// Unmarshal map value.
v := reflect.New(targetType.Elem()).Elem()
if err := u.unmarshalValue(v, raw, valprop); err != nil {
return err
}
target.SetMapIndex(k, v)
}
if !k.Type().AssignableTo(targetType.Key()) {
k = k.Convert(targetType.Key())
}
// Unmarshal map value.
v := reflect.New(targetType.Elem()).Elem()
if err := u.unmarshalValue(v, raw, valprop); err != nil {
return err
}
target.SetMapIndex(k, v)
}
return nil
}
@@ -1084,6 +1156,15 @@ func (u *Unmarshaler) unmarshalValue(target reflect.Value, inputValue json.RawMe
inputValue = inputValue[1 : len(inputValue)-1]
}
// Non-finite numbers can be encoded as strings.
isFloat := targetType.Kind() == reflect.Float32 || targetType.Kind() == reflect.Float64
if isFloat {
if num, ok := nonFinite[string(inputValue)]; ok {
target.SetFloat(num)
return nil
}
}
// Use the encoding/json for parsing other value types.
return json.Unmarshal(inputValue, target.Addr().Interface())
}
-686
View File
@@ -1,686 +0,0 @@
// Go support for Protocol Buffers - Google's data interchange format
//
// Copyright 2015 The Go Authors. All rights reserved.
// https://github.com/golang/protobuf
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package jsonpb
import (
"bytes"
"encoding/json"
"io"
"reflect"
"strings"
"testing"
pb "github.com/gogo/protobuf/jsonpb/jsonpb_test_proto"
"github.com/gogo/protobuf/proto"
proto3pb "github.com/gogo/protobuf/proto/proto3_proto"
"github.com/gogo/protobuf/types"
)
var (
marshaler = Marshaler{}
marshalerAllOptions = Marshaler{
Indent: " ",
}
simpleObject = &pb.Simple{
OInt32: proto.Int32(-32),
OInt64: proto.Int64(-6400000000),
OUint32: proto.Uint32(32),
OUint64: proto.Uint64(6400000000),
OSint32: proto.Int32(-13),
OSint64: proto.Int64(-2600000000),
OFloat: proto.Float32(3.14),
ODouble: proto.Float64(6.02214179e23),
OBool: proto.Bool(true),
OString: proto.String("hello \"there\""),
OBytes: []byte("beep boop"),
OCastBytes: pb.Bytes("wow"),
}
simpleObjectJSON = `{` +
`"oBool":true,` +
`"oInt32":-32,` +
`"oInt64":"-6400000000",` +
`"oUint32":32,` +
`"oUint64":"6400000000",` +
`"oSint32":-13,` +
`"oSint64":"-2600000000",` +
`"oFloat":3.14,` +
`"oDouble":6.02214179e+23,` +
`"oString":"hello \"there\"",` +
`"oBytes":"YmVlcCBib29w",` +
`"oCastBytes":"d293"` +
`}`
simpleObjectPrettyJSON = `{
"oBool": true,
"oInt32": -32,
"oInt64": "-6400000000",
"oUint32": 32,
"oUint64": "6400000000",
"oSint32": -13,
"oSint64": "-2600000000",
"oFloat": 3.14,
"oDouble": 6.02214179e+23,
"oString": "hello \"there\"",
"oBytes": "YmVlcCBib29w",
"oCastBytes": "d293"
}`
repeatsObject = &pb.Repeats{
RBool: []bool{true, false, true},
RInt32: []int32{-3, -4, -5},
RInt64: []int64{-123456789, -987654321},
RUint32: []uint32{1, 2, 3},
RUint64: []uint64{6789012345, 3456789012},
RSint32: []int32{-1, -2, -3},
RSint64: []int64{-6789012345, -3456789012},
RFloat: []float32{3.14, 6.28},
RDouble: []float64{299792458 * 1e20, 6.62606957e-34},
RString: []string{"happy", "days"},
RBytes: [][]byte{[]byte("skittles"), []byte("m&m's")},
}
repeatsObjectJSON = `{` +
`"rBool":[true,false,true],` +
`"rInt32":[-3,-4,-5],` +
`"rInt64":["-123456789","-987654321"],` +
`"rUint32":[1,2,3],` +
`"rUint64":["6789012345","3456789012"],` +
`"rSint32":[-1,-2,-3],` +
`"rSint64":["-6789012345","-3456789012"],` +
`"rFloat":[3.14,6.28],` +
`"rDouble":[2.99792458e+28,6.62606957e-34],` +
`"rString":["happy","days"],` +
`"rBytes":["c2tpdHRsZXM=","bSZtJ3M="]` +
`}`
repeatsObjectPrettyJSON = `{
"rBool": [
true,
false,
true
],
"rInt32": [
-3,
-4,
-5
],
"rInt64": [
"-123456789",
"-987654321"
],
"rUint32": [
1,
2,
3
],
"rUint64": [
"6789012345",
"3456789012"
],
"rSint32": [
-1,
-2,
-3
],
"rSint64": [
"-6789012345",
"-3456789012"
],
"rFloat": [
3.14,
6.28
],
"rDouble": [
2.99792458e+28,
6.62606957e-34
],
"rString": [
"happy",
"days"
],
"rBytes": [
"c2tpdHRsZXM=",
"bSZtJ3M="
]
}`
innerSimple = &pb.Simple{OInt32: proto.Int32(-32)}
innerSimple2 = &pb.Simple{OInt64: proto.Int64(25)}
innerRepeats = &pb.Repeats{RString: []string{"roses", "red"}}
innerRepeats2 = &pb.Repeats{RString: []string{"violets", "blue"}}
complexObject = &pb.Widget{
Color: pb.Widget_GREEN.Enum(),
RColor: []pb.Widget_Color{pb.Widget_RED, pb.Widget_GREEN, pb.Widget_BLUE},
Simple: innerSimple,
RSimple: []*pb.Simple{innerSimple, innerSimple2},
Repeats: innerRepeats,
RRepeats: []*pb.Repeats{innerRepeats, innerRepeats2},
}
complexObjectJSON = `{"color":"GREEN",` +
`"rColor":["RED","GREEN","BLUE"],` +
`"simple":{"oInt32":-32},` +
`"rSimple":[{"oInt32":-32},{"oInt64":"25"}],` +
`"repeats":{"rString":["roses","red"]},` +
`"rRepeats":[{"rString":["roses","red"]},{"rString":["violets","blue"]}]` +
`}`
complexObjectPrettyJSON = `{
"color": "GREEN",
"rColor": [
"RED",
"GREEN",
"BLUE"
],
"simple": {
"oInt32": -32
},
"rSimple": [
{
"oInt32": -32
},
{
"oInt64": "25"
}
],
"repeats": {
"rString": [
"roses",
"red"
]
},
"rRepeats": [
{
"rString": [
"roses",
"red"
]
},
{
"rString": [
"violets",
"blue"
]
}
]
}`
colorPrettyJSON = `{
"color": 2
}`
colorListPrettyJSON = `{
"color": 1000,
"rColor": [
"RED"
]
}`
nummyPrettyJSON = `{
"nummy": {
"1": 2,
"3": 4
}
}`
objjyPrettyJSON = `{
"objjy": {
"1": {
"dub": 1
}
}
}`
realNumber = &pb.Real{Value: proto.Float64(3.14159265359)}
realNumberName = "Pi"
complexNumber = &pb.Complex{Imaginary: proto.Float64(0.5772156649)}
realNumberJSON = `{` +
`"value":3.14159265359,` +
`"[jsonpb.Complex.real_extension]":{"imaginary":0.5772156649},` +
`"[jsonpb.name]":"Pi"` +
`}`
anySimple = &pb.KnownTypes{
An: &types.Any{
TypeUrl: "something.example.com/jsonpb.Simple",
Value: []byte{
// &pb.Simple{OBool:true}
1 << 3, 1,
},
},
}
anySimpleJSON = `{"an":{"@type":"something.example.com/jsonpb.Simple","oBool":true}}`
anySimplePrettyJSON = `{
"an": {
"@type": "something.example.com/jsonpb.Simple",
"oBool": true
}
}`
anyWellKnown = &pb.KnownTypes{
An: &types.Any{
TypeUrl: "type.googleapis.com/google.protobuf.Duration",
Value: []byte{
// &durpb.Duration{Seconds: 1, Nanos: 212000000 }
1 << 3, 1, // seconds
2 << 3, 0x80, 0xba, 0x8b, 0x65, // nanos
},
},
}
anyWellKnownJSON = `{"an":{"@type":"type.googleapis.com/google.protobuf.Duration","value":"1.212s"}}`
anyWellKnownPrettyJSON = `{
"an": {
"@type": "type.googleapis.com/google.protobuf.Duration",
"value": "1.212s"
}
}`
)
func init() {
if err := proto.SetExtension(realNumber, pb.E_Name, &realNumberName); err != nil {
panic(err)
}
if err := proto.SetExtension(realNumber, pb.E_Complex_RealExtension, complexNumber); err != nil {
panic(err)
}
}
var marshalingTests = []struct {
desc string
marshaler Marshaler
pb proto.Message
json string
}{
{"simple flat object", marshaler, simpleObject, simpleObjectJSON},
{"simple pretty object", marshalerAllOptions, simpleObject, simpleObjectPrettyJSON},
{"repeated fields flat object", marshaler, repeatsObject, repeatsObjectJSON},
{"repeated fields pretty object", marshalerAllOptions, repeatsObject, repeatsObjectPrettyJSON},
{"nested message/enum flat object", marshaler, complexObject, complexObjectJSON},
{"nested message/enum pretty object", marshalerAllOptions, complexObject, complexObjectPrettyJSON},
{"enum-string flat object", Marshaler{},
&pb.Widget{Color: pb.Widget_BLUE.Enum()}, `{"color":"BLUE"}`},
{"enum-value pretty object", Marshaler{EnumsAsInts: true, Indent: " "},
&pb.Widget{Color: pb.Widget_BLUE.Enum()}, colorPrettyJSON},
{"unknown enum value object", marshalerAllOptions,
&pb.Widget{Color: pb.Widget_Color(1000).Enum(), RColor: []pb.Widget_Color{pb.Widget_RED}}, colorListPrettyJSON},
{"repeated proto3 enum", Marshaler{},
&proto3pb.Message{RFunny: []proto3pb.Message_Humour{
proto3pb.Message_PUNS,
proto3pb.Message_SLAPSTICK,
}},
`{"rFunny":["PUNS","SLAPSTICK"]}`},
{"repeated proto3 enum as int", Marshaler{EnumsAsInts: true},
&proto3pb.Message{RFunny: []proto3pb.Message_Humour{
proto3pb.Message_PUNS,
proto3pb.Message_SLAPSTICK,
}},
`{"rFunny":[1,2]}`},
{"empty value", marshaler, &pb.Simple3{}, `{}`},
{"empty value emitted", Marshaler{EmitDefaults: true}, &pb.Simple3{}, `{"dub":0}`},
{"empty repeated emitted", Marshaler{EmitDefaults: true}, &pb.SimpleSlice3{}, `{"slices":[]}`},
{"empty map emitted", Marshaler{EmitDefaults: true}, &pb.SimpleMap3{}, `{"stringy":{}}`},
{"nested struct null", Marshaler{EmitDefaults: true}, &pb.SimpleNull3{}, `{"simple":null}`},
{"map<int64, int32>", marshaler, &pb.Mappy{Nummy: map[int64]int32{1: 2, 3: 4}}, `{"nummy":{"1":2,"3":4}}`},
{"map<int64, int32>", marshalerAllOptions, &pb.Mappy{Nummy: map[int64]int32{1: 2, 3: 4}}, nummyPrettyJSON},
{"map<string, string>", marshaler,
&pb.Mappy{Strry: map[string]string{`"one"`: "two", "three": "four"}},
`{"strry":{"\"one\"":"two","three":"four"}}`},
{"map<int32, Object>", marshaler,
&pb.Mappy{Objjy: map[int32]*pb.Simple3{1: {Dub: 1}}}, `{"objjy":{"1":{"dub":1}}}`},
{"map<int32, Object>", marshalerAllOptions,
&pb.Mappy{Objjy: map[int32]*pb.Simple3{1: {Dub: 1}}}, objjyPrettyJSON},
{"map<int64, string>", marshaler, &pb.Mappy{Buggy: map[int64]string{1234: "yup"}},
`{"buggy":{"1234":"yup"}}`},
{"map<bool, bool>", marshaler, &pb.Mappy{Booly: map[bool]bool{false: true}}, `{"booly":{"false":true}}`},
// TODO: This is broken.
//{"map<string, enum>", marshaler, &pb.Mappy{Enumy: map[string]pb.Numeral{"XIV": pb.Numeral_ROMAN}}, `{"enumy":{"XIV":"ROMAN"}`},
{"map<string, enum as int>", Marshaler{EnumsAsInts: true}, &pb.Mappy{Enumy: map[string]pb.Numeral{"XIV": pb.Numeral_ROMAN}}, `{"enumy":{"XIV":2}}`},
{"map<int32, bool>", marshaler, &pb.Mappy{S32Booly: map[int32]bool{1: true, 3: false, 10: true, 12: false}}, `{"s32booly":{"1":true,"3":false,"10":true,"12":false}}`},
{"map<int64, bool>", marshaler, &pb.Mappy{S64Booly: map[int64]bool{1: true, 3: false, 10: true, 12: false}}, `{"s64booly":{"1":true,"3":false,"10":true,"12":false}}`},
{"map<uint32, bool>", marshaler, &pb.Mappy{U32Booly: map[uint32]bool{1: true, 3: false, 10: true, 12: false}}, `{"u32booly":{"1":true,"3":false,"10":true,"12":false}}`},
{"map<uint64, bool>", marshaler, &pb.Mappy{U64Booly: map[uint64]bool{1: true, 3: false, 10: true, 12: false}}, `{"u64booly":{"1":true,"3":false,"10":true,"12":false}}`},
{"proto2 map<int64, string>", marshaler, &pb.Maps{MInt64Str: map[int64]string{213: "cat"}},
`{"mInt64Str":{"213":"cat"}}`},
{"proto2 map<bool, Object>", marshaler,
&pb.Maps{MBoolSimple: map[bool]*pb.Simple{true: {OInt32: proto.Int32(1)}}},
`{"mBoolSimple":{"true":{"oInt32":1}}}`},
{"oneof, not set", marshaler, &pb.MsgWithOneof{}, `{}`},
{"oneof, set", marshaler, &pb.MsgWithOneof{Union: &pb.MsgWithOneof_Title{Title: "Grand Poobah"}}, `{"title":"Grand Poobah"}`},
{"force orig_name", Marshaler{OrigName: true}, &pb.Simple{OInt32: proto.Int32(4)},
`{"o_int32":4}`},
{"proto2 extension", marshaler, realNumber, realNumberJSON},
{"Any with message", marshaler, anySimple, anySimpleJSON},
{"Any with message and indent", marshalerAllOptions, anySimple, anySimplePrettyJSON},
{"Any with WKT", marshaler, anyWellKnown, anyWellKnownJSON},
{"Any with WKT and indent", marshalerAllOptions, anyWellKnown, anyWellKnownPrettyJSON},
{"Duration", marshaler, &pb.KnownTypes{Dur: &types.Duration{Seconds: 3}}, `{"dur":"3.000s"}`},
{"Struct", marshaler, &pb.KnownTypes{St: &types.Struct{
Fields: map[string]*types.Value{
"one": {Kind: &types.Value_StringValue{StringValue: "loneliest number"}},
"two": {Kind: &types.Value_NullValue{NullValue: types.NULL_VALUE}},
},
}}, `{"st":{"one":"loneliest number","two":null}}`},
{"empty ListValue", marshaler, &pb.KnownTypes{Lv: &types.ListValue{}}, `{"lv":[]}`},
{"basic ListValue", marshaler, &pb.KnownTypes{Lv: &types.ListValue{Values: []*types.Value{
{Kind: &types.Value_StringValue{StringValue: "x"}},
{Kind: &types.Value_NullValue{}},
{Kind: &types.Value_NumberValue{NumberValue: 3}},
{Kind: &types.Value_BoolValue{BoolValue: true}},
}}}, `{"lv":["x",null,3,true]}`},
{"Timestamp", marshaler, &pb.KnownTypes{Ts: &types.Timestamp{Seconds: 14e8, Nanos: 21e6}}, `{"ts":"2014-05-13T16:53:20.021Z"}`},
{"number Value", marshaler, &pb.KnownTypes{Val: &types.Value{Kind: &types.Value_NumberValue{NumberValue: 1}}}, `{"val":1}`},
{"null Value", marshaler, &pb.KnownTypes{Val: &types.Value{Kind: &types.Value_NullValue{NullValue: types.NULL_VALUE}}}, `{"val":null}`},
{"string number value", marshaler, &pb.KnownTypes{Val: &types.Value{Kind: &types.Value_StringValue{StringValue: "9223372036854775807"}}}, `{"val":"9223372036854775807"}`},
{"list of lists Value", marshaler, &pb.KnownTypes{Val: &types.Value{
Kind: &types.Value_ListValue{ListValue: &types.ListValue{
Values: []*types.Value{
{Kind: &types.Value_StringValue{StringValue: "x"}},
{Kind: &types.Value_ListValue{ListValue: &types.ListValue{
Values: []*types.Value{
{Kind: &types.Value_ListValue{ListValue: &types.ListValue{
Values: []*types.Value{{Kind: &types.Value_StringValue{StringValue: "y"}}},
}}},
{Kind: &types.Value_StringValue{StringValue: "z"}},
},
}}},
},
}},
}}, `{"val":["x",[["y"],"z"]]}`},
{"DoubleValue", marshaler, &pb.KnownTypes{Dbl: &types.DoubleValue{Value: 1.2}}, `{"dbl":1.2}`},
{"FloatValue", marshaler, &pb.KnownTypes{Flt: &types.FloatValue{Value: 1.2}}, `{"flt":1.2}`},
{"Int64Value", marshaler, &pb.KnownTypes{I64: &types.Int64Value{Value: -3}}, `{"i64":"-3"}`},
{"UInt64Value", marshaler, &pb.KnownTypes{U64: &types.UInt64Value{Value: 3}}, `{"u64":"3"}`},
{"Int32Value", marshaler, &pb.KnownTypes{I32: &types.Int32Value{Value: -4}}, `{"i32":-4}`},
{"UInt32Value", marshaler, &pb.KnownTypes{U32: &types.UInt32Value{Value: 4}}, `{"u32":4}`},
{"BoolValue", marshaler, &pb.KnownTypes{Bool: &types.BoolValue{Value: true}}, `{"bool":true}`},
{"StringValue", marshaler, &pb.KnownTypes{Str: &types.StringValue{Value: "plush"}}, `{"str":"plush"}`},
{"BytesValue", marshaler, &pb.KnownTypes{Bytes: &types.BytesValue{Value: []byte("wow")}}, `{"bytes":"d293"}`},
}
func TestMarshaling(t *testing.T) {
for _, tt := range marshalingTests {
json, err := tt.marshaler.MarshalToString(tt.pb)
if err != nil {
t.Errorf("%s: marshaling error: %v", tt.desc, err)
} else if tt.json != json {
t.Errorf("%s: got [%v] want [%v]", tt.desc, json, tt.json)
}
}
}
func TestMarshalingWithJSONPBMarshaler(t *testing.T) {
rawJson := `{ "foo": "bar", "baz": [0, 1, 2, 3] }`
msg := dynamicMessage{rawJson: rawJson}
str, err := new(Marshaler).MarshalToString(&msg)
if err != nil {
t.Errorf("an unexpected error occurred when marshalling JSONPBMarshaler: %v", err)
}
if str != rawJson {
t.Errorf("marshalling JSON produced incorrect output: got %s, wanted %s", str, rawJson)
}
}
var unmarshalingTests = []struct {
desc string
unmarshaler Unmarshaler
json string
pb proto.Message
}{
{"simple flat object", Unmarshaler{}, simpleObjectJSON, simpleObject},
{"simple pretty object", Unmarshaler{}, simpleObjectPrettyJSON, simpleObject},
{"repeated fields flat object", Unmarshaler{}, repeatsObjectJSON, repeatsObject},
{"repeated fields pretty object", Unmarshaler{}, repeatsObjectPrettyJSON, repeatsObject},
{"nested message/enum flat object", Unmarshaler{}, complexObjectJSON, complexObject},
{"nested message/enum pretty object", Unmarshaler{}, complexObjectPrettyJSON, complexObject},
{"enum-string object", Unmarshaler{}, `{"color":"BLUE"}`, &pb.Widget{Color: pb.Widget_BLUE.Enum()}},
{"enum-value object", Unmarshaler{}, "{\n \"color\": 2\n}", &pb.Widget{Color: pb.Widget_BLUE.Enum()}},
{"unknown field with allowed option", Unmarshaler{AllowUnknownFields: true}, `{"unknown": "foo"}`, new(pb.Simple)},
{"proto3 enum string", Unmarshaler{}, `{"hilarity":"PUNS"}`, &proto3pb.Message{Hilarity: proto3pb.Message_PUNS}},
{"proto3 enum value", Unmarshaler{}, `{"hilarity":1}`, &proto3pb.Message{Hilarity: proto3pb.Message_PUNS}},
{"unknown enum value object",
Unmarshaler{},
"{\n \"color\": 1000,\n \"r_color\": [\n \"RED\"\n ]\n}",
&pb.Widget{Color: pb.Widget_Color(1000).Enum(), RColor: []pb.Widget_Color{pb.Widget_RED}}},
{"repeated proto3 enum", Unmarshaler{}, `{"rFunny":["PUNS","SLAPSTICK"]}`,
&proto3pb.Message{RFunny: []proto3pb.Message_Humour{
proto3pb.Message_PUNS,
proto3pb.Message_SLAPSTICK,
}}},
{"repeated proto3 enum as int", Unmarshaler{}, `{"rFunny":[1,2]}`,
&proto3pb.Message{RFunny: []proto3pb.Message_Humour{
proto3pb.Message_PUNS,
proto3pb.Message_SLAPSTICK,
}}},
{"repeated proto3 enum as mix of strings and ints", Unmarshaler{}, `{"rFunny":["PUNS",2]}`,
&proto3pb.Message{RFunny: []proto3pb.Message_Humour{
proto3pb.Message_PUNS,
proto3pb.Message_SLAPSTICK,
}}},
{"unquoted int64 object", Unmarshaler{}, `{"oInt64":-314}`, &pb.Simple{OInt64: proto.Int64(-314)}},
{"unquoted uint64 object", Unmarshaler{}, `{"oUint64":123}`, &pb.Simple{OUint64: proto.Uint64(123)}},
{"map<int64, int32>", Unmarshaler{}, `{"nummy":{"1":2,"3":4}}`, &pb.Mappy{Nummy: map[int64]int32{1: 2, 3: 4}}},
{"map<string, string>", Unmarshaler{}, `{"strry":{"\"one\"":"two","three":"four"}}`, &pb.Mappy{Strry: map[string]string{`"one"`: "two", "three": "four"}}},
{"map<int32, Object>", Unmarshaler{}, `{"objjy":{"1":{"dub":1}}}`, &pb.Mappy{Objjy: map[int32]*pb.Simple3{1: {Dub: 1}}}},
{"proto2 extension", Unmarshaler{}, realNumberJSON, realNumber},
// TODO does not work with go version 1.7, but works with go version 1.8 {"Any with message", Unmarshaler{}, anySimpleJSON, anySimple},
// TODO does not work with go version 1.7, but works with go version 1.8 {"Any with message and indent", Unmarshaler{}, anySimplePrettyJSON, anySimple},
{"Any with WKT", Unmarshaler{}, anyWellKnownJSON, anyWellKnown},
{"Any with WKT and indent", Unmarshaler{}, anyWellKnownPrettyJSON, anyWellKnown},
// TODO: This is broken.
//{"map<string, enum>", Unmarshaler{}, `{"enumy":{"XIV":"ROMAN"}`, &pb.Mappy{Enumy: map[string]pb.Numeral{"XIV": pb.Numeral_ROMAN}}},
{"map<string, enum as int>", Unmarshaler{}, `{"enumy":{"XIV":2}}`, &pb.Mappy{Enumy: map[string]pb.Numeral{"XIV": pb.Numeral_ROMAN}}},
{"oneof", Unmarshaler{}, `{"salary":31000}`, &pb.MsgWithOneof{Union: &pb.MsgWithOneof_Salary{Salary: 31000}}},
{"oneof spec name", Unmarshaler{}, `{"Country":"Australia"}`, &pb.MsgWithOneof{Union: &pb.MsgWithOneof_Country{Country: "Australia"}}},
{"oneof orig_name", Unmarshaler{}, `{"Country":"Australia"}`, &pb.MsgWithOneof{Union: &pb.MsgWithOneof_Country{Country: "Australia"}}},
{"oneof spec name2", Unmarshaler{}, `{"homeAddress":"Australia"}`, &pb.MsgWithOneof{Union: &pb.MsgWithOneof_HomeAddress{HomeAddress: "Australia"}}},
{"oneof orig_name2", Unmarshaler{}, `{"home_address":"Australia"}`, &pb.MsgWithOneof{Union: &pb.MsgWithOneof_HomeAddress{HomeAddress: "Australia"}}},
{"orig_name input", Unmarshaler{}, `{"o_bool":true}`, &pb.Simple{OBool: proto.Bool(true)}},
{"camelName input", Unmarshaler{}, `{"oBool":true}`, &pb.Simple{OBool: proto.Bool(true)}},
{"Duration", Unmarshaler{}, `{"dur":"3.000s"}`, &pb.KnownTypes{Dur: &types.Duration{Seconds: 3}}},
{"null Duration", Unmarshaler{}, `{"dur":null}`, &pb.KnownTypes{Dur: &types.Duration{Seconds: 0}}},
{"Timestamp", Unmarshaler{}, `{"ts":"2014-05-13T16:53:20.021Z"}`, &pb.KnownTypes{Ts: &types.Timestamp{Seconds: 14e8, Nanos: 21e6}}},
{"PreEpochTimestamp", Unmarshaler{}, `{"ts":"1969-12-31T23:59:58.999999995Z"}`, &pb.KnownTypes{Ts: &types.Timestamp{Seconds: -2, Nanos: 999999995}}},
{"ZeroTimeTimestamp", Unmarshaler{}, `{"ts":"0001-01-01T00:00:00Z"}`, &pb.KnownTypes{Ts: &types.Timestamp{Seconds: -62135596800, Nanos: 0}}},
{"null Timestamp", Unmarshaler{}, `{"ts":null}`, &pb.KnownTypes{Ts: &types.Timestamp{Seconds: 0, Nanos: 0}}},
{"null Struct", Unmarshaler{}, `{"st": null}`, &pb.KnownTypes{St: &types.Struct{}}},
{"empty Struct", Unmarshaler{}, `{"st": {}}`, &pb.KnownTypes{St: &types.Struct{}}},
{"basic Struct", Unmarshaler{}, `{"st": {"a": "x", "b": null, "c": 3, "d": true}}`, &pb.KnownTypes{St: &types.Struct{Fields: map[string]*types.Value{
"a": {Kind: &types.Value_StringValue{StringValue: "x"}},
"b": {Kind: &types.Value_NullValue{}},
"c": {Kind: &types.Value_NumberValue{NumberValue: 3}},
"d": {Kind: &types.Value_BoolValue{BoolValue: true}},
}}}},
{"nested Struct", Unmarshaler{}, `{"st": {"a": {"b": 1, "c": [{"d": true}, "f"]}}}`, &pb.KnownTypes{St: &types.Struct{Fields: map[string]*types.Value{
"a": {Kind: &types.Value_StructValue{StructValue: &types.Struct{Fields: map[string]*types.Value{
"b": {Kind: &types.Value_NumberValue{NumberValue: 1}},
"c": {Kind: &types.Value_ListValue{ListValue: &types.ListValue{Values: []*types.Value{
{Kind: &types.Value_StructValue{StructValue: &types.Struct{Fields: map[string]*types.Value{"d": {Kind: &types.Value_BoolValue{BoolValue: true}}}}}},
{Kind: &types.Value_StringValue{StringValue: "f"}},
}}}},
}}}},
}}}},
{"null ListValue", Unmarshaler{}, `{"lv": null}`, &pb.KnownTypes{Lv: &types.ListValue{}}},
{"empty ListValue", Unmarshaler{}, `{"lv": []}`, &pb.KnownTypes{Lv: &types.ListValue{}}},
{"basic ListValue", Unmarshaler{}, `{"lv": ["x", null, 3, true]}`, &pb.KnownTypes{Lv: &types.ListValue{Values: []*types.Value{
{Kind: &types.Value_StringValue{StringValue: "x"}},
{Kind: &types.Value_NullValue{}},
{Kind: &types.Value_NumberValue{NumberValue: 3}},
{Kind: &types.Value_BoolValue{BoolValue: true}},
}}}},
{"number Value", Unmarshaler{}, `{"val":1}`, &pb.KnownTypes{Val: &types.Value{Kind: &types.Value_NumberValue{NumberValue: 1}}}},
{"null Value", Unmarshaler{}, `{"val":null}`, &pb.KnownTypes{Val: &types.Value{Kind: &types.Value_NullValue{NullValue: types.NULL_VALUE}}}},
{"bool Value", Unmarshaler{}, `{"val":true}`, &pb.KnownTypes{Val: &types.Value{Kind: &types.Value_BoolValue{BoolValue: true}}}},
{"string Value", Unmarshaler{}, `{"val":"x"}`, &pb.KnownTypes{Val: &types.Value{Kind: &types.Value_StringValue{StringValue: "x"}}}},
{"string number value", Unmarshaler{}, `{"val":"9223372036854775807"}`, &pb.KnownTypes{Val: &types.Value{Kind: &types.Value_StringValue{StringValue: "9223372036854775807"}}}},
{"list of lists Value", Unmarshaler{}, `{"val":["x", [["y"], "z"]]}`, &pb.KnownTypes{Val: &types.Value{
Kind: &types.Value_ListValue{ListValue: &types.ListValue{
Values: []*types.Value{
{Kind: &types.Value_StringValue{StringValue: "x"}},
{Kind: &types.Value_ListValue{ListValue: &types.ListValue{
Values: []*types.Value{
{Kind: &types.Value_ListValue{ListValue: &types.ListValue{
Values: []*types.Value{{Kind: &types.Value_StringValue{StringValue: "y"}}},
}}},
{Kind: &types.Value_StringValue{StringValue: "z"}},
},
}}},
},
}}}}},
{"DoubleValue", Unmarshaler{}, `{"dbl":1.2}`, &pb.KnownTypes{Dbl: &types.DoubleValue{Value: 1.2}}},
{"FloatValue", Unmarshaler{}, `{"flt":1.2}`, &pb.KnownTypes{Flt: &types.FloatValue{Value: 1.2}}},
{"Int64Value", Unmarshaler{}, `{"i64":"-3"}`, &pb.KnownTypes{I64: &types.Int64Value{Value: -3}}},
{"UInt64Value", Unmarshaler{}, `{"u64":"3"}`, &pb.KnownTypes{U64: &types.UInt64Value{Value: 3}}},
{"Int32Value", Unmarshaler{}, `{"i32":-4}`, &pb.KnownTypes{I32: &types.Int32Value{Value: -4}}},
{"UInt32Value", Unmarshaler{}, `{"u32":4}`, &pb.KnownTypes{U32: &types.UInt32Value{Value: 4}}},
{"BoolValue", Unmarshaler{}, `{"bool":true}`, &pb.KnownTypes{Bool: &types.BoolValue{Value: true}}},
{"StringValue", Unmarshaler{}, `{"str":"plush"}`, &pb.KnownTypes{Str: &types.StringValue{Value: "plush"}}},
{"BytesValue", Unmarshaler{}, `{"bytes":"d293"}`, &pb.KnownTypes{Bytes: &types.BytesValue{Value: []byte("wow")}}},
// `null` is also a permissible value. Let's just test one.
{"null DoubleValue", Unmarshaler{}, `{"dbl":null}`, &pb.KnownTypes{Dbl: &types.DoubleValue{}}},
}
func TestUnmarshaling(t *testing.T) {
for _, tt := range unmarshalingTests {
// Make a new instance of the type of our expected object.
p := reflect.New(reflect.TypeOf(tt.pb).Elem()).Interface().(proto.Message)
err := tt.unmarshaler.Unmarshal(strings.NewReader(tt.json), p)
if err != nil {
t.Errorf("%s: %v", tt.desc, err)
continue
}
// For easier diffs, compare text strings of the protos.
exp := proto.MarshalTextString(tt.pb)
act := proto.MarshalTextString(p)
if string(exp) != string(act) {
t.Errorf("%s: got [%s] want [%s]", tt.desc, act, exp)
}
}
}
func TestUnmarshalNext(t *testing.T) {
// We only need to check against a few, not all of them.
tests := unmarshalingTests[:5]
// Create a buffer with many concatenated JSON objects.
var b bytes.Buffer
for _, tt := range tests {
b.WriteString(tt.json)
}
dec := json.NewDecoder(&b)
for _, tt := range tests {
// Make a new instance of the type of our expected object.
p := reflect.New(reflect.TypeOf(tt.pb).Elem()).Interface().(proto.Message)
err := tt.unmarshaler.UnmarshalNext(dec, p)
if err != nil {
t.Errorf("%s: %v", tt.desc, err)
continue
}
// For easier diffs, compare text strings of the protos.
exp := proto.MarshalTextString(tt.pb)
act := proto.MarshalTextString(p)
if string(exp) != string(act) {
t.Errorf("%s: got [%s] want [%s]", tt.desc, act, exp)
}
}
p := &pb.Simple{}
err := new(Unmarshaler).UnmarshalNext(dec, p)
if err != io.EOF {
t.Errorf("eof: got %v, expected io.EOF", err)
}
}
var unmarshalingShouldError = []struct {
desc string
in string
pb proto.Message
}{
{"a value", "666", new(pb.Simple)},
{"gibberish", "{adskja123;l23=-=", new(pb.Simple)},
{"unknown field", `{"unknown": "foo"}`, new(pb.Simple)},
{"unknown enum name", `{"hilarity":"DAVE"}`, new(proto3pb.Message)},
}
func TestUnmarshalingBadInput(t *testing.T) {
for _, tt := range unmarshalingShouldError {
err := UnmarshalString(tt.in, tt.pb)
if err == nil {
t.Errorf("an error was expected when parsing %q instead of an object", tt.desc)
}
}
}
func TestUnmarshalWithJSONPBUnmarshaler(t *testing.T) {
rawJson := `{ "foo": "bar", "baz": [0, 1, 2, 3] }`
var msg dynamicMessage
err := Unmarshal(strings.NewReader(rawJson), &msg)
if err != nil {
t.Errorf("an unexpected error occurred when parsing into JSONPBUnmarshaler: %v", err)
}
if msg.rawJson != rawJson {
t.Errorf("message contents not set correctly after unmarshalling JSON: got %s, wanted %s", msg.rawJson, rawJson)
}
}
// dynamicMessage implements protobuf.Message but is not a normal generated message type.
// It provides implementations of JSONPBMarshaler and JSONPBUnmarshaler for JSON support.
type dynamicMessage struct {
rawJson string
}
func (m *dynamicMessage) Reset() {
m.rawJson = "{}"
}
func (m *dynamicMessage) String() string {
return m.rawJson
}
func (m *dynamicMessage) ProtoMessage() {
}
func (m *dynamicMessage) MarshalJSONPB(jm *Marshaler) ([]byte, error) {
return []byte(m.rawJson), nil
}
func (m *dynamicMessage) UnmarshalJSONPB(jum *Unmarshaler, json []byte) error {
m.rawJson = string(json)
return nil
}
-33
View File
@@ -1,33 +0,0 @@
# Go support for Protocol Buffers - Google's data interchange format
#
# Copyright 2015 The Go Authors. All rights reserved.
# https://github.com/golang/protobuf
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following disclaimer
# in the documentation and/or other materials provided with the
# distribution.
# * Neither the name of Google Inc. nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
regenerate:
protoc-min-version --version="3.0.0" --gogo_out=Mgoogle/protobuf/any.proto=github.com/gogo/protobuf/types,Mgoogle/protobuf/duration.proto=github.com/gogo/protobuf/types,Mgoogle/protobuf/timestamp.proto=github.com/gogo/protobuf/types,Mgoogle/protobuf/wrappers.proto=github.com/gogo/protobuf/types,Mgoogle/protobuf/struct.proto=github.com/gogo/protobuf/types:. *.proto -I . -I ../../ -I ../../protobuf/
@@ -15,6 +15,7 @@ It has these top-level messages:
SimpleNull3
Mappy
Simple
NonFinites
Repeats
Widget
Maps
@@ -1,69 +0,0 @@
// Go support for Protocol Buffers - Google's data interchange format
//
// Copyright 2015 The Go Authors. All rights reserved.
// https://github.com/golang/protobuf
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
syntax = "proto3";
package jsonpb;
message Simple3 {
double dub = 1;
}
message SimpleSlice3 {
repeated string slices = 1;
}
message SimpleMap3 {
map<string,string> stringy = 1;
}
message SimpleNull3 {
Simple3 simple = 1;
}
enum Numeral {
UNKNOWN = 0;
ARABIC = 1;
ROMAN = 2;
}
message Mappy {
map<int64, int32> nummy = 1;
map<string, string> strry = 2;
map<int32, Simple3> objjy = 3;
map<int64, string> buggy = 4;
map<bool, bool> booly = 5;
map<string, Numeral> enumy = 6;
map<int32, bool> s32booly = 7;
map<int64, bool> s64booly = 8;
map<uint32, bool> u32booly = 9;
map<uint64, bool> u64booly = 10;
}
+145 -81
View File
@@ -12,7 +12,7 @@ import google_protobuf2 "github.com/gogo/protobuf/types"
import google_protobuf3 "github.com/gogo/protobuf/types"
import google_protobuf4 "github.com/gogo/protobuf/types"
// skipping weak import gogoproto "gogoproto"
// skipping weak import gogoproto "github.com/gogo/protobuf/gogoproto"
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
@@ -54,7 +54,7 @@ func (x *Widget_Color) UnmarshalJSON(data []byte) error {
*x = Widget_Color(value)
return nil
}
func (Widget_Color) EnumDescriptor() ([]byte, []int) { return fileDescriptorTestObjects, []int{2, 0} }
func (Widget_Color) EnumDescriptor() ([]byte, []int) { return fileDescriptorTestObjects, []int{3, 0} }
// Test message for holding primitive types.
type Simple struct {
@@ -162,6 +162,64 @@ func (m *Simple) GetOCastBytes() Bytes {
return nil
}
// Test message for holding special non-finites primitives.
type NonFinites struct {
FNan *float32 `protobuf:"fixed32,1,opt,name=f_nan,json=fNan" json:"f_nan,omitempty"`
FPinf *float32 `protobuf:"fixed32,2,opt,name=f_pinf,json=fPinf" json:"f_pinf,omitempty"`
FNinf *float32 `protobuf:"fixed32,3,opt,name=f_ninf,json=fNinf" json:"f_ninf,omitempty"`
DNan *float64 `protobuf:"fixed64,4,opt,name=d_nan,json=dNan" json:"d_nan,omitempty"`
DPinf *float64 `protobuf:"fixed64,5,opt,name=d_pinf,json=dPinf" json:"d_pinf,omitempty"`
DNinf *float64 `protobuf:"fixed64,6,opt,name=d_ninf,json=dNinf" json:"d_ninf,omitempty"`
XXX_unrecognized []byte `json:"-"`
}
func (m *NonFinites) Reset() { *m = NonFinites{} }
func (m *NonFinites) String() string { return proto.CompactTextString(m) }
func (*NonFinites) ProtoMessage() {}
func (*NonFinites) Descriptor() ([]byte, []int) { return fileDescriptorTestObjects, []int{1} }
func (m *NonFinites) GetFNan() float32 {
if m != nil && m.FNan != nil {
return *m.FNan
}
return 0
}
func (m *NonFinites) GetFPinf() float32 {
if m != nil && m.FPinf != nil {
return *m.FPinf
}
return 0
}
func (m *NonFinites) GetFNinf() float32 {
if m != nil && m.FNinf != nil {
return *m.FNinf
}
return 0
}
func (m *NonFinites) GetDNan() float64 {
if m != nil && m.DNan != nil {
return *m.DNan
}
return 0
}
func (m *NonFinites) GetDPinf() float64 {
if m != nil && m.DPinf != nil {
return *m.DPinf
}
return 0
}
func (m *NonFinites) GetDNinf() float64 {
if m != nil && m.DNinf != nil {
return *m.DNinf
}
return 0
}
// Test message for holding repeated primitives.
type Repeats struct {
RBool []bool `protobuf:"varint,1,rep,name=r_bool,json=rBool" json:"r_bool,omitempty"`
@@ -181,7 +239,7 @@ type Repeats struct {
func (m *Repeats) Reset() { *m = Repeats{} }
func (m *Repeats) String() string { return proto.CompactTextString(m) }
func (*Repeats) ProtoMessage() {}
func (*Repeats) Descriptor() ([]byte, []int) { return fileDescriptorTestObjects, []int{1} }
func (*Repeats) Descriptor() ([]byte, []int) { return fileDescriptorTestObjects, []int{2} }
func (m *Repeats) GetRBool() []bool {
if m != nil {
@@ -274,7 +332,7 @@ type Widget struct {
func (m *Widget) Reset() { *m = Widget{} }
func (m *Widget) String() string { return proto.CompactTextString(m) }
func (*Widget) ProtoMessage() {}
func (*Widget) Descriptor() ([]byte, []int) { return fileDescriptorTestObjects, []int{2} }
func (*Widget) Descriptor() ([]byte, []int) { return fileDescriptorTestObjects, []int{3} }
func (m *Widget) GetColor() Widget_Color {
if m != nil && m.Color != nil {
@@ -327,7 +385,7 @@ type Maps struct {
func (m *Maps) Reset() { *m = Maps{} }
func (m *Maps) String() string { return proto.CompactTextString(m) }
func (*Maps) ProtoMessage() {}
func (*Maps) Descriptor() ([]byte, []int) { return fileDescriptorTestObjects, []int{3} }
func (*Maps) Descriptor() ([]byte, []int) { return fileDescriptorTestObjects, []int{4} }
func (m *Maps) GetMInt64Str() map[int64]string {
if m != nil {
@@ -356,7 +414,7 @@ type MsgWithOneof struct {
func (m *MsgWithOneof) Reset() { *m = MsgWithOneof{} }
func (m *MsgWithOneof) String() string { return proto.CompactTextString(m) }
func (*MsgWithOneof) ProtoMessage() {}
func (*MsgWithOneof) Descriptor() ([]byte, []int) { return fileDescriptorTestObjects, []int{4} }
func (*MsgWithOneof) Descriptor() ([]byte, []int) { return fileDescriptorTestObjects, []int{5} }
type isMsgWithOneof_Union interface {
isMsgWithOneof_Union()
@@ -519,7 +577,7 @@ type Real struct {
func (m *Real) Reset() { *m = Real{} }
func (m *Real) String() string { return proto.CompactTextString(m) }
func (*Real) ProtoMessage() {}
func (*Real) Descriptor() ([]byte, []int) { return fileDescriptorTestObjects, []int{5} }
func (*Real) Descriptor() ([]byte, []int) { return fileDescriptorTestObjects, []int{6} }
var extRange_Real = []proto.ExtensionRange{
{Start: 100, End: 536870911},
@@ -545,7 +603,7 @@ type Complex struct {
func (m *Complex) Reset() { *m = Complex{} }
func (m *Complex) String() string { return proto.CompactTextString(m) }
func (*Complex) ProtoMessage() {}
func (*Complex) Descriptor() ([]byte, []int) { return fileDescriptorTestObjects, []int{6} }
func (*Complex) Descriptor() ([]byte, []int) { return fileDescriptorTestObjects, []int{7} }
var extRange_Complex = []proto.ExtensionRange{
{Start: 100, End: 536870911},
@@ -593,7 +651,7 @@ type KnownTypes struct {
func (m *KnownTypes) Reset() { *m = KnownTypes{} }
func (m *KnownTypes) String() string { return proto.CompactTextString(m) }
func (*KnownTypes) ProtoMessage() {}
func (*KnownTypes) Descriptor() ([]byte, []int) { return fileDescriptorTestObjects, []int{7} }
func (*KnownTypes) Descriptor() ([]byte, []int) { return fileDescriptorTestObjects, []int{8} }
func (m *KnownTypes) GetAn() *google_protobuf.Any {
if m != nil {
@@ -711,6 +769,7 @@ var E_Name = &proto.ExtensionDesc{
func init() {
proto.RegisterType((*Simple)(nil), "jsonpb.Simple")
proto.RegisterType((*NonFinites)(nil), "jsonpb.NonFinites")
proto.RegisterType((*Repeats)(nil), "jsonpb.Repeats")
proto.RegisterType((*Widget)(nil), "jsonpb.Widget")
proto.RegisterType((*Maps)(nil), "jsonpb.Maps")
@@ -726,76 +785,81 @@ func init() {
func init() { proto.RegisterFile("test_objects.proto", fileDescriptorTestObjects) }
var fileDescriptorTestObjects = []byte{
// 1128 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x74, 0x95, 0xdd, 0x92, 0xdb, 0x34,
0x14, 0xc7, 0x6b, 0x3b, 0xce, 0x87, 0x92, 0x6e, 0x83, 0x66, 0xdb, 0xba, 0xa1, 0x50, 0x4f, 0x28,
0xc5, 0xb4, 0x34, 0x1d, 0xbc, 0x99, 0x0c, 0x53, 0xb8, 0xd9, 0x8f, 0x40, 0x19, 0xba, 0x65, 0x46,
0xdb, 0xa5, 0xdc, 0x65, 0x9c, 0x8d, 0x36, 0x75, 0x71, 0xac, 0x8c, 0x24, 0xef, 0x36, 0x03, 0x17,
0x7b, 0xcd, 0x35, 0xcf, 0xc0, 0x23, 0x70, 0xc1, 0x63, 0xf0, 0x00, 0x3c, 0x08, 0x57, 0xcc, 0x39,
0xb2, 0xe3, 0xdd, 0x64, 0x73, 0x15, 0x4b, 0xe7, 0x7f, 0xfe, 0x91, 0x7e, 0x3a, 0xd2, 0x21, 0x54,
0x73, 0xa5, 0x47, 0x62, 0xfc, 0x8e, 0x9f, 0x68, 0xd5, 0x9b, 0x4b, 0xa1, 0x05, 0xad, 0xbe, 0x53,
0x22, 0x9d, 0x8f, 0x3b, 0xf7, 0xa6, 0x42, 0x4c, 0x13, 0xfe, 0x0c, 0x67, 0xc7, 0xd9, 0xe9, 0xb3,
0x28, 0x5d, 0x18, 0x49, 0xe7, 0xe3, 0xd5, 0xd0, 0x24, 0x93, 0x91, 0x8e, 0x45, 0x9a, 0xc7, 0xef,
0xaf, 0xc6, 0x95, 0x96, 0xd9, 0x89, 0xce, 0xa3, 0x0f, 0x56, 0xa3, 0x3a, 0x9e, 0x71, 0xa5, 0xa3,
0xd9, 0x7c, 0x93, 0xfd, 0xb9, 0x8c, 0xe6, 0x73, 0x2e, 0xf3, 0x15, 0x76, 0xb6, 0xa7, 0x62, 0x2a,
0xf0, 0xf3, 0x19, 0x7c, 0x99, 0xd9, 0xee, 0x3f, 0x36, 0xa9, 0x1e, 0xc5, 0xb3, 0x79, 0xc2, 0xe9,
0x6d, 0x52, 0x15, 0xa3, 0xb1, 0x10, 0x89, 0x67, 0xf9, 0x56, 0x50, 0x67, 0xae, 0xd8, 0x13, 0x22,
0xa1, 0x77, 0x49, 0x4d, 0x8c, 0xe2, 0x54, 0xef, 0x84, 0x9e, 0xed, 0x5b, 0x81, 0xcb, 0xaa, 0xe2,
0x7b, 0x18, 0x2d, 0x03, 0x83, 0xbe, 0xe7, 0xf8, 0x56, 0xe0, 0x98, 0xc0, 0xa0, 0x4f, 0xef, 0x91,
0xba, 0x18, 0x65, 0x26, 0xa5, 0xe2, 0x5b, 0xc1, 0x4d, 0x56, 0x13, 0xc7, 0x38, 0x2c, 0x43, 0x83,
0xbe, 0xe7, 0xfa, 0x56, 0x50, 0xc9, 0x43, 0x45, 0x96, 0x32, 0x59, 0x55, 0xdf, 0x0a, 0x3e, 0x60,
0x35, 0x71, 0x74, 0x29, 0x4b, 0x99, 0xac, 0x9a, 0x6f, 0x05, 0x34, 0x0f, 0x0d, 0xfa, 0x66, 0x11,
0xa7, 0x89, 0x88, 0xb4, 0x57, 0xf7, 0xad, 0xc0, 0x66, 0x55, 0xf1, 0x2d, 0x8c, 0x4c, 0xce, 0x44,
0x64, 0xe3, 0x84, 0x7b, 0x0d, 0xdf, 0x0a, 0x2c, 0x56, 0x13, 0x07, 0x38, 0xcc, 0xed, 0xb4, 0x8c,
0xd3, 0xa9, 0x47, 0x7c, 0x2b, 0x68, 0x80, 0x1d, 0x0e, 0x8d, 0xdd, 0x78, 0xa1, 0xb9, 0xf2, 0x9a,
0xbe, 0x15, 0xb4, 0x58, 0x55, 0xec, 0xc1, 0x88, 0x3e, 0x21, 0x2d, 0x31, 0x3a, 0x89, 0x94, 0xce,
0xa3, 0x2d, 0x88, 0xee, 0x35, 0xfe, 0xfb, 0xf7, 0x81, 0x8b, 0x02, 0x46, 0xc4, 0x7e, 0xa4, 0x34,
0x7e, 0x77, 0xff, 0xb4, 0x49, 0x8d, 0xf1, 0x39, 0x8f, 0xb4, 0x02, 0xaa, 0xb2, 0xa0, 0xea, 0x00,
0x55, 0x59, 0x50, 0x95, 0x4b, 0xaa, 0x0e, 0x50, 0x95, 0x4b, 0xaa, 0x72, 0x49, 0xd5, 0x01, 0xaa,
0x72, 0x49, 0x55, 0x96, 0x54, 0x1d, 0xa0, 0x2a, 0x4b, 0xaa, 0xb2, 0xa4, 0xea, 0x00, 0x55, 0x59,
0x52, 0x95, 0x25, 0x55, 0x07, 0xa8, 0xca, 0xa3, 0x4b, 0x59, 0x4b, 0xaa, 0x0e, 0x50, 0x95, 0x25,
0x55, 0xb9, 0xa4, 0xea, 0x00, 0x55, 0xb9, 0xa4, 0x2a, 0x4b, 0xaa, 0x0e, 0x50, 0x95, 0x25, 0x55,
0x59, 0x52, 0x75, 0x80, 0xaa, 0x2c, 0xa9, 0xca, 0x25, 0x55, 0x07, 0xa8, 0x4a, 0x03, 0xea, 0x2f,
0x9b, 0x54, 0xdf, 0xc4, 0x93, 0x29, 0xd7, 0xf4, 0x31, 0x71, 0x4f, 0x44, 0x22, 0x24, 0x16, 0xdf,
0x56, 0xb8, 0xdd, 0x33, 0x17, 0xaa, 0x67, 0xc2, 0xbd, 0x7d, 0x88, 0x31, 0x23, 0xa1, 0x4f, 0xc1,
0xcf, 0xa8, 0x01, 0xde, 0x26, 0x75, 0x55, 0xe2, 0x2f, 0x7d, 0x44, 0xaa, 0x0a, 0x4b, 0x1c, 0x4f,
0xbb, 0x19, 0x6e, 0x15, 0x6a, 0x53, 0xf8, 0x2c, 0x8f, 0xd2, 0xcf, 0x0d, 0x10, 0x54, 0xc2, 0x3a,
0xd7, 0x95, 0x00, 0x28, 0x97, 0xd6, 0xa4, 0x39, 0x60, 0x6f, 0x1b, 0x3d, 0x6f, 0x15, 0xca, 0xfc,
0xdc, 0x59, 0x11, 0xa7, 0x5f, 0x90, 0x86, 0x1c, 0x15, 0xe2, 0xdb, 0x68, 0xbb, 0x26, 0xae, 0xcb,
0xfc, 0xab, 0xfb, 0x29, 0x71, 0xcd, 0xa2, 0x6b, 0xc4, 0x61, 0xc3, 0x83, 0xf6, 0x0d, 0xda, 0x20,
0xee, 0x77, 0x6c, 0x38, 0x7c, 0xd5, 0xb6, 0x68, 0x9d, 0x54, 0xf6, 0x5e, 0x1e, 0x0f, 0xdb, 0x76,
0xf7, 0x0f, 0x9b, 0x54, 0x0e, 0xa3, 0xb9, 0xa2, 0x5f, 0x93, 0xe6, 0xcc, 0x94, 0x0b, 0xb0, 0xc7,
0x1a, 0x6b, 0x86, 0x1f, 0x16, 0xfe, 0x20, 0xe9, 0x1d, 0x62, 0xfd, 0x1c, 0x69, 0x39, 0x4c, 0xb5,
0x5c, 0xb0, 0xc6, 0xac, 0x18, 0xd3, 0x5d, 0x72, 0x73, 0x86, 0xb5, 0x59, 0xec, 0xda, 0xc6, 0xf4,
0x8f, 0xae, 0xa6, 0x43, 0xbd, 0x9a, 0x6d, 0x1b, 0x83, 0xe6, 0xac, 0x9c, 0xe9, 0x7c, 0x43, 0xb6,
0xae, 0xfa, 0xd3, 0x36, 0x71, 0x7e, 0xe1, 0x0b, 0x3c, 0x46, 0x87, 0xc1, 0x27, 0xdd, 0x26, 0xee,
0x59, 0x94, 0x64, 0x1c, 0xdf, 0x8f, 0x06, 0x33, 0x83, 0xe7, 0xf6, 0x57, 0x56, 0xe7, 0x15, 0x69,
0xaf, 0xda, 0x5f, 0xce, 0xaf, 0x9b, 0xfc, 0x87, 0x97, 0xf3, 0xd7, 0x0f, 0xa5, 0xf4, 0xeb, 0xfe,
0x6e, 0x91, 0xd6, 0xa1, 0x9a, 0xbe, 0x89, 0xf5, 0xdb, 0x1f, 0x53, 0x2e, 0x4e, 0xe9, 0x1d, 0xe2,
0xea, 0x58, 0x27, 0x1c, 0xed, 0x1a, 0x2f, 0x6e, 0x30, 0x33, 0xa4, 0x1e, 0xa9, 0xaa, 0x28, 0x89,
0xe4, 0x02, 0x3d, 0x9d, 0x17, 0x37, 0x58, 0x3e, 0xa6, 0x1d, 0x52, 0xdb, 0x17, 0x19, 0xac, 0x04,
0x5f, 0x35, 0xc8, 0x29, 0x26, 0xe8, 0x27, 0xa4, 0xf5, 0x56, 0xcc, 0xf8, 0x28, 0x9a, 0x4c, 0x24,
0x57, 0x0a, 0x1f, 0x37, 0x10, 0x34, 0x61, 0x76, 0xd7, 0x4c, 0xee, 0xd5, 0x88, 0x9b, 0xa5, 0xb1,
0x48, 0xbb, 0x8f, 0x48, 0x85, 0xf1, 0x28, 0x29, 0xb7, 0x6f, 0xe1, 0x33, 0x64, 0x06, 0x8f, 0xeb,
0xf5, 0x49, 0xfb, 0xe2, 0xe2, 0xe2, 0xc2, 0xee, 0x9e, 0xc3, 0x3f, 0xc2, 0x4e, 0xde, 0xd3, 0xfb,
0xa4, 0x11, 0xcf, 0xa2, 0x69, 0x9c, 0xc2, 0xca, 0x8c, 0xbc, 0x9c, 0x28, 0x53, 0xc2, 0x03, 0xb2,
0x25, 0x79, 0x94, 0x8c, 0xf8, 0x7b, 0xcd, 0x53, 0x15, 0x8b, 0x94, 0xb6, 0xca, 0x92, 0x8a, 0x12,
0xef, 0xd7, 0xab, 0x35, 0x99, 0xdb, 0xb3, 0x9b, 0x90, 0x34, 0x2c, 0x72, 0xba, 0x7f, 0xbb, 0x84,
0xfc, 0x90, 0x8a, 0xf3, 0xf4, 0xf5, 0x62, 0xce, 0x15, 0x7d, 0x48, 0xec, 0x28, 0xf5, 0xb6, 0x30,
0x75, 0xbb, 0x67, 0xba, 0x49, 0xaf, 0xe8, 0x26, 0xbd, 0xdd, 0x74, 0xc1, 0xec, 0x28, 0xa5, 0x4f,
0x88, 0x33, 0xc9, 0xcc, 0x2d, 0x6d, 0x86, 0xf7, 0xd6, 0x64, 0x07, 0x79, 0x4f, 0x63, 0xa0, 0xa2,
0x9f, 0x11, 0x5b, 0x69, 0x7c, 0x2b, 0x9b, 0xe1, 0xdd, 0x35, 0xed, 0x11, 0xf6, 0x37, 0x66, 0x2b,
0xb8, 0xfd, 0xb6, 0x56, 0xf9, 0xf9, 0x76, 0xd6, 0x84, 0xaf, 0x8b, 0x56, 0xc7, 0x6c, 0xad, 0x40,
0x9b, 0x9c, 0x79, 0xb7, 0x36, 0x68, 0x5f, 0xc6, 0x4a, 0xff, 0x04, 0x84, 0x99, 0x9d, 0x9c, 0xd1,
0x80, 0x38, 0x67, 0x51, 0xe2, 0xb5, 0x51, 0x7c, 0x67, 0x4d, 0x6c, 0x84, 0x20, 0xa1, 0x3d, 0xe2,
0x4c, 0xc6, 0x09, 0x9e, 0x79, 0x33, 0xbc, 0xbf, 0xbe, 0x2f, 0x7c, 0xe4, 0x72, 0xfd, 0x64, 0x9c,
0xd0, 0xa7, 0xc4, 0x39, 0x4d, 0x34, 0x96, 0x00, 0x5c, 0xb8, 0x55, 0x3d, 0x3e, 0x97, 0xb9, 0xfc,
0x34, 0xd1, 0x20, 0x8f, 0xf3, 0x9e, 0x77, 0x9d, 0x1c, 0xaf, 0x50, 0x2e, 0x8f, 0x07, 0x7d, 0x58,
0x4d, 0x36, 0xe8, 0x63, 0x1f, 0xbc, 0x6e, 0x35, 0xc7, 0x97, 0xf5, 0xd9, 0xa0, 0x8f, 0xf6, 0x3b,
0x21, 0x36, 0xc7, 0x0d, 0xf6, 0x3b, 0x61, 0x61, 0xbf, 0x13, 0xa2, 0xfd, 0x4e, 0x88, 0x1d, 0x73,
0x93, 0xfd, 0x52, 0x9f, 0xa1, 0xbe, 0x82, 0x2d, 0xac, 0xb1, 0x01, 0x3a, 0xdc, 0x61, 0x23, 0x47,
0x1d, 0xf8, 0xc3, 0x6b, 0x44, 0x36, 0xf8, 0x9b, 0xb6, 0x90, 0xfb, 0x2b, 0x2d, 0xe9, 0x97, 0xc4,
0x2d, 0x9b, 0xee, 0x75, 0x1b, 0xc0, 0x76, 0x61, 0x12, 0x8c, 0xf2, 0xb9, 0x4f, 0x2a, 0x69, 0x34,
0xe3, 0x2b, 0x85, 0xff, 0x1b, 0xbe, 0x30, 0x18, 0xf9, 0xd9, 0xfd, 0x3f, 0x00, 0x00, 0xff, 0xff,
0xa5, 0x08, 0x41, 0xc3, 0xa9, 0x09, 0x00, 0x00,
// 1206 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x74, 0x56, 0xcf, 0x72, 0x13, 0xc7,
0x13, 0x66, 0x77, 0xb5, 0xfa, 0xd3, 0x32, 0x46, 0xbf, 0xc1, 0xc0, 0xa2, 0x1f, 0x09, 0x2a, 0x85,
0x10, 0x05, 0x82, 0xa8, 0xc8, 0x2a, 0x55, 0x8a, 0xe4, 0x82, 0xb1, 0x09, 0xa9, 0x80, 0x93, 0x1a,
0x43, 0xc8, 0x4d, 0xb5, 0xf2, 0xae, 0xc4, 0x92, 0xd5, 0x8c, 0x6a, 0x66, 0xd6, 0xa0, 0x4a, 0x0e,
0x3e, 0xe7, 0x98, 0xca, 0x33, 0xe4, 0x11, 0x72, 0xc8, 0x63, 0xe4, 0x01, 0xf2, 0x20, 0x39, 0xa5,
0xba, 0x67, 0x57, 0x6b, 0x2c, 0x74, 0xf2, 0x76, 0xf7, 0xf7, 0x7d, 0x9e, 0x99, 0xaf, 0x67, 0x5a,
0xc0, 0x4c, 0xac, 0xcd, 0x58, 0x4e, 0x5e, 0xc7, 0xc7, 0x46, 0xf7, 0x17, 0x4a, 0x1a, 0xc9, 0xaa,
0xaf, 0xb5, 0x14, 0x8b, 0x49, 0xfb, 0xfa, 0x4c, 0xca, 0x59, 0x1a, 0xdf, 0xa7, 0xec, 0x24, 0x9b,
0xde, 0x0f, 0xc5, 0xd2, 0x42, 0xda, 0x1f, 0x9e, 0x2f, 0x45, 0x99, 0x0a, 0x4d, 0x22, 0x45, 0x5e,
0xbf, 0x71, 0xbe, 0xae, 0x8d, 0xca, 0x8e, 0x4d, 0x5e, 0xbd, 0x79, 0xbe, 0x6a, 0x92, 0x79, 0xac,
0x4d, 0x38, 0x5f, 0x6c, 0x92, 0x7f, 0xa3, 0xc2, 0xc5, 0x22, 0x56, 0xf9, 0x0a, 0xdb, 0x3b, 0x33,
0x39, 0x93, 0xf4, 0x79, 0x1f, 0xbf, 0x6c, 0xb6, 0xfb, 0xb7, 0x0b, 0xd5, 0xa3, 0x64, 0xbe, 0x48,
0x63, 0x76, 0x05, 0xaa, 0x72, 0x3c, 0x91, 0x32, 0x0d, 0x9c, 0x8e, 0xd3, 0xab, 0x73, 0x5f, 0xee,
0x49, 0x99, 0xb2, 0x6b, 0x50, 0x93, 0xe3, 0x44, 0x98, 0xdd, 0x41, 0xe0, 0x76, 0x9c, 0x9e, 0xcf,
0xab, 0xf2, 0x1b, 0x8c, 0x56, 0x85, 0xd1, 0x30, 0xf0, 0x3a, 0x4e, 0xcf, 0xb3, 0x85, 0xd1, 0x90,
0x5d, 0x87, 0xba, 0x1c, 0x67, 0x96, 0x52, 0xe9, 0x38, 0xbd, 0x8b, 0xbc, 0x26, 0x5f, 0x50, 0x58,
0x96, 0x46, 0xc3, 0xc0, 0xef, 0x38, 0xbd, 0x4a, 0x5e, 0x2a, 0x58, 0xda, 0xb2, 0xaa, 0x1d, 0xa7,
0xf7, 0x3f, 0x5e, 0x93, 0x47, 0x67, 0x58, 0xda, 0xb2, 0x6a, 0x1d, 0xa7, 0xc7, 0xf2, 0xd2, 0x68,
0x68, 0x17, 0x31, 0x4d, 0x65, 0x68, 0x82, 0x7a, 0xc7, 0xe9, 0xb9, 0xbc, 0x2a, 0x1f, 0x63, 0x64,
0x39, 0x91, 0xcc, 0x26, 0x69, 0x1c, 0x34, 0x3a, 0x4e, 0xcf, 0xe1, 0x35, 0xb9, 0x4f, 0x61, 0x2e,
0x67, 0x54, 0x22, 0x66, 0x01, 0x74, 0x9c, 0x5e, 0x03, 0xe5, 0x28, 0xb4, 0x72, 0x93, 0xa5, 0x89,
0x75, 0xd0, 0xec, 0x38, 0xbd, 0x2d, 0x5e, 0x95, 0x7b, 0x18, 0xb1, 0xbb, 0xb0, 0x25, 0xc7, 0xc7,
0xa1, 0x36, 0x79, 0x75, 0x0b, 0xab, 0x7b, 0x8d, 0x7f, 0xff, 0xb9, 0xe9, 0x13, 0x80, 0x83, 0x7c,
0x14, 0x6a, 0x43, 0xdf, 0xdd, 0xdf, 0x1c, 0x80, 0x43, 0x29, 0x1e, 0x27, 0x22, 0x41, 0xee, 0x65,
0xf0, 0xa7, 0x63, 0x11, 0x0a, 0x3a, 0x57, 0x97, 0x57, 0xa6, 0x87, 0xa1, 0xc0, 0xd3, 0x9e, 0x8e,
0x17, 0x89, 0x98, 0xd2, 0xa9, 0xba, 0xdc, 0x9f, 0x7e, 0x9f, 0x88, 0xa9, 0x4d, 0x0b, 0x4c, 0x7b,
0x79, 0xfa, 0x10, 0xd3, 0x97, 0xc1, 0x8f, 0x48, 0xa2, 0x42, 0x5b, 0xa9, 0x44, 0xb9, 0x44, 0x64,
0x25, 0x7c, 0xca, 0xfa, 0x51, 0x21, 0x11, 0x59, 0x89, 0x6a, 0x9e, 0x46, 0x89, 0xee, 0x1f, 0x2e,
0xd4, 0x78, 0xbc, 0x88, 0x43, 0xa3, 0x11, 0xa2, 0x0a, 0xab, 0x3d, 0xb4, 0x5a, 0x15, 0x56, 0xab,
0x95, 0xd5, 0x1e, 0x5a, 0xad, 0x56, 0x56, 0xab, 0x95, 0xd5, 0x1e, 0x5a, 0xad, 0x56, 0x56, 0xab,
0xd2, 0x6a, 0x0f, 0xad, 0x56, 0xa5, 0xd5, 0xaa, 0xb4, 0xda, 0x43, 0xab, 0x55, 0x69, 0xb5, 0x2a,
0xad, 0xf6, 0xd0, 0x6a, 0x75, 0x74, 0x86, 0xb5, 0xb2, 0xda, 0x43, 0xab, 0x55, 0x69, 0xb5, 0x5a,
0x59, 0xed, 0xa1, 0xd5, 0x6a, 0x65, 0xb5, 0x2a, 0xad, 0xf6, 0xd0, 0x6a, 0x55, 0x5a, 0xad, 0x4a,
0xab, 0x3d, 0xb4, 0x5a, 0x95, 0x56, 0xab, 0x95, 0xd5, 0x1e, 0x5a, 0xad, 0xac, 0x7b, 0x7f, 0xba,
0x50, 0x7d, 0x99, 0x44, 0xb3, 0xd8, 0xb0, 0x3b, 0xe0, 0x1f, 0xcb, 0x54, 0x2a, 0x72, 0x6e, 0x7b,
0xb0, 0xd3, 0xb7, 0xb7, 0xbc, 0x6f, 0xcb, 0xfd, 0x47, 0x58, 0xe3, 0x16, 0xc2, 0xee, 0xa1, 0x9e,
0x45, 0xe3, 0xe1, 0x6d, 0x42, 0x57, 0x15, 0xfd, 0x65, 0xb7, 0xa1, 0xaa, 0xe9, 0xde, 0x51, 0x0b,
0x36, 0x07, 0xdb, 0x05, 0xda, 0xde, 0x46, 0x9e, 0x57, 0xd9, 0xa7, 0xf6, 0x40, 0x08, 0x89, 0xeb,
0x5c, 0x47, 0xe2, 0x01, 0xe5, 0xd0, 0x9a, 0xb2, 0x06, 0x07, 0x3b, 0xa4, 0x79, 0xa9, 0x40, 0xe6,
0xbe, 0xf3, 0xa2, 0xce, 0x3e, 0x83, 0x86, 0x1a, 0x17, 0xe0, 0x2b, 0x24, 0xbb, 0x06, 0xae, 0xab,
0xfc, 0xab, 0xfb, 0x31, 0xf8, 0x76, 0xd1, 0x35, 0xf0, 0xf8, 0xc1, 0x7e, 0xeb, 0x02, 0x6b, 0x80,
0xff, 0x35, 0x3f, 0x38, 0x38, 0x6c, 0x39, 0xac, 0x0e, 0x95, 0xbd, 0xa7, 0x2f, 0x0e, 0x5a, 0x6e,
0xf7, 0x77, 0x17, 0x2a, 0xcf, 0xc2, 0x85, 0x66, 0x5f, 0x42, 0x73, 0x6e, 0xdb, 0x05, 0xcf, 0x9e,
0x7a, 0xac, 0x39, 0xf8, 0x7f, 0xa1, 0x8f, 0x90, 0xfe, 0x33, 0xea, 0x9f, 0x23, 0xa3, 0x0e, 0x84,
0x51, 0x4b, 0xde, 0x98, 0x17, 0x31, 0x7b, 0x08, 0x17, 0xe7, 0xd4, 0x9b, 0xc5, 0xae, 0x5d, 0xa2,
0x7f, 0xf0, 0x2e, 0x1d, 0xfb, 0xd5, 0x6e, 0xdb, 0x0a, 0x34, 0xe7, 0x65, 0xa6, 0xfd, 0x15, 0x6c,
0xbf, 0xab, 0xcf, 0x5a, 0xe0, 0xfd, 0x14, 0x2f, 0xc9, 0x46, 0x8f, 0xe3, 0x27, 0xdb, 0x01, 0xff,
0x24, 0x4c, 0xb3, 0x98, 0xae, 0x5f, 0x83, 0xdb, 0xe0, 0x81, 0xfb, 0x85, 0xd3, 0x3e, 0x84, 0xd6,
0x79, 0xf9, 0xb3, 0xfc, 0xba, 0xe5, 0xdf, 0x3a, 0xcb, 0x5f, 0x37, 0xa5, 0xd4, 0xeb, 0xfe, 0xea,
0xc0, 0xd6, 0x33, 0x3d, 0x7b, 0x99, 0x98, 0x57, 0xdf, 0x89, 0x58, 0x4e, 0xd9, 0x55, 0xf0, 0x4d,
0x62, 0xd2, 0x98, 0xe4, 0x1a, 0x4f, 0x2e, 0x70, 0x1b, 0xb2, 0x00, 0xaa, 0x3a, 0x4c, 0x43, 0xb5,
0x24, 0x4d, 0xef, 0xc9, 0x05, 0x9e, 0xc7, 0xac, 0x0d, 0xb5, 0x47, 0x32, 0xc3, 0x95, 0xd0, 0xb3,
0x80, 0x9c, 0x22, 0xc1, 0x3e, 0x82, 0xad, 0x57, 0x72, 0x1e, 0x8f, 0xc3, 0x28, 0x52, 0xb1, 0xd6,
0xf4, 0x42, 0x20, 0xa0, 0x89, 0xd9, 0x87, 0x36, 0xb9, 0x57, 0x03, 0x3f, 0x13, 0x89, 0x14, 0xdd,
0xdb, 0x50, 0xe1, 0x71, 0x98, 0x96, 0xdb, 0x77, 0xec, 0x1b, 0x41, 0xc1, 0x9d, 0x7a, 0x3d, 0x6a,
0x9d, 0x9e, 0x9e, 0x9e, 0xba, 0xdd, 0x37, 0xf8, 0x1f, 0x71, 0x27, 0x6f, 0xd9, 0x0d, 0x68, 0x24,
0xf3, 0x70, 0x96, 0x08, 0x5c, 0x99, 0x85, 0x97, 0x89, 0x92, 0x32, 0xd8, 0x87, 0x6d, 0x15, 0x87,
0xe9, 0x38, 0x7e, 0x6b, 0x62, 0xa1, 0x13, 0x29, 0xd8, 0x56, 0xd9, 0x52, 0x61, 0x1a, 0xfc, 0xfc,
0x6e, 0x4f, 0xe6, 0xf2, 0xfc, 0x22, 0x92, 0x0e, 0x0a, 0x4e, 0xf7, 0x2f, 0x1f, 0xe0, 0x5b, 0x21,
0xdf, 0x88, 0xe7, 0xcb, 0x45, 0xac, 0xd9, 0x2d, 0x70, 0x43, 0x11, 0x6c, 0x13, 0x75, 0xa7, 0x6f,
0x47, 0x5c, 0xbf, 0x18, 0x71, 0xfd, 0x87, 0x62, 0xc9, 0xdd, 0x50, 0xb0, 0xbb, 0xe0, 0x45, 0x99,
0xbd, 0xa5, 0xcd, 0xc1, 0xf5, 0x35, 0xd8, 0x7e, 0x3e, 0x68, 0x39, 0xa2, 0xd8, 0x27, 0xe0, 0x6a,
0x43, 0x0f, 0x78, 0x73, 0x70, 0x6d, 0x0d, 0x7b, 0x44, 0x43, 0x97, 0xbb, 0x1a, 0x6f, 0xbf, 0x6b,
0x74, 0xee, 0x6f, 0x7b, 0x0d, 0xf8, 0xbc, 0x98, 0xbf, 0xdc, 0x35, 0x1a, 0xb1, 0xe9, 0x49, 0x70,
0x69, 0x03, 0xf6, 0x69, 0xa2, 0xcd, 0x0f, 0x78, 0xc2, 0xdc, 0x4d, 0x4f, 0x58, 0x0f, 0xbc, 0x93,
0x30, 0x0d, 0x5a, 0x04, 0xbe, 0xba, 0x06, 0xb6, 0x40, 0x84, 0xb0, 0x3e, 0x78, 0xd1, 0x24, 0x25,
0xcf, 0x9b, 0x83, 0x1b, 0xeb, 0xfb, 0xa2, 0x47, 0x2e, 0xc7, 0x47, 0x93, 0x94, 0xdd, 0x03, 0x6f,
0x9a, 0x1a, 0x6a, 0x01, 0xbc, 0x70, 0xe7, 0xf1, 0xf4, 0x5c, 0xe6, 0xf0, 0x69, 0x6a, 0x10, 0x9e,
0xe4, 0x83, 0xf8, 0x7d, 0x70, 0xba, 0x42, 0x39, 0x3c, 0x19, 0x0d, 0x71, 0x35, 0xd9, 0x68, 0x48,
0x53, 0xe5, 0x7d, 0xab, 0x79, 0x71, 0x16, 0x9f, 0x8d, 0x86, 0x24, 0xbf, 0x3b, 0xa0, 0x89, 0xbd,
0x41, 0x7e, 0x77, 0x50, 0xc8, 0xef, 0x0e, 0x48, 0x7e, 0x77, 0x40, 0x63, 0x7c, 0x93, 0xfc, 0x0a,
0x9f, 0x11, 0xbe, 0x42, 0x23, 0xac, 0xb1, 0xe1, 0xd0, 0xf1, 0x0e, 0x5b, 0x38, 0xe1, 0x50, 0x1f,
0x5f, 0x23, 0xd8, 0xa0, 0x6f, 0xc7, 0x42, 0xae, 0xaf, 0x8d, 0x62, 0x9f, 0x83, 0x5f, 0xfe, 0x12,
0x78, 0xdf, 0x06, 0x68, 0x5c, 0x58, 0x82, 0x45, 0x3e, 0xe8, 0x40, 0x45, 0x84, 0xf3, 0xf8, 0x5c,
0xe3, 0xff, 0x42, 0x2f, 0x0c, 0x55, 0x7e, 0xf4, 0xff, 0x0b, 0x00, 0x00, 0xff, 0xff, 0x9a, 0xa6,
0x21, 0x68, 0x3e, 0x0a, 0x00, 0x00,
}
@@ -1,140 +0,0 @@
// Go support for Protocol Buffers - Google's data interchange format
//
// Copyright 2015 The Go Authors. All rights reserved.
// https://github.com/golang/protobuf
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
syntax = "proto2";
import "google/protobuf/any.proto";
import "google/protobuf/duration.proto";
import "google/protobuf/struct.proto";
import "google/protobuf/timestamp.proto";
import "google/protobuf/wrappers.proto";
package jsonpb;
import weak "gogoproto/gogo.proto";
// Test message for holding primitive types.
message Simple {
optional bool o_bool = 1;
optional int32 o_int32 = 2;
optional int64 o_int64 = 3;
optional uint32 o_uint32 = 4;
optional uint64 o_uint64 = 5;
optional sint32 o_sint32 = 6;
optional sint64 o_sint64 = 7;
optional float o_float = 8;
optional double o_double = 9;
optional string o_string = 10;
optional bytes o_bytes = 11;
optional bytes o_cast_bytes = 12 [(gogoproto.casttype) = "Bytes"];
}
// Test message for holding repeated primitives.
message Repeats {
repeated bool r_bool = 1;
repeated int32 r_int32 = 2;
repeated int64 r_int64 = 3;
repeated uint32 r_uint32 = 4;
repeated uint64 r_uint64 = 5;
repeated sint32 r_sint32 = 6;
repeated sint64 r_sint64 = 7;
repeated float r_float = 8;
repeated double r_double = 9;
repeated string r_string = 10;
repeated bytes r_bytes = 11;
}
// Test message for holding enums and nested messages.
message Widget {
enum Color {
RED = 0;
GREEN = 1;
BLUE = 2;
};
optional Color color = 1;
repeated Color r_color = 2;
optional Simple simple = 10;
repeated Simple r_simple = 11;
optional Repeats repeats = 20;
repeated Repeats r_repeats = 21;
}
message Maps {
map<int64, string> m_int64_str = 1;
map<bool, Simple> m_bool_simple = 2;
}
message MsgWithOneof {
oneof union {
string title = 1;
int64 salary = 2;
string Country = 3;
string home_address = 4;
}
}
message Real {
optional double value = 1;
extensions 100 to max;
}
extend Real {
optional string name = 124;
}
message Complex {
extend Real {
optional Complex real_extension = 123;
}
optional double imaginary = 1;
extensions 100 to max;
}
message KnownTypes {
optional google.protobuf.Any an = 14;
optional google.protobuf.Duration dur = 1;
optional google.protobuf.Struct st = 12;
optional google.protobuf.Timestamp ts = 2;
optional google.protobuf.ListValue lv = 15;
optional google.protobuf.Value val = 16;
optional google.protobuf.DoubleValue dbl = 3;
optional google.protobuf.FloatValue flt = 4;
optional google.protobuf.Int64Value i64 = 5;
optional google.protobuf.UInt64Value u64 = 6;
optional google.protobuf.Int32Value i32 = 7;
optional google.protobuf.UInt32Value u32 = 8;
optional google.protobuf.BoolValue bool = 9;
optional google.protobuf.StringValue str = 10;
optional google.protobuf.BytesValue bytes = 11;
}
+1 -1
View File
@@ -512,7 +512,7 @@ func (p *plugin) generateMessage(file *generator.FileDescriptor, message *genera
p.In()
p.generateMsgNullAndTypeCheck(ccTypeName)
vanity.TurnOffNullableForNativeTypesWithoutDefaultsOnly(field)
vanity.TurnOffNullableForNativeTypes(field)
p.generateField(file, message, field)
p.P(`return 0`)
+13 -27
View File
@@ -107,10 +107,7 @@ given to the equal plugin, will generate the following code:
func (this *B) Equal(that interface{}) bool {
if that == nil {
if this == nil {
return true
}
return false
return this == nil
}
that1, ok := that.(*B)
@@ -118,10 +115,7 @@ given to the equal plugin, will generate the following code:
return false
}
if that1 == nil {
if this == nil {
return true
}
return false
return this == nil
} else if this == nil {
return false
}
@@ -236,19 +230,15 @@ func (p *plugin) generateNullableField(fieldname string, verbose bool) {
func (p *plugin) generateMsgNullAndTypeCheck(ccTypeName string, verbose bool) {
p.P(`if that == nil {`)
p.In()
p.P(`if this == nil {`)
p.In()
if verbose {
p.P(`if this == nil {`)
p.In()
p.P(`return nil`)
} else {
p.P(`return true`)
}
p.Out()
p.P(`}`)
if verbose {
p.Out()
p.P(`}`)
p.P(`return `, p.fmtPkg.Use(), `.Errorf("that == nil && this != nil")`)
} else {
p.P(`return false`)
p.P(`return this == nil`)
}
p.Out()
p.P(`}`)
@@ -274,19 +264,15 @@ func (p *plugin) generateMsgNullAndTypeCheck(ccTypeName string, verbose bool) {
p.P(`}`)
p.P(`if that1 == nil {`)
p.In()
p.P(`if this == nil {`)
p.In()
if verbose {
p.P(`if this == nil {`)
p.In()
p.P(`return nil`)
} else {
p.P(`return true`)
}
p.Out()
p.P(`}`)
if verbose {
p.Out()
p.P(`}`)
p.P(`return `, p.fmtPkg.Use(), `.Errorf("that is type *`, ccTypeName, ` but is nil && this != nil")`)
} else {
p.P(`return false`)
p.P(`return this == nil`)
}
p.Out()
p.P(`} else if this == nil {`)
@@ -627,7 +613,7 @@ func (p *plugin) generateMessage(file *generator.FileDescriptor, message *genera
p.In()
p.generateMsgNullAndTypeCheck(ccTypeName, verbose)
vanity.TurnOffNullableForNativeTypesWithoutDefaultsOnly(field)
vanity.TurnOffNullableForNativeTypes(field)
p.generateField(file, message, field, verbose)
if verbose {
+27 -18
View File
@@ -98,11 +98,12 @@ package gostring
import (
"fmt"
"github.com/gogo/protobuf/gogoproto"
"github.com/gogo/protobuf/protoc-gen-gogo/generator"
"os"
"strconv"
"strings"
"github.com/gogo/protobuf/gogoproto"
"github.com/gogo/protobuf/protoc-gen-gogo/generator"
)
type gostring struct {
@@ -229,8 +230,22 @@ func (p *gostring) Generate(file *generator.FileDescriptor) {
p.P(`if this.`, fieldname, ` != nil {`)
p.In()
}
if nullable || repeated {
if nullable {
p.P(`s = append(s, "`, fieldname, `: " + `, fmtPkg.Use(), `.Sprintf("%#v", this.`, fieldname, `) + ",\n")`)
} else if repeated {
if nullable {
p.P(`s = append(s, "`, fieldname, `: " + `, fmtPkg.Use(), `.Sprintf("%#v", this.`, fieldname, `) + ",\n")`)
} else {
goTyp, _ := p.GoType(message, field)
goTyp = strings.Replace(goTyp, "[]", "", 1)
p.P("vs := make([]*", goTyp, ", len(this.", fieldname, "))")
p.P("for i := range vs {")
p.In()
p.P("vs[i] = &this.", fieldname, "[i]")
p.Out()
p.P("}")
p.P(`s = append(s, "`, fieldname, `: " + `, fmtPkg.Use(), `.Sprintf("%#v", vs) + ",\n")`)
}
} else {
p.P(`s = append(s, "`, fieldname, `: " + `, stringsPkg.Use(), `.Replace(this.`, fieldname, `.GoString()`, ",`&`,``,1)", ` + ",\n")`)
}
@@ -246,7 +261,7 @@ func (p *gostring) Generate(file *generator.FileDescriptor) {
if field.IsEnum() {
if nullable && !repeated && !proto3 {
goTyp, _ := p.GoType(message, field)
p.P(`s = append(s, "`, fieldname, `: " + valueToGoString`, p.localName, `(this.`, fieldname, `,"`, packageName, ".", generator.GoTypeToName(goTyp), `"`, `) + ",\n")`)
p.P(`s = append(s, "`, fieldname, `: " + valueToGoString`, p.localName, `(this.`, fieldname, `,"`, generator.GoTypeToName(goTyp), `"`, `) + ",\n")`)
} else {
p.P(`s = append(s, "`, fieldname, `: " + `, fmtPkg.Use(), `.Sprintf("%#v", this.`, fieldname, `) + ",\n")`)
}
@@ -285,7 +300,6 @@ func (p *gostring) Generate(file *generator.FileDescriptor) {
}
p.P(`s = append(s, "}")`)
//outStr += strings.Join([]string{" + `}`", `}`, `,", "`, ")"}, "")
p.P(`return `, stringsPkg.Use(), `.Join(s, "")`)
p.Out()
p.P(`}`)
@@ -304,20 +318,15 @@ func (p *gostring) Generate(file *generator.FileDescriptor) {
p.P(`return "nil"`)
p.Out()
p.P(`}`)
outFlds := []string{}
fieldname := p.GetOneOfFieldName(message, field)
if field.IsMessage() || p.IsGroup(field) {
tmp := strings.Join([]string{"`", fieldname, ":` + "}, "")
tmp += strings.Join([]string{fmtPkg.Use(), `.Sprintf("%#v", this.`, fieldname, `)`}, "")
outFlds = append(outFlds, tmp)
} else {
tmp := strings.Join([]string{"`", fieldname, ":` + "}, "")
tmp += strings.Join([]string{fmtPkg.Use(), `.Sprintf("%#v", this.`, fieldname, ")"}, "")
outFlds = append(outFlds, tmp)
}
outStr := strings.Join([]string{"s := ", stringsPkg.Use(), ".Join([]string{`&", packageName, ".", ccTypeName, "{` + \n"}, "")
outStr += strings.Join(outFlds, ",\n")
outStr += strings.Join([]string{" + `}`", `}`, `,", "`, ")"}, "")
outStr := strings.Join([]string{
"s := ",
stringsPkg.Use(), ".Join([]string{`&", packageName, ".", ccTypeName, "{` + \n",
"`", fieldname, ":` + ", fmtPkg.Use(), `.Sprintf("%#v", this.`, fieldname, `)`,
" + `}`",
`}`,
`,", "`,
`)`}, "")
p.P(outStr)
p.P(`return s`)
p.Out()
+1 -1
View File
@@ -74,7 +74,7 @@ func (p *test) Generate(imports generator.PluginImports, file *generator.FileDes
p.P(`_, err := `, parserPkg.Use(), `.ParseExpr(s1)`)
p.P(`if err != nil {`)
p.In()
p.P(`panic(err)`)
p.P(`t.Fatal(err)`)
p.Out()
p.P(`}`)
p.Out()
+123 -341
View File
@@ -172,28 +172,20 @@ type marshalto struct {
*generator.Generator
generator.PluginImports
atleastOne bool
unsafePkg generator.Single
errorsPkg generator.Single
protoPkg generator.Single
sortKeysPkg generator.Single
mathPkg generator.Single
typesPkg generator.Single
binaryPkg generator.Single
localName string
unsafe bool
}
func NewMarshal() *marshalto {
return &marshalto{}
}
func NewUnsafeMarshal() *marshalto {
return &marshalto{unsafe: true}
}
func (p *marshalto) Name() string {
if p.unsafe {
return "unsafemarshaler"
}
return "marshalto"
}
@@ -202,11 +194,13 @@ func (p *marshalto) Init(g *generator.Generator) {
}
func (p *marshalto) callFixed64(varName ...string) {
p.P(`i = encodeFixed64`, p.localName, `(dAtA, i, uint64(`, strings.Join(varName, ""), `))`)
p.P(p.binaryPkg.Use(), `.LittleEndian.PutUint64(dAtA[i:], uint64(`, strings.Join(varName, ""), `))`)
p.P(`i += 8`)
}
func (p *marshalto) callFixed32(varName ...string) {
p.P(`i = encodeFixed32`, p.localName, `(dAtA, i, uint32(`, strings.Join(varName, ""), `))`)
p.P(p.binaryPkg.Use(), `.LittleEndian.PutUint32(dAtA[i:], uint32(`, strings.Join(varName, ""), `))`)
p.P(`i += 4`)
}
func (p *marshalto) callVarint(varName ...string) {
@@ -225,46 +219,6 @@ func (p *marshalto) encodeVarint(varName string) {
p.P(`i++`)
}
func (p *marshalto) encodeFixed64(varName string) {
p.P(`dAtA[i] = uint8(`, varName, `)`)
p.P(`i++`)
p.P(`dAtA[i] = uint8(`, varName, ` >> 8)`)
p.P(`i++`)
p.P(`dAtA[i] = uint8(`, varName, ` >> 16)`)
p.P(`i++`)
p.P(`dAtA[i] = uint8(`, varName, ` >> 24)`)
p.P(`i++`)
p.P(`dAtA[i] = uint8(`, varName, ` >> 32)`)
p.P(`i++`)
p.P(`dAtA[i] = uint8(`, varName, ` >> 40)`)
p.P(`i++`)
p.P(`dAtA[i] = uint8(`, varName, ` >> 48)`)
p.P(`i++`)
p.P(`dAtA[i] = uint8(`, varName, ` >> 56)`)
p.P(`i++`)
}
func (p *marshalto) unsafeFixed64(varName string, someType string) {
p.P(`*(*`, someType, `)(`, p.unsafePkg.Use(), `.Pointer(&dAtA[i])) = `, varName)
p.P(`i+=8`)
}
func (p *marshalto) encodeFixed32(varName string) {
p.P(`dAtA[i] = uint8(`, varName, `)`)
p.P(`i++`)
p.P(`dAtA[i] = uint8(`, varName, ` >> 8)`)
p.P(`i++`)
p.P(`dAtA[i] = uint8(`, varName, ` >> 16)`)
p.P(`i++`)
p.P(`dAtA[i] = uint8(`, varName, ` >> 24)`)
p.P(`i++`)
}
func (p *marshalto) unsafeFixed32(varName string, someType string) {
p.P(`*(*`, someType, `)(`, p.unsafePkg.Use(), `.Pointer(&dAtA[i])) = `, varName)
p.P(`i+=4`)
}
func (p *marshalto) encodeKey(fieldNumber int32, wireType int) {
x := uint32(fieldNumber)<<3 | uint32(wireType)
i := 0
@@ -428,132 +382,68 @@ func (p *marshalto) generateField(proto3 bool, numGen NumGen, file *generator.Fi
}
switch *field.Type {
case descriptor.FieldDescriptorProto_TYPE_DOUBLE:
if !p.unsafe || gogoproto.IsCastType(field) {
if packed {
p.encodeKey(fieldNumber, wireType)
p.callVarint(`len(m.`, fieldname, `) * 8`)
p.P(`for _, num := range m.`, fieldname, ` {`)
p.In()
p.P(`f`, numGen.Next(), ` := `, p.mathPkg.Use(), `.Float64bits(float64(num))`)
p.encodeFixed64("f" + numGen.Current())
p.Out()
p.P(`}`)
} else if repeated {
p.P(`for _, num := range m.`, fieldname, ` {`)
p.In()
p.encodeKey(fieldNumber, wireType)
p.P(`f`, numGen.Next(), ` := `, p.mathPkg.Use(), `.Float64bits(float64(num))`)
p.encodeFixed64("f" + numGen.Current())
p.Out()
p.P(`}`)
} else if proto3 {
p.P(`if m.`, fieldname, ` != 0 {`)
p.In()
p.encodeKey(fieldNumber, wireType)
p.callFixed64(p.mathPkg.Use(), `.Float64bits(float64(m.`+fieldname, `))`)
p.Out()
p.P(`}`)
} else if !nullable {
p.encodeKey(fieldNumber, wireType)
p.callFixed64(p.mathPkg.Use(), `.Float64bits(float64(m.`+fieldname, `))`)
} else {
p.encodeKey(fieldNumber, wireType)
p.callFixed64(p.mathPkg.Use(), `.Float64bits(float64(*m.`+fieldname, `))`)
}
if packed {
p.encodeKey(fieldNumber, wireType)
p.callVarint(`len(m.`, fieldname, `) * 8`)
p.P(`for _, num := range m.`, fieldname, ` {`)
p.In()
p.P(`f`, numGen.Next(), ` := `, p.mathPkg.Use(), `.Float64bits(float64(num))`)
p.callFixed64("f" + numGen.Current())
p.Out()
p.P(`}`)
} else if repeated {
p.P(`for _, num := range m.`, fieldname, ` {`)
p.In()
p.encodeKey(fieldNumber, wireType)
p.P(`f`, numGen.Next(), ` := `, p.mathPkg.Use(), `.Float64bits(float64(num))`)
p.callFixed64("f" + numGen.Current())
p.Out()
p.P(`}`)
} else if proto3 {
p.P(`if m.`, fieldname, ` != 0 {`)
p.In()
p.encodeKey(fieldNumber, wireType)
p.callFixed64(p.mathPkg.Use(), `.Float64bits(float64(m.`+fieldname, `))`)
p.Out()
p.P(`}`)
} else if !nullable {
p.encodeKey(fieldNumber, wireType)
p.callFixed64(p.mathPkg.Use(), `.Float64bits(float64(m.`+fieldname, `))`)
} else {
if packed {
p.encodeKey(fieldNumber, wireType)
p.callVarint(`len(m.`, fieldname, `) * 8`)
p.P(`for _, num := range m.`, fieldname, ` {`)
p.In()
p.unsafeFixed64("num", "float64")
p.Out()
p.P(`}`)
} else if repeated {
p.P(`for _, num := range m.`, fieldname, ` {`)
p.In()
p.encodeKey(fieldNumber, wireType)
p.unsafeFixed64("num", "float64")
p.Out()
p.P(`}`)
} else if proto3 {
p.P(`if m.`, fieldname, ` != 0 {`)
p.In()
p.encodeKey(fieldNumber, wireType)
p.unsafeFixed64(`m.`+fieldname, "float64")
p.Out()
p.P(`}`)
} else if !nullable {
p.encodeKey(fieldNumber, wireType)
p.unsafeFixed64(`m.`+fieldname, "float64")
} else {
p.encodeKey(fieldNumber, wireType)
p.unsafeFixed64(`*m.`+fieldname, `float64`)
}
p.encodeKey(fieldNumber, wireType)
p.callFixed64(p.mathPkg.Use(), `.Float64bits(float64(*m.`+fieldname, `))`)
}
case descriptor.FieldDescriptorProto_TYPE_FLOAT:
if !p.unsafe || gogoproto.IsCastType(field) {
if packed {
p.encodeKey(fieldNumber, wireType)
p.callVarint(`len(m.`, fieldname, `) * 4`)
p.P(`for _, num := range m.`, fieldname, ` {`)
p.In()
p.P(`f`, numGen.Next(), ` := `, p.mathPkg.Use(), `.Float32bits(float32(num))`)
p.encodeFixed32("f" + numGen.Current())
p.Out()
p.P(`}`)
} else if repeated {
p.P(`for _, num := range m.`, fieldname, ` {`)
p.In()
p.encodeKey(fieldNumber, wireType)
p.P(`f`, numGen.Next(), ` := `, p.mathPkg.Use(), `.Float32bits(float32(num))`)
p.encodeFixed32("f" + numGen.Current())
p.Out()
p.P(`}`)
} else if proto3 {
p.P(`if m.`, fieldname, ` != 0 {`)
p.In()
p.encodeKey(fieldNumber, wireType)
p.callFixed32(p.mathPkg.Use(), `.Float32bits(float32(m.`+fieldname, `))`)
p.Out()
p.P(`}`)
} else if !nullable {
p.encodeKey(fieldNumber, wireType)
p.callFixed32(p.mathPkg.Use(), `.Float32bits(float32(m.`+fieldname, `))`)
} else {
p.encodeKey(fieldNumber, wireType)
p.callFixed32(p.mathPkg.Use(), `.Float32bits(float32(*m.`+fieldname, `))`)
}
if packed {
p.encodeKey(fieldNumber, wireType)
p.callVarint(`len(m.`, fieldname, `) * 4`)
p.P(`for _, num := range m.`, fieldname, ` {`)
p.In()
p.P(`f`, numGen.Next(), ` := `, p.mathPkg.Use(), `.Float32bits(float32(num))`)
p.callFixed32("f" + numGen.Current())
p.Out()
p.P(`}`)
} else if repeated {
p.P(`for _, num := range m.`, fieldname, ` {`)
p.In()
p.encodeKey(fieldNumber, wireType)
p.P(`f`, numGen.Next(), ` := `, p.mathPkg.Use(), `.Float32bits(float32(num))`)
p.callFixed32("f" + numGen.Current())
p.Out()
p.P(`}`)
} else if proto3 {
p.P(`if m.`, fieldname, ` != 0 {`)
p.In()
p.encodeKey(fieldNumber, wireType)
p.callFixed32(p.mathPkg.Use(), `.Float32bits(float32(m.`+fieldname, `))`)
p.Out()
p.P(`}`)
} else if !nullable {
p.encodeKey(fieldNumber, wireType)
p.callFixed32(p.mathPkg.Use(), `.Float32bits(float32(m.`+fieldname, `))`)
} else {
if packed {
p.encodeKey(fieldNumber, wireType)
p.callVarint(`len(m.`, fieldname, `) * 4`)
p.P(`for _, num := range m.`, fieldname, ` {`)
p.In()
p.unsafeFixed32("num", "float32")
p.Out()
p.P(`}`)
} else if repeated {
p.P(`for _, num := range m.`, fieldname, ` {`)
p.In()
p.encodeKey(fieldNumber, wireType)
p.unsafeFixed32("num", "float32")
p.Out()
p.P(`}`)
} else if proto3 {
p.P(`if m.`, fieldname, ` != 0 {`)
p.In()
p.encodeKey(fieldNumber, wireType)
p.unsafeFixed32(`m.`+fieldname, `float32`)
p.Out()
p.P(`}`)
} else if !nullable {
p.encodeKey(fieldNumber, wireType)
p.unsafeFixed32(`m.`+fieldname, `float32`)
} else {
p.encodeKey(fieldNumber, wireType)
p.unsafeFixed32(`*m.`+fieldname, "float32")
}
p.encodeKey(fieldNumber, wireType)
p.callFixed32(p.mathPkg.Use(), `.Float32bits(float32(*m.`+fieldname, `))`)
}
case descriptor.FieldDescriptorProto_TYPE_INT64,
descriptor.FieldDescriptorProto_TYPE_UINT64,
@@ -610,137 +500,65 @@ func (p *marshalto) generateField(proto3 bool, numGen NumGen, file *generator.Fi
}
case descriptor.FieldDescriptorProto_TYPE_FIXED64,
descriptor.FieldDescriptorProto_TYPE_SFIXED64:
if !p.unsafe {
if packed {
p.encodeKey(fieldNumber, wireType)
p.callVarint(`len(m.`, fieldname, `) * 8`)
p.P(`for _, num := range m.`, fieldname, ` {`)
p.In()
p.encodeFixed64("num")
p.Out()
p.P(`}`)
} else if repeated {
p.P(`for _, num := range m.`, fieldname, ` {`)
p.In()
p.encodeKey(fieldNumber, wireType)
p.encodeFixed64("num")
p.Out()
p.P(`}`)
} else if proto3 {
p.P(`if m.`, fieldname, ` != 0 {`)
p.In()
p.encodeKey(fieldNumber, wireType)
p.callFixed64("m." + fieldname)
p.Out()
p.P(`}`)
} else if !nullable {
p.encodeKey(fieldNumber, wireType)
p.callFixed64("m." + fieldname)
} else {
p.encodeKey(fieldNumber, wireType)
p.callFixed64("*m." + fieldname)
}
if packed {
p.encodeKey(fieldNumber, wireType)
p.callVarint(`len(m.`, fieldname, `) * 8`)
p.P(`for _, num := range m.`, fieldname, ` {`)
p.In()
p.callFixed64("num")
p.Out()
p.P(`}`)
} else if repeated {
p.P(`for _, num := range m.`, fieldname, ` {`)
p.In()
p.encodeKey(fieldNumber, wireType)
p.callFixed64("num")
p.Out()
p.P(`}`)
} else if proto3 {
p.P(`if m.`, fieldname, ` != 0 {`)
p.In()
p.encodeKey(fieldNumber, wireType)
p.callFixed64("m." + fieldname)
p.Out()
p.P(`}`)
} else if !nullable {
p.encodeKey(fieldNumber, wireType)
p.callFixed64("m." + fieldname)
} else {
typeName := "int64"
if *field.Type == descriptor.FieldDescriptorProto_TYPE_FIXED64 {
typeName = "uint64"
}
if packed {
p.encodeKey(fieldNumber, wireType)
p.callVarint(`len(m.`, fieldname, `) * 8`)
p.P(`for _, num := range m.`, fieldname, ` {`)
p.In()
p.unsafeFixed64("num", typeName)
p.Out()
p.P(`}`)
} else if repeated {
p.P(`for _, num := range m.`, fieldname, ` {`)
p.In()
p.encodeKey(fieldNumber, wireType)
p.unsafeFixed64("num", typeName)
p.Out()
p.P(`}`)
} else if proto3 {
p.P(`if m.`, fieldname, ` != 0 {`)
p.In()
p.encodeKey(fieldNumber, wireType)
p.unsafeFixed64("m."+fieldname, typeName)
p.Out()
p.P(`}`)
} else if !nullable {
p.encodeKey(fieldNumber, wireType)
p.unsafeFixed64("m."+fieldname, typeName)
} else {
p.encodeKey(fieldNumber, wireType)
p.unsafeFixed64("*m."+fieldname, typeName)
}
p.encodeKey(fieldNumber, wireType)
p.callFixed64("*m." + fieldname)
}
case descriptor.FieldDescriptorProto_TYPE_FIXED32,
descriptor.FieldDescriptorProto_TYPE_SFIXED32:
if !p.unsafe {
if packed {
p.encodeKey(fieldNumber, wireType)
p.callVarint(`len(m.`, fieldname, `) * 4`)
p.P(`for _, num := range m.`, fieldname, ` {`)
p.In()
p.encodeFixed32("num")
p.Out()
p.P(`}`)
} else if repeated {
p.P(`for _, num := range m.`, fieldname, ` {`)
p.In()
p.encodeKey(fieldNumber, wireType)
p.encodeFixed32("num")
p.Out()
p.P(`}`)
} else if proto3 {
p.P(`if m.`, fieldname, ` != 0 {`)
p.In()
p.encodeKey(fieldNumber, wireType)
p.callFixed32("m." + fieldname)
p.Out()
p.P(`}`)
} else if !nullable {
p.encodeKey(fieldNumber, wireType)
p.callFixed32("m." + fieldname)
} else {
p.encodeKey(fieldNumber, wireType)
p.callFixed32("*m." + fieldname)
}
if packed {
p.encodeKey(fieldNumber, wireType)
p.callVarint(`len(m.`, fieldname, `) * 4`)
p.P(`for _, num := range m.`, fieldname, ` {`)
p.In()
p.callFixed32("num")
p.Out()
p.P(`}`)
} else if repeated {
p.P(`for _, num := range m.`, fieldname, ` {`)
p.In()
p.encodeKey(fieldNumber, wireType)
p.callFixed32("num")
p.Out()
p.P(`}`)
} else if proto3 {
p.P(`if m.`, fieldname, ` != 0 {`)
p.In()
p.encodeKey(fieldNumber, wireType)
p.callFixed32("m." + fieldname)
p.Out()
p.P(`}`)
} else if !nullable {
p.encodeKey(fieldNumber, wireType)
p.callFixed32("m." + fieldname)
} else {
typeName := "int32"
if *field.Type == descriptor.FieldDescriptorProto_TYPE_FIXED32 {
typeName = "uint32"
}
if packed {
p.encodeKey(fieldNumber, wireType)
p.callVarint(`len(m.`, fieldname, `) * 4`)
p.P(`for _, num := range m.`, fieldname, ` {`)
p.In()
p.unsafeFixed32("num", typeName)
p.Out()
p.P(`}`)
} else if repeated {
p.P(`for _, num := range m.`, fieldname, ` {`)
p.In()
p.encodeKey(fieldNumber, wireType)
p.unsafeFixed32("num", typeName)
p.Out()
p.P(`}`)
} else if proto3 {
p.P(`if m.`, fieldname, ` != 0 {`)
p.In()
p.encodeKey(fieldNumber, wireType)
p.unsafeFixed32("m."+fieldname, typeName)
p.Out()
p.P(`}`)
} else if !nullable {
p.encodeKey(fieldNumber, wireType)
p.unsafeFixed32("m."+fieldname, typeName)
} else {
p.encodeKey(fieldNumber, wireType)
p.unsafeFixed32("*m."+fieldname, typeName)
}
p.encodeKey(fieldNumber, wireType)
p.callFixed32("*m." + fieldname)
}
case descriptor.FieldDescriptorProto_TYPE_BOOL:
if packed {
@@ -1240,6 +1058,7 @@ func (p *marshalto) generateField(proto3 bool, numGen NumGen, file *generator.Fi
func (p *marshalto) Generate(file *generator.FileDescriptor) {
numGen := NewNumGen()
p.PluginImports = generator.NewPluginImports(p.Generator)
p.atleastOne = false
p.localName = generator.FileName(file)
@@ -1249,8 +1068,8 @@ func (p *marshalto) Generate(file *generator.FileDescriptor) {
if !gogoproto.ImportsGoGoProto(file.FileDescriptorProto) {
p.protoPkg = p.NewImport("github.com/golang/protobuf/proto")
}
p.unsafePkg = p.NewImport("unsafe")
p.errorsPkg = p.NewImport("errors")
p.binaryPkg = p.NewImport("encoding/binary")
p.typesPkg = p.NewImport("github.com/gogo/protobuf/types")
for _, message := range file.Messages() {
@@ -1258,21 +1077,9 @@ func (p *marshalto) Generate(file *generator.FileDescriptor) {
continue
}
ccTypeName := generator.CamelCaseSlice(message.TypeName())
if p.unsafe {
if !gogoproto.IsUnsafeMarshaler(file.FileDescriptorProto, message.DescriptorProto) {
continue
}
if gogoproto.IsMarshaler(file.FileDescriptorProto, message.DescriptorProto) {
panic(fmt.Sprintf("unsafe_marshaler and marshalto enabled for %v", ccTypeName))
}
}
if !p.unsafe {
if !gogoproto.IsMarshaler(file.FileDescriptorProto, message.DescriptorProto) {
continue
}
if gogoproto.IsUnsafeMarshaler(file.FileDescriptorProto, message.DescriptorProto) {
panic(fmt.Sprintf("unsafe_marshaler and marshalto enabled for %v", ccTypeName))
}
if !gogoproto.IsMarshaler(file.FileDescriptorProto, message.DescriptorProto) &&
!gogoproto.IsUnsafeMarshaler(file.FileDescriptorProto, message.DescriptorProto) {
continue
}
p.atleastOne = true
@@ -1367,7 +1174,7 @@ func (p *marshalto) Generate(file *generator.FileDescriptor) {
p.P(`func (m *`, ccTypeName, `) MarshalTo(dAtA []byte) (int, error) {`)
p.In()
p.P(`i := 0`)
vanity.TurnOffNullableForNativeTypesWithoutDefaultsOnly(field)
vanity.TurnOffNullableForNativeTypes(field)
p.generateField(false, numGen, file, message, field)
p.P(`return i, nil`)
p.Out()
@@ -1376,30 +1183,6 @@ func (p *marshalto) Generate(file *generator.FileDescriptor) {
}
if p.atleastOne {
p.P(`func encodeFixed64`, p.localName, `(dAtA []byte, offset int, v uint64) int {`)
p.In()
p.P(`dAtA[offset] = uint8(v)`)
p.P(`dAtA[offset+1] = uint8(v >> 8)`)
p.P(`dAtA[offset+2] = uint8(v >> 16)`)
p.P(`dAtA[offset+3] = uint8(v >> 24)`)
p.P(`dAtA[offset+4] = uint8(v >> 32)`)
p.P(`dAtA[offset+5] = uint8(v >> 40)`)
p.P(`dAtA[offset+6] = uint8(v >> 48)`)
p.P(`dAtA[offset+7] = uint8(v >> 56)`)
p.P(`return offset+8`)
p.Out()
p.P(`}`)
p.P(`func encodeFixed32`, p.localName, `(dAtA []byte, offset int, v uint32) int {`)
p.In()
p.P(`dAtA[offset] = uint8(v)`)
p.P(`dAtA[offset+1] = uint8(v >> 8)`)
p.P(`dAtA[offset+2] = uint8(v >> 16)`)
p.P(`dAtA[offset+3] = uint8(v >> 24)`)
p.P(`return offset+4`)
p.Out()
p.P(`}`)
p.P(`func encodeVarint`, p.localName, `(dAtA []byte, offset int, v uint64) int {`)
p.In()
p.P(`for v >= 1<<7 {`)
@@ -1419,5 +1202,4 @@ func (p *marshalto) Generate(file *generator.FileDescriptor) {
func init() {
generator.RegisterPlugin(NewMarshal())
generator.RegisterPlugin(NewUnsafeMarshal())
}
+8 -8
View File
@@ -443,7 +443,7 @@ func (p *plugin) GenerateField(file *generator.FileDescriptor, message *generato
}
}
func (p *plugin) hasLoop(field *descriptor.FieldDescriptorProto, visited []*generator.Descriptor, excludes []*generator.Descriptor) *generator.Descriptor {
func (p *plugin) hasLoop(pkg string, field *descriptor.FieldDescriptorProto, visited []*generator.Descriptor, excludes []*generator.Descriptor) *generator.Descriptor {
if field.IsMessage() || p.IsGroup(field) || p.IsMap(field) {
var fieldMessage *generator.Descriptor
if p.IsMap(field) {
@@ -467,11 +467,11 @@ func (p *plugin) hasLoop(field *descriptor.FieldDescriptorProto, visited []*gene
return fieldMessage
}
}
pkg := strings.Split(field.GetTypeName(), ".")[1]
for _, f := range fieldMessage.Field {
if strings.HasPrefix(f.GetTypeName(), "."+pkg+".") {
if strings.HasPrefix(f.GetTypeName(), "."+pkg) {
visited = append(visited, fieldMessage)
loopTo := p.hasLoop(f, visited, excludes)
loopTo := p.hasLoop(pkg, f, visited, excludes)
if loopTo != nil {
return loopTo
}
@@ -481,13 +481,13 @@ func (p *plugin) hasLoop(field *descriptor.FieldDescriptorProto, visited []*gene
return nil
}
func (p *plugin) loops(field *descriptor.FieldDescriptorProto, message *generator.Descriptor) int {
func (p *plugin) loops(pkg string, field *descriptor.FieldDescriptorProto, message *generator.Descriptor) int {
//fmt.Fprintf(os.Stderr, "loops %v %v\n", field.GetTypeName(), generator.CamelCaseSlice(message.TypeName()))
excludes := []*generator.Descriptor{}
loops := 0
for {
visited := []*generator.Descriptor{}
loopTo := p.hasLoop(field, visited, excludes)
loopTo := p.hasLoop(pkg, field, visited, excludes)
if loopTo == nil {
break
}
@@ -522,7 +522,7 @@ func (p *plugin) Generate(file *generator.FileDescriptor) {
loopLevels := make([]int, len(message.Field))
maxLoopLevel := 0
for i, field := range message.Field {
loopLevels[i] = p.loops(field, message)
loopLevels[i] = p.loops(file.GetPackage(), field, message)
if loopLevels[i] > maxLoopLevel {
maxLoopLevel = loopLevels[i]
}
@@ -667,7 +667,7 @@ func (p *plugin) Generate(file *generator.FileDescriptor) {
p.P(`func NewPopulated`, ccTypeName, `(r randy`, p.localName, `, easy bool) *`, ccTypeName, ` {`)
p.In()
p.P(`this := &`, ccTypeName, `{}`)
vanity.TurnOffNullableForNativeTypesWithoutDefaultsOnly(f)
vanity.TurnOffNullableForNativeTypes(f)
p.GenerateField(file, message, f)
p.P(`return this`)
p.Out()
+1 -1
View File
@@ -652,7 +652,7 @@ func (p *size) Generate(file *generator.FileDescriptor) {
p.In()
p.P(`var l int`)
p.P(`_ = l`)
vanity.TurnOffNullableForNativeTypesWithoutDefaultsOnly(f)
vanity.TurnOffNullableForNativeTypes(f)
p.generateField(false, file, message, f, sizeName)
p.P(`return n`)
p.Out()
-19
View File
@@ -270,7 +270,6 @@ func (p *testProto) Generate(imports generator.PluginImports, file *generator.Fi
testingPkg := imports.NewImport("testing")
randPkg := imports.NewImport("math/rand")
timePkg := imports.NewImport("time")
unsafePkg := imports.NewImport("unsafe")
protoPkg := imports.NewImport("github.com/gogo/protobuf/proto")
if !gogoproto.ImportsGoGoProto(file.FileDescriptorProto) {
protoPkg = imports.NewImport("github.com/golang/protobuf/proto")
@@ -280,21 +279,11 @@ func (p *testProto) Generate(imports generator.PluginImports, file *generator.Fi
if message.DescriptorProto.GetOptions().GetMapEntry() {
continue
}
hasUnsafe := gogoproto.IsUnsafeMarshaler(file.FileDescriptorProto, message.DescriptorProto) ||
gogoproto.IsUnsafeUnmarshaler(file.FileDescriptorProto, message.DescriptorProto)
if gogoproto.HasTestGen(file.FileDescriptorProto, message.DescriptorProto) {
used = true
p.P(`func Test`, ccTypeName, `Proto(t *`, testingPkg.Use(), `.T) {`)
p.In()
if hasUnsafe {
p.P(`var bigendian uint32 = 0x01020304`)
p.P(`if *(*byte)(`, unsafePkg.Use(), `.Pointer(&bigendian)) == 1 {`)
p.In()
p.P(`t.Skip("unsafe does not work on big endian architectures")`)
p.Out()
p.P(`}`)
}
p.P(`seed := `, timePkg.Use(), `.Now().UnixNano()`)
p.P(`popr := `, randPkg.Use(), `.New(`, randPkg.Use(), `.NewSource(seed))`)
p.P(`p := NewPopulated`, ccTypeName, `(popr, false)`)
@@ -351,14 +340,6 @@ func (p *testProto) Generate(imports generator.PluginImports, file *generator.Fi
if gogoproto.IsMarshaler(file.FileDescriptorProto, message.DescriptorProto) || gogoproto.IsUnsafeMarshaler(file.FileDescriptorProto, message.DescriptorProto) {
p.P(`func Test`, ccTypeName, `MarshalTo(t *`, testingPkg.Use(), `.T) {`)
p.In()
if hasUnsafe {
p.P(`var bigendian uint32 = 0x01020304`)
p.P(`if *(*byte)(`, unsafePkg.Use(), `.Pointer(&bigendian)) == 1 {`)
p.In()
p.P(`t.Skip("unsafe does not work on big endian architectures")`)
p.Out()
p.P(`}`)
}
p.P(`seed := `, timePkg.Use(), `.Now().UnixNano()`)
p.P(`popr := `, randPkg.Use(), `.New(`, randPkg.Use(), `.NewSource(seed))`)
p.P(`p := NewPopulated`, ccTypeName, `(popr, false)`)
+203 -303
View File
@@ -187,13 +187,12 @@ import (
type unmarshal struct {
*generator.Generator
unsafe bool
generator.PluginImports
atleastOne bool
ioPkg generator.Single
mathPkg generator.Single
unsafePkg generator.Single
typesPkg generator.Single
binaryPkg generator.Single
localName string
}
@@ -201,14 +200,7 @@ func NewUnmarshal() *unmarshal {
return &unmarshal{}
}
func NewUnsafeUnmarshal() *unmarshal {
return &unmarshal{unsafe: true}
}
func (p *unmarshal) Name() string {
if p.unsafe {
return "unsafeunmarshaler"
}
return "unmarshal"
}
@@ -247,20 +239,7 @@ func (p *unmarshal) decodeFixed32(varName string, typeName string) {
p.P(`return `, p.ioPkg.Use(), `.ErrUnexpectedEOF`)
p.Out()
p.P(`}`)
p.P(`iNdEx += 4`)
p.P(varName, ` = `, typeName, `(dAtA[iNdEx-4])`)
p.P(varName, ` |= `, typeName, `(dAtA[iNdEx-3]) << 8`)
p.P(varName, ` |= `, typeName, `(dAtA[iNdEx-2]) << 16`)
p.P(varName, ` |= `, typeName, `(dAtA[iNdEx-1]) << 24`)
}
func (p *unmarshal) unsafeFixed32(varName string, typeName string) {
p.P(`if iNdEx + 4 > l {`)
p.In()
p.P(`return `, p.ioPkg.Use(), `.ErrUnexpectedEOF`)
p.Out()
p.P(`}`)
p.P(varName, ` = *(*`, typeName, `)(`, p.unsafePkg.Use(), `.Pointer(&dAtA[iNdEx]))`)
p.P(varName, ` = `, typeName, `(`, p.binaryPkg.Use(), `.LittleEndian.Uint32(dAtA[iNdEx:]))`)
p.P(`iNdEx += 4`)
}
@@ -270,25 +249,71 @@ func (p *unmarshal) decodeFixed64(varName string, typeName string) {
p.P(`return `, p.ioPkg.Use(), `.ErrUnexpectedEOF`)
p.Out()
p.P(`}`)
p.P(varName, ` = `, typeName, `(`, p.binaryPkg.Use(), `.LittleEndian.Uint64(dAtA[iNdEx:]))`)
p.P(`iNdEx += 8`)
p.P(varName, ` = `, typeName, `(dAtA[iNdEx-8])`)
p.P(varName, ` |= `, typeName, `(dAtA[iNdEx-7]) << 8`)
p.P(varName, ` |= `, typeName, `(dAtA[iNdEx-6]) << 16`)
p.P(varName, ` |= `, typeName, `(dAtA[iNdEx-5]) << 24`)
p.P(varName, ` |= `, typeName, `(dAtA[iNdEx-4]) << 32`)
p.P(varName, ` |= `, typeName, `(dAtA[iNdEx-3]) << 40`)
p.P(varName, ` |= `, typeName, `(dAtA[iNdEx-2]) << 48`)
p.P(varName, ` |= `, typeName, `(dAtA[iNdEx-1]) << 56`)
}
func (p *unmarshal) unsafeFixed64(varName string, typeName string) {
p.P(`if iNdEx + 8 > l {`)
p.In()
p.P(`return `, p.ioPkg.Use(), `.ErrUnexpectedEOF`)
p.Out()
p.P(`}`)
p.P(varName, ` = *(*`, typeName, `)(`, p.unsafePkg.Use(), `.Pointer(&dAtA[iNdEx]))`)
p.P(`iNdEx += 8`)
func (p *unmarshal) declareMapField(varName string, nullable bool, customType bool, field *descriptor.FieldDescriptorProto) {
switch field.GetType() {
case descriptor.FieldDescriptorProto_TYPE_DOUBLE:
p.P(`var `, varName, ` float64`)
case descriptor.FieldDescriptorProto_TYPE_FLOAT:
p.P(`var `, varName, ` float32`)
case descriptor.FieldDescriptorProto_TYPE_INT64:
p.P(`var `, varName, ` int64`)
case descriptor.FieldDescriptorProto_TYPE_UINT64:
p.P(`var `, varName, ` uint64`)
case descriptor.FieldDescriptorProto_TYPE_INT32:
p.P(`var `, varName, ` int32`)
case descriptor.FieldDescriptorProto_TYPE_FIXED64:
p.P(`var `, varName, ` uint64`)
case descriptor.FieldDescriptorProto_TYPE_FIXED32:
p.P(`var `, varName, ` uint32`)
case descriptor.FieldDescriptorProto_TYPE_BOOL:
p.P(`var `, varName, ` bool`)
case descriptor.FieldDescriptorProto_TYPE_STRING:
cast, _ := p.GoType(nil, field)
cast = strings.Replace(cast, "*", "", 1)
p.P(`var `, varName, ` `, cast)
case descriptor.FieldDescriptorProto_TYPE_MESSAGE:
if gogoproto.IsStdTime(field) {
p.P(varName, ` := new(time.Time)`)
} else if gogoproto.IsStdDuration(field) {
p.P(varName, ` := new(time.Duration)`)
} else {
desc := p.ObjectNamed(field.GetTypeName())
msgname := p.TypeName(desc)
if nullable {
p.P(`var `, varName, ` *`, msgname)
} else {
p.P(varName, ` := &`, msgname, `{}`)
}
}
case descriptor.FieldDescriptorProto_TYPE_BYTES:
if customType {
_, ctyp, err := generator.GetCustomType(field)
if err != nil {
panic(err)
}
p.P(`var `, varName, `1 `, ctyp)
p.P(`var `, varName, ` = &`, varName, `1`)
} else {
p.P(varName, ` := []byte{}`)
}
case descriptor.FieldDescriptorProto_TYPE_UINT32:
p.P(`var `, varName, ` uint32`)
case descriptor.FieldDescriptorProto_TYPE_ENUM:
typName := p.TypeName(p.ObjectNamed(field.GetTypeName()))
p.P(`var `, varName, ` `, typName)
case descriptor.FieldDescriptorProto_TYPE_SFIXED32:
p.P(`var `, varName, ` int32`)
case descriptor.FieldDescriptorProto_TYPE_SFIXED64:
p.P(`var `, varName, ` int64`)
case descriptor.FieldDescriptorProto_TYPE_SINT32:
p.P(`var `, varName, ` int32`)
case descriptor.FieldDescriptorProto_TYPE_SINT64:
p.P(`var `, varName, ` int64`)
}
}
func (p *unmarshal) mapField(varName string, customType bool, field *descriptor.FieldDescriptorProto) {
@@ -296,30 +321,25 @@ func (p *unmarshal) mapField(varName string, customType bool, field *descriptor.
case descriptor.FieldDescriptorProto_TYPE_DOUBLE:
p.P(`var `, varName, `temp uint64`)
p.decodeFixed64(varName+"temp", "uint64")
p.P(varName, ` := `, p.mathPkg.Use(), `.Float64frombits(`, varName, `temp)`)
p.P(varName, ` = `, p.mathPkg.Use(), `.Float64frombits(`, varName, `temp)`)
case descriptor.FieldDescriptorProto_TYPE_FLOAT:
p.P(`var `, varName, `temp uint32`)
p.decodeFixed32(varName+"temp", "uint32")
p.P(varName, ` := `, p.mathPkg.Use(), `.Float32frombits(`, varName, `temp)`)
p.P(varName, ` = `, p.mathPkg.Use(), `.Float32frombits(`, varName, `temp)`)
case descriptor.FieldDescriptorProto_TYPE_INT64:
p.P(`var `, varName, ` int64`)
p.decodeVarint(varName, "int64")
case descriptor.FieldDescriptorProto_TYPE_UINT64:
p.P(`var `, varName, ` uint64`)
p.decodeVarint(varName, "uint64")
case descriptor.FieldDescriptorProto_TYPE_INT32:
p.P(`var `, varName, ` int32`)
p.decodeVarint(varName, "int32")
case descriptor.FieldDescriptorProto_TYPE_FIXED64:
p.P(`var `, varName, ` uint64`)
p.decodeFixed64(varName, "uint64")
case descriptor.FieldDescriptorProto_TYPE_FIXED32:
p.P(`var `, varName, ` uint32`)
p.decodeFixed32(varName, "uint32")
case descriptor.FieldDescriptorProto_TYPE_BOOL:
p.P(`var `, varName, `temp int`)
p.decodeVarint(varName+"temp", "int")
p.P(varName, ` := bool(`, varName, `temp != 0)`)
p.P(varName, ` = bool(`, varName, `temp != 0)`)
case descriptor.FieldDescriptorProto_TYPE_STRING:
p.P(`var stringLen`, varName, ` uint64`)
p.decodeVarint("stringLen"+varName, "uint64")
@@ -337,7 +357,7 @@ func (p *unmarshal) mapField(varName string, customType bool, field *descriptor.
p.P(`}`)
cast, _ := p.GoType(nil, field)
cast = strings.Replace(cast, "*", "", 1)
p.P(varName, ` := `, cast, `(dAtA[iNdEx:postStringIndex`, varName, `])`)
p.P(varName, ` = `, cast, `(dAtA[iNdEx:postStringIndex`, varName, `])`)
p.P(`iNdEx = postStringIndex`, varName)
case descriptor.FieldDescriptorProto_TYPE_MESSAGE:
p.P(`var mapmsglen int`)
@@ -358,17 +378,15 @@ func (p *unmarshal) mapField(varName string, customType bool, field *descriptor.
p.P(`return `, p.ioPkg.Use(), `.ErrUnexpectedEOF`)
p.Out()
p.P(`}`)
desc := p.ObjectNamed(field.GetTypeName())
msgname := p.TypeName(desc)
buf := `dAtA[iNdEx:postmsgIndex]`
if gogoproto.IsStdTime(field) {
p.P(varName, ` := new(time.Time)`)
p.P(`if err := `, p.typesPkg.Use(), `.StdTimeUnmarshal(`, varName, `, `, buf, `); err != nil {`)
} else if gogoproto.IsStdDuration(field) {
p.P(varName, ` := new(time.Duration)`)
p.P(`if err := `, p.typesPkg.Use(), `.StdDurationUnmarshal(`, varName, `, `, buf, `); err != nil {`)
} else {
p.P(varName, ` := &`, msgname, `{}`)
desc := p.ObjectNamed(field.GetTypeName())
msgname := p.TypeName(desc)
p.P(varName, ` = &`, msgname, `{}`)
p.P(`if err := `, varName, `.Unmarshal(`, buf, `); err != nil {`)
}
p.In()
@@ -392,45 +410,35 @@ func (p *unmarshal) mapField(varName string, customType bool, field *descriptor.
p.Out()
p.P(`}`)
if customType {
_, ctyp, err := generator.GetCustomType(field)
if err != nil {
panic(err)
}
p.P(`var `, varName, `1 `, ctyp)
p.P(`var `, varName, ` = &`, varName, `1`)
p.P(`if err := `, varName, `.Unmarshal(dAtA[iNdEx:postbytesIndex]); err != nil {`)
p.In()
p.P(`return err`)
p.Out()
p.P(`}`)
} else {
p.P(varName, ` := make([]byte, mapbyteLen)`)
p.P(varName, ` = make([]byte, mapbyteLen)`)
p.P(`copy(`, varName, `, dAtA[iNdEx:postbytesIndex])`)
}
p.P(`iNdEx = postbytesIndex`)
case descriptor.FieldDescriptorProto_TYPE_UINT32:
p.P(`var `, varName, ` uint32`)
p.decodeVarint(varName, "uint32")
case descriptor.FieldDescriptorProto_TYPE_ENUM:
typName := p.TypeName(p.ObjectNamed(field.GetTypeName()))
p.P(`var `, varName, ` `, typName)
p.decodeVarint(varName, typName)
case descriptor.FieldDescriptorProto_TYPE_SFIXED32:
p.P(`var `, varName, ` int32`)
p.decodeFixed32(varName, "int32")
case descriptor.FieldDescriptorProto_TYPE_SFIXED64:
p.P(`var `, varName, ` int64`)
p.decodeFixed64(varName, "int64")
case descriptor.FieldDescriptorProto_TYPE_SINT32:
p.P(`var `, varName, `temp int32`)
p.decodeVarint(varName+"temp", "int32")
p.P(varName, `temp = int32((uint32(`, varName, `temp) >> 1) ^ uint32(((`, varName, `temp&1)<<31)>>31))`)
p.P(varName, ` := int32(`, varName, `temp)`)
p.P(varName, ` = int32(`, varName, `temp)`)
case descriptor.FieldDescriptorProto_TYPE_SINT64:
p.P(`var `, varName, `temp uint64`)
p.decodeVarint(varName+"temp", "uint64")
p.P(varName, `temp = (`, varName, `temp >> 1) ^ uint64((int64(`, varName, `temp&1)<<63)>>63)`)
p.P(varName, ` := int64(`, varName, `temp)`)
p.P(varName, ` = int64(`, varName, `temp)`)
}
}
@@ -452,68 +460,32 @@ func (p *unmarshal) field(file *generator.FileDescriptor, msg *generator.Descrip
oneof := field.OneofIndex != nil
switch *field.Type {
case descriptor.FieldDescriptorProto_TYPE_DOUBLE:
if !p.unsafe || gogoproto.IsCastType(field) {
p.P(`var v uint64`)
p.decodeFixed64("v", "uint64")
if oneof {
p.P(`m.`, fieldname, ` = &`, p.OneOfTypeName(msg, field), `{`, typ, "(", p.mathPkg.Use(), `.Float64frombits(v))}`)
} else if repeated {
p.P(`v2 := `, typ, "(", p.mathPkg.Use(), `.Float64frombits(v))`)
p.P(`m.`, fieldname, ` = append(m.`, fieldname, `, v2)`)
} else if proto3 || !nullable {
p.P(`m.`, fieldname, ` = `, typ, "(", p.mathPkg.Use(), `.Float64frombits(v))`)
} else {
p.P(`v2 := `, typ, "(", p.mathPkg.Use(), `.Float64frombits(v))`)
p.P(`m.`, fieldname, ` = &v2`)
}
p.P(`var v uint64`)
p.decodeFixed64("v", "uint64")
if oneof {
p.P(`m.`, fieldname, ` = &`, p.OneOfTypeName(msg, field), `{`, typ, "(", p.mathPkg.Use(), `.Float64frombits(v))}`)
} else if repeated {
p.P(`v2 := `, typ, "(", p.mathPkg.Use(), `.Float64frombits(v))`)
p.P(`m.`, fieldname, ` = append(m.`, fieldname, `, v2)`)
} else if proto3 || !nullable {
p.P(`m.`, fieldname, ` = `, typ, "(", p.mathPkg.Use(), `.Float64frombits(v))`)
} else {
if oneof {
p.P(`var v float64`)
p.unsafeFixed64("v", "float64")
p.P(`m.`, fieldname, ` = &`, p.OneOfTypeName(msg, field), `{v}`)
} else if repeated {
p.P(`var v float64`)
p.unsafeFixed64("v", "float64")
p.P(`m.`, fieldname, ` = append(m.`, fieldname, `, v)`)
} else if proto3 || !nullable {
p.unsafeFixed64(`m.`+fieldname, "float64")
} else {
p.P(`var v float64`)
p.unsafeFixed64("v", "float64")
p.P(`m.`, fieldname, ` = &v`)
}
p.P(`v2 := `, typ, "(", p.mathPkg.Use(), `.Float64frombits(v))`)
p.P(`m.`, fieldname, ` = &v2`)
}
case descriptor.FieldDescriptorProto_TYPE_FLOAT:
if !p.unsafe || gogoproto.IsCastType(field) {
p.P(`var v uint32`)
p.decodeFixed32("v", "uint32")
if oneof {
p.P(`m.`, fieldname, ` = &`, p.OneOfTypeName(msg, field), `{`, typ, "(", p.mathPkg.Use(), `.Float32frombits(v))}`)
} else if repeated {
p.P(`v2 := `, typ, "(", p.mathPkg.Use(), `.Float32frombits(v))`)
p.P(`m.`, fieldname, ` = append(m.`, fieldname, `, v2)`)
} else if proto3 || !nullable {
p.P(`m.`, fieldname, ` = `, typ, "(", p.mathPkg.Use(), `.Float32frombits(v))`)
} else {
p.P(`v2 := `, typ, "(", p.mathPkg.Use(), `.Float32frombits(v))`)
p.P(`m.`, fieldname, ` = &v2`)
}
p.P(`var v uint32`)
p.decodeFixed32("v", "uint32")
if oneof {
p.P(`m.`, fieldname, ` = &`, p.OneOfTypeName(msg, field), `{`, typ, "(", p.mathPkg.Use(), `.Float32frombits(v))}`)
} else if repeated {
p.P(`v2 := `, typ, "(", p.mathPkg.Use(), `.Float32frombits(v))`)
p.P(`m.`, fieldname, ` = append(m.`, fieldname, `, v2)`)
} else if proto3 || !nullable {
p.P(`m.`, fieldname, ` = `, typ, "(", p.mathPkg.Use(), `.Float32frombits(v))`)
} else {
if oneof {
p.P(`var v float32`)
p.unsafeFixed32("v", "float32")
p.P(`m.`, fieldname, ` = &`, p.OneOfTypeName(msg, field), `{v}`)
} else if repeated {
p.P(`var v float32`)
p.unsafeFixed32("v", "float32")
p.P(`m.`, fieldname, ` = append(m.`, fieldname, `, v)`)
} else if proto3 || !nullable {
p.unsafeFixed32("m."+fieldname, "float32")
} else {
p.P(`var v float32`)
p.unsafeFixed32("v", "float32")
p.P(`m.`, fieldname, ` = &v`)
}
p.P(`v2 := `, typ, "(", p.mathPkg.Use(), `.Float32frombits(v))`)
p.P(`m.`, fieldname, ` = &v2`)
}
case descriptor.FieldDescriptorProto_TYPE_INT64:
if oneof {
@@ -567,74 +539,38 @@ func (p *unmarshal) field(file *generator.FileDescriptor, msg *generator.Descrip
p.P(`m.`, fieldname, ` = &v`)
}
case descriptor.FieldDescriptorProto_TYPE_FIXED64:
if !p.unsafe || gogoproto.IsCastType(field) {
if oneof {
p.P(`var v `, typ)
p.decodeFixed64("v", typ)
p.P(`m.`, fieldname, ` = &`, p.OneOfTypeName(msg, field), `{v}`)
} else if repeated {
p.P(`var v `, typ)
p.decodeFixed64("v", typ)
p.P(`m.`, fieldname, ` = append(m.`, fieldname, `, v)`)
} else if proto3 || !nullable {
p.P(`m.`, fieldname, ` = 0`)
p.decodeFixed64("m."+fieldname, typ)
} else {
p.P(`var v `, typ)
p.decodeFixed64("v", typ)
p.P(`m.`, fieldname, ` = &v`)
}
if oneof {
p.P(`var v `, typ)
p.decodeFixed64("v", typ)
p.P(`m.`, fieldname, ` = &`, p.OneOfTypeName(msg, field), `{v}`)
} else if repeated {
p.P(`var v `, typ)
p.decodeFixed64("v", typ)
p.P(`m.`, fieldname, ` = append(m.`, fieldname, `, v)`)
} else if proto3 || !nullable {
p.P(`m.`, fieldname, ` = 0`)
p.decodeFixed64("m."+fieldname, typ)
} else {
if oneof {
p.P(`var v uint64`)
p.unsafeFixed64("v", "uint64")
p.P(`m.`, fieldname, ` = &`, p.OneOfTypeName(msg, field), `{v}`)
} else if repeated {
p.P(`var v uint64`)
p.unsafeFixed64("v", "uint64")
p.P(`m.`, fieldname, ` = append(m.`, fieldname, `, v)`)
} else if proto3 || !nullable {
p.unsafeFixed64("m."+fieldname, "uint64")
} else {
p.P(`var v uint64`)
p.unsafeFixed64("v", "uint64")
p.P(`m.`, fieldname, ` = &v`)
}
p.P(`var v `, typ)
p.decodeFixed64("v", typ)
p.P(`m.`, fieldname, ` = &v`)
}
case descriptor.FieldDescriptorProto_TYPE_FIXED32:
if !p.unsafe || gogoproto.IsCastType(field) {
if oneof {
p.P(`var v `, typ)
p.decodeFixed32("v", typ)
p.P(`m.`, fieldname, ` = &`, p.OneOfTypeName(msg, field), `{v}`)
} else if repeated {
p.P(`var v `, typ)
p.decodeFixed32("v", typ)
p.P(`m.`, fieldname, ` = append(m.`, fieldname, `, v)`)
} else if proto3 || !nullable {
p.P(`m.`, fieldname, ` = 0`)
p.decodeFixed32("m."+fieldname, typ)
} else {
p.P(`var v `, typ)
p.decodeFixed32("v", typ)
p.P(`m.`, fieldname, ` = &v`)
}
if oneof {
p.P(`var v `, typ)
p.decodeFixed32("v", typ)
p.P(`m.`, fieldname, ` = &`, p.OneOfTypeName(msg, field), `{v}`)
} else if repeated {
p.P(`var v `, typ)
p.decodeFixed32("v", typ)
p.P(`m.`, fieldname, ` = append(m.`, fieldname, `, v)`)
} else if proto3 || !nullable {
p.P(`m.`, fieldname, ` = 0`)
p.decodeFixed32("m."+fieldname, typ)
} else {
if oneof {
p.P(`var v uint32`)
p.unsafeFixed32("v", "uint32")
p.P(`m.`, fieldname, ` = &`, p.OneOfTypeName(msg, field), `{v}`)
} else if repeated {
p.P(`var v uint32`)
p.unsafeFixed32("v", "uint32")
p.P(`m.`, fieldname, ` = append(m.`, fieldname, `, v)`)
} else if proto3 || !nullable {
p.unsafeFixed32("m."+fieldname, "uint32")
} else {
p.P(`var v uint32`)
p.unsafeFixed32("v", "uint32")
p.P(`m.`, fieldname, ` = &v`)
}
p.P(`var v `, typ)
p.decodeFixed32("v", typ)
p.P(`m.`, fieldname, ` = &v`)
}
case descriptor.FieldDescriptorProto_TYPE_BOOL:
p.P(`var v int`)
@@ -747,20 +683,63 @@ func (p *unmarshal) field(file *generator.FileDescriptor, msg *generator.Descrip
valuegoTyp = valuegoAliasTyp
}
p.P(`var keykey uint64`)
p.decodeVarint("keykey", "uint64")
p.mapField("mapkey", false, m.KeyAliasField)
p.P(`if m.`, fieldname, ` == nil {`)
p.In()
p.P(`m.`, fieldname, ` = make(`, m.GoType, `)`)
p.Out()
p.P(`}`)
p.declareMapField("mapkey", false, false, m.KeyAliasField)
p.declareMapField("mapvalue", nullable, gogoproto.IsCustomType(field), m.ValueAliasField)
p.P(`for iNdEx < postIndex {`)
p.In()
p.P(`entryPreIndex := iNdEx`)
p.P(`var wire uint64`)
p.decodeVarint("wire", "uint64")
p.P(`fieldNum := int32(wire >> 3)`)
p.P(`if fieldNum == 1 {`)
p.In()
p.mapField("mapkey", false, m.KeyAliasField)
p.Out()
p.P(`} else if fieldNum == 2 {`)
p.In()
p.mapField("mapvalue", gogoproto.IsCustomType(field), m.ValueAliasField)
p.Out()
p.P(`} else {`)
p.In()
p.P(`iNdEx = entryPreIndex`)
p.P(`skippy, err := skip`, p.localName, `(dAtA[iNdEx:])`)
p.P(`if err != nil {`)
p.In()
p.P(`return err`)
p.Out()
p.P(`}`)
p.P(`if skippy < 0 {`)
p.In()
p.P(`return ErrInvalidLength`, p.localName)
p.Out()
p.P(`}`)
p.P(`if (iNdEx + skippy) > postIndex {`)
p.In()
p.P(`return `, p.ioPkg.Use(), `.ErrUnexpectedEOF`)
p.Out()
p.P(`}`)
p.P(`iNdEx += skippy`)
p.Out()
p.P(`}`)
p.Out()
p.P(`}`)
s := `m.` + fieldname
if keygoTyp == keygoAliasTyp {
s += `[mapkey]`
} else {
s += `[` + keygoAliasTyp + `(mapkey)]`
}
v := `mapvalue`
if (m.ValueField.IsMessage() || gogoproto.IsCustomType(field)) && !nullable {
v = `*` + v
@@ -768,35 +747,8 @@ func (p *unmarshal) field(file *generator.FileDescriptor, msg *generator.Descrip
if valuegoTyp != valuegoAliasTyp {
v = `((` + valuegoAliasTyp + `)(` + v + `))`
}
p.P(`if iNdEx < postIndex {`)
p.In()
p.P(`var valuekey uint64`)
p.decodeVarint("valuekey", "uint64")
p.mapField("mapvalue", gogoproto.IsCustomType(field), m.ValueAliasField)
p.P(s, ` = `, v)
p.Out()
p.P(`} else {`)
p.In()
if gogoproto.IsStdTime(field) {
p.P(`var mapvalue = new(time.Time)`)
if nullable {
p.P(s, ` = mapvalue`)
} else {
p.P(s, ` = *mapvalue`)
}
} else if gogoproto.IsStdDuration(field) {
p.P(`var mapvalue = new(time.Duration)`)
if nullable {
p.P(s, ` = mapvalue`)
} else {
p.P(s, ` = *mapvalue`)
}
} else {
p.P(`var mapvalue `, valuegoAliasTyp)
p.P(s, ` = mapvalue`)
}
p.Out()
p.P(`}`)
} else if repeated {
if gogoproto.IsStdTime(field) {
if nullable {
@@ -984,74 +936,38 @@ func (p *unmarshal) field(file *generator.FileDescriptor, msg *generator.Descrip
p.P(`m.`, fieldname, ` = &v`)
}
case descriptor.FieldDescriptorProto_TYPE_SFIXED32:
if !p.unsafe || gogoproto.IsCastType(field) {
if oneof {
p.P(`var v `, typ)
p.decodeFixed32("v", typ)
p.P(`m.`, fieldname, ` = &`, p.OneOfTypeName(msg, field), `{v}`)
} else if repeated {
p.P(`var v `, typ)
p.decodeFixed32("v", typ)
p.P(`m.`, fieldname, ` = append(m.`, fieldname, `, v)`)
} else if proto3 || !nullable {
p.P(`m.`, fieldname, ` = 0`)
p.decodeFixed32("m."+fieldname, typ)
} else {
p.P(`var v `, typ)
p.decodeFixed32("v", typ)
p.P(`m.`, fieldname, ` = &v`)
}
if oneof {
p.P(`var v `, typ)
p.decodeFixed32("v", typ)
p.P(`m.`, fieldname, ` = &`, p.OneOfTypeName(msg, field), `{v}`)
} else if repeated {
p.P(`var v `, typ)
p.decodeFixed32("v", typ)
p.P(`m.`, fieldname, ` = append(m.`, fieldname, `, v)`)
} else if proto3 || !nullable {
p.P(`m.`, fieldname, ` = 0`)
p.decodeFixed32("m."+fieldname, typ)
} else {
if oneof {
p.P(`var v int32`)
p.unsafeFixed32("v", "int32")
p.P(`m.`, fieldname, ` = &`, p.OneOfTypeName(msg, field), `{v}`)
} else if repeated {
p.P(`var v int32`)
p.unsafeFixed32("v", "int32")
p.P(`m.`, fieldname, ` = append(m.`, fieldname, `, v)`)
} else if proto3 || !nullable {
p.unsafeFixed32("m."+fieldname, "int32")
} else {
p.P(`var v int32`)
p.unsafeFixed32("v", "int32")
p.P(`m.`, fieldname, ` = &v`)
}
p.P(`var v `, typ)
p.decodeFixed32("v", typ)
p.P(`m.`, fieldname, ` = &v`)
}
case descriptor.FieldDescriptorProto_TYPE_SFIXED64:
if !p.unsafe || gogoproto.IsCastType(field) {
if oneof {
p.P(`var v `, typ)
p.decodeFixed64("v", typ)
p.P(`m.`, fieldname, ` = &`, p.OneOfTypeName(msg, field), `{v}`)
} else if repeated {
p.P(`var v `, typ)
p.decodeFixed64("v", typ)
p.P(`m.`, fieldname, ` = append(m.`, fieldname, `, v)`)
} else if proto3 || !nullable {
p.P(`m.`, fieldname, ` = 0`)
p.decodeFixed64("m."+fieldname, typ)
} else {
p.P(`var v `, typ)
p.decodeFixed64("v", typ)
p.P(`m.`, fieldname, ` = &v`)
}
if oneof {
p.P(`var v `, typ)
p.decodeFixed64("v", typ)
p.P(`m.`, fieldname, ` = &`, p.OneOfTypeName(msg, field), `{v}`)
} else if repeated {
p.P(`var v `, typ)
p.decodeFixed64("v", typ)
p.P(`m.`, fieldname, ` = append(m.`, fieldname, `, v)`)
} else if proto3 || !nullable {
p.P(`m.`, fieldname, ` = 0`)
p.decodeFixed64("m."+fieldname, typ)
} else {
if oneof {
p.P(`var v int64`)
p.unsafeFixed64("v", "int64")
p.P(`m.`, fieldname, ` = &`, p.OneOfTypeName(msg, field), `{v}`)
} else if repeated {
p.P(`var v int64`)
p.unsafeFixed64("v", "int64")
p.P(`m.`, fieldname, ` = append(m.`, fieldname, `, v)`)
} else if proto3 || !nullable {
p.unsafeFixed64("m."+fieldname, "int64")
} else {
p.P(`var v int64`)
p.unsafeFixed64("v", "int64")
p.P(`m.`, fieldname, ` = &v`)
}
p.P(`var v `, typ)
p.decodeFixed64("v", typ)
p.P(`m.`, fieldname, ` = &v`)
}
case descriptor.FieldDescriptorProto_TYPE_SINT32:
p.P(`var v `, typ)
@@ -1090,14 +1006,11 @@ func (p *unmarshal) Generate(file *generator.FileDescriptor) {
p.PluginImports = generator.NewPluginImports(p.Generator)
p.atleastOne = false
p.localName = generator.FileName(file)
if p.unsafe {
p.localName += "Unsafe"
}
p.ioPkg = p.NewImport("io")
p.mathPkg = p.NewImport("math")
p.unsafePkg = p.NewImport("unsafe")
p.typesPkg = p.NewImport("github.com/gogo/protobuf/types")
p.binaryPkg = p.NewImport("encoding/binary")
fmtPkg := p.NewImport("fmt")
protoPkg := p.NewImport("github.com/gogo/protobuf/proto")
if !gogoproto.ImportsGoGoProto(file.FileDescriptorProto) {
@@ -1106,21 +1019,9 @@ func (p *unmarshal) Generate(file *generator.FileDescriptor) {
for _, message := range file.Messages() {
ccTypeName := generator.CamelCaseSlice(message.TypeName())
if p.unsafe {
if !gogoproto.IsUnsafeUnmarshaler(file.FileDescriptorProto, message.DescriptorProto) {
continue
}
if gogoproto.IsUnmarshaler(file.FileDescriptorProto, message.DescriptorProto) {
panic(fmt.Sprintf("unsafe_unmarshaler and unmarshaler enabled for %v", ccTypeName))
}
}
if !p.unsafe {
if !gogoproto.IsUnmarshaler(file.FileDescriptorProto, message.DescriptorProto) {
continue
}
if gogoproto.IsUnsafeUnmarshaler(file.FileDescriptorProto, message.DescriptorProto) {
panic(fmt.Sprintf("unsafe_unmarshaler and unmarshaler enabled for %v", ccTypeName))
}
if !gogoproto.IsUnmarshaler(file.FileDescriptorProto, message.DescriptorProto) &&
!gogoproto.IsUnsafeUnmarshaler(file.FileDescriptorProto, message.DescriptorProto) {
continue
}
if message.DescriptorProto.GetOptions().GetMapEntry() {
continue
@@ -1445,5 +1346,4 @@ func (p *unmarshal) Generate(file *generator.FileDescriptor) {
func init() {
generator.RegisterPlugin(NewUnmarshal())
generator.RegisterPlugin(NewUnsafeUnmarshal())
}
-43
View File
@@ -1,43 +0,0 @@
# Go support for Protocol Buffers - Google's data interchange format
#
# Copyright 2010 The Go Authors. All rights reserved.
# https://github.com/golang/protobuf
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following disclaimer
# in the documentation and/or other materials provided with the
# distribution.
# * Neither the name of Google Inc. nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
install:
go install
test: install generate-test-pbs
go test
generate-test-pbs:
make install
make -C testdata
protoc-min-version --version="3.0.0" --proto_path=.:../../../../:../protobuf --gogo_out=Mtestdata/test.proto=github.com/gogo/protobuf/proto/testdata,Mgoogle/protobuf/any.proto=github.com/gogo/protobuf/types:. proto3_proto/proto3.proto
make
-2278
View File
File diff suppressed because it is too large Load Diff
-300
View File
@@ -1,300 +0,0 @@
// Go support for Protocol Buffers - Google's data interchange format
//
// Copyright 2016 The Go Authors. All rights reserved.
// https://github.com/golang/protobuf
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package proto_test
import (
"strings"
"testing"
"github.com/gogo/protobuf/proto"
pb "github.com/gogo/protobuf/proto/proto3_proto"
testpb "github.com/gogo/protobuf/proto/testdata"
"github.com/gogo/protobuf/types"
)
var (
expandedMarshaler = proto.TextMarshaler{ExpandAny: true}
expandedCompactMarshaler = proto.TextMarshaler{Compact: true, ExpandAny: true}
)
// anyEqual reports whether two messages which may be google.protobuf.Any or may
// contain google.protobuf.Any fields are equal. We can't use proto.Equal for
// comparison, because semantically equivalent messages may be marshaled to
// binary in different tag order. Instead, trust that TextMarshaler with
// ExpandAny option works and compare the text marshaling results.
func anyEqual(got, want proto.Message) bool {
// if messages are proto.Equal, no need to marshal.
if proto.Equal(got, want) {
return true
}
g := expandedMarshaler.Text(got)
w := expandedMarshaler.Text(want)
return g == w
}
type golden struct {
m proto.Message
t, c string
}
var goldenMessages = makeGolden()
func makeGolden() []golden {
nested := &pb.Nested{Bunny: "Monty"}
nb, err := proto.Marshal(nested)
if err != nil {
panic(err)
}
m1 := &pb.Message{
Name: "David",
ResultCount: 47,
Anything: &types.Any{TypeUrl: "type.googleapis.com/" + proto.MessageName(nested), Value: nb},
}
m2 := &pb.Message{
Name: "David",
ResultCount: 47,
Anything: &types.Any{TypeUrl: "http://[::1]/type.googleapis.com/" + proto.MessageName(nested), Value: nb},
}
m3 := &pb.Message{
Name: "David",
ResultCount: 47,
Anything: &types.Any{TypeUrl: `type.googleapis.com/"/` + proto.MessageName(nested), Value: nb},
}
m4 := &pb.Message{
Name: "David",
ResultCount: 47,
Anything: &types.Any{TypeUrl: "type.googleapis.com/a/path/" + proto.MessageName(nested), Value: nb},
}
m5 := &types.Any{TypeUrl: "type.googleapis.com/" + proto.MessageName(nested), Value: nb}
any1 := &testpb.MyMessage{Count: proto.Int32(47), Name: proto.String("David")}
proto.SetExtension(any1, testpb.E_Ext_More, &testpb.Ext{Data: proto.String("foo")})
proto.SetExtension(any1, testpb.E_Ext_Text, proto.String("bar"))
any1b, err := proto.Marshal(any1)
if err != nil {
panic(err)
}
any2 := &testpb.MyMessage{Count: proto.Int32(42), Bikeshed: testpb.MyMessage_GREEN.Enum(), RepBytes: [][]byte{[]byte("roboto")}}
proto.SetExtension(any2, testpb.E_Ext_More, &testpb.Ext{Data: proto.String("baz")})
any2b, err := proto.Marshal(any2)
if err != nil {
panic(err)
}
m6 := &pb.Message{
Name: "David",
ResultCount: 47,
Anything: &types.Any{TypeUrl: "type.googleapis.com/" + proto.MessageName(any1), Value: any1b},
ManyThings: []*types.Any{
{TypeUrl: "type.googleapis.com/" + proto.MessageName(any2), Value: any2b},
{TypeUrl: "type.googleapis.com/" + proto.MessageName(any1), Value: any1b},
},
}
const (
m1Golden = `
name: "David"
result_count: 47
anything: <
[type.googleapis.com/proto3_proto.Nested]: <
bunny: "Monty"
>
>
`
m2Golden = `
name: "David"
result_count: 47
anything: <
["http://[::1]/type.googleapis.com/proto3_proto.Nested"]: <
bunny: "Monty"
>
>
`
m3Golden = `
name: "David"
result_count: 47
anything: <
["type.googleapis.com/\"/proto3_proto.Nested"]: <
bunny: "Monty"
>
>
`
m4Golden = `
name: "David"
result_count: 47
anything: <
[type.googleapis.com/a/path/proto3_proto.Nested]: <
bunny: "Monty"
>
>
`
m5Golden = `
[type.googleapis.com/proto3_proto.Nested]: <
bunny: "Monty"
>
`
m6Golden = `
name: "David"
result_count: 47
anything: <
[type.googleapis.com/testdata.MyMessage]: <
count: 47
name: "David"
[testdata.Ext.more]: <
data: "foo"
>
[testdata.Ext.text]: "bar"
>
>
many_things: <
[type.googleapis.com/testdata.MyMessage]: <
count: 42
bikeshed: GREEN
rep_bytes: "roboto"
[testdata.Ext.more]: <
data: "baz"
>
>
>
many_things: <
[type.googleapis.com/testdata.MyMessage]: <
count: 47
name: "David"
[testdata.Ext.more]: <
data: "foo"
>
[testdata.Ext.text]: "bar"
>
>
`
)
return []golden{
{m1, strings.TrimSpace(m1Golden) + "\n", strings.TrimSpace(compact(m1Golden)) + " "},
{m2, strings.TrimSpace(m2Golden) + "\n", strings.TrimSpace(compact(m2Golden)) + " "},
{m3, strings.TrimSpace(m3Golden) + "\n", strings.TrimSpace(compact(m3Golden)) + " "},
{m4, strings.TrimSpace(m4Golden) + "\n", strings.TrimSpace(compact(m4Golden)) + " "},
{m5, strings.TrimSpace(m5Golden) + "\n", strings.TrimSpace(compact(m5Golden)) + " "},
{m6, strings.TrimSpace(m6Golden) + "\n", strings.TrimSpace(compact(m6Golden)) + " "},
}
}
func TestMarshalGolden(t *testing.T) {
for _, tt := range goldenMessages {
if got, want := expandedMarshaler.Text(tt.m), tt.t; got != want {
t.Errorf("message %v: got:\n%s\nwant:\n%s", tt.m, got, want)
}
if got, want := expandedCompactMarshaler.Text(tt.m), tt.c; got != want {
t.Errorf("message %v: got:\n`%s`\nwant:\n`%s`", tt.m, got, want)
}
}
}
func TestUnmarshalGolden(t *testing.T) {
for _, tt := range goldenMessages {
want := tt.m
got := proto.Clone(tt.m)
got.Reset()
if err := proto.UnmarshalText(tt.t, got); err != nil {
t.Errorf("failed to unmarshal\n%s\nerror: %v", tt.t, err)
}
if !anyEqual(got, want) {
t.Errorf("message:\n%s\ngot:\n%s\nwant:\n%s", tt.t, got, want)
}
got.Reset()
if err := proto.UnmarshalText(tt.c, got); err != nil {
t.Errorf("failed to unmarshal\n%s\nerror: %v", tt.c, err)
}
if !anyEqual(got, want) {
t.Errorf("message:\n%s\ngot:\n%s\nwant:\n%s", tt.c, got, want)
}
}
}
func TestMarshalUnknownAny(t *testing.T) {
m := &pb.Message{
Anything: &types.Any{
TypeUrl: "foo",
Value: []byte("bar"),
},
}
want := `anything: <
type_url: "foo"
value: "bar"
>
`
got := expandedMarshaler.Text(m)
if got != want {
t.Errorf("got\n`%s`\nwant\n`%s`", got, want)
}
}
func TestAmbiguousAny(t *testing.T) {
pb := &types.Any{}
err := proto.UnmarshalText(`
type_url: "ttt/proto3_proto.Nested"
value: "\n\x05Monty"
`, pb)
t.Logf("result: %v (error: %v)", expandedMarshaler.Text(pb), err)
if err != nil {
t.Errorf("failed to parse ambiguous Any message: %v", err)
}
}
func TestUnmarshalOverwriteAny(t *testing.T) {
pb := &types.Any{}
err := proto.UnmarshalText(`
[type.googleapis.com/a/path/proto3_proto.Nested]: <
bunny: "Monty"
>
[type.googleapis.com/a/path/proto3_proto.Nested]: <
bunny: "Rabbit of Caerbannog"
>
`, pb)
want := `line 7: Any message unpacked multiple times, or "type_url" already set`
if err.Error() != want {
t.Errorf("incorrect error.\nHave: %v\nWant: %v", err.Error(), want)
}
}
func TestUnmarshalAnyMixAndMatch(t *testing.T) {
pb := &types.Any{}
err := proto.UnmarshalText(`
value: "\n\x05Monty"
[type.googleapis.com/a/path/proto3_proto.Nested]: <
bunny: "Rabbit of Caerbannog"
>
`, pb)
want := `line 5: Any message unpacked multiple times, or "value" already set`
if err.Error() != want {
t.Errorf("incorrect error.\nHave: %v\nWant: %v", err.Error(), want)
}
}
-300
View File
@@ -1,300 +0,0 @@
// Go support for Protocol Buffers - Google's data interchange format
//
// Copyright 2011 The Go Authors. All rights reserved.
// https://github.com/golang/protobuf
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package proto_test
import (
"testing"
"github.com/gogo/protobuf/proto"
proto3pb "github.com/gogo/protobuf/proto/proto3_proto"
pb "github.com/gogo/protobuf/proto/testdata"
)
var cloneTestMessage = &pb.MyMessage{
Count: proto.Int32(42),
Name: proto.String("Dave"),
Pet: []string{"bunny", "kitty", "horsey"},
Inner: &pb.InnerMessage{
Host: proto.String("niles"),
Port: proto.Int32(9099),
Connected: proto.Bool(true),
},
Others: []*pb.OtherMessage{
{
Value: []byte("some bytes"),
},
},
Somegroup: &pb.MyMessage_SomeGroup{
GroupField: proto.Int32(6),
},
RepBytes: [][]byte{[]byte("sham"), []byte("wow")},
}
func init() {
ext := &pb.Ext{
Data: proto.String("extension"),
}
if err := proto.SetExtension(cloneTestMessage, pb.E_Ext_More, ext); err != nil {
panic("SetExtension: " + err.Error())
}
}
func TestClone(t *testing.T) {
m := proto.Clone(cloneTestMessage).(*pb.MyMessage)
if !proto.Equal(m, cloneTestMessage) {
t.Errorf("Clone(%v) = %v", cloneTestMessage, m)
}
// Verify it was a deep copy.
*m.Inner.Port++
if proto.Equal(m, cloneTestMessage) {
t.Error("Mutating clone changed the original")
}
// Byte fields and repeated fields should be copied.
if &m.Pet[0] == &cloneTestMessage.Pet[0] {
t.Error("Pet: repeated field not copied")
}
if &m.Others[0] == &cloneTestMessage.Others[0] {
t.Error("Others: repeated field not copied")
}
if &m.Others[0].Value[0] == &cloneTestMessage.Others[0].Value[0] {
t.Error("Others[0].Value: bytes field not copied")
}
if &m.RepBytes[0] == &cloneTestMessage.RepBytes[0] {
t.Error("RepBytes: repeated field not copied")
}
if &m.RepBytes[0][0] == &cloneTestMessage.RepBytes[0][0] {
t.Error("RepBytes[0]: bytes field not copied")
}
}
func TestCloneNil(t *testing.T) {
var m *pb.MyMessage
if c := proto.Clone(m); !proto.Equal(m, c) {
t.Errorf("Clone(%v) = %v", m, c)
}
}
var mergeTests = []struct {
src, dst, want proto.Message
}{
{
src: &pb.MyMessage{
Count: proto.Int32(42),
},
dst: &pb.MyMessage{
Name: proto.String("Dave"),
},
want: &pb.MyMessage{
Count: proto.Int32(42),
Name: proto.String("Dave"),
},
},
{
src: &pb.MyMessage{
Inner: &pb.InnerMessage{
Host: proto.String("hey"),
Connected: proto.Bool(true),
},
Pet: []string{"horsey"},
Others: []*pb.OtherMessage{
{
Value: []byte("some bytes"),
},
},
},
dst: &pb.MyMessage{
Inner: &pb.InnerMessage{
Host: proto.String("niles"),
Port: proto.Int32(9099),
},
Pet: []string{"bunny", "kitty"},
Others: []*pb.OtherMessage{
{
Key: proto.Int64(31415926535),
},
{
// Explicitly test a src=nil field
Inner: nil,
},
},
},
want: &pb.MyMessage{
Inner: &pb.InnerMessage{
Host: proto.String("hey"),
Connected: proto.Bool(true),
Port: proto.Int32(9099),
},
Pet: []string{"bunny", "kitty", "horsey"},
Others: []*pb.OtherMessage{
{
Key: proto.Int64(31415926535),
},
{},
{
Value: []byte("some bytes"),
},
},
},
},
{
src: &pb.MyMessage{
RepBytes: [][]byte{[]byte("wow")},
},
dst: &pb.MyMessage{
Somegroup: &pb.MyMessage_SomeGroup{
GroupField: proto.Int32(6),
},
RepBytes: [][]byte{[]byte("sham")},
},
want: &pb.MyMessage{
Somegroup: &pb.MyMessage_SomeGroup{
GroupField: proto.Int32(6),
},
RepBytes: [][]byte{[]byte("sham"), []byte("wow")},
},
},
// Check that a scalar bytes field replaces rather than appends.
{
src: &pb.OtherMessage{Value: []byte("foo")},
dst: &pb.OtherMessage{Value: []byte("bar")},
want: &pb.OtherMessage{Value: []byte("foo")},
},
{
src: &pb.MessageWithMap{
NameMapping: map[int32]string{6: "Nigel"},
MsgMapping: map[int64]*pb.FloatingPoint{
0x4001: {F: proto.Float64(2.0)},
0x4002: {
F: proto.Float64(2.0),
},
},
ByteMapping: map[bool][]byte{true: []byte("wowsa")},
},
dst: &pb.MessageWithMap{
NameMapping: map[int32]string{
6: "Bruce", // should be overwritten
7: "Andrew",
},
MsgMapping: map[int64]*pb.FloatingPoint{
0x4002: {
F: proto.Float64(3.0),
Exact: proto.Bool(true),
}, // the entire message should be overwritten
},
},
want: &pb.MessageWithMap{
NameMapping: map[int32]string{
6: "Nigel",
7: "Andrew",
},
MsgMapping: map[int64]*pb.FloatingPoint{
0x4001: {F: proto.Float64(2.0)},
0x4002: {
F: proto.Float64(2.0),
},
},
ByteMapping: map[bool][]byte{true: []byte("wowsa")},
},
},
// proto3 shouldn't merge zero values,
// in the same way that proto2 shouldn't merge nils.
{
src: &proto3pb.Message{
Name: "Aaron",
Data: []byte(""), // zero value, but not nil
},
dst: &proto3pb.Message{
HeightInCm: 176,
Data: []byte("texas!"),
},
want: &proto3pb.Message{
Name: "Aaron",
HeightInCm: 176,
Data: []byte("texas!"),
},
},
// Oneof fields should merge by assignment.
{
src: &pb.Communique{
Union: &pb.Communique_Number{Number: 41},
},
dst: &pb.Communique{
Union: &pb.Communique_Name{Name: "Bobby Tables"},
},
want: &pb.Communique{
Union: &pb.Communique_Number{Number: 41},
},
},
// Oneof nil is the same as not set.
{
src: &pb.Communique{},
dst: &pb.Communique{
Union: &pb.Communique_Name{Name: "Bobby Tables"},
},
want: &pb.Communique{
Union: &pb.Communique_Name{Name: "Bobby Tables"},
},
},
{
src: &proto3pb.Message{
Terrain: map[string]*proto3pb.Nested{
"kay_a": {Cute: true}, // replace
"kay_b": {Bunny: "rabbit"}, // insert
},
},
dst: &proto3pb.Message{
Terrain: map[string]*proto3pb.Nested{
"kay_a": {Bunny: "lost"}, // replaced
"kay_c": {Bunny: "bunny"}, // keep
},
},
want: &proto3pb.Message{
Terrain: map[string]*proto3pb.Nested{
"kay_a": {Cute: true},
"kay_b": {Bunny: "rabbit"},
"kay_c": {Bunny: "bunny"},
},
},
},
}
func TestMerge(t *testing.T) {
for _, m := range mergeTests {
got := proto.Clone(m.dst)
proto.Merge(got, m.src)
if !proto.Equal(got, m.want) {
t.Errorf("Merge(%v, %v)\n got %v\nwant %v\n", m.dst, m.src, got, m.want)
}
}
}
-260
View File
@@ -1,260 +0,0 @@
// Go support for Protocol Buffers - Google's data interchange format
//
// Copyright 2010 The Go Authors. All rights reserved.
// https://github.com/golang/protobuf
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package proto_test
import (
"testing"
"github.com/gogo/protobuf/proto"
tpb "github.com/gogo/protobuf/proto/proto3_proto"
)
var (
bytesBlackhole []byte
msgBlackhole = new(tpb.Message)
)
// Disabled this Benchmark because it is using features (b.Run) from go1.7 and gogoprotobuf still have compatibility with go1.5
// BenchmarkVarint32ArraySmall shows the performance on an array of small int32 fields (1 and
// 2 bytes long).
// func BenchmarkVarint32ArraySmall(b *testing.B) {
// for i := uint(1); i <= 10; i++ {
// dist := genInt32Dist([7]int{0, 3, 1}, 1<<i)
// raw, err := proto.Marshal(&tpb.Message{
// ShortKey: dist,
// })
// if err != nil {
// b.Error("wrong encode", err)
// }
// b.Run(fmt.Sprintf("Len%v", len(dist)), func(b *testing.B) {
// scratchBuf := proto.NewBuffer(nil)
// b.ResetTimer()
// for k := 0; k < b.N; k++ {
// scratchBuf.SetBuf(raw)
// msgBlackhole.Reset()
// if err := scratchBuf.Unmarshal(msgBlackhole); err != nil {
// b.Error("wrong decode", err)
// }
// }
// })
// }
// }
// Disabled this Benchmark because it is using features (b.Run) from go1.7 and gogoprotobuf still have compatibility with go1.5
// BenchmarkVarint32ArrayLarge shows the performance on an array of large int32 fields (3 and
// 4 bytes long, with a small number of 1, 2, 5 and 10 byte long versions).
// func BenchmarkVarint32ArrayLarge(b *testing.B) {
// for i := uint(1); i <= 10; i++ {
// dist := genInt32Dist([7]int{0, 1, 2, 4, 8, 1, 1}, 1<<i)
// raw, err := proto.Marshal(&tpb.Message{
// ShortKey: dist,
// })
// if err != nil {
// b.Error("wrong encode", err)
// }
// b.Run(fmt.Sprintf("Len%v", len(dist)), func(b *testing.B) {
// scratchBuf := proto.NewBuffer(nil)
// b.ResetTimer()
// for k := 0; k < b.N; k++ {
// scratchBuf.SetBuf(raw)
// msgBlackhole.Reset()
// if err := scratchBuf.Unmarshal(msgBlackhole); err != nil {
// b.Error("wrong decode", err)
// }
// }
// })
// }
// }
// Disabled this Benchmark because it is using features (b.Run) from go1.7 and gogoprotobuf still have compatibility with go1.5
// BenchmarkVarint64ArraySmall shows the performance on an array of small int64 fields (1 and
// 2 bytes long).
// func BenchmarkVarint64ArraySmall(b *testing.B) {
// for i := uint(1); i <= 10; i++ {
// dist := genUint64Dist([11]int{0, 3, 1}, 1<<i)
// raw, err := proto.Marshal(&tpb.Message{
// Key: dist,
// })
// if err != nil {
// b.Error("wrong encode", err)
// }
// b.Run(fmt.Sprintf("Len%v", len(dist)), func(b *testing.B) {
// scratchBuf := proto.NewBuffer(nil)
// b.ResetTimer()
// for k := 0; k < b.N; k++ {
// scratchBuf.SetBuf(raw)
// msgBlackhole.Reset()
// if err := scratchBuf.Unmarshal(msgBlackhole); err != nil {
// b.Error("wrong decode", err)
// }
// }
// })
// }
// }
// Disabled this Benchmark because it is using features (b.Run) from go1.7 and gogoprotobuf still have compatibility with go1.5
// BenchmarkVarint64ArrayLarge shows the performance on an array of large int64 fields (6, 7,
// and 8 bytes long with a small number of the other sizes).
// func BenchmarkVarint64ArrayLarge(b *testing.B) {
// for i := uint(1); i <= 10; i++ {
// dist := genUint64Dist([11]int{0, 1, 1, 2, 4, 8, 16, 32, 16, 1, 1}, 1<<i)
// raw, err := proto.Marshal(&tpb.Message{
// Key: dist,
// })
// if err != nil {
// b.Error("wrong encode", err)
// }
// b.Run(fmt.Sprintf("Len%v", len(dist)), func(b *testing.B) {
// scratchBuf := proto.NewBuffer(nil)
// b.ResetTimer()
// for k := 0; k < b.N; k++ {
// scratchBuf.SetBuf(raw)
// msgBlackhole.Reset()
// if err := scratchBuf.Unmarshal(msgBlackhole); err != nil {
// b.Error("wrong decode", err)
// }
// }
// })
// }
// }
// Disabled this Benchmark because it is using features (b.Run) from go1.7 and gogoprotobuf still have compatibility with go1.5
// BenchmarkVarint64ArrayMixed shows the performance of lots of small messages, each
// containing a small number of large (3, 4, and 5 byte) repeated int64s.
// func BenchmarkVarint64ArrayMixed(b *testing.B) {
// for i := uint(1); i <= 1<<5; i <<= 1 {
// dist := genUint64Dist([11]int{0, 0, 0, 4, 6, 4, 0, 0, 0, 0, 0}, int(i))
// // number of sub fields
// for k := uint(1); k <= 1<<10; k <<= 2 {
// msg := &tpb.Message{}
// for m := uint(0); m < k; m++ {
// msg.Children = append(msg.Children, &tpb.Message{
// Key: dist,
// })
// }
// raw, err := proto.Marshal(msg)
// if err != nil {
// b.Error("wrong encode", err)
// }
// b.Run(fmt.Sprintf("Fields%vLen%v", k, i), func(b *testing.B) {
// scratchBuf := proto.NewBuffer(nil)
// b.ResetTimer()
// for k := 0; k < b.N; k++ {
// scratchBuf.SetBuf(raw)
// msgBlackhole.Reset()
// if err := scratchBuf.Unmarshal(msgBlackhole); err != nil {
// b.Error("wrong decode", err)
// }
// }
// })
// }
// }
// }
// genInt32Dist generates a slice of ints that will match the size distribution of dist.
// A size of 6 corresponds to a max length varint32, which is 10 bytes. The distribution
// is 1-indexed. (i.e. the value at index 1 is how many 1 byte ints to create).
func genInt32Dist(dist [7]int, count int) (dest []int32) {
for i := 0; i < count; i++ {
for k := 0; k < len(dist); k++ {
var num int32
switch k {
case 1:
num = 1<<7 - 1
case 2:
num = 1<<14 - 1
case 3:
num = 1<<21 - 1
case 4:
num = 1<<28 - 1
case 5:
num = 1<<29 - 1
case 6:
num = -1
}
for m := 0; m < dist[k]; m++ {
dest = append(dest, num)
}
}
}
return
}
// genUint64Dist generates a slice of ints that will match the size distribution of dist.
// The distribution is 1-indexed. (i.e. the value at index 1 is how many 1 byte ints to create).
func genUint64Dist(dist [11]int, count int) (dest []uint64) {
for i := 0; i < count; i++ {
for k := 0; k < len(dist); k++ {
var num uint64
switch k {
case 1:
num = 1<<7 - 1
case 2:
num = 1<<14 - 1
case 3:
num = 1<<21 - 1
case 4:
num = 1<<28 - 1
case 5:
num = 1<<35 - 1
case 6:
num = 1<<42 - 1
case 7:
num = 1<<49 - 1
case 8:
num = 1<<56 - 1
case 9:
num = 1<<63 - 1
case 10:
num = 1<<64 - 1
}
for m := 0; m < dist[k]; m++ {
dest = append(dest, num)
}
}
}
return
}
// BenchmarkDecodeEmpty measures the overhead of doing the minimal possible decode.
func BenchmarkDecodeEmpty(b *testing.B) {
raw, err := proto.Marshal(&tpb.Message{})
if err != nil {
b.Error("wrong encode", err)
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
if err := proto.Unmarshal(raw, msgBlackhole); err != nil {
b.Error("wrong decode", err)
}
}
}
+2 -2
View File
@@ -174,11 +174,11 @@ func sizeFixed32(x uint64) int {
// This is the format used for the sint64 protocol buffer type.
func (p *Buffer) EncodeZigzag64(x uint64) error {
// use signed number to get arithmetic right shift.
return p.EncodeVarint(uint64((x << 1) ^ uint64((int64(x) >> 63))))
return p.EncodeVarint((x << 1) ^ uint64((int64(x) >> 63)))
}
func sizeZigzag64(x uint64) int {
return sizeVarint(uint64((x << 1) ^ uint64((int64(x) >> 63))))
return sizeVarint((x << 1) ^ uint64((int64(x) >> 63)))
}
// EncodeZigzag32 writes a zigzag-encoded 32-bit integer
-82
View File
@@ -1,82 +0,0 @@
// Go support for Protocol Buffers - Google's data interchange format
//
// Copyright 2010 The Go Authors. All rights reserved.
// https://github.com/golang/protobuf
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package proto_test
import (
"testing"
"github.com/gogo/protobuf/proto"
tpb "github.com/gogo/protobuf/proto/proto3_proto"
)
var (
blackhole []byte
)
// Disabled this Benchmark because it is using features (b.Run) from go1.7 and gogoprotobuf still have compatibility with go1.5
// BenchmarkAny creates increasingly large arbitrary Any messages. The type is always the
// same.
// func BenchmarkAny(b *testing.B) {
// data := make([]byte, 1<<20)
// quantum := 1 << 10
// for i := uint(0); i <= 10; i++ {
// b.Run(strconv.Itoa(quantum<<i), func(b *testing.B) {
// for k := 0; k < b.N; k++ {
// inner := &tpb.Message{
// Data: data[:quantum<<i],
// }
// outer, err := types.MarshalAny(inner)
// if err != nil {
// b.Error("wrong encode", err)
// }
// raw, err := proto.Marshal(&tpb.Message{
// Anything: outer,
// })
// if err != nil {
// b.Error("wrong encode", err)
// }
// blackhole = raw
// }
// })
// }
// }
// BenchmarkEmpy measures the overhead of doing the minimal possible encode.
func BenchmarkEmpy(b *testing.B) {
for i := 0; i < b.N; i++ {
raw, err := proto.Marshal(&tpb.Message{})
if err != nil {
b.Error("wrong encode", err)
}
blackhole = raw
}
}
-224
View File
@@ -1,224 +0,0 @@
// Go support for Protocol Buffers - Google's data interchange format
//
// Copyright 2011 The Go Authors. All rights reserved.
// https://github.com/golang/protobuf
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package proto_test
import (
"testing"
. "github.com/gogo/protobuf/proto"
proto3pb "github.com/gogo/protobuf/proto/proto3_proto"
pb "github.com/gogo/protobuf/proto/testdata"
)
// Four identical base messages.
// The init function adds extensions to some of them.
var messageWithoutExtension = &pb.MyMessage{Count: Int32(7)}
var messageWithExtension1a = &pb.MyMessage{Count: Int32(7)}
var messageWithExtension1b = &pb.MyMessage{Count: Int32(7)}
var messageWithExtension2 = &pb.MyMessage{Count: Int32(7)}
// Two messages with non-message extensions.
var messageWithInt32Extension1 = &pb.MyMessage{Count: Int32(8)}
var messageWithInt32Extension2 = &pb.MyMessage{Count: Int32(8)}
func init() {
ext1 := &pb.Ext{Data: String("Kirk")}
ext2 := &pb.Ext{Data: String("Picard")}
// messageWithExtension1a has ext1, but never marshals it.
if err := SetExtension(messageWithExtension1a, pb.E_Ext_More, ext1); err != nil {
panic("SetExtension on 1a failed: " + err.Error())
}
// messageWithExtension1b is the unmarshaled form of messageWithExtension1a.
if err := SetExtension(messageWithExtension1b, pb.E_Ext_More, ext1); err != nil {
panic("SetExtension on 1b failed: " + err.Error())
}
buf, err := Marshal(messageWithExtension1b)
if err != nil {
panic("Marshal of 1b failed: " + err.Error())
}
messageWithExtension1b.Reset()
if err := Unmarshal(buf, messageWithExtension1b); err != nil {
panic("Unmarshal of 1b failed: " + err.Error())
}
// messageWithExtension2 has ext2.
if err := SetExtension(messageWithExtension2, pb.E_Ext_More, ext2); err != nil {
panic("SetExtension on 2 failed: " + err.Error())
}
if err := SetExtension(messageWithInt32Extension1, pb.E_Ext_Number, Int32(23)); err != nil {
panic("SetExtension on Int32-1 failed: " + err.Error())
}
if err := SetExtension(messageWithInt32Extension1, pb.E_Ext_Number, Int32(24)); err != nil {
panic("SetExtension on Int32-2 failed: " + err.Error())
}
}
var EqualTests = []struct {
desc string
a, b Message
exp bool
}{
{"different types", &pb.GoEnum{}, &pb.GoTestField{}, false},
{"equal empty", &pb.GoEnum{}, &pb.GoEnum{}, true},
{"nil vs nil", nil, nil, true},
{"typed nil vs typed nil", (*pb.GoEnum)(nil), (*pb.GoEnum)(nil), true},
{"typed nil vs empty", (*pb.GoEnum)(nil), &pb.GoEnum{}, false},
{"different typed nil", (*pb.GoEnum)(nil), (*pb.GoTestField)(nil), false},
{"one set field, one unset field", &pb.GoTestField{Label: String("foo")}, &pb.GoTestField{}, false},
{"one set field zero, one unset field", &pb.GoTest{Param: Int32(0)}, &pb.GoTest{}, false},
{"different set fields", &pb.GoTestField{Label: String("foo")}, &pb.GoTestField{Label: String("bar")}, false},
{"equal set", &pb.GoTestField{Label: String("foo")}, &pb.GoTestField{Label: String("foo")}, true},
{"repeated, one set", &pb.GoTest{F_Int32Repeated: []int32{2, 3}}, &pb.GoTest{}, false},
{"repeated, different length", &pb.GoTest{F_Int32Repeated: []int32{2, 3}}, &pb.GoTest{F_Int32Repeated: []int32{2}}, false},
{"repeated, different value", &pb.GoTest{F_Int32Repeated: []int32{2}}, &pb.GoTest{F_Int32Repeated: []int32{3}}, false},
{"repeated, equal", &pb.GoTest{F_Int32Repeated: []int32{2, 4}}, &pb.GoTest{F_Int32Repeated: []int32{2, 4}}, true},
{"repeated, nil equal nil", &pb.GoTest{F_Int32Repeated: nil}, &pb.GoTest{F_Int32Repeated: nil}, true},
{"repeated, nil equal empty", &pb.GoTest{F_Int32Repeated: nil}, &pb.GoTest{F_Int32Repeated: []int32{}}, true},
{"repeated, empty equal nil", &pb.GoTest{F_Int32Repeated: []int32{}}, &pb.GoTest{F_Int32Repeated: nil}, true},
{
"nested, different",
&pb.GoTest{RequiredField: &pb.GoTestField{Label: String("foo")}},
&pb.GoTest{RequiredField: &pb.GoTestField{Label: String("bar")}},
false,
},
{
"nested, equal",
&pb.GoTest{RequiredField: &pb.GoTestField{Label: String("wow")}},
&pb.GoTest{RequiredField: &pb.GoTestField{Label: String("wow")}},
true,
},
{"bytes", &pb.OtherMessage{Value: []byte("foo")}, &pb.OtherMessage{Value: []byte("foo")}, true},
{"bytes, empty", &pb.OtherMessage{Value: []byte{}}, &pb.OtherMessage{Value: []byte{}}, true},
{"bytes, empty vs nil", &pb.OtherMessage{Value: []byte{}}, &pb.OtherMessage{Value: nil}, false},
{
"repeated bytes",
&pb.MyMessage{RepBytes: [][]byte{[]byte("sham"), []byte("wow")}},
&pb.MyMessage{RepBytes: [][]byte{[]byte("sham"), []byte("wow")}},
true,
},
// In proto3, []byte{} and []byte(nil) are equal.
{"proto3 bytes, empty vs nil", &proto3pb.Message{Data: []byte{}}, &proto3pb.Message{Data: nil}, true},
{"extension vs. no extension", messageWithoutExtension, messageWithExtension1a, false},
{"extension vs. same extension", messageWithExtension1a, messageWithExtension1b, true},
{"extension vs. different extension", messageWithExtension1a, messageWithExtension2, false},
{"int32 extension vs. itself", messageWithInt32Extension1, messageWithInt32Extension1, true},
{"int32 extension vs. a different int32", messageWithInt32Extension1, messageWithInt32Extension2, false},
{
"message with group",
&pb.MyMessage{
Count: Int32(1),
Somegroup: &pb.MyMessage_SomeGroup{
GroupField: Int32(5),
},
},
&pb.MyMessage{
Count: Int32(1),
Somegroup: &pb.MyMessage_SomeGroup{
GroupField: Int32(5),
},
},
true,
},
{
"map same",
&pb.MessageWithMap{NameMapping: map[int32]string{1: "Ken"}},
&pb.MessageWithMap{NameMapping: map[int32]string{1: "Ken"}},
true,
},
{
"map different entry",
&pb.MessageWithMap{NameMapping: map[int32]string{1: "Ken"}},
&pb.MessageWithMap{NameMapping: map[int32]string{2: "Rob"}},
false,
},
{
"map different key only",
&pb.MessageWithMap{NameMapping: map[int32]string{1: "Ken"}},
&pb.MessageWithMap{NameMapping: map[int32]string{2: "Ken"}},
false,
},
{
"map different value only",
&pb.MessageWithMap{NameMapping: map[int32]string{1: "Ken"}},
&pb.MessageWithMap{NameMapping: map[int32]string{1: "Rob"}},
false,
},
{
"zero-length maps same",
&pb.MessageWithMap{NameMapping: map[int32]string{}},
&pb.MessageWithMap{NameMapping: nil},
true,
},
{
"orders in map don't matter",
&pb.MessageWithMap{NameMapping: map[int32]string{1: "Ken", 2: "Rob"}},
&pb.MessageWithMap{NameMapping: map[int32]string{2: "Rob", 1: "Ken"}},
true,
},
{
"oneof same",
&pb.Communique{Union: &pb.Communique_Number{Number: 41}},
&pb.Communique{Union: &pb.Communique_Number{Number: 41}},
true,
},
{
"oneof one nil",
&pb.Communique{Union: &pb.Communique_Number{Number: 41}},
&pb.Communique{},
false,
},
{
"oneof different",
&pb.Communique{Union: &pb.Communique_Number{Number: 41}},
&pb.Communique{Union: &pb.Communique_Name{Name: "Bobby Tables"}},
false,
},
}
func TestEqual(t *testing.T) {
for _, tc := range EqualTests {
if res := Equal(tc.a, tc.b); res != tc.exp {
t.Errorf("%v: Equal(%v, %v) = %v, want %v", tc.desc, tc.a, tc.b, res, tc.exp)
}
}
}
-538
View File
@@ -1,538 +0,0 @@
// Go support for Protocol Buffers - Google's data interchange format
//
// Copyright 2014 The Go Authors. All rights reserved.
// https://github.com/golang/protobuf
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package proto_test
import (
"bytes"
"fmt"
"reflect"
"sort"
"testing"
"github.com/gogo/protobuf/proto"
pb "github.com/gogo/protobuf/proto/testdata"
)
func TestGetExtensionsWithMissingExtensions(t *testing.T) {
msg := &pb.MyMessage{}
ext1 := &pb.Ext{}
if err := proto.SetExtension(msg, pb.E_Ext_More, ext1); err != nil {
t.Fatalf("Could not set ext1: %s", err)
}
exts, err := proto.GetExtensions(msg, []*proto.ExtensionDesc{
pb.E_Ext_More,
pb.E_Ext_Text,
})
if err != nil {
t.Fatalf("GetExtensions() failed: %s", err)
}
if exts[0] != ext1 {
t.Errorf("ext1 not in returned extensions: %T %v", exts[0], exts[0])
}
if exts[1] != nil {
t.Errorf("ext2 in returned extensions: %T %v", exts[1], exts[1])
}
}
func TestExtensionDescsWithMissingExtensions(t *testing.T) {
msg := &pb.MyMessage{Count: proto.Int32(0)}
extdesc1 := pb.E_Ext_More
if descs, err := proto.ExtensionDescs(msg); len(descs) != 0 || err != nil {
t.Errorf("proto.ExtensionDescs: got %d descs, error %v; want 0, nil", len(descs), err)
}
ext1 := &pb.Ext{}
if err := proto.SetExtension(msg, extdesc1, ext1); err != nil {
t.Fatalf("Could not set ext1: %s", err)
}
extdesc2 := &proto.ExtensionDesc{
ExtendedType: (*pb.MyMessage)(nil),
ExtensionType: (*bool)(nil),
Field: 123456789,
Name: "a.b",
Tag: "varint,123456789,opt",
}
ext2 := proto.Bool(false)
if err := proto.SetExtension(msg, extdesc2, ext2); err != nil {
t.Fatalf("Could not set ext2: %s", err)
}
b, err := proto.Marshal(msg)
if err != nil {
t.Fatalf("Could not marshal msg: %v", err)
}
if err = proto.Unmarshal(b, msg); err != nil {
t.Fatalf("Could not unmarshal into msg: %v", err)
}
descs, err := proto.ExtensionDescs(msg)
if err != nil {
t.Fatalf("proto.ExtensionDescs: got error %v", err)
}
sortExtDescs(descs)
wantDescs := []*proto.ExtensionDesc{extdesc1, {Field: extdesc2.Field}}
if !reflect.DeepEqual(descs, wantDescs) {
t.Errorf("proto.ExtensionDescs(msg) sorted extension ids: got %+v, want %+v", descs, wantDescs)
}
}
type ExtensionDescSlice []*proto.ExtensionDesc
func (s ExtensionDescSlice) Len() int { return len(s) }
func (s ExtensionDescSlice) Less(i, j int) bool { return s[i].Field < s[j].Field }
func (s ExtensionDescSlice) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
func sortExtDescs(s []*proto.ExtensionDesc) {
sort.Sort(ExtensionDescSlice(s))
}
func TestGetExtensionStability(t *testing.T) {
check := func(m *pb.MyMessage) bool {
ext1, err := proto.GetExtension(m, pb.E_Ext_More)
if err != nil {
t.Fatalf("GetExtension() failed: %s", err)
}
ext2, err := proto.GetExtension(m, pb.E_Ext_More)
if err != nil {
t.Fatalf("GetExtension() failed: %s", err)
}
return ext1 == ext2
}
msg := &pb.MyMessage{Count: proto.Int32(4)}
ext0 := &pb.Ext{}
if err := proto.SetExtension(msg, pb.E_Ext_More, ext0); err != nil {
t.Fatalf("Could not set ext1: %s", ext0)
}
if !check(msg) {
t.Errorf("GetExtension() not stable before marshaling")
}
bb, err := proto.Marshal(msg)
if err != nil {
t.Fatalf("Marshal() failed: %s", err)
}
msg1 := &pb.MyMessage{}
err = proto.Unmarshal(bb, msg1)
if err != nil {
t.Fatalf("Unmarshal() failed: %s", err)
}
if !check(msg1) {
t.Errorf("GetExtension() not stable after unmarshaling")
}
}
func TestGetExtensionDefaults(t *testing.T) {
var setFloat64 float64 = 1
var setFloat32 float32 = 2
var setInt32 int32 = 3
var setInt64 int64 = 4
var setUint32 uint32 = 5
var setUint64 uint64 = 6
var setBool = true
var setBool2 = false
var setString = "Goodnight string"
var setBytes = []byte("Goodnight bytes")
var setEnum = pb.DefaultsMessage_TWO
type testcase struct {
ext *proto.ExtensionDesc // Extension we are testing.
want interface{} // Expected value of extension, or nil (meaning that GetExtension will fail).
def interface{} // Expected value of extension after ClearExtension().
}
tests := []testcase{
{pb.E_NoDefaultDouble, setFloat64, nil},
{pb.E_NoDefaultFloat, setFloat32, nil},
{pb.E_NoDefaultInt32, setInt32, nil},
{pb.E_NoDefaultInt64, setInt64, nil},
{pb.E_NoDefaultUint32, setUint32, nil},
{pb.E_NoDefaultUint64, setUint64, nil},
{pb.E_NoDefaultSint32, setInt32, nil},
{pb.E_NoDefaultSint64, setInt64, nil},
{pb.E_NoDefaultFixed32, setUint32, nil},
{pb.E_NoDefaultFixed64, setUint64, nil},
{pb.E_NoDefaultSfixed32, setInt32, nil},
{pb.E_NoDefaultSfixed64, setInt64, nil},
{pb.E_NoDefaultBool, setBool, nil},
{pb.E_NoDefaultBool, setBool2, nil},
{pb.E_NoDefaultString, setString, nil},
{pb.E_NoDefaultBytes, setBytes, nil},
{pb.E_NoDefaultEnum, setEnum, nil},
{pb.E_DefaultDouble, setFloat64, float64(3.1415)},
{pb.E_DefaultFloat, setFloat32, float32(3.14)},
{pb.E_DefaultInt32, setInt32, int32(42)},
{pb.E_DefaultInt64, setInt64, int64(43)},
{pb.E_DefaultUint32, setUint32, uint32(44)},
{pb.E_DefaultUint64, setUint64, uint64(45)},
{pb.E_DefaultSint32, setInt32, int32(46)},
{pb.E_DefaultSint64, setInt64, int64(47)},
{pb.E_DefaultFixed32, setUint32, uint32(48)},
{pb.E_DefaultFixed64, setUint64, uint64(49)},
{pb.E_DefaultSfixed32, setInt32, int32(50)},
{pb.E_DefaultSfixed64, setInt64, int64(51)},
{pb.E_DefaultBool, setBool, true},
{pb.E_DefaultBool, setBool2, true},
{pb.E_DefaultString, setString, "Hello, string"},
{pb.E_DefaultBytes, setBytes, []byte("Hello, bytes")},
{pb.E_DefaultEnum, setEnum, pb.DefaultsMessage_ONE},
}
checkVal := func(test testcase, msg *pb.DefaultsMessage, valWant interface{}) error {
val, err := proto.GetExtension(msg, test.ext)
if err != nil {
if valWant != nil {
return fmt.Errorf("GetExtension(): %s", err)
}
if want := proto.ErrMissingExtension; err != want {
return fmt.Errorf("Unexpected error: got %v, want %v", err, want)
}
return nil
}
// All proto2 extension values are either a pointer to a value or a slice of values.
ty := reflect.TypeOf(val)
tyWant := reflect.TypeOf(test.ext.ExtensionType)
if got, want := ty, tyWant; got != want {
return fmt.Errorf("unexpected reflect.TypeOf(): got %v want %v", got, want)
}
tye := ty.Elem()
tyeWant := tyWant.Elem()
if got, want := tye, tyeWant; got != want {
return fmt.Errorf("unexpected reflect.TypeOf().Elem(): got %v want %v", got, want)
}
// Check the name of the type of the value.
// If it is an enum it will be type int32 with the name of the enum.
if got, want := tye.Name(), tye.Name(); got != want {
return fmt.Errorf("unexpected reflect.TypeOf().Elem().Name(): got %v want %v", got, want)
}
// Check that value is what we expect.
// If we have a pointer in val, get the value it points to.
valExp := val
if ty.Kind() == reflect.Ptr {
valExp = reflect.ValueOf(val).Elem().Interface()
}
if got, want := valExp, valWant; !reflect.DeepEqual(got, want) {
return fmt.Errorf("unexpected reflect.DeepEqual(): got %v want %v", got, want)
}
return nil
}
setTo := func(test testcase) interface{} {
setTo := reflect.ValueOf(test.want)
if typ := reflect.TypeOf(test.ext.ExtensionType); typ.Kind() == reflect.Ptr {
setTo = reflect.New(typ).Elem()
setTo.Set(reflect.New(setTo.Type().Elem()))
setTo.Elem().Set(reflect.ValueOf(test.want))
}
return setTo.Interface()
}
for _, test := range tests {
msg := &pb.DefaultsMessage{}
name := test.ext.Name
// Check the initial value.
if err := checkVal(test, msg, test.def); err != nil {
t.Errorf("%s: %v", name, err)
}
// Set the per-type value and check value.
name = fmt.Sprintf("%s (set to %T %v)", name, test.want, test.want)
if err := proto.SetExtension(msg, test.ext, setTo(test)); err != nil {
t.Errorf("%s: SetExtension(): %v", name, err)
continue
}
if err := checkVal(test, msg, test.want); err != nil {
t.Errorf("%s: %v", name, err)
continue
}
// Set and check the value.
name += " (cleared)"
proto.ClearExtension(msg, test.ext)
if err := checkVal(test, msg, test.def); err != nil {
t.Errorf("%s: %v", name, err)
}
}
}
func TestExtensionsRoundTrip(t *testing.T) {
msg := &pb.MyMessage{}
ext1 := &pb.Ext{
Data: proto.String("hi"),
}
ext2 := &pb.Ext{
Data: proto.String("there"),
}
exists := proto.HasExtension(msg, pb.E_Ext_More)
if exists {
t.Error("Extension More present unexpectedly")
}
if err := proto.SetExtension(msg, pb.E_Ext_More, ext1); err != nil {
t.Error(err)
}
if err := proto.SetExtension(msg, pb.E_Ext_More, ext2); err != nil {
t.Error(err)
}
e, err := proto.GetExtension(msg, pb.E_Ext_More)
if err != nil {
t.Error(err)
}
x, ok := e.(*pb.Ext)
if !ok {
t.Errorf("e has type %T, expected testdata.Ext", e)
} else if *x.Data != "there" {
t.Errorf("SetExtension failed to overwrite, got %+v, not 'there'", x)
}
proto.ClearExtension(msg, pb.E_Ext_More)
if _, err = proto.GetExtension(msg, pb.E_Ext_More); err != proto.ErrMissingExtension {
t.Errorf("got %v, expected ErrMissingExtension", e)
}
if _, err := proto.GetExtension(msg, pb.E_X215); err == nil {
t.Error("expected bad extension error, got nil")
}
if err := proto.SetExtension(msg, pb.E_X215, 12); err == nil {
t.Error("expected extension err")
}
if err := proto.SetExtension(msg, pb.E_Ext_More, 12); err == nil {
t.Error("expected some sort of type mismatch error, got nil")
}
}
func TestNilExtension(t *testing.T) {
msg := &pb.MyMessage{
Count: proto.Int32(1),
}
if err := proto.SetExtension(msg, pb.E_Ext_Text, proto.String("hello")); err != nil {
t.Fatal(err)
}
if err := proto.SetExtension(msg, pb.E_Ext_More, (*pb.Ext)(nil)); err == nil {
t.Error("expected SetExtension to fail due to a nil extension")
} else if want := "proto: SetExtension called with nil value of type *testdata.Ext"; err.Error() != want {
t.Errorf("expected error %v, got %v", want, err)
}
// Note: if the behavior of Marshal is ever changed to ignore nil extensions, update
// this test to verify that E_Ext_Text is properly propagated through marshal->unmarshal.
}
func TestMarshalUnmarshalRepeatedExtension(t *testing.T) {
// Add a repeated extension to the result.
tests := []struct {
name string
ext []*pb.ComplexExtension
}{
{
"two fields",
[]*pb.ComplexExtension{
{First: proto.Int32(7)},
{Second: proto.Int32(11)},
},
},
{
"repeated field",
[]*pb.ComplexExtension{
{Third: []int32{1000}},
{Third: []int32{2000}},
},
},
{
"two fields and repeated field",
[]*pb.ComplexExtension{
{Third: []int32{1000}},
{First: proto.Int32(9)},
{Second: proto.Int32(21)},
{Third: []int32{2000}},
},
},
}
for _, test := range tests {
// Marshal message with a repeated extension.
msg1 := new(pb.OtherMessage)
err := proto.SetExtension(msg1, pb.E_RComplex, test.ext)
if err != nil {
t.Fatalf("[%s] Error setting extension: %v", test.name, err)
}
b, err := proto.Marshal(msg1)
if err != nil {
t.Fatalf("[%s] Error marshaling message: %v", test.name, err)
}
// Unmarshal and read the merged proto.
msg2 := new(pb.OtherMessage)
err = proto.Unmarshal(b, msg2)
if err != nil {
t.Fatalf("[%s] Error unmarshaling message: %v", test.name, err)
}
e, err := proto.GetExtension(msg2, pb.E_RComplex)
if err != nil {
t.Fatalf("[%s] Error getting extension: %v", test.name, err)
}
ext := e.([]*pb.ComplexExtension)
if ext == nil {
t.Fatalf("[%s] Invalid extension", test.name)
}
if !reflect.DeepEqual(ext, test.ext) {
t.Errorf("[%s] Wrong value for ComplexExtension: got: %v want: %v\n", test.name, ext, test.ext)
}
}
}
func TestUnmarshalRepeatingNonRepeatedExtension(t *testing.T) {
// We may see multiple instances of the same extension in the wire
// format. For example, the proto compiler may encode custom options in
// this way. Here, we verify that we merge the extensions together.
tests := []struct {
name string
ext []*pb.ComplexExtension
}{
{
"two fields",
[]*pb.ComplexExtension{
{First: proto.Int32(7)},
{Second: proto.Int32(11)},
},
},
{
"repeated field",
[]*pb.ComplexExtension{
{Third: []int32{1000}},
{Third: []int32{2000}},
},
},
{
"two fields and repeated field",
[]*pb.ComplexExtension{
{Third: []int32{1000}},
{First: proto.Int32(9)},
{Second: proto.Int32(21)},
{Third: []int32{2000}},
},
},
}
for _, test := range tests {
var buf bytes.Buffer
var want pb.ComplexExtension
// Generate a serialized representation of a repeated extension
// by catenating bytes together.
for i, e := range test.ext {
// Merge to create the wanted proto.
proto.Merge(&want, e)
// serialize the message
msg := new(pb.OtherMessage)
err := proto.SetExtension(msg, pb.E_Complex, e)
if err != nil {
t.Fatalf("[%s] Error setting extension %d: %v", test.name, i, err)
}
b, err := proto.Marshal(msg)
if err != nil {
t.Fatalf("[%s] Error marshaling message %d: %v", test.name, i, err)
}
buf.Write(b)
}
// Unmarshal and read the merged proto.
msg2 := new(pb.OtherMessage)
err := proto.Unmarshal(buf.Bytes(), msg2)
if err != nil {
t.Fatalf("[%s] Error unmarshaling message: %v", test.name, err)
}
e, err := proto.GetExtension(msg2, pb.E_Complex)
if err != nil {
t.Fatalf("[%s] Error getting extension: %v", test.name, err)
}
ext := e.(*pb.ComplexExtension)
if ext == nil {
t.Fatalf("[%s] Invalid extension", test.name)
}
if !reflect.DeepEqual(*ext, want) {
t.Errorf("[%s] Wrong value for ComplexExtension: got: %v want: %v\n", test.name, ext, want)
}
}
}
func TestClearAllExtensions(t *testing.T) {
// unregistered extension
desc := &proto.ExtensionDesc{
ExtendedType: (*pb.MyMessage)(nil),
ExtensionType: (*bool)(nil),
Field: 101010100,
Name: "emptyextension",
Tag: "varint,0,opt",
}
m := &pb.MyMessage{}
if proto.HasExtension(m, desc) {
t.Errorf("proto.HasExtension(%s): got true, want false", proto.MarshalTextString(m))
}
if err := proto.SetExtension(m, desc, proto.Bool(true)); err != nil {
t.Errorf("proto.SetExtension(m, desc, true): got error %q, want nil", err)
}
if !proto.HasExtension(m, desc) {
t.Errorf("proto.HasExtension(%s): got false, want true", proto.MarshalTextString(m))
}
proto.ClearAllExtensions(m)
if proto.HasExtension(m, desc) {
t.Errorf("proto.HasExtension(%s): got true, want false", proto.MarshalTextString(m))
}
}
func TestMarshalRace(t *testing.T) {
// unregistered extension
desc := &proto.ExtensionDesc{
ExtendedType: (*pb.MyMessage)(nil),
ExtensionType: (*bool)(nil),
Field: 101010100,
Name: "emptyextension",
Tag: "varint,0,opt",
}
m := &pb.MyMessage{Count: proto.Int32(4)}
if err := proto.SetExtension(m, desc, proto.Bool(true)); err != nil {
t.Errorf("proto.SetExtension(m, desc, true): got error %q, want nil", err)
}
errChan := make(chan error, 3)
for n := 3; n > 0; n-- {
go func() {
_, err := proto.Marshal(m)
errChan <- err
}()
}
for i := 0; i < 3; i++ {
err := <-errChan
if err != nil {
t.Fatal(err)
}
}
}
-1
View File
@@ -73,7 +73,6 @@ for a protocol buffer variable v:
When the .proto file specifies `syntax="proto3"`, there are some differences:
- Non-repeated fields of non-message type are values instead of pointers.
- Getters are only generated for message and oneof fields.
- Enum types do not get an Enum method.
The simplest way to describe this is to see an example.
-46
View File
@@ -1,46 +0,0 @@
package proto_test
import (
"fmt"
"testing"
"github.com/gogo/protobuf/proto"
ppb "github.com/gogo/protobuf/proto/proto3_proto"
)
func marshalled() []byte {
m := &ppb.IntMaps{}
for i := 0; i < 1000; i++ {
m.Maps = append(m.Maps, &ppb.IntMap{
Rtt: map[int32]int32{1: 2},
})
}
b, err := proto.Marshal(m)
if err != nil {
panic(fmt.Sprintf("Can't marshal %+v: %v", m, err))
}
return b
}
func BenchmarkConcurrentMapUnmarshal(b *testing.B) {
in := marshalled()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
var out ppb.IntMaps
if err := proto.Unmarshal(in, &out); err != nil {
b.Errorf("Can't unmarshal ppb.IntMaps: %v", err)
}
}
})
}
func BenchmarkSequentialMapUnmarshal(b *testing.B) {
in := marshalled()
b.ResetTimer()
for i := 0; i < b.N; i++ {
var out ppb.IntMaps
if err := proto.Unmarshal(in, &out); err != nil {
b.Errorf("Can't unmarshal ppb.IntMaps: %v", err)
}
}
}
-66
View File
@@ -1,66 +0,0 @@
// Go support for Protocol Buffers - Google's data interchange format
//
// Copyright 2014 The Go Authors. All rights reserved.
// https://github.com/golang/protobuf
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package proto
import (
"bytes"
"testing"
)
func TestUnmarshalMessageSetWithDuplicate(t *testing.T) {
// Check that a repeated message set entry will be concatenated.
in := &messageSet{
Item: []*_MessageSet_Item{
{TypeId: Int32(12345), Message: []byte("hoo")},
{TypeId: Int32(12345), Message: []byte("hah")},
},
}
b, err := Marshal(in)
if err != nil {
t.Fatalf("Marshal: %v", err)
}
t.Logf("Marshaled bytes: %q", b)
var extensions XXX_InternalExtensions
if err := UnmarshalMessageSet(b, &extensions); err != nil {
t.Fatalf("UnmarshalMessageSet: %v", err)
}
ext, ok := extensions.p.extensionMap[12345]
if !ok {
t.Fatalf("Didn't retrieve extension 12345; map is %v", extensions.p.extensionMap)
}
// Skip wire type/field number and length varints.
got := skipVarint(skipVarint(ext.enc))
if want := []byte("hoohah"); !bytes.Equal(got, want) {
t.Errorf("Combined extension is %q, want %q", got, want)
}
}
+3
View File
@@ -193,6 +193,7 @@ type Properties struct {
Default string // default value
HasDefault bool // whether an explicit default was provided
CustomType string
CastType string
StdTime bool
StdDuration bool
@@ -341,6 +342,8 @@ func (p *Properties) Parse(s string) {
p.OrigName = strings.Split(f, "=")[1]
case strings.HasPrefix(f, "customtype="):
p.CustomType = strings.Split(f, "=")[1]
case strings.HasPrefix(f, "casttype="):
p.CastType = strings.Split(f, "=")[1]
case f == "stdtime":
p.StdTime = true
case f == "stdduration":
-87
View File
@@ -1,87 +0,0 @@
// Go support for Protocol Buffers - Google's data interchange format
//
// Copyright 2014 The Go Authors. All rights reserved.
// https://github.com/golang/protobuf
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
syntax = "proto3";
import "google/protobuf/any.proto";
import "testdata/test.proto";
package proto3_proto;
message Message {
enum Humour {
UNKNOWN = 0;
PUNS = 1;
SLAPSTICK = 2;
BILL_BAILEY = 3;
}
string name = 1;
Humour hilarity = 2;
uint32 height_in_cm = 3;
bytes data = 4;
int64 result_count = 7;
bool true_scotsman = 8;
float score = 9;
repeated uint64 key = 5;
repeated int32 short_key = 19;
Nested nested = 6;
repeated Humour r_funny = 16;
map<string, Nested> terrain = 10;
testdata.SubDefaults proto2_field = 11;
map<string, testdata.SubDefaults> proto2_value = 13;
google.protobuf.Any anything = 14;
repeated google.protobuf.Any many_things = 15;
Message submessage = 17;
repeated Message children = 18;
}
message Nested {
string bunny = 1;
bool cute = 2;
}
message MessageWithMap {
map<bool, bytes> byte_mapping = 1;
}
message IntMap {
map<int32, int32> rtt = 1;
}
message IntMaps {
repeated IntMap maps = 1;
}
-135
View File
@@ -1,135 +0,0 @@
// Go support for Protocol Buffers - Google's data interchange format
//
// Copyright 2014 The Go Authors. All rights reserved.
// https://github.com/golang/protobuf
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package proto_test
import (
"testing"
"github.com/gogo/protobuf/proto"
pb "github.com/gogo/protobuf/proto/proto3_proto"
tpb "github.com/gogo/protobuf/proto/testdata"
)
func TestProto3ZeroValues(t *testing.T) {
tests := []struct {
desc string
m proto.Message
}{
{"zero message", &pb.Message{}},
{"empty bytes field", &pb.Message{Data: []byte{}}},
}
for _, test := range tests {
b, err := proto.Marshal(test.m)
if err != nil {
t.Errorf("%s: proto.Marshal: %v", test.desc, err)
continue
}
if len(b) > 0 {
t.Errorf("%s: Encoding is non-empty: %q", test.desc, b)
}
}
}
func TestRoundTripProto3(t *testing.T) {
m := &pb.Message{
Name: "David", // (2 | 1<<3): 0x0a 0x05 "David"
Hilarity: pb.Message_PUNS, // (0 | 2<<3): 0x10 0x01
HeightInCm: 178, // (0 | 3<<3): 0x18 0xb2 0x01
Data: []byte("roboto"), // (2 | 4<<3): 0x20 0x06 "roboto"
ResultCount: 47, // (0 | 7<<3): 0x38 0x2f
TrueScotsman: true, // (0 | 8<<3): 0x40 0x01
Score: 8.1, // (5 | 9<<3): 0x4d <8.1>
Key: []uint64{1, 0xdeadbeef},
Nested: &pb.Nested{
Bunny: "Monty",
},
}
t.Logf(" m: %v", m)
b, err := proto.Marshal(m)
if err != nil {
t.Fatalf("proto.Marshal: %v", err)
}
t.Logf(" b: %q", b)
m2 := new(pb.Message)
if err := proto.Unmarshal(b, m2); err != nil {
t.Fatalf("proto.Unmarshal: %v", err)
}
t.Logf("m2: %v", m2)
if !proto.Equal(m, m2) {
t.Errorf("proto.Equal returned false:\n m: %v\nm2: %v", m, m2)
}
}
func TestGettersForBasicTypesExist(t *testing.T) {
var m pb.Message
if got := m.GetNested().GetBunny(); got != "" {
t.Errorf("m.GetNested().GetBunny() = %q, want empty string", got)
}
if got := m.GetNested().GetCute(); got {
t.Errorf("m.GetNested().GetCute() = %t, want false", got)
}
}
func TestProto3SetDefaults(t *testing.T) {
in := &pb.Message{
Terrain: map[string]*pb.Nested{
"meadow": new(pb.Nested),
},
Proto2Field: new(tpb.SubDefaults),
Proto2Value: map[string]*tpb.SubDefaults{
"badlands": new(tpb.SubDefaults),
},
}
got := proto.Clone(in).(*pb.Message)
proto.SetDefaults(got)
// There are no defaults in proto3. Everything should be the zero value, but
// we need to remember to set defaults for nested proto2 messages.
want := &pb.Message{
Terrain: map[string]*pb.Nested{
"meadow": new(pb.Nested),
},
Proto2Field: &tpb.SubDefaults{N: proto.Int64(7)},
Proto2Value: map[string]*tpb.SubDefaults{
"badlands": {N: proto.Int64(7)},
},
}
if !proto.Equal(got, want) {
t.Errorf("with in = %v\nproto.SetDefaults(in) =>\ngot %v\nwant %v", in, got, want)
}
}
-63
View File
@@ -1,63 +0,0 @@
// Go support for Protocol Buffers - Google's data interchange format
//
// Copyright 2012 The Go Authors. All rights reserved.
// https://github.com/golang/protobuf
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package proto
import (
"testing"
)
// This is a separate file and package from size_test.go because that one uses
// generated messages and thus may not be in package proto without having a circular
// dependency, whereas this file tests unexported details of size.go.
func TestVarintSize(t *testing.T) {
// Check the edge cases carefully.
testCases := []struct {
n uint64
size int
}{
{0, 1},
{1, 1},
{127, 1},
{128, 2},
{16383, 2},
{16384, 3},
{1<<63 - 1, 9},
{1 << 63, 10},
}
for _, tc := range testCases {
size := sizeVarint(tc.n)
if size != tc.size {
t.Errorf("sizeVarint(%d) = %d, want %d", tc.n, size, tc.size)
}
}
}
-164
View File
@@ -1,164 +0,0 @@
// Go support for Protocol Buffers - Google's data interchange format
//
// Copyright 2012 The Go Authors. All rights reserved.
// https://github.com/golang/protobuf
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package proto_test
import (
"log"
"strings"
"testing"
. "github.com/gogo/protobuf/proto"
proto3pb "github.com/gogo/protobuf/proto/proto3_proto"
pb "github.com/gogo/protobuf/proto/testdata"
)
var messageWithExtension1 = &pb.MyMessage{Count: Int32(7)}
// messageWithExtension2 is in equal_test.go.
var messageWithExtension3 = &pb.MyMessage{Count: Int32(8)}
func init() {
if err := SetExtension(messageWithExtension1, pb.E_Ext_More, &pb.Ext{Data: String("Abbott")}); err != nil {
log.Panicf("SetExtension: %v", err)
}
if err := SetExtension(messageWithExtension3, pb.E_Ext_More, &pb.Ext{Data: String("Costello")}); err != nil {
log.Panicf("SetExtension: %v", err)
}
// Force messageWithExtension3 to have the extension encoded.
Marshal(messageWithExtension3)
}
var SizeTests = []struct {
desc string
pb Message
}{
{"empty", &pb.OtherMessage{}},
// Basic types.
{"bool", &pb.Defaults{F_Bool: Bool(true)}},
{"int32", &pb.Defaults{F_Int32: Int32(12)}},
{"negative int32", &pb.Defaults{F_Int32: Int32(-1)}},
{"small int64", &pb.Defaults{F_Int64: Int64(1)}},
{"big int64", &pb.Defaults{F_Int64: Int64(1 << 20)}},
{"negative int64", &pb.Defaults{F_Int64: Int64(-1)}},
{"fixed32", &pb.Defaults{F_Fixed32: Uint32(71)}},
{"fixed64", &pb.Defaults{F_Fixed64: Uint64(72)}},
{"uint32", &pb.Defaults{F_Uint32: Uint32(123)}},
{"uint64", &pb.Defaults{F_Uint64: Uint64(124)}},
{"float", &pb.Defaults{F_Float: Float32(12.6)}},
{"double", &pb.Defaults{F_Double: Float64(13.9)}},
{"string", &pb.Defaults{F_String: String("niles")}},
{"bytes", &pb.Defaults{F_Bytes: []byte("wowsa")}},
{"bytes, empty", &pb.Defaults{F_Bytes: []byte{}}},
{"sint32", &pb.Defaults{F_Sint32: Int32(65)}},
{"sint64", &pb.Defaults{F_Sint64: Int64(67)}},
{"enum", &pb.Defaults{F_Enum: pb.Defaults_BLUE.Enum()}},
// Repeated.
{"empty repeated bool", &pb.MoreRepeated{Bools: []bool{}}},
{"repeated bool", &pb.MoreRepeated{Bools: []bool{false, true, true, false}}},
{"packed repeated bool", &pb.MoreRepeated{BoolsPacked: []bool{false, true, true, false, true, true, true}}},
{"repeated int32", &pb.MoreRepeated{Ints: []int32{1, 12203, 1729, -1}}},
{"repeated int32 packed", &pb.MoreRepeated{IntsPacked: []int32{1, 12203, 1729}}},
{"repeated int64 packed", &pb.MoreRepeated{Int64SPacked: []int64{
// Need enough large numbers to verify that the header is counting the number of bytes
// for the field, not the number of elements.
1 << 62, 1 << 62, 1 << 62, 1 << 62, 1 << 62, 1 << 62, 1 << 62, 1 << 62, 1 << 62, 1 << 62,
1 << 62, 1 << 62, 1 << 62, 1 << 62, 1 << 62, 1 << 62, 1 << 62, 1 << 62, 1 << 62, 1 << 62,
}}},
{"repeated string", &pb.MoreRepeated{Strings: []string{"r", "ken", "gri"}}},
{"repeated fixed", &pb.MoreRepeated{Fixeds: []uint32{1, 2, 3, 4}}},
// Nested.
{"nested", &pb.OldMessage{Nested: &pb.OldMessage_Nested{Name: String("whatever")}}},
{"group", &pb.GroupOld{G: &pb.GroupOld_G{X: Int32(12345)}}},
// Other things.
{"unrecognized", &pb.MoreRepeated{XXX_unrecognized: []byte{13<<3 | 0, 4}}},
{"extension (unencoded)", messageWithExtension1},
{"extension (encoded)", messageWithExtension3},
// proto3 message
{"proto3 empty", &proto3pb.Message{}},
{"proto3 bool", &proto3pb.Message{TrueScotsman: true}},
{"proto3 int64", &proto3pb.Message{ResultCount: 1}},
{"proto3 uint32", &proto3pb.Message{HeightInCm: 123}},
{"proto3 float", &proto3pb.Message{Score: 12.6}},
{"proto3 string", &proto3pb.Message{Name: "Snezana"}},
{"proto3 bytes", &proto3pb.Message{Data: []byte("wowsa")}},
{"proto3 bytes, empty", &proto3pb.Message{Data: []byte{}}},
{"proto3 enum", &proto3pb.Message{Hilarity: proto3pb.Message_PUNS}},
{"proto3 map field with empty bytes", &proto3pb.MessageWithMap{ByteMapping: map[bool][]byte{false: {}}}},
{"map field", &pb.MessageWithMap{NameMapping: map[int32]string{1: "Rob", 7: "Andrew"}}},
{"map field with message", &pb.MessageWithMap{MsgMapping: map[int64]*pb.FloatingPoint{0x7001: {F: Float64(2.0)}}}},
{"map field with bytes", &pb.MessageWithMap{ByteMapping: map[bool][]byte{true: []byte("this time for sure")}}},
{"map field with empty bytes", &pb.MessageWithMap{ByteMapping: map[bool][]byte{true: {}}}},
{"map field with big entry", &pb.MessageWithMap{NameMapping: map[int32]string{8: strings.Repeat("x", 125)}}},
{"map field with big key and val", &pb.MessageWithMap{StrToStr: map[string]string{strings.Repeat("x", 70): strings.Repeat("y", 70)}}},
{"map field with big numeric key", &pb.MessageWithMap{NameMapping: map[int32]string{0xf00d: "om nom nom"}}},
{"oneof not set", &pb.Oneof{}},
{"oneof bool", &pb.Oneof{Union: &pb.Oneof_F_Bool{F_Bool: true}}},
{"oneof zero int32", &pb.Oneof{Union: &pb.Oneof_F_Int32{F_Int32: 0}}},
{"oneof big int32", &pb.Oneof{Union: &pb.Oneof_F_Int32{F_Int32: 1 << 20}}},
{"oneof int64", &pb.Oneof{Union: &pb.Oneof_F_Int64{F_Int64: 42}}},
{"oneof fixed32", &pb.Oneof{Union: &pb.Oneof_F_Fixed32{F_Fixed32: 43}}},
{"oneof fixed64", &pb.Oneof{Union: &pb.Oneof_F_Fixed64{F_Fixed64: 44}}},
{"oneof uint32", &pb.Oneof{Union: &pb.Oneof_F_Uint32{F_Uint32: 45}}},
{"oneof uint64", &pb.Oneof{Union: &pb.Oneof_F_Uint64{F_Uint64: 46}}},
{"oneof float", &pb.Oneof{Union: &pb.Oneof_F_Float{F_Float: 47.1}}},
{"oneof double", &pb.Oneof{Union: &pb.Oneof_F_Double{F_Double: 48.9}}},
{"oneof string", &pb.Oneof{Union: &pb.Oneof_F_String{F_String: "Rhythmic Fman"}}},
{"oneof bytes", &pb.Oneof{Union: &pb.Oneof_F_Bytes{F_Bytes: []byte("let go")}}},
{"oneof sint32", &pb.Oneof{Union: &pb.Oneof_F_Sint32{F_Sint32: 50}}},
{"oneof sint64", &pb.Oneof{Union: &pb.Oneof_F_Sint64{F_Sint64: 51}}},
{"oneof enum", &pb.Oneof{Union: &pb.Oneof_F_Enum{F_Enum: pb.MyMessage_BLUE}}},
{"message for oneof", &pb.GoTestField{Label: String("k"), Type: String("v")}},
{"oneof message", &pb.Oneof{Union: &pb.Oneof_F_Message{F_Message: &pb.GoTestField{Label: String("k"), Type: String("v")}}}},
{"oneof group", &pb.Oneof{Union: &pb.Oneof_FGroup{FGroup: &pb.Oneof_F_Group{X: Int32(52)}}}},
{"oneof largest tag", &pb.Oneof{Union: &pb.Oneof_F_Largest_Tag{F_Largest_Tag: 1}}},
{"multiple oneofs", &pb.Oneof{Union: &pb.Oneof_F_Int32{F_Int32: 1}, Tormato: &pb.Oneof_Value{Value: 2}}},
}
func TestSize(t *testing.T) {
for _, tc := range SizeTests {
size := Size(tc.pb)
b, err := Marshal(tc.pb)
if err != nil {
t.Errorf("%v: Marshal failed: %v", tc.desc, err)
continue
}
if size != len(b) {
t.Errorf("%v: Size(%v) = %d, want %d", tc.desc, tc.pb, size, len(b))
t.Logf("%v: bytes: %#v", tc.desc, b)
}
}
}
-37
View File
@@ -1,37 +0,0 @@
# Go support for Protocol Buffers - Google's data interchange format
#
# Copyright 2010 The Go Authors. All rights reserved.
# https://github.com/golang/protobuf
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following disclaimer
# in the documentation and/or other materials provided with the
# distribution.
# * Neither the name of Google Inc. nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
all: regenerate
regenerate:
go install github.com/gogo/protobuf/protoc-min-version
protoc-min-version --version="3.0.0" --gogo_out=. test.proto
-86
View File
@@ -1,86 +0,0 @@
// Go support for Protocol Buffers - Google's data interchange format
//
// Copyright 2012 The Go Authors. All rights reserved.
// https://github.com/golang/protobuf
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Verify that the compiler output for test.proto is unchanged.
package testdata
import (
"crypto/sha1"
"fmt"
"io/ioutil"
"os"
"os/exec"
"path/filepath"
"testing"
)
// sum returns in string form (for easy comparison) the SHA-1 hash of the named file.
func sum(t *testing.T, name string) string {
data, err := ioutil.ReadFile(name)
if err != nil {
t.Fatal(err)
}
t.Logf("sum(%q): length is %d", name, len(data))
hash := sha1.New()
_, err = hash.Write(data)
if err != nil {
t.Fatal(err)
}
return fmt.Sprintf("% x", hash.Sum(nil))
}
func run(t *testing.T, name string, args ...string) {
cmd := exec.Command(name, args...)
cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
err := cmd.Run()
if err != nil {
t.Fatal(err)
}
}
func TestGolden(t *testing.T) {
// Compute the original checksum.
goldenSum := sum(t, "test.pb.go")
// Run the proto compiler.
run(t, "protoc", "--gogo_out="+os.TempDir(), "test.proto")
newFile := filepath.Join(os.TempDir(), "test.pb.go")
defer os.Remove(newFile)
// Compute the new checksum.
newSum := sum(t, newFile)
// Verify
if newSum != goldenSum {
run(t, "diff", "-u", "test.pb.go", newFile)
t.Fatal("Code generated by protoc-gen-go has changed; update test.pb.go")
}
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
-548
View File
@@ -1,548 +0,0 @@
// Go support for Protocol Buffers - Google's data interchange format
//
// Copyright 2010 The Go Authors. All rights reserved.
// https://github.com/golang/protobuf
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// A feature-rich test file for the protocol compiler and libraries.
syntax = "proto2";
package testdata;
enum FOO { FOO1 = 1; };
message GoEnum {
required FOO foo = 1;
}
message GoTestField {
required string Label = 1;
required string Type = 2;
}
message GoTest {
// An enum, for completeness.
enum KIND {
VOID = 0;
// Basic types
BOOL = 1;
BYTES = 2;
FINGERPRINT = 3;
FLOAT = 4;
INT = 5;
STRING = 6;
TIME = 7;
// Groupings
TUPLE = 8;
ARRAY = 9;
MAP = 10;
// Table types
TABLE = 11;
// Functions
FUNCTION = 12; // last tag
};
// Some typical parameters
required KIND Kind = 1;
optional string Table = 2;
optional int32 Param = 3;
// Required, repeated and optional foreign fields.
required GoTestField RequiredField = 4;
repeated GoTestField RepeatedField = 5;
optional GoTestField OptionalField = 6;
// Required fields of all basic types
required bool F_Bool_required = 10;
required int32 F_Int32_required = 11;
required int64 F_Int64_required = 12;
required fixed32 F_Fixed32_required = 13;
required fixed64 F_Fixed64_required = 14;
required uint32 F_Uint32_required = 15;
required uint64 F_Uint64_required = 16;
required float F_Float_required = 17;
required double F_Double_required = 18;
required string F_String_required = 19;
required bytes F_Bytes_required = 101;
required sint32 F_Sint32_required = 102;
required sint64 F_Sint64_required = 103;
// Repeated fields of all basic types
repeated bool F_Bool_repeated = 20;
repeated int32 F_Int32_repeated = 21;
repeated int64 F_Int64_repeated = 22;
repeated fixed32 F_Fixed32_repeated = 23;
repeated fixed64 F_Fixed64_repeated = 24;
repeated uint32 F_Uint32_repeated = 25;
repeated uint64 F_Uint64_repeated = 26;
repeated float F_Float_repeated = 27;
repeated double F_Double_repeated = 28;
repeated string F_String_repeated = 29;
repeated bytes F_Bytes_repeated = 201;
repeated sint32 F_Sint32_repeated = 202;
repeated sint64 F_Sint64_repeated = 203;
// Optional fields of all basic types
optional bool F_Bool_optional = 30;
optional int32 F_Int32_optional = 31;
optional int64 F_Int64_optional = 32;
optional fixed32 F_Fixed32_optional = 33;
optional fixed64 F_Fixed64_optional = 34;
optional uint32 F_Uint32_optional = 35;
optional uint64 F_Uint64_optional = 36;
optional float F_Float_optional = 37;
optional double F_Double_optional = 38;
optional string F_String_optional = 39;
optional bytes F_Bytes_optional = 301;
optional sint32 F_Sint32_optional = 302;
optional sint64 F_Sint64_optional = 303;
// Default-valued fields of all basic types
optional bool F_Bool_defaulted = 40 [default=true];
optional int32 F_Int32_defaulted = 41 [default=32];
optional int64 F_Int64_defaulted = 42 [default=64];
optional fixed32 F_Fixed32_defaulted = 43 [default=320];
optional fixed64 F_Fixed64_defaulted = 44 [default=640];
optional uint32 F_Uint32_defaulted = 45 [default=3200];
optional uint64 F_Uint64_defaulted = 46 [default=6400];
optional float F_Float_defaulted = 47 [default=314159.];
optional double F_Double_defaulted = 48 [default=271828.];
optional string F_String_defaulted = 49 [default="hello, \"world!\"\n"];
optional bytes F_Bytes_defaulted = 401 [default="Bignose"];
optional sint32 F_Sint32_defaulted = 402 [default = -32];
optional sint64 F_Sint64_defaulted = 403 [default = -64];
// Packed repeated fields (no string or bytes).
repeated bool F_Bool_repeated_packed = 50 [packed=true];
repeated int32 F_Int32_repeated_packed = 51 [packed=true];
repeated int64 F_Int64_repeated_packed = 52 [packed=true];
repeated fixed32 F_Fixed32_repeated_packed = 53 [packed=true];
repeated fixed64 F_Fixed64_repeated_packed = 54 [packed=true];
repeated uint32 F_Uint32_repeated_packed = 55 [packed=true];
repeated uint64 F_Uint64_repeated_packed = 56 [packed=true];
repeated float F_Float_repeated_packed = 57 [packed=true];
repeated double F_Double_repeated_packed = 58 [packed=true];
repeated sint32 F_Sint32_repeated_packed = 502 [packed=true];
repeated sint64 F_Sint64_repeated_packed = 503 [packed=true];
// Required, repeated, and optional groups.
required group RequiredGroup = 70 {
required string RequiredField = 71;
};
repeated group RepeatedGroup = 80 {
required string RequiredField = 81;
};
optional group OptionalGroup = 90 {
required string RequiredField = 91;
};
}
// For testing a group containing a required field.
message GoTestRequiredGroupField {
required group Group = 1 {
required int32 Field = 2;
};
}
// For testing skipping of unrecognized fields.
// Numbers are all big, larger than tag numbers in GoTestField,
// the message used in the corresponding test.
message GoSkipTest {
required int32 skip_int32 = 11;
required fixed32 skip_fixed32 = 12;
required fixed64 skip_fixed64 = 13;
required string skip_string = 14;
required group SkipGroup = 15 {
required int32 group_int32 = 16;
required string group_string = 17;
}
}
// For testing packed/non-packed decoder switching.
// A serialized instance of one should be deserializable as the other.
message NonPackedTest {
repeated int32 a = 1;
}
message PackedTest {
repeated int32 b = 1 [packed=true];
}
message MaxTag {
// Maximum possible tag number.
optional string last_field = 536870911;
}
message OldMessage {
message Nested {
optional string name = 1;
}
optional Nested nested = 1;
optional int32 num = 2;
}
// NewMessage is wire compatible with OldMessage;
// imagine it as a future version.
message NewMessage {
message Nested {
optional string name = 1;
optional string food_group = 2;
}
optional Nested nested = 1;
// This is an int32 in OldMessage.
optional int64 num = 2;
}
// Smaller tests for ASCII formatting.
message InnerMessage {
required string host = 1;
optional int32 port = 2 [default=4000];
optional bool connected = 3;
}
message OtherMessage {
optional int64 key = 1;
optional bytes value = 2;
optional float weight = 3;
optional InnerMessage inner = 4;
extensions 100 to max;
}
message RequiredInnerMessage {
required InnerMessage leo_finally_won_an_oscar = 1;
}
message MyMessage {
required int32 count = 1;
optional string name = 2;
optional string quote = 3;
repeated string pet = 4;
optional InnerMessage inner = 5;
repeated OtherMessage others = 6;
optional RequiredInnerMessage we_must_go_deeper = 13;
repeated InnerMessage rep_inner = 12;
enum Color {
RED = 0;
GREEN = 1;
BLUE = 2;
};
optional Color bikeshed = 7;
optional group SomeGroup = 8 {
optional int32 group_field = 9;
}
// This field becomes [][]byte in the generated code.
repeated bytes rep_bytes = 10;
optional double bigfloat = 11;
extensions 100 to max;
}
message Ext {
extend MyMessage {
optional Ext more = 103;
optional string text = 104;
optional int32 number = 105;
}
optional string data = 1;
}
extend MyMessage {
repeated string greeting = 106;
}
message ComplexExtension {
optional int32 first = 1;
optional int32 second = 2;
repeated int32 third = 3;
}
extend OtherMessage {
optional ComplexExtension complex = 200;
repeated ComplexExtension r_complex = 201;
}
message DefaultsMessage {
enum DefaultsEnum {
ZERO = 0;
ONE = 1;
TWO = 2;
};
extensions 100 to max;
}
extend DefaultsMessage {
optional double no_default_double = 101;
optional float no_default_float = 102;
optional int32 no_default_int32 = 103;
optional int64 no_default_int64 = 104;
optional uint32 no_default_uint32 = 105;
optional uint64 no_default_uint64 = 106;
optional sint32 no_default_sint32 = 107;
optional sint64 no_default_sint64 = 108;
optional fixed32 no_default_fixed32 = 109;
optional fixed64 no_default_fixed64 = 110;
optional sfixed32 no_default_sfixed32 = 111;
optional sfixed64 no_default_sfixed64 = 112;
optional bool no_default_bool = 113;
optional string no_default_string = 114;
optional bytes no_default_bytes = 115;
optional DefaultsMessage.DefaultsEnum no_default_enum = 116;
optional double default_double = 201 [default = 3.1415];
optional float default_float = 202 [default = 3.14];
optional int32 default_int32 = 203 [default = 42];
optional int64 default_int64 = 204 [default = 43];
optional uint32 default_uint32 = 205 [default = 44];
optional uint64 default_uint64 = 206 [default = 45];
optional sint32 default_sint32 = 207 [default = 46];
optional sint64 default_sint64 = 208 [default = 47];
optional fixed32 default_fixed32 = 209 [default = 48];
optional fixed64 default_fixed64 = 210 [default = 49];
optional sfixed32 default_sfixed32 = 211 [default = 50];
optional sfixed64 default_sfixed64 = 212 [default = 51];
optional bool default_bool = 213 [default = true];
optional string default_string = 214 [default = "Hello, string"];
optional bytes default_bytes = 215 [default = "Hello, bytes"];
optional DefaultsMessage.DefaultsEnum default_enum = 216 [default = ONE];
}
message MyMessageSet {
option message_set_wire_format = true;
extensions 100 to max;
}
message Empty {
}
extend MyMessageSet {
optional Empty x201 = 201;
optional Empty x202 = 202;
optional Empty x203 = 203;
optional Empty x204 = 204;
optional Empty x205 = 205;
optional Empty x206 = 206;
optional Empty x207 = 207;
optional Empty x208 = 208;
optional Empty x209 = 209;
optional Empty x210 = 210;
optional Empty x211 = 211;
optional Empty x212 = 212;
optional Empty x213 = 213;
optional Empty x214 = 214;
optional Empty x215 = 215;
optional Empty x216 = 216;
optional Empty x217 = 217;
optional Empty x218 = 218;
optional Empty x219 = 219;
optional Empty x220 = 220;
optional Empty x221 = 221;
optional Empty x222 = 222;
optional Empty x223 = 223;
optional Empty x224 = 224;
optional Empty x225 = 225;
optional Empty x226 = 226;
optional Empty x227 = 227;
optional Empty x228 = 228;
optional Empty x229 = 229;
optional Empty x230 = 230;
optional Empty x231 = 231;
optional Empty x232 = 232;
optional Empty x233 = 233;
optional Empty x234 = 234;
optional Empty x235 = 235;
optional Empty x236 = 236;
optional Empty x237 = 237;
optional Empty x238 = 238;
optional Empty x239 = 239;
optional Empty x240 = 240;
optional Empty x241 = 241;
optional Empty x242 = 242;
optional Empty x243 = 243;
optional Empty x244 = 244;
optional Empty x245 = 245;
optional Empty x246 = 246;
optional Empty x247 = 247;
optional Empty x248 = 248;
optional Empty x249 = 249;
optional Empty x250 = 250;
}
message MessageList {
repeated group Message = 1 {
required string name = 2;
required int32 count = 3;
}
}
message Strings {
optional string string_field = 1;
optional bytes bytes_field = 2;
}
message Defaults {
enum Color {
RED = 0;
GREEN = 1;
BLUE = 2;
}
// Default-valued fields of all basic types.
// Same as GoTest, but copied here to make testing easier.
optional bool F_Bool = 1 [default=true];
optional int32 F_Int32 = 2 [default=32];
optional int64 F_Int64 = 3 [default=64];
optional fixed32 F_Fixed32 = 4 [default=320];
optional fixed64 F_Fixed64 = 5 [default=640];
optional uint32 F_Uint32 = 6 [default=3200];
optional uint64 F_Uint64 = 7 [default=6400];
optional float F_Float = 8 [default=314159.];
optional double F_Double = 9 [default=271828.];
optional string F_String = 10 [default="hello, \"world!\"\n"];
optional bytes F_Bytes = 11 [default="Bignose"];
optional sint32 F_Sint32 = 12 [default=-32];
optional sint64 F_Sint64 = 13 [default=-64];
optional Color F_Enum = 14 [default=GREEN];
// More fields with crazy defaults.
optional float F_Pinf = 15 [default=inf];
optional float F_Ninf = 16 [default=-inf];
optional float F_Nan = 17 [default=nan];
// Sub-message.
optional SubDefaults sub = 18;
// Redundant but explicit defaults.
optional string str_zero = 19 [default=""];
}
message SubDefaults {
optional int64 n = 1 [default=7];
}
message RepeatedEnum {
enum Color {
RED = 1;
}
repeated Color color = 1;
}
message MoreRepeated {
repeated bool bools = 1;
repeated bool bools_packed = 2 [packed=true];
repeated int32 ints = 3;
repeated int32 ints_packed = 4 [packed=true];
repeated int64 int64s_packed = 7 [packed=true];
repeated string strings = 5;
repeated fixed32 fixeds = 6;
}
// GroupOld and GroupNew have the same wire format.
// GroupNew has a new field inside a group.
message GroupOld {
optional group G = 101 {
optional int32 x = 2;
}
}
message GroupNew {
optional group G = 101 {
optional int32 x = 2;
optional int32 y = 3;
}
}
message FloatingPoint {
required double f = 1;
optional bool exact = 2;
}
message MessageWithMap {
map<int32, string> name_mapping = 1;
map<sint64, FloatingPoint> msg_mapping = 2;
map<bool, bytes> byte_mapping = 3;
map<string, string> str_to_str = 4;
}
message Oneof {
oneof union {
bool F_Bool = 1;
int32 F_Int32 = 2;
int64 F_Int64 = 3;
fixed32 F_Fixed32 = 4;
fixed64 F_Fixed64 = 5;
uint32 F_Uint32 = 6;
uint64 F_Uint64 = 7;
float F_Float = 8;
double F_Double = 9;
string F_String = 10;
bytes F_Bytes = 11;
sint32 F_Sint32 = 12;
sint64 F_Sint64 = 13;
MyMessage.Color F_Enum = 14;
GoTestField F_Message = 15;
group F_Group = 16 {
optional int32 x = 17;
}
int32 F_Largest_Tag = 536870911;
}
oneof tormato {
int32 value = 100;
}
}
message Communique {
optional bool make_me_cry = 1;
// This is a oneof, called "union".
oneof union {
int32 number = 5;
string name = 6;
bytes data = 7;
double temp_c = 8;
MyMessage.Color col = 9;
Strings msg = 10;
}
}

Some files were not shown because too many files have changed in this diff Show More