774 lines
18 KiB
Go
774 lines
18 KiB
Go
/**
|
|
* Copyright 2014 Paul Querna
|
|
*
|
|
* 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.
|
|
*
|
|
*/
|
|
|
|
package ffjsoninception
|
|
|
|
import (
|
|
"reflect"
|
|
"strconv"
|
|
"text/template"
|
|
)
|
|
|
|
var decodeTpl map[string]*template.Template
|
|
|
|
func init() {
|
|
decodeTpl = make(map[string]*template.Template)
|
|
|
|
funcs := map[string]string{
|
|
"handlerNumeric": handlerNumericTxt,
|
|
"allowTokens": allowTokensTxt,
|
|
"handleFallback": handleFallbackTxt,
|
|
"handleString": handleStringTxt,
|
|
"handleObject": handleObjectTxt,
|
|
"handleArray": handleArrayTxt,
|
|
"handleSlice": handleSliceTxt,
|
|
"handleByteSlice": handleByteSliceTxt,
|
|
"handleBool": handleBoolTxt,
|
|
"handlePtr": handlePtrTxt,
|
|
"header": headerTxt,
|
|
"ujFunc": ujFuncTxt,
|
|
"handleUnmarshaler": handleUnmarshalerTxt,
|
|
}
|
|
|
|
tplFuncs := template.FuncMap{
|
|
"getAllowTokens": getAllowTokens,
|
|
"getNumberSize": getNumberSize,
|
|
"getType": getType,
|
|
"handleField": handleField,
|
|
"handleFieldAddr": handleFieldAddr,
|
|
"unquoteField": unquoteField,
|
|
"getTmpVarFor": getTmpVarFor,
|
|
}
|
|
|
|
for k, v := range funcs {
|
|
decodeTpl[k] = template.Must(template.New(k).Funcs(tplFuncs).Parse(v))
|
|
}
|
|
}
|
|
|
|
type handlerNumeric struct {
|
|
IC *Inception
|
|
Name string
|
|
ParseFunc string
|
|
Typ reflect.Type
|
|
TakeAddr bool
|
|
}
|
|
|
|
var handlerNumericTxt = `
|
|
{
|
|
{{$ic := .IC}}
|
|
|
|
if tok == fflib.FFTok_null {
|
|
{{if eq .TakeAddr true}}
|
|
{{.Name}} = nil
|
|
{{end}}
|
|
} else {
|
|
{{if eq .ParseFunc "ParseFloat" }}
|
|
tval, err := fflib.{{ .ParseFunc}}(fs.Output.Bytes(), {{getNumberSize .Typ}})
|
|
{{else}}
|
|
tval, err := fflib.{{ .ParseFunc}}(fs.Output.Bytes(), 10, {{getNumberSize .Typ}})
|
|
{{end}}
|
|
|
|
if err != nil {
|
|
return fs.WrapErr(err)
|
|
}
|
|
{{if eq .TakeAddr true}}
|
|
ttypval := {{getType $ic .Name .Typ}}(tval)
|
|
{{.Name}} = &ttypval
|
|
{{else}}
|
|
{{.Name}} = {{getType $ic .Name .Typ}}(tval)
|
|
{{end}}
|
|
}
|
|
}
|
|
`
|
|
|
|
type allowTokens struct {
|
|
Name string
|
|
Tokens []string
|
|
}
|
|
|
|
var allowTokensTxt = `
|
|
{
|
|
if {{range $index, $element := .Tokens}}{{if ne $index 0 }}&&{{end}} tok != fflib.{{$element}}{{end}} {
|
|
return fs.WrapErr(fmt.Errorf("cannot unmarshal %s into Go value for {{.Name}}", tok))
|
|
}
|
|
}
|
|
`
|
|
|
|
type handleFallback struct {
|
|
Name string
|
|
Typ reflect.Type
|
|
Kind reflect.Kind
|
|
}
|
|
|
|
var handleFallbackTxt = `
|
|
{
|
|
/* Falling back. type={{printf "%v" .Typ}} kind={{printf "%v" .Kind}} */
|
|
tbuf, err := fs.CaptureField(tok)
|
|
if err != nil {
|
|
return fs.WrapErr(err)
|
|
}
|
|
|
|
err = json.Unmarshal(tbuf, &{{.Name}})
|
|
if err != nil {
|
|
return fs.WrapErr(err)
|
|
}
|
|
}
|
|
`
|
|
|
|
type handleString struct {
|
|
IC *Inception
|
|
Name string
|
|
Typ reflect.Type
|
|
TakeAddr bool
|
|
Quoted bool
|
|
}
|
|
|
|
var handleStringTxt = `
|
|
{
|
|
{{$ic := .IC}}
|
|
|
|
{{getAllowTokens .Typ.Name "FFTok_string" "FFTok_null"}}
|
|
if tok == fflib.FFTok_null {
|
|
{{if eq .TakeAddr true}}
|
|
{{.Name}} = nil
|
|
{{end}}
|
|
} else {
|
|
{{if eq .TakeAddr true}}
|
|
var tval {{getType $ic .Name .Typ}}
|
|
outBuf := fs.Output.Bytes()
|
|
{{unquoteField .Quoted}}
|
|
tval = {{getType $ic .Name .Typ}}(string(outBuf))
|
|
{{.Name}} = &tval
|
|
{{else}}
|
|
outBuf := fs.Output.Bytes()
|
|
{{unquoteField .Quoted}}
|
|
{{.Name}} = {{getType $ic .Name .Typ}}(string(outBuf))
|
|
{{end}}
|
|
}
|
|
}
|
|
`
|
|
|
|
type handleObject struct {
|
|
IC *Inception
|
|
Name string
|
|
Typ reflect.Type
|
|
Ptr reflect.Kind
|
|
TakeAddr bool
|
|
}
|
|
|
|
var handleObjectTxt = `
|
|
{
|
|
{{$ic := .IC}}
|
|
{{getAllowTokens .Typ.Name "FFTok_left_bracket" "FFTok_null"}}
|
|
if tok == fflib.FFTok_null {
|
|
{{.Name}} = nil
|
|
} else {
|
|
|
|
{{if eq .TakeAddr true}}
|
|
{{if eq .Typ.Elem.Kind .Ptr }}
|
|
{{if eq .Typ.Key.Kind .Ptr }}
|
|
var tval = make(map[*{{getType $ic .Name .Typ.Key.Elem}}]*{{getType $ic .Name .Typ.Elem.Elem}}, 0)
|
|
{{else}}
|
|
var tval = make(map[{{getType $ic .Name .Typ.Key}}]*{{getType $ic .Name .Typ.Elem.Elem}}, 0)
|
|
{{end}}
|
|
{{else}}
|
|
{{if eq .Typ.Key.Kind .Ptr }}
|
|
var tval = make(map[*{{getType $ic .Name .Typ.Key.Elem}}]{{getType $ic .Name .Typ.Elem}}, 0)
|
|
{{else}}
|
|
var tval = make(map[{{getType $ic .Name .Typ.Key}}]{{getType $ic .Name .Typ.Elem}}, 0)
|
|
{{end}}
|
|
{{end}}
|
|
{{else}}
|
|
{{if eq .Typ.Elem.Kind .Ptr }}
|
|
{{if eq .Typ.Key.Kind .Ptr }}
|
|
{{.Name}} = make(map[*{{getType $ic .Name .Typ.Key.Elem}}]*{{getType $ic .Name .Typ.Elem.Elem}}, 0)
|
|
{{else}}
|
|
{{.Name}} = make(map[{{getType $ic .Name .Typ.Key}}]*{{getType $ic .Name .Typ.Elem.Elem}}, 0)
|
|
{{end}}
|
|
{{else}}
|
|
{{if eq .Typ.Key.Kind .Ptr }}
|
|
{{.Name}} = make(map[*{{getType $ic .Name .Typ.Key.Elem}}]{{getType $ic .Name .Typ.Elem}}, 0)
|
|
{{else}}
|
|
{{.Name}} = make(map[{{getType $ic .Name .Typ.Key}}]{{getType $ic .Name .Typ.Elem}}, 0)
|
|
{{end}}
|
|
{{end}}
|
|
{{end}}
|
|
|
|
wantVal := true
|
|
|
|
for {
|
|
{{$keyPtr := false}}
|
|
{{if eq .Typ.Key.Kind .Ptr }}
|
|
{{$keyPtr := true}}
|
|
var k *{{getType $ic .Name .Typ.Key.Elem}}
|
|
{{else}}
|
|
var k {{getType $ic .Name .Typ.Key}}
|
|
{{end}}
|
|
|
|
{{$valPtr := false}}
|
|
{{$tmpVar := getTmpVarFor .Name}}
|
|
{{if eq .Typ.Elem.Kind .Ptr }}
|
|
{{$valPtr := true}}
|
|
var {{$tmpVar}} *{{getType $ic .Name .Typ.Elem.Elem}}
|
|
{{else}}
|
|
var {{$tmpVar}} {{getType $ic .Name .Typ.Elem}}
|
|
{{end}}
|
|
|
|
tok = fs.Scan()
|
|
if tok == fflib.FFTok_error {
|
|
goto tokerror
|
|
}
|
|
if tok == fflib.FFTok_right_bracket {
|
|
break
|
|
}
|
|
|
|
if tok == fflib.FFTok_comma {
|
|
if wantVal == true {
|
|
// TODO(pquerna): this isn't an ideal error message, this handles
|
|
// things like [,,,] as an array value.
|
|
return fs.WrapErr(fmt.Errorf("wanted value token, but got token: %v", tok))
|
|
}
|
|
continue
|
|
} else {
|
|
wantVal = true
|
|
}
|
|
|
|
{{handleField .IC "k" .Typ.Key $keyPtr false}}
|
|
|
|
// Expect ':' after key
|
|
tok = fs.Scan()
|
|
if tok != fflib.FFTok_colon {
|
|
return fs.WrapErr(fmt.Errorf("wanted colon token, but got token: %v", tok))
|
|
}
|
|
|
|
tok = fs.Scan()
|
|
{{handleField .IC $tmpVar .Typ.Elem $valPtr false}}
|
|
|
|
{{if eq .TakeAddr true}}
|
|
tval[k] = {{$tmpVar}}
|
|
{{else}}
|
|
{{.Name}}[k] = {{$tmpVar}}
|
|
{{end}}
|
|
wantVal = false
|
|
}
|
|
|
|
{{if eq .TakeAddr true}}
|
|
{{.Name}} = &tval
|
|
{{end}}
|
|
}
|
|
}
|
|
`
|
|
|
|
type handleArray struct {
|
|
IC *Inception
|
|
Name string
|
|
Typ reflect.Type
|
|
Ptr reflect.Kind
|
|
UseReflectToSet bool
|
|
IsPtr bool
|
|
}
|
|
|
|
var handleArrayTxt = `
|
|
{
|
|
{{$ic := .IC}}
|
|
{{getAllowTokens .Typ.Name "FFTok_left_brace" "FFTok_null"}}
|
|
{{if eq .Typ.Elem.Kind .Ptr}}
|
|
{{.Name}} = [{{.Typ.Len}}]*{{getType $ic .Name .Typ.Elem.Elem}}{}
|
|
{{else}}
|
|
{{.Name}} = [{{.Typ.Len}}]{{getType $ic .Name .Typ.Elem}}{}
|
|
{{end}}
|
|
if tok != fflib.FFTok_null {
|
|
wantVal := true
|
|
|
|
idx := 0
|
|
for {
|
|
{{$ptr := false}}
|
|
{{$tmpVar := getTmpVarFor .Name}}
|
|
{{if eq .Typ.Elem.Kind .Ptr }}
|
|
{{$ptr := true}}
|
|
var {{$tmpVar}} *{{getType $ic .Name .Typ.Elem.Elem}}
|
|
{{else}}
|
|
var {{$tmpVar}} {{getType $ic .Name .Typ.Elem}}
|
|
{{end}}
|
|
|
|
tok = fs.Scan()
|
|
if tok == fflib.FFTok_error {
|
|
goto tokerror
|
|
}
|
|
if tok == fflib.FFTok_right_brace {
|
|
break
|
|
}
|
|
|
|
if tok == fflib.FFTok_comma {
|
|
if wantVal == true {
|
|
// TODO(pquerna): this isn't an ideal error message, this handles
|
|
// things like [,,,] as an array value.
|
|
return fs.WrapErr(fmt.Errorf("wanted value token, but got token: %v", tok))
|
|
}
|
|
continue
|
|
} else {
|
|
wantVal = true
|
|
}
|
|
|
|
{{handleField .IC $tmpVar .Typ.Elem $ptr false}}
|
|
|
|
// Standard json.Unmarshal ignores elements out of array bounds,
|
|
// that what we do as well.
|
|
if idx < {{.Typ.Len}} {
|
|
{{.Name}}[idx] = {{$tmpVar}}
|
|
idx++
|
|
}
|
|
|
|
wantVal = false
|
|
}
|
|
}
|
|
}
|
|
`
|
|
|
|
var handleSliceTxt = `
|
|
{
|
|
{{$ic := .IC}}
|
|
{{getAllowTokens .Typ.Name "FFTok_left_brace" "FFTok_null"}}
|
|
if tok == fflib.FFTok_null {
|
|
{{.Name}} = nil
|
|
} else {
|
|
{{if eq .Typ.Elem.Kind .Ptr }}
|
|
{{if eq .IsPtr true}}
|
|
{{.Name}} = &[]*{{getType $ic .Name .Typ.Elem.Elem}}{}
|
|
{{else}}
|
|
{{.Name}} = []*{{getType $ic .Name .Typ.Elem.Elem}}{}
|
|
{{end}}
|
|
{{else}}
|
|
{{if eq .IsPtr true}}
|
|
{{.Name}} = &[]{{getType $ic .Name .Typ.Elem}}{}
|
|
{{else}}
|
|
{{.Name}} = []{{getType $ic .Name .Typ.Elem}}{}
|
|
{{end}}
|
|
{{end}}
|
|
|
|
wantVal := true
|
|
|
|
for {
|
|
{{$ptr := false}}
|
|
{{$tmpVar := getTmpVarFor .Name}}
|
|
{{if eq .Typ.Elem.Kind .Ptr }}
|
|
{{$ptr := true}}
|
|
var {{$tmpVar}} *{{getType $ic .Name .Typ.Elem.Elem}}
|
|
{{else}}
|
|
var {{$tmpVar}} {{getType $ic .Name .Typ.Elem}}
|
|
{{end}}
|
|
|
|
tok = fs.Scan()
|
|
if tok == fflib.FFTok_error {
|
|
goto tokerror
|
|
}
|
|
if tok == fflib.FFTok_right_brace {
|
|
break
|
|
}
|
|
|
|
if tok == fflib.FFTok_comma {
|
|
if wantVal == true {
|
|
// TODO(pquerna): this isn't an ideal error message, this handles
|
|
// things like [,,,] as an array value.
|
|
return fs.WrapErr(fmt.Errorf("wanted value token, but got token: %v", tok))
|
|
}
|
|
continue
|
|
} else {
|
|
wantVal = true
|
|
}
|
|
|
|
{{handleField .IC $tmpVar .Typ.Elem $ptr false}}
|
|
{{if eq .IsPtr true}}
|
|
*{{.Name}} = append(*{{.Name}}, {{$tmpVar}})
|
|
{{else}}
|
|
{{.Name}} = append({{.Name}}, {{$tmpVar}})
|
|
{{end}}
|
|
wantVal = false
|
|
}
|
|
}
|
|
}
|
|
`
|
|
|
|
var handleByteSliceTxt = `
|
|
{
|
|
{{getAllowTokens .Typ.Name "FFTok_string" "FFTok_null"}}
|
|
if tok == fflib.FFTok_null {
|
|
{{.Name}} = nil
|
|
} else {
|
|
b := make([]byte, base64.StdEncoding.DecodedLen(fs.Output.Len()))
|
|
n, err := base64.StdEncoding.Decode(b, fs.Output.Bytes())
|
|
if err != nil {
|
|
return fs.WrapErr(err)
|
|
}
|
|
{{if eq .UseReflectToSet true}}
|
|
v := reflect.ValueOf(&{{.Name}}).Elem()
|
|
v.SetBytes(b[0:n])
|
|
{{else}}
|
|
{{.Name}} = append([]byte(), b[0:n]...)
|
|
{{end}}
|
|
}
|
|
}
|
|
`
|
|
|
|
type handleBool struct {
|
|
Name string
|
|
Typ reflect.Type
|
|
TakeAddr bool
|
|
}
|
|
|
|
var handleBoolTxt = `
|
|
{
|
|
if tok == fflib.FFTok_null {
|
|
{{if eq .TakeAddr true}}
|
|
{{.Name}} = nil
|
|
{{end}}
|
|
} else {
|
|
tmpb := fs.Output.Bytes()
|
|
|
|
{{if eq .TakeAddr true}}
|
|
var tval bool
|
|
{{end}}
|
|
|
|
if bytes.Compare([]byte{'t', 'r', 'u', 'e'}, tmpb) == 0 {
|
|
{{if eq .TakeAddr true}}
|
|
tval = true
|
|
{{else}}
|
|
{{.Name}} = true
|
|
{{end}}
|
|
} else if bytes.Compare([]byte{'f', 'a', 'l', 's', 'e'}, tmpb) == 0 {
|
|
{{if eq .TakeAddr true}}
|
|
tval = false
|
|
{{else}}
|
|
{{.Name}} = false
|
|
{{end}}
|
|
} else {
|
|
err = errors.New("unexpected bytes for true/false value")
|
|
return fs.WrapErr(err)
|
|
}
|
|
|
|
{{if eq .TakeAddr true}}
|
|
{{.Name}} = &tval
|
|
{{end}}
|
|
}
|
|
}
|
|
`
|
|
|
|
type handlePtr struct {
|
|
IC *Inception
|
|
Name string
|
|
Typ reflect.Type
|
|
Quoted bool
|
|
}
|
|
|
|
var handlePtrTxt = `
|
|
{
|
|
{{$ic := .IC}}
|
|
|
|
if tok == fflib.FFTok_null {
|
|
{{.Name}} = nil
|
|
} else {
|
|
if {{.Name}} == nil {
|
|
{{.Name}} = new({{getType $ic .Typ.Elem.Name .Typ.Elem}})
|
|
}
|
|
|
|
{{handleFieldAddr .IC .Name true .Typ.Elem false .Quoted}}
|
|
}
|
|
}
|
|
`
|
|
|
|
type header struct {
|
|
IC *Inception
|
|
SI *StructInfo
|
|
}
|
|
|
|
var headerTxt = `
|
|
const (
|
|
ffjt{{.SI.Name}}base = iota
|
|
ffjt{{.SI.Name}}nosuchkey
|
|
{{with $si := .SI}}
|
|
{{range $index, $field := $si.Fields}}
|
|
{{if ne $field.JsonName "-"}}
|
|
ffjt{{$si.Name}}{{$field.Name}}
|
|
{{end}}
|
|
{{end}}
|
|
{{end}}
|
|
)
|
|
|
|
{{with $si := .SI}}
|
|
{{range $index, $field := $si.Fields}}
|
|
{{if ne $field.JsonName "-"}}
|
|
var ffjKey{{$si.Name}}{{$field.Name}} = []byte({{$field.JsonName}})
|
|
{{end}}
|
|
{{end}}
|
|
{{end}}
|
|
|
|
`
|
|
|
|
type ujFunc struct {
|
|
IC *Inception
|
|
SI *StructInfo
|
|
ValidValues []string
|
|
ResetFields bool
|
|
}
|
|
|
|
var ujFuncTxt = `
|
|
{{$si := .SI}}
|
|
{{$ic := .IC}}
|
|
|
|
// UnmarshalJSON umarshall json - template of ffjson
|
|
func (j *{{.SI.Name}}) UnmarshalJSON(input []byte) error {
|
|
fs := fflib.NewFFLexer(input)
|
|
return j.UnmarshalJSONFFLexer(fs, fflib.FFParse_map_start)
|
|
}
|
|
|
|
// UnmarshalJSONFFLexer fast json unmarshall - template ffjson
|
|
func (j *{{.SI.Name}}) UnmarshalJSONFFLexer(fs *fflib.FFLexer, state fflib.FFParseState) error {
|
|
var err error
|
|
currentKey := ffjt{{.SI.Name}}base
|
|
_ = currentKey
|
|
tok := fflib.FFTok_init
|
|
wantedTok := fflib.FFTok_init
|
|
|
|
{{if eq .ResetFields true}}
|
|
{{range $index, $field := $si.Fields}}
|
|
var ffjSet{{$si.Name}}{{$field.Name}} = false
|
|
{{end}}
|
|
{{end}}
|
|
|
|
mainparse:
|
|
for {
|
|
tok = fs.Scan()
|
|
// println(fmt.Sprintf("debug: tok: %v state: %v", tok, state))
|
|
if tok == fflib.FFTok_error {
|
|
goto tokerror
|
|
}
|
|
|
|
switch state {
|
|
|
|
case fflib.FFParse_map_start:
|
|
if tok != fflib.FFTok_left_bracket {
|
|
wantedTok = fflib.FFTok_left_bracket
|
|
goto wrongtokenerror
|
|
}
|
|
state = fflib.FFParse_want_key
|
|
continue
|
|
|
|
case fflib.FFParse_after_value:
|
|
if tok == fflib.FFTok_comma {
|
|
state = fflib.FFParse_want_key
|
|
} else if tok == fflib.FFTok_right_bracket {
|
|
goto done
|
|
} else {
|
|
wantedTok = fflib.FFTok_comma
|
|
goto wrongtokenerror
|
|
}
|
|
|
|
case fflib.FFParse_want_key:
|
|
// json {} ended. goto exit. woo.
|
|
if tok == fflib.FFTok_right_bracket {
|
|
goto done
|
|
}
|
|
if tok != fflib.FFTok_string {
|
|
wantedTok = fflib.FFTok_string
|
|
goto wrongtokenerror
|
|
}
|
|
|
|
kn := fs.Output.Bytes()
|
|
if len(kn) <= 0 {
|
|
// "" case. hrm.
|
|
currentKey = ffjt{{.SI.Name}}nosuchkey
|
|
state = fflib.FFParse_want_colon
|
|
goto mainparse
|
|
} else {
|
|
switch kn[0] {
|
|
{{range $byte, $fields := $si.FieldsByFirstByte}}
|
|
case '{{$byte}}':
|
|
{{range $index, $field := $fields}}
|
|
{{if ne $index 0 }}} else if {{else}}if {{end}} bytes.Equal(ffjKey{{$si.Name}}{{$field.Name}}, kn) {
|
|
currentKey = ffjt{{$si.Name}}{{$field.Name}}
|
|
state = fflib.FFParse_want_colon
|
|
goto mainparse
|
|
{{end}} }
|
|
{{end}}
|
|
}
|
|
{{range $index, $field := $si.ReverseFields}}
|
|
if {{$field.FoldFuncName}}(ffjKey{{$si.Name}}{{$field.Name}}, kn) {
|
|
currentKey = ffjt{{$si.Name}}{{$field.Name}}
|
|
state = fflib.FFParse_want_colon
|
|
goto mainparse
|
|
}
|
|
{{end}}
|
|
currentKey = ffjt{{.SI.Name}}nosuchkey
|
|
state = fflib.FFParse_want_colon
|
|
goto mainparse
|
|
}
|
|
|
|
case fflib.FFParse_want_colon:
|
|
if tok != fflib.FFTok_colon {
|
|
wantedTok = fflib.FFTok_colon
|
|
goto wrongtokenerror
|
|
}
|
|
state = fflib.FFParse_want_value
|
|
continue
|
|
case fflib.FFParse_want_value:
|
|
|
|
if {{range $index, $v := .ValidValues}}{{if ne $index 0 }}||{{end}}tok == fflib.{{$v}}{{end}} {
|
|
switch currentKey {
|
|
{{range $index, $field := $si.Fields}}
|
|
case ffjt{{$si.Name}}{{$field.Name}}:
|
|
goto handle_{{$field.Name}}
|
|
{{end}}
|
|
case ffjt{{$si.Name}}nosuchkey:
|
|
err = fs.SkipField(tok)
|
|
if err != nil {
|
|
return fs.WrapErr(err)
|
|
}
|
|
state = fflib.FFParse_after_value
|
|
goto mainparse
|
|
}
|
|
} else {
|
|
goto wantedvalue
|
|
}
|
|
}
|
|
}
|
|
{{range $index, $field := $si.Fields}}
|
|
handle_{{$field.Name}}:
|
|
{{with $fieldName := $field.Name | printf "j.%s"}}
|
|
{{handleField $ic $fieldName $field.Typ $field.Pointer $field.ForceString}}
|
|
{{if eq $.ResetFields true}}
|
|
ffjSet{{$si.Name}}{{$field.Name}} = true
|
|
{{end}}
|
|
state = fflib.FFParse_after_value
|
|
goto mainparse
|
|
{{end}}
|
|
{{end}}
|
|
|
|
wantedvalue:
|
|
return fs.WrapErr(fmt.Errorf("wanted value token, but got token: %v", tok))
|
|
wrongtokenerror:
|
|
return fs.WrapErr(fmt.Errorf("ffjson: wanted token: %v, but got token: %v output=%s", wantedTok, tok, fs.Output.String()))
|
|
tokerror:
|
|
if fs.BigError != nil {
|
|
return fs.WrapErr(fs.BigError)
|
|
}
|
|
err = fs.Error.ToError()
|
|
if err != nil {
|
|
return fs.WrapErr(err)
|
|
}
|
|
panic("ffjson-generated: unreachable, please report bug.")
|
|
done:
|
|
{{if eq .ResetFields true}}
|
|
{{range $index, $field := $si.Fields}}
|
|
if !ffjSet{{$si.Name}}{{$field.Name}} {
|
|
{{with $fieldName := $field.Name | printf "j.%s"}}
|
|
{{if eq $field.Pointer true}}
|
|
{{$fieldName}} = nil
|
|
{{else if eq $field.Typ.Kind ` + strconv.FormatUint(uint64(reflect.Interface), 10) + `}}
|
|
{{$fieldName}} = nil
|
|
{{else if eq $field.Typ.Kind ` + strconv.FormatUint(uint64(reflect.Slice), 10) + `}}
|
|
{{$fieldName}} = nil
|
|
{{else if eq $field.Typ.Kind ` + strconv.FormatUint(uint64(reflect.Array), 10) + `}}
|
|
{{$fieldName}} = [{{$field.Typ.Len}}]{{getType $ic $fieldName $field.Typ.Elem}}{}
|
|
{{else if eq $field.Typ.Kind ` + strconv.FormatUint(uint64(reflect.Map), 10) + `}}
|
|
{{$fieldName}} = nil
|
|
{{else if eq $field.Typ.Kind ` + strconv.FormatUint(uint64(reflect.Bool), 10) + `}}
|
|
{{$fieldName}} = false
|
|
{{else if eq $field.Typ.Kind ` + strconv.FormatUint(uint64(reflect.String), 10) + `}}
|
|
{{$fieldName}} = ""
|
|
{{else if eq $field.Typ.Kind ` + strconv.FormatUint(uint64(reflect.Struct), 10) + `}}
|
|
{{$fieldName}} = {{getType $ic $fieldName $field.Typ}}{}
|
|
{{else}}
|
|
{{$fieldName}} = {{getType $ic $fieldName $field.Typ}}(0)
|
|
{{end}}
|
|
{{end}}
|
|
}
|
|
{{end}}
|
|
{{end}}
|
|
return nil
|
|
}
|
|
`
|
|
|
|
type handleUnmarshaler struct {
|
|
IC *Inception
|
|
Name string
|
|
Typ reflect.Type
|
|
Ptr reflect.Kind
|
|
TakeAddr bool
|
|
UnmarshalJSONFFLexer bool
|
|
Unmarshaler bool
|
|
}
|
|
|
|
var handleUnmarshalerTxt = `
|
|
{{$ic := .IC}}
|
|
|
|
{{if eq .UnmarshalJSONFFLexer true}}
|
|
{
|
|
if tok == fflib.FFTok_null {
|
|
{{if eq .Typ.Kind .Ptr }}
|
|
{{.Name}} = nil
|
|
{{end}}
|
|
{{if eq .TakeAddr true }}
|
|
{{.Name}} = nil
|
|
{{end}}
|
|
} else {
|
|
{{if eq .Typ.Kind .Ptr }}
|
|
if {{.Name}} == nil {
|
|
{{.Name}} = new({{getType $ic .Typ.Elem.Name .Typ.Elem}})
|
|
}
|
|
{{end}}
|
|
{{if eq .TakeAddr true }}
|
|
if {{.Name}} == nil {
|
|
{{.Name}} = new({{getType $ic .Typ.Name .Typ}})
|
|
}
|
|
{{end}}
|
|
err = {{.Name}}.UnmarshalJSONFFLexer(fs, fflib.FFParse_want_key)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
state = fflib.FFParse_after_value
|
|
}
|
|
{{else}}
|
|
{{if eq .Unmarshaler true}}
|
|
{
|
|
if tok == fflib.FFTok_null {
|
|
{{if eq .TakeAddr true }}
|
|
{{.Name}} = nil
|
|
{{end}}
|
|
} else {
|
|
|
|
tbuf, err := fs.CaptureField(tok)
|
|
if err != nil {
|
|
return fs.WrapErr(err)
|
|
}
|
|
|
|
{{if eq .TakeAddr true }}
|
|
if {{.Name}} == nil {
|
|
{{.Name}} = new({{getType $ic .Typ.Name .Typ}})
|
|
}
|
|
{{end}}
|
|
err = {{.Name}}.UnmarshalJSON(tbuf)
|
|
if err != nil {
|
|
return fs.WrapErr(err)
|
|
}
|
|
}
|
|
state = fflib.FFParse_after_value
|
|
}
|
|
{{end}}
|
|
{{end}}
|
|
`
|