@@ -546,6 +546,25 @@ func (tmm TextMarshalerMode) valid() bool {
546546 return tmm >= 0 && tmm < maxTextMarshalerMode
547547}
548548
549+ // ToIndefArrayStructTagMode specifies whether to honor the `toindefarray`
550+ // struct tag option. Indefinite-length encoding via the streaming API is
551+ // governed separately by IndefLength.
552+ type ToIndefArrayStructTagMode int
553+
554+ const (
555+ // ToIndefArrayStructTagForbidden rejects encoding of structs tagged with `toindefarray`.
556+ ToIndefArrayStructTagForbidden ToIndefArrayStructTagMode = iota
557+
558+ // ToIndefArrayStructTagAllowed encodes structs tagged with `toindefarray` as indefinite-length arrays.
559+ ToIndefArrayStructTagAllowed
560+
561+ maxToIndefArrayStructTagMode
562+ )
563+
564+ func (m ToIndefArrayStructTagMode ) valid () bool {
565+ return m >= 0 && m < maxToIndefArrayStructTagMode
566+ }
567+
549568// EncOptions specifies encoding options.
550569type EncOptions struct {
551570 // Sort specifies sorting order.
@@ -611,6 +630,9 @@ type EncOptions struct {
611630 // json.Marshaler but do not also implement cbor.Marshaler. If nil, encoding behavior is not
612631 // influenced by whether or not a type implements json.Marshaler.
613632 JSONMarshalerTranscoder Transcoder
633+
634+ // ToIndefArrayStructTag specifies whether the `toindefarray` struct tag option is honored.
635+ ToIndefArrayStructTag ToIndefArrayStructTagMode
614636}
615637
616638// CanonicalEncOptions returns EncOptions for "Canonical CBOR" encoding,
@@ -824,6 +846,12 @@ func (opts EncOptions) encMode() (*encMode, error) { //nolint:gocritic // ignore
824846 if ! opts .TextMarshaler .valid () {
825847 return nil , errors .New ("cbor: invalid TextMarshaler " + strconv .Itoa (int (opts .TextMarshaler )))
826848 }
849+ if ! opts .ToIndefArrayStructTag .valid () {
850+ return nil , errors .New ("cbor: invalid ToIndefArrayStructTag " + strconv .Itoa (int (opts .ToIndefArrayStructTag )))
851+ }
852+ if opts .IndefLength == IndefLengthForbidden && opts .ToIndefArrayStructTag == ToIndefArrayStructTagAllowed {
853+ return nil , errors .New ("cbor: cannot set ToIndefArrayStructTag to ToIndefArrayStructTagAllowed when IndefLength is IndefLengthForbidden" )
854+ }
827855 em := encMode {
828856 sort : opts .Sort ,
829857 shortestFloat : opts .ShortestFloat ,
@@ -845,6 +873,7 @@ func (opts EncOptions) encMode() (*encMode, error) { //nolint:gocritic // ignore
845873 binaryMarshaler : opts .BinaryMarshaler ,
846874 textMarshaler : opts .TextMarshaler ,
847875 jsonMarshalerTranscoder : opts .JSONMarshalerTranscoder ,
876+ toIndefArrayStructTag : opts .ToIndefArrayStructTag ,
848877 }
849878 return & em , nil
850879}
@@ -892,6 +921,7 @@ type encMode struct {
892921 binaryMarshaler BinaryMarshalerMode
893922 textMarshaler TextMarshalerMode
894923 jsonMarshalerTranscoder Transcoder
924+ toIndefArrayStructTag ToIndefArrayStructTagMode
895925}
896926
897927var defaultEncMode , _ = EncOptions {}.encMode ()
@@ -986,6 +1016,7 @@ func (em *encMode) EncOptions() EncOptions {
9861016 BinaryMarshaler : em .binaryMarshaler ,
9871017 TextMarshaler : em .textMarshaler ,
9881018 JSONMarshalerTranscoder : em .jsonMarshalerTranscoder ,
1019+ ToIndefArrayStructTag : em .toIndefArrayStructTag ,
9891020 }
9901021}
9911022
@@ -1457,13 +1488,22 @@ func encodeStructToArray(e *bytes.Buffer, em *encMode, v reflect.Value) (err err
14571488 return err
14581489 }
14591490
1491+ if structType .toIndefArray && em .toIndefArrayStructTag != ToIndefArrayStructTagAllowed {
1492+ return errors .New ("cbor: cannot encode struct " + v .Type ().String () +
1493+ " with `toindefarray` when ToIndefArrayStructTag is not ToIndefArrayStructTagAllowed" )
1494+ }
1495+
14601496 if b := em .encTagBytes (v .Type ()); b != nil {
14611497 e .Write (b )
14621498 }
14631499
14641500 flds := structType .fields
14651501
1466- encodeHead (e , byte (cborTypeArray ), uint64 (len (flds )))
1502+ if structType .toIndefArray {
1503+ e .WriteByte (cborArrayWithIndefiniteLengthHead )
1504+ } else {
1505+ encodeHead (e , byte (cborTypeArray ), uint64 (len (flds )))
1506+ }
14671507 for i := range flds {
14681508 f := flds [i ]
14691509
@@ -1486,6 +1526,9 @@ func encodeStructToArray(e *bytes.Buffer, em *encMode, v reflect.Value) (err err
14861526 return err
14871527 }
14881528 }
1529+ if structType .toIndefArray {
1530+ e .WriteByte (cborBreakFlag )
1531+ }
14891532 return nil
14901533}
14911534
@@ -2050,7 +2093,7 @@ func getEncodeFuncInternal(t reflect.Type) (ef encodeFunc, ief isEmptyFunc, izf
20502093 if f , ok := t .FieldByName ("_" ); ok {
20512094 tag := f .Tag .Get ("cbor" )
20522095 if tag != "-" {
2053- if hasToArrayOption (tag ) {
2096+ if hasToArrayOption (tag ) || hasToIndefArrayOption ( tag ) {
20542097 return encodeStructToArray , isEmptyStruct , isZeroFieldStruct
20552098 }
20562099 }
@@ -2133,7 +2176,7 @@ func isEmptyStruct(em *encMode, v reflect.Value) (bool, error) {
21332176 return false , nil
21342177 }
21352178
2136- if structType .toArray {
2179+ if structType .toArray || structType . toIndefArray {
21372180 return len (structType .fields ) == 0 , nil
21382181 }
21392182
0 commit comments