-
Notifications
You must be signed in to change notification settings - Fork 17
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add UnmarshallValidateMsg to generated functions #25
Changes from all commits
824bc15
22412b7
2f0ca70
f40ca6c
fad54b1
eeedb47
33f2a55
82123d5
3da9157
2b3dae1
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -60,12 +60,17 @@ func (u *unmarshalGen) Execute(p Elem) ([]string, error) { | |
u.p.printf("\n return ((*(%s))(%s)).UnmarshalMsg(bts)", baseType, c) | ||
u.p.printf("\n}") | ||
|
||
u.p.printf("\nfunc (%s %s) UnmarshalValidateMsg(bts []byte) ([]byte, error) {", c, methodRecv) | ||
u.p.printf("\n return ((*(%s))(%s)).UnmarshalValidateMsg(bts)", baseType, c) | ||
u.p.printf("\n}") | ||
|
||
u.p.printf("\nfunc (_ %[2]s) CanUnmarshalMsg(%[1]s interface{}) bool {", c, methodRecv) | ||
u.p.printf("\n _, ok := (%s).(%s)", c, methodRecv) | ||
u.p.printf("\n return ok") | ||
u.p.printf("\n}") | ||
|
||
u.topics.Add(methodRecv, "UnmarshalMsg") | ||
u.topics.Add(methodRecv, "UnmarshalValidateMsg") | ||
u.topics.Add(methodRecv, "CanUnmarshalMsg") | ||
|
||
return u.msgs, u.p.err | ||
|
@@ -75,7 +80,7 @@ func (u *unmarshalGen) Execute(p Elem) ([]string, error) { | |
c := p.Varname() | ||
methodRecv := methodReceiver(p) | ||
|
||
u.p.printf("\nfunc (%s %s) UnmarshalMsg(bts []byte) (o []byte, err error) {", c, methodRecv) | ||
u.p.printf("\nfunc (%s %s) unmarshalMsg(bts []byte, validate bool) (o []byte, err error) {", c, methodRecv) | ||
next(u, p) | ||
u.p.print("\no = bts") | ||
|
||
|
@@ -91,12 +96,21 @@ func (u *unmarshalGen) Execute(p Elem) ([]string, error) { | |
} | ||
u.p.nakedReturn() | ||
|
||
u.p.printf("\nfunc (%s %s) UnmarshalMsg(bts []byte) (o []byte, err error) {", c, methodRecv) | ||
u.p.printf("\n return %s.unmarshalMsg(bts, false)", c) | ||
u.p.printf("\n}") | ||
|
||
u.p.printf("\nfunc (%s %s) UnmarshalValidateMsg(bts []byte) (o []byte, err error) {", c, methodRecv) | ||
u.p.printf("\n return %s.unmarshalMsg(bts, true)", c) | ||
u.p.printf("\n}") | ||
|
||
u.p.printf("\nfunc (_ %[2]s) CanUnmarshalMsg(%[1]s interface{}) bool {", c, methodRecv) | ||
u.p.printf("\n _, ok := (%s).(%s)", c, methodRecv) | ||
u.p.printf("\n return ok") | ||
u.p.printf("\n}") | ||
|
||
u.topics.Add(methodRecv, "UnmarshalMsg") | ||
u.topics.Add(methodRecv, "UnmarshalValidateMsg") | ||
u.topics.Add(methodRecv, "CanUnmarshalMsg") | ||
|
||
return u.msgs, u.p.err | ||
|
@@ -144,8 +158,13 @@ func (u *unmarshalGen) mapstruct(s *Struct) { | |
u.needsField() | ||
sz := randIdent() | ||
isnil := randIdent() | ||
last := randIdent() | ||
lastIsSet := randIdent() | ||
u.p.declare(sz, "int") | ||
u.p.declare(last, "string") | ||
u.p.declare(lastIsSet, "bool") | ||
u.p.declare(isnil, "bool") | ||
u.p.printf("\n_=%s;\n_=%s", last, lastIsSet) // we might not use these for empty structs | ||
|
||
// go-codec compat: decode an array as sequential elements from this struct, | ||
// in the order they are defined in the Go type (as opposed to canonical | ||
|
@@ -155,6 +174,11 @@ func (u *unmarshalGen) mapstruct(s *Struct) { | |
|
||
u.assignAndCheck(sz, isnil, arrayHeader) | ||
|
||
u.p.print("\nif validate {") // map encoded as array => non canonical | ||
u.p.print("\nerr = &msgp.ErrNonCanonical{}") | ||
u.p.print("\nreturn") | ||
u.p.print("\n}") | ||
|
||
u.ctx.PushString("struct-from-array") | ||
for i := range s.Fields { | ||
if !ast.IsExported(s.Fields[i].FieldName) { | ||
|
@@ -195,13 +219,19 @@ func (u *unmarshalGen) mapstruct(s *Struct) { | |
return | ||
} | ||
u.p.printf("\ncase \"%s\":", s.Fields[i].FieldTag) | ||
u.p.printf("\nif validate && %s && \"%s\" < %s {", lastIsSet, s.Fields[i].FieldTag, last) | ||
u.p.print("\nerr = &msgp.ErrNonCanonical{}") | ||
u.p.printf("\nreturn") | ||
u.p.print("\n}") | ||
u.ctx.PushString(s.Fields[i].FieldName) | ||
next(u, s.Fields[i].FieldElem) | ||
u.ctx.Pop() | ||
u.p.printf("\n%s = \"%s\"", last, s.Fields[i].FieldTag) | ||
} | ||
u.p.print("\ndefault:\nerr = msgp.ErrNoField(string(field))") | ||
u.p.wrapErrCheck(u.ctx.ArgsStr()) | ||
u.p.print("\n}") // close switch | ||
u.p.printf("\n%s = true", lastIsSet) | ||
u.p.print("\n}") // close for loop | ||
u.p.print("\n}") // close else statement for array decode | ||
} | ||
|
@@ -325,9 +355,27 @@ func (u *unmarshalGen) gMap(m *Map) { | |
u.msgs = append(u.msgs, resizemsgs...) | ||
|
||
// loop and get key,value | ||
last := randIdent() | ||
lastSet := randIdent() | ||
u.p.printf("\nvar %s %s; _ = %s", last, m.Key.TypeName(), last) // we might not use the sort if it's not defined | ||
algorandskiy marked this conversation as resolved.
Show resolved
Hide resolved
|
||
u.p.declare(lastSet, "bool") | ||
u.p.printf("\n_ = %s", lastSet) // we might not use the flag | ||
u.p.printf("\nfor %s > 0 {", sz) | ||
u.p.printf("\nvar %s %s; var %s %s; %s--", m.Keyidx, m.Key.TypeName(), m.Validx, m.Value.TypeName(), sz) | ||
next(u, m.Key) | ||
u.p.printf("\nif validate {") | ||
if m.Key.LessFunction() != "" { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. maybe do not require less func for all types? since numbers, strings, arrays are comparable, byte slices can be generated with bytes.Compare if m.Key.TypeName() == []bytes - i.e. to make this feature more usable by requiring less work by a user. Btw, it looks like I can call UnmarshalValidateMsg on a type without providing LessFunction, this code would not be generated and I might get no err even there is an ordering issue. I guess we need to go one of the roads:
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I agree -- I can make it smarter
These two don't seem mutually exclusive to me. The first one is a correctness issue and the second seems like a performance concern. I could fix the issue by including the |
||
u.p.printf("\nif %s && %s(%s, %s) {", lastSet, m.Key.LessFunction(), m.Keyidx, last) | ||
u.p.printf("\nerr = &msgp.ErrNonCanonical{}") | ||
u.p.printf("\nreturn") | ||
u.p.printf("\n}") | ||
} else { | ||
u.p.printf("\nerr = &msgp.ErrMissingLessFn{}") | ||
u.p.printf("\nreturn") | ||
} | ||
u.p.printf("\n}") // close if validate block | ||
u.p.printf("\n%s=%s", last, m.Keyidx) | ||
u.p.printf("\n%s=true", lastSet) | ||
u.ctx.PushVar(m.Keyidx) | ||
next(u, m.Value) | ||
u.ctx.Pop() | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
add a code that errs if LessFunction not set for this type?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LessFunction missing is a compile time issue not runtime. Should I just emit a panic inside the code if LessFn is expected and missing?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah I see yeah I can just return a nil slice and error since I already have error interface.