From 03660a8691397932bc7f985fde4752a4373d16a4 Mon Sep 17 00:00:00 2001 From: Philipp Jahn Date: Tue, 25 Nov 2025 19:47:29 +0100 Subject: [PATCH] added null support --- README.md | 1 + major.go | 5 +++++ major_test.go | 41 +++++++++++++++++++++++++++++++++++++++++ simple.go | 8 ++++++++ 4 files changed, 55 insertions(+) diff --git a/README.md b/README.md index 24d7500..3d33962 100644 --- a/README.md +++ b/README.md @@ -15,6 +15,7 @@ developed to be used in [`dtn7-go`][dtn7-go], an implementation of the - Arrays, both of definite and indefinite length - Maps of definite length - Booleans + - Null - Small and clear codebase: - Only works on streams, Go's `io.Reader` or `io.Writer` - Does *not* use reflection or make any strange assumptions diff --git a/major.go b/major.go index 4171ed6..dcc63c1 100644 --- a/major.go +++ b/major.go @@ -19,6 +19,7 @@ const ( const ( IndefiniteArray byte = 0x9F + Null byte = SimpleData | simpleNull BreakCode byte = 0xFF ) @@ -31,6 +32,7 @@ func (f Flag) Error() string { const ( FlagIndefiniteArray = Flag(iota) FlagBreakCode = Flag(iota) + FlagNull = Flag(iota) ) func readMajorType(b byte) (major MajorType, adds byte) { @@ -56,6 +58,9 @@ func ReadMajors(r io.Reader) (m MajorType, n uint64, err error) { case BreakCode: err = FlagBreakCode + case Null: + err = FlagNull + default: var adds byte m, adds = readMajorType(b) diff --git a/major_test.go b/major_test.go index e2b1e6e..338633c 100644 --- a/major_test.go +++ b/major_test.go @@ -3,6 +3,7 @@ package cboring import ( "bufio" "bytes" + "io" "reflect" "testing" @@ -207,3 +208,43 @@ func TestReadBigData(t *testing.T) { } }) } + +func asUntyped[T any](read func(reader io.Reader) (T, error)) func(reader io.Reader) (any, error) { + return func(reader io.Reader) (any, error) { + return read(reader) + } +} + +func TestNull(t *testing.T) { + tests := []struct { + data []byte + value any + read func(reader io.Reader) (any, error) + }{ + {[]byte{Null, 0xfb, 0xc0, 0x10, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66}, -4.1, asUntyped(ReadFloat64)}, + {[]byte{Null, 0x64, 0x74, 0x65, 0x73, 0x74}, "test", asUntyped(ReadTextString)}, + {[]byte{Null, SimpleData | simpleTrue}, true, asUntyped(ReadBoolean)}, + {[]byte{Null, 0x0a}, uint64(10), asUntyped(ReadUInt)}, + } + + for _, test := range tests { + // Read + buff := bytes.NewBuffer(test.data) + if v, err := test.read(buff); err != FlagNull { + t.Fatalf("found Value %s", v) + } + if v, err := test.read(buff); err != nil { + t.Fatal(err) + } else if v != test.value { + t.Fatalf("Resulting value %s not expected %s", v, test.value) + } + } + + buff := &bytes.Buffer{} + err := WriteNull(buff) + if err != nil { + t.Fatal(err) + } else if buff.Len() != 1 || buff.Bytes()[0] != Null { + t.Fatal("written value not null") + } +} diff --git a/simple.go b/simple.go index 64b7e22..7dfd382 100644 --- a/simple.go +++ b/simple.go @@ -9,6 +9,7 @@ import ( const ( simpleFalse byte = 20 simpleTrue byte = 21 + simpleNull byte = 22 ) // ReadBoolean reads a bool value from the Reader. @@ -31,6 +32,8 @@ func ReadBoolean(r io.Reader) (b bool, err error) { b = false case simpleTrue: b = true + case simpleNull: + err = FlagNull default: err = fmt.Errorf("ReadBoolean: Unknown additional 0x%x", adds) } @@ -86,3 +89,8 @@ func WriteFloat64(f float64, w io.Writer) (err error) { fbits := math.Float64bits(f) return WriteMajors(SimpleData, fbits, w) } + +// WriteNull writes a null into the Writer. +func WriteNull(w io.Writer) (err error) { + return WriteMajors(SimpleData, uint64(simpleNull), w) +}