Merge branch 'master' into feature/slice_in_body

This commit is contained in:
Aleksandr Petrukhin
2016-07-15 17:50:16 +03:00
7 changed files with 182 additions and 84 deletions
+3 -1
View File
@@ -20,9 +20,11 @@ generate: root build
.root/bin/easyjson -stubs \
.root/src/$(PKG)/tests/snake.go \
.root/src/$(PKG)/tests/data.go \
.root/src/$(PKG)/tests/omitempty.go
.root/src/$(PKG)/tests/omitempty.go \
.root/src/$(PKG)/tests/nothing.go
.root/bin/easyjson -all .root/src/$(PKG)/tests/data.go
.root/bin/easyjson -all .root/src/$(PKG)/tests/nothing.go
.root/bin/easyjson -snake_case .root/src/$(PKG)/tests/snake.go
.root/bin/easyjson -omit_empty .root/src/$(PKG)/tests/omitempty.go
.root/bin/easyjson -build_tags=use_easyjson .root/src/$(PKG)/benchmark/data.go
+14 -9
View File
@@ -50,20 +50,23 @@ func (g *Generator) writeStub() error {
fmt.Fprintln(f, "// compilable during generation.")
fmt.Fprintln(f)
fmt.Fprintln(f, "package ", g.PkgName)
fmt.Fprintln(f)
fmt.Fprintln(f, "import (")
fmt.Fprintln(f, ` "`+pkgWriter+`"`)
fmt.Fprintln(f, ` "`+pkgLexer+`"`)
fmt.Fprintln(f, ")")
if len(g.Types) > 0 {
fmt.Fprintln(f)
fmt.Fprintln(f, "import (")
fmt.Fprintln(f, ` "`+pkgWriter+`"`)
fmt.Fprintln(f, ` "`+pkgLexer+`"`)
fmt.Fprintln(f, ")")
}
for _, t := range g.Types {
fmt.Fprintln(f)
if !g.NoStdMarshalers {
fmt.Fprintln(f, "func (*", t, ") MarshalJSON() ([]byte, error) { return nil, nil }")
fmt.Fprintln(f, "func (", t, ") MarshalJSON() ([]byte, error) { return nil, nil }")
fmt.Fprintln(f, "func (*", t, ") UnmarshalJSON([]byte) error { return nil }")
}
fmt.Fprintln(f, "func (*", t, ") MarshalEasyJSON(w *jwriter.Writer) {}")
fmt.Fprintln(f, "func (", t, ") MarshalEasyJSON(w *jwriter.Writer) {}")
fmt.Fprintln(f, "func (*", t, ") UnmarshalEasyJSON(l *jlexer.Lexer) {}")
fmt.Fprintln(f)
fmt.Fprintln(f, "type EasyJSON_exporter_"+t+" *"+t)
@@ -90,8 +93,10 @@ func (g *Generator) writeMain() (path string, err error) {
fmt.Fprintln(f, ` "os"`)
fmt.Fprintln(f)
fmt.Fprintf(f, " %q\n", genPackage)
fmt.Fprintln(f)
fmt.Fprintf(f, " pkg %q\n", g.PkgPath)
if len(g.Types) > 0 {
fmt.Fprintln(f)
fmt.Fprintf(f, " pkg %q\n", g.PkgPath)
}
fmt.Fprintln(f, ")")
fmt.Fprintln(f)
fmt.Fprintln(f, "func main() {")
+15 -8
View File
@@ -156,7 +156,12 @@ func (g *Generator) printHeader() {
fmt.Println(")")
fmt.Println("")
fmt.Println("var _ = json.RawMessage{} // suppress unused package warning")
fmt.Println("// suppress unused package warning")
fmt.Println("var (")
fmt.Println(" _ = json.RawMessage{}")
fmt.Println(" _ = jlexer.Lexer{}")
fmt.Println(" _ = jwriter.Writer{}")
fmt.Println(")")
fmt.Println()
}
@@ -222,13 +227,15 @@ func (g *Generator) pkgAlias(pkgPath string) string {
// getType return the textual type name of given type that can be used in generated code.
func (g *Generator) getType(t reflect.Type) string {
switch t.Kind() {
case reflect.Ptr:
return "*" + g.getType(t.Elem())
case reflect.Slice:
return "[]" + g.getType(t.Elem())
case reflect.Map:
return "map[" + g.getType(t.Key()) + "]" + g.getType(t.Elem())
if t.Name() == "" {
switch t.Kind() {
case reflect.Ptr:
return "*" + g.getType(t.Elem())
case reflect.Slice:
return "[]" + g.getType(t.Elem())
case reflect.Map:
return "map[" + g.getType(t.Key()) + "]" + g.getType(t.Elem())
}
}
if t.Name() == "" || t.PkgPath() == "" {
+58 -37
View File
@@ -4,15 +4,15 @@ package jwriter
import (
"io"
"strconv"
"unicode/utf8"
"github.com/mailru/easyjson/buffer"
)
// Writer is a JSON writer.
type Writer struct {
EscapeLtGt bool
Error error
Buffer buffer.Buffer
Error error
Buffer buffer.Buffer
}
// Size returns the size of the data that was written out.
@@ -198,10 +198,7 @@ func (w *Writer) Bool(v bool) {
}
}
func hex(c byte) byte {
const chars = "0123456789abcdef"
return chars[c&0xf]
}
const chars = "0123456789abcdef"
func (w *Writer) String(s string) {
w.Buffer.AppendByte('"')
@@ -211,41 +208,65 @@ func (w *Writer) String(s string) {
p := 0 // last non-escape symbol
for i := 0; i < len(s); i++ {
c := s[i]
var escape byte
switch c {
case '\t':
escape = 't'
case '\r':
escape = 'r'
case '\n':
escape = 'n'
case '\\':
escape = '\\'
case '"':
escape = '"'
case '<', '>':
if !w.EscapeLtGt {
continue
for i := 0; i < len(s); {
// single-with character
if c := s[i]; c < utf8.RuneSelf {
var escape byte
switch c {
case '\t':
escape = 't'
case '\r':
escape = 'r'
case '\n':
escape = 'n'
case '\\':
escape = '\\'
case '"':
escape = '"'
case '<', '>':
// do nothing
default:
if c >= 0x20 {
// no escaping is required
i++
continue
}
}
default:
if c >= 0x20 {
// no escaping is required
continue
if escape != 0 {
w.Buffer.AppendString(s[p:i])
w.Buffer.AppendByte('\\')
w.Buffer.AppendByte(escape)
} else {
w.Buffer.AppendString(s[p:i])
w.Buffer.AppendString(`\u00`)
w.Buffer.AppendByte(chars[c>>4])
w.Buffer.AppendByte(chars[c&0xf])
}
i++
p = i
continue
}
if escape != 0 {
// broken utf
runeValue, runeWidth := utf8.DecodeRuneInString(s[i:])
if runeValue == utf8.RuneError && runeWidth == 1 {
w.Buffer.AppendString(s[p:i])
w.Buffer.AppendByte('\\')
w.Buffer.AppendByte(escape)
} else {
w.Buffer.AppendString(s[p:i])
w.Buffer.AppendString(`\u00`)
w.Buffer.AppendByte(hex(c >> 4))
w.Buffer.AppendByte(hex(c))
w.Buffer.AppendString(`\ufffd`)
i++
p = i
continue
}
p = i + 1
// jsonp stuff - tab separator and line separator
if runeValue == '\u2028' || runeValue == '\u2029' {
w.Buffer.AppendString(s[p:i])
w.Buffer.AppendString(`\u202`)
w.Buffer.AppendByte(chars[runeValue&0xf])
i += runeWidth
p = i
continue
}
i += runeWidth
}
w.Buffer.AppendString(s[p:])
w.Buffer.AppendByte('"')
+20 -16
View File
@@ -105,24 +105,28 @@ func TestParseNull(t *testing.T) {
}
}
var testCasesEncodeLtGt = []struct {
Writer *jwriter.Writer
Encoded string
var testSpecialCases = []struct {
EncodedString string
Value string
}{
{&jwriter.Writer{
EscapeLtGt: false,
}, encodeLtGtFalseWantString},
{&jwriter.Writer{
EscapeLtGt: true,
}, encodeLtGtTrueWantString},
{`"Username \u003cuser@example.com\u003e"`, `Username <user@example.com>`},
{`"Username\ufffd"`, "Username\xc5"},
{`"тестzтест"`, "тестzтест"},
{`"тест\ufffdтест"`, "тест\xc5тест"},
{`"绿茶"`, "绿茶"},
{`"绿\ufffd茶"`, "绿\xc5茶"},
{`"тест\u2028"`, "тест\xE2\x80\xA8"},
{`"\\\r\n\t\""`, "\\\r\n\t\""},
{`"ü"`, "ü"},
}
func TestEncodeLtGt(t *testing.T) {
for i, test := range testCasesEncodeLtGt {
test.Writer.String(encodeLtGtString)
got := string(test.Writer.Buffer.BuildBytes())
if got != test.Encoded {
t.Errorf("[%d] Encoded() = %+v; want %+v", i, got, test.Encoded)
func TestSpecialCases(t *testing.T) {
for i, test := range testSpecialCases {
w := jwriter.Writer{}
w.String(test.Value)
got := string(w.Buffer.BuildBytes())
if got != test.EncodedString {
t.Errorf("[%d] Encoded() = %+v; want %+v", i, got, test.EncodedString)
}
}
}
}
+69 -13
View File
@@ -436,41 +436,97 @@ var mapsString = `{` +
`"CustomMap":{"c":"d"}` +
`}`
type NamedSlice []Str
type NamedMap map[Str]Str
type DeepNest struct {
SliceMap map[Str][]Str
MapSlice []map[Str]Str
SliceMap map[Str][]Str
SliceMap1 map[Str][]Str
NamedSliceMap map[Str]NamedSlice
NamedMapMap map[Str]NamedMap
MapSlice []map[Str]Str
NamedSliceSlice []NamedSlice
NamedMapSlice []NamedMap
NamedStringSlice []NamedString
}
var deepNestValue = DeepNest{
SliceMap: map[Str][]Str{
"testSliceMap1": []Str{
"testSliceMap": []Str{
"0",
"1",
},
"testSliceMap2": nil,
},
SliceMap1: map[Str][]Str{
"testSliceMap1": nil,
},
NamedSliceMap: map[Str]NamedSlice{
"testNamedSliceMap": NamedSlice{
"2",
"3",
},
},
NamedMapMap: map[Str]NamedMap{
"testNamedMapMap": NamedMap{
"key1": "value1",
},
},
MapSlice: []map[Str]Str{
map[Str]Str{
"testMapSlice1": "someValue",
"testMapSlice": "someValue",
},
},
NamedSliceSlice: []NamedSlice{
NamedSlice{
"someValue1",
"someValue2",
},
NamedSlice{
"someValue3",
"someValue4",
},
},
NamedMapSlice: []NamedMap{
NamedMap{
"key2": "value2",
},
NamedMap{
"key3": "value3",
},
},
NamedStringSlice: []NamedString{
"value4", "value5",
},
}
var deepNestString = `{` +
`"SliceMap":{` +
`"testSliceMap1":["0","1"],` +
`"testSliceMap2":[]` +
`"testSliceMap":["0","1"]` +
`},` +
`"SliceMap1":{` +
`"testSliceMap1":[]` +
`},` +
`"NamedSliceMap":{` +
`"testNamedSliceMap":["2","3"]` +
`},` +
`"NamedMapMap":{` +
`"testNamedMapMap":{"key1":"value1"}` +
`},` +
`"MapSlice":[` +
`{"testMapSlice1":"someValue"}` +
`]` +
`{"testMapSlice":"someValue"}` +
`],` +
`"NamedSliceSlice":[` +
`["someValue1","someValue2"],` +
`["someValue3","someValue4"]` +
`],` +
`"NamedMapSlice":[` +
`{"key2":"value2"},` +
`{"key3":"value3"}` +
`],` +
`"NamedStringSlice":["value4","value5"]` +
`}`
type RequiredOptionalStruct struct {
FirstName string `json:"first_name,required"`
Lastname string `json:"last_name"`
}
var encodeLtGtString = `Username <user@example.com>`
var encodeLtGtFalseWantString = `"Username <user@example.com>"`
var encodeLtGtTrueWantString = `"Username \u003cuser@example.com\u003e"`
+3
View File
@@ -0,0 +1,3 @@
package tests
// No structs in this file