diff --git a/gen.go b/gen.go index 0727fae..f7bbc9b 100644 --- a/gen.go +++ b/gen.go @@ -89,6 +89,7 @@ type Field struct { Pointer bool Type reflect.Type Pkg string + Const *string OmitEmpty bool IterLabel string @@ -204,6 +205,14 @@ func ParseTypeInfo(i interface{}) (*GenTypeInfo, error) { usrMaxLen = val } + var constval *string + if cv, hasconst := tags["const"]; hasconst { + if ft.Kind() != reflect.String { + return nil, fmt.Errorf("const vals are only supported for string types") + } + constval = &cv + } + _, omitempty := tags["omitempty"] out.Fields = append(out.Fields, Field{ @@ -214,6 +223,7 @@ func ParseTypeInfo(i interface{}) (*GenTypeInfo, error) { Pkg: pkg, OmitEmpty: omitempty, MaxLen: usrMaxLen, + Const: constval, }) } @@ -297,6 +307,16 @@ func emitCborMarshalStringField(w io.Writer, f Field) error { `) } + if f.Const != nil { + return doTemplate(w, f, ` + {{ MajorType "cw" "cbg.MajTextString" (print "len(" .Name ")") }} + if _, err := io.WriteString(w, string("{{ .Const }}")); err != nil { + return err + } +`) + + } + return doTemplate(w, f, ` if len({{ .Name }}) > {{ MaxLen .MaxLen "cbg.MaxLength" }} { return xerrors.Errorf("Value in field {{ .Name | js }} was too long") @@ -1228,12 +1248,12 @@ func emitCborMarshalStructMap(w io.Writer, gti *GenTypeInfo) error { } if hasOmitEmpty { - fmt.Fprintln(w, "var emptyFieldCount int") + fmt.Fprintf(w, "fieldCount := %d\n", len(gti.Fields)) for _, f := range gti.Fields { if f.OmitEmpty { err := doTemplate(w, f, ` if t.{{ .Name }} == nil { - emptyFieldCount++ + fieldCount-- } `) if err != nil { @@ -1243,10 +1263,10 @@ func emitCborMarshalStructMap(w io.Writer, gti *GenTypeInfo) error { } fmt.Fprintf(w, ` - if _, err := cw.Write(cbg.CborEncodeMajorType(cbg.MajMap, uint64(%d - emptyFieldCount))); err != nil { + if _, err := cw.Write(cbg.CborEncodeMajorType(cbg.MajMap, uint64(fieldCount))); err != nil { return err } -`, len(gti.Fields)) +`) if err != nil { return err } diff --git a/testgen/main.go b/testgen/main.go index ac4115c..c4ba59a 100644 --- a/testgen/main.go +++ b/testgen/main.go @@ -25,6 +25,7 @@ func main() { types.SimpleStructV2{}, types.RenamedFields{}, types.TestEmpty{}, + types.TestConstField{}, ); err != nil { panic(err) } diff --git a/testing/cbor_map_gen.go b/testing/cbor_map_gen.go index b4e1d84..a995808 100644 --- a/testing/cbor_map_gen.go +++ b/testing/cbor_map_gen.go @@ -1815,13 +1815,13 @@ func (t *TestEmpty) MarshalCBOR(w io.Writer) error { } cw := cbg.NewCborWriter(w) - var emptyFieldCount int + fieldCount := 2 if t.Foo == nil { - emptyFieldCount++ + fieldCount-- } - if _, err := cw.Write(cbg.CborEncodeMajorType(cbg.MajMap, uint64(2-emptyFieldCount))); err != nil { + if _, err := cw.Write(cbg.CborEncodeMajorType(cbg.MajMap, uint64(fieldCount))); err != nil { return err } @@ -1975,3 +1975,142 @@ func (t *TestEmpty) UnmarshalCBOR(r io.Reader) (err error) { return nil } +func (t *TestConstField) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + + cw := cbg.NewCborWriter(w) + + if _, err := cw.Write([]byte{162}); err != nil { + return err + } + + // t.Cats (string) (string) + if len("Cats") > cbg.MaxLength { + return xerrors.Errorf("Value in field \"Cats\" was too long") + } + + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len("Cats"))); err != nil { + return err + } + if _, err := io.WriteString(w, string("Cats")); err != nil { + return err + } + + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len(t.Cats))); err != nil { + return err + } + if _, err := io.WriteString(w, string("dogsdrool")); err != nil { + return err + } + + // t.Thing (int64) (int64) + if len("Thing") > cbg.MaxLength { + return xerrors.Errorf("Value in field \"Thing\" was too long") + } + + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len("Thing"))); err != nil { + return err + } + if _, err := io.WriteString(w, string("Thing")); err != nil { + return err + } + + if t.Thing >= 0 { + if err := cw.WriteMajorTypeHeader(cbg.MajUnsignedInt, uint64(t.Thing)); err != nil { + return err + } + } else { + if err := cw.WriteMajorTypeHeader(cbg.MajNegativeInt, uint64(-t.Thing-1)); err != nil { + return err + } + } + return nil +} + +func (t *TestConstField) UnmarshalCBOR(r io.Reader) (err error) { + *t = TestConstField{} + + cr := cbg.NewCborReader(r) + + maj, extra, err := cr.ReadHeader() + if err != nil { + return err + } + defer func() { + if err == io.EOF { + err = io.ErrUnexpectedEOF + } + }() + + if maj != cbg.MajMap { + return fmt.Errorf("cbor input should be of type map") + } + + if extra > cbg.MaxLength { + return fmt.Errorf("TestConstField: map struct too large (%d)", extra) + } + + var name string + n := extra + + for i := uint64(0); i < n; i++ { + + { + sval, err := cbg.ReadString(cr) + if err != nil { + return err + } + + name = string(sval) + } + + switch name { + // t.Cats (string) (string) + case "Cats": + + { + sval, err := cbg.ReadString(cr) + if err != nil { + return err + } + + t.Cats = string(sval) + } + // t.Thing (int64) (int64) + case "Thing": + { + maj, extra, err := cr.ReadHeader() + var extraI int64 + if err != nil { + return err + } + switch maj { + case cbg.MajUnsignedInt: + extraI = int64(extra) + if extraI < 0 { + return fmt.Errorf("int64 positive overflow") + } + case cbg.MajNegativeInt: + extraI = int64(extra) + if extraI < 0 { + return fmt.Errorf("int64 negative oveflow") + } + extraI = -1 - extraI + default: + return fmt.Errorf("wrong type for int64 field: %d", maj) + } + + t.Thing = int64(extraI) + } + + default: + // Field doesn't exist on this type, so ignore it + cbg.ScanForLinks(r, func(cid.Cid) {}) + } + } + + return nil +} diff --git a/testing/types.go b/testing/types.go index bc927e5..51c6b7b 100644 --- a/testing/types.go +++ b/testing/types.go @@ -115,3 +115,8 @@ type TestEmpty struct { Foo *string `cborgen:"omitempty"` Cat int64 } + +type TestConstField struct { + Cats string `cborgen:"const=dogsdrool"` + Thing int64 +}