Compare commits

...

5 Commits

3 changed files with 80 additions and 18 deletions

View File

@ -1,5 +1,7 @@
package tape package tape
import "iter"
// encoding and decoding functions must not make any allocations // encoding and decoding functions must not make any allocations
type TablePushFunc func(tag uint16, value []byte) (n int, err error) type TablePushFunc func(tag uint16, value []byte) (n int, err error)
@ -7,7 +9,8 @@ type TablePushFunc func(tag uint16, value []byte) (n int, err error)
type TablePullFunc func() (tag uint16, value []byte, n int, err error) type TablePullFunc func() (tag uint16, value []byte, n int, err error)
func DecodeTable(data []byte) TablePullFunc { func DecodeTable(data []byte) TablePullFunc {
return func() (tag uint16, value []byte, n int, err error) { n := 0
return func() (tag uint16, value []byte, n_ int, err error) {
tag, nn, err := DecodeI16[uint16](data[n:]) tag, nn, err := DecodeI16[uint16](data[n:])
if err != nil { return tag, value, n, err } if err != nil { return tag, value, n, err }
n += nn n += nn
@ -22,6 +25,17 @@ func DecodeTable(data []byte) TablePullFunc {
} }
} }
func DecodeTableIter(data []byte) iter.Seq2[uint16, []byte] {
return func(yield func(uint16, []byte) bool) {
pull := DecodeTable(data)
for {
tag, value, _, err := pull()
if err != nil { return }
if !yield(tag, value) { return }
}
}
}
func EncodeTable(data []byte) TablePushFunc { func EncodeTable(data []byte) TablePushFunc {
return func(tag uint16, value []byte) (n int, err error) { return func(tag uint16, value []byte) (n int, err error) {
if n >= len(data) { return n, ErrWrongBufferLength } if n >= len(data) { return n, ErrWrongBufferLength }

View File

@ -113,10 +113,10 @@ func DecodeGBEU[T UInt](data []byte) (value T, n int, err error) {
fullValue *= 0x80 fullValue *= 0x80
fullValue += uint64(chunk & 0x7F) fullValue += uint64(chunk & 0x7F)
ccb := chunk >> 7 ccb := chunk >> 7
n += 1
if ccb == 0 { if ccb == 0 {
return T(fullValue), n, nil return T(fullValue), n, nil
} }
n += 1
} }
return 0, n, fmt.Errorf("decoding GBEU: %w", ErrGBEUNotTerminated) return 0, n, fmt.Errorf("decoding GBEU: %w", ErrGBEUNotTerminated)
} }

View File

@ -21,10 +21,16 @@ func TestI8(test *testing.T) {
if err.Error() != "decoding int8: wrong buffer length" { test.Fatal(err) } if err.Error() != "decoding int8: wrong buffer length" { test.Fatal(err) }
for number := range uint8(255) { for number := range uint8(255) {
_, err := EncodeI8[uint8](buffer[:1], number) n, err := EncodeI8[uint8](buffer[:1], number)
if err != nil { test.Fatal(err) } if err != nil { test.Fatal(err) }
decoded, _, err := DecodeI8[uint8](buffer[:1]) if correct, got := 1, n; correct != got {
test.Fatal("not equal:", got)
}
decoded, n, err := DecodeI8[uint8](buffer[:1])
if err != nil { test.Fatal(err) } if err != nil { test.Fatal(err) }
if correct, got := 1, n; correct != got {
test.Fatal("not equal:", got)
}
if decoded != number { if decoded != number {
test.Fatalf("%d != %d", decoded, number) test.Fatalf("%d != %d", decoded, number)
} }
@ -44,10 +50,16 @@ func TestI16(test *testing.T) {
for _ = range largeNumberNTestRounds { for _ = range largeNumberNTestRounds {
number := uint16(rand.Int()) number := uint16(rand.Int())
_, err := EncodeI16[uint16](buffer[:2], number) n, err := EncodeI16[uint16](buffer[:2], number)
if err != nil { test.Fatal(err) } if err != nil { test.Fatal(err) }
decoded, _, err := DecodeI16[uint16](buffer[:2]) if correct, got := 2, n; correct != got {
test.Fatal("not equal:", got)
}
decoded, n, err := DecodeI16[uint16](buffer[:2])
if err != nil { test.Fatal(err) } if err != nil { test.Fatal(err) }
if correct, got := 2, n; correct != got {
test.Fatal("not equal:", got)
}
if decoded != number { if decoded != number {
test.Fatalf("%d != %d", decoded, number) test.Fatalf("%d != %d", decoded, number)
} }
@ -67,10 +79,16 @@ func TestI32(test *testing.T) {
for _ = range largeNumberNTestRounds { for _ = range largeNumberNTestRounds {
number := uint32(rand.Int()) number := uint32(rand.Int())
_, err := EncodeI32[uint32](buffer[:4], number) n, err := EncodeI32[uint32](buffer[:4], number)
if err != nil { test.Fatal(err) } if err != nil { test.Fatal(err) }
decoded, _, err := DecodeI32[uint32](buffer[:4]) if correct, got := 4, n; correct != got {
test.Fatal("not equal:", got)
}
decoded, n, err := DecodeI32[uint32](buffer[:4])
if err != nil { test.Fatal(err) } if err != nil { test.Fatal(err) }
if correct, got := 4, n; correct != got {
test.Fatal("not equal:", got)
}
if decoded != number { if decoded != number {
test.Fatalf("%d != %d", decoded, number) test.Fatalf("%d != %d", decoded, number)
} }
@ -90,10 +108,16 @@ func TestI64(test *testing.T) {
for _ = range largeNumberNTestRounds { for _ = range largeNumberNTestRounds {
number := uint64(rand.Int()) number := uint64(rand.Int())
_, err := EncodeI64[uint64](buffer[:8], number) n, err := EncodeI64[uint64](buffer[:8], number)
if err != nil { test.Fatal(err) } if err != nil { test.Fatal(err) }
decoded, _, err := DecodeI64[uint64](buffer[:8]) if correct, got := 8, n; correct != got {
test.Fatal("not equal:", got)
}
decoded, n, err := DecodeI64[uint64](buffer[:8])
if err != nil { test.Fatal(err) } if err != nil { test.Fatal(err) }
if correct, got := 8, n; correct != got {
test.Fatal("not equal:", got)
}
if decoded != number { if decoded != number {
test.Fatalf("%d != %d", decoded, number) test.Fatalf("%d != %d", decoded, number)
} }
@ -117,8 +141,11 @@ func TestGBEU(test *testing.T) {
if err == nil { test.Fatal("no error") } if err == nil { test.Fatal("no error") }
if err.Error() != "decoding GBEU: GBEU not terminated" { test.Fatal(err) } if err.Error() != "decoding GBEU: GBEU not terminated" { test.Fatal(err) }
_, err = EncodeGBEU[uint64](buffer[:], 0x97) n, err := EncodeGBEU[uint64](buffer[:], 0x97)
if err != nil { test.Fatal(err) } if err != nil { test.Fatal(err) }
if correct, got := 2, n; correct != got {
test.Fatal("not equal:", got)
}
if correct, got := []byte { 0x81, 0x17 }, buffer[:2]; !slices.Equal(correct, got) { if correct, got := []byte { 0x81, 0x17 }, buffer[:2]; !slices.Equal(correct, got) {
message := "not equal:" message := "not equal:"
for _, item := range got { for _, item := range got {
@ -126,14 +153,20 @@ func TestGBEU(test *testing.T) {
} }
test.Fatal(message) test.Fatal(message)
} }
decoded, _, err := DecodeGBEU[uint64](buffer[:]) decoded, n, err := DecodeGBEU[uint64](buffer[:])
if err != nil { test.Fatal(err) } if err != nil { test.Fatal(err) }
if correct, got := 2, n; correct != got {
test.Fatal("not equal:", got)
}
if correct, got := uint64(0x97), decoded; correct != got { if correct, got := uint64(0x97), decoded; correct != got {
test.Fatalf("not equal: %x", got) test.Fatalf("not equal: %x", got)
} }
_, err = EncodeGBEU[uint64](buffer[:], 0x123456) n, err = EncodeGBEU[uint64](buffer[:], 0x123456)
if err != nil { test.Fatal(err) } if err != nil { test.Fatal(err) }
if correct, got := 3, n; correct != got {
test.Fatal("not equal:", got)
}
if correct, got := []byte { 0xc8, 0xe8, 0x56 }, buffer[:3]; !slices.Equal(correct, got) { if correct, got := []byte { 0xc8, 0xe8, 0x56 }, buffer[:3]; !slices.Equal(correct, got) {
message := "not equal:" message := "not equal:"
for _, item := range got { for _, item := range got {
@ -141,15 +174,21 @@ func TestGBEU(test *testing.T) {
} }
test.Fatal(message) test.Fatal(message)
} }
decoded, _, err = DecodeGBEU[uint64](buffer[:]) decoded, n, err = DecodeGBEU[uint64](buffer[:])
if err != nil { test.Fatal(err) } if err != nil { test.Fatal(err) }
if correct, got := 3, n; correct != got {
test.Fatal("not equal:", got)
}
if correct, got := uint64(0x123456), decoded; correct != got { if correct, got := uint64(0x123456), decoded; correct != got {
test.Fatalf("not equal: %x", got) test.Fatalf("not equal: %x", got)
} }
maxGBEU64 := []byte { 0x81, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F } maxGBEU64 := []byte { 0x81, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F }
_, err = EncodeGBEU[uint64](buffer[:], 0xFFFFFFFFFFFFFFFF) n, err = EncodeGBEU[uint64](buffer[:], 0xFFFFFFFFFFFFFFFF)
if err != nil { test.Fatal(err) } if err != nil { test.Fatal(err) }
if correct, got := 10, n; correct != got {
test.Fatal("not equal:", got)
}
if correct, got := maxGBEU64, buffer[:10]; !slices.Equal(correct, got) { if correct, got := maxGBEU64, buffer[:10]; !slices.Equal(correct, got) {
message := "not equal:" message := "not equal:"
for _, item := range got { for _, item := range got {
@ -157,19 +196,28 @@ func TestGBEU(test *testing.T) {
} }
test.Fatal(message) test.Fatal(message)
} }
decoded, _, err = DecodeGBEU[uint64](buffer[:]) decoded, n, err = DecodeGBEU[uint64](buffer[:])
if err != nil { test.Fatal(err) } if err != nil { test.Fatal(err) }
if correct, got := 10, n; correct != got {
test.Fatal("not equal:", got)
}
if correct, got := uint64(0xFFFFFFFFFFFFFFFF), decoded; correct != got { if correct, got := uint64(0xFFFFFFFFFFFFFFFF), decoded; correct != got {
test.Fatalf("not equal: %x", got) test.Fatalf("not equal: %x", got)
} }
_, err = EncodeGBEU[uint64](buffer[:], 11) n, err = EncodeGBEU[uint64](buffer[:], 11)
if err != nil { test.Fatal(err) } if err != nil { test.Fatal(err) }
if correct, got := 1, n; correct != got {
test.Fatal("not equal:", got)
}
if correct, got := byte(0xb), buffer[0]; correct != got { if correct, got := byte(0xb), buffer[0]; correct != got {
test.Fatal("not equal:", got) test.Fatal("not equal:", got)
} }
decoded, _, err = DecodeGBEU[uint64](buffer[:]) decoded, n, err = DecodeGBEU[uint64](buffer[:])
if err != nil { test.Fatal(err) } if err != nil { test.Fatal(err) }
if correct, got := 1, n; correct != got {
test.Fatal("not equal:", got)
}
if correct, got := uint64(0xb), decoded; correct != got { if correct, got := uint64(0xb), decoded; correct != got {
test.Fatalf("not equal: %x", got) test.Fatalf("not equal: %x", got)
} }