1
0
mirror of https://github.com/fumiama/go-simple-protobuf.git synced 2026-06-05 02:00:33 +08:00

feat: add iterator

This commit is contained in:
源文雨
2024-02-26 03:44:30 +09:00
parent 93032ad80a
commit 6c9102f75f
3 changed files with 115 additions and 5 deletions

67
reader.go Normal file
View File

@@ -0,0 +1,67 @@
package spb
import "io"
type Iterator struct {
r io.Reader
structlen, reallen uint32
i uint32
v []byte
}
// NewReader 迭代器形式读取而非一次解析完
func NewReader(r io.Reader) (it Iterator, err error) {
it.structlen, it.reallen, err = ReadNum(r)
if err != nil {
return
}
if it.structlen <= 1 || it.structlen >= uint32(1)<<20 {
err = ErrInvalidStructLen
return
}
it.r = r
return
}
// Next 是否有下一个
func (it *Iterator) Next() bool {
if it.i >= it.structlen {
return false
}
var offset, datalen, n uint32
var err error
offset, n, err = ReadNum(it.r)
it.reallen += n
if err != nil {
return false
}
datalen, n, err = ReadNum(it.r)
it.reallen += n
if err != nil {
return false
}
if datalen == 0 {
return false
}
if datalen > offset {
return false
}
it.v = append(it.v[:0], make([]byte, datalen)...)
x, err := it.r.Read(it.v)
it.reallen += uint32(x)
if err != nil {
return false
}
it.i += offset
return true
}
// Bytes 本次迭代的原始值
func (it *Iterator) Bytes() []byte {
return it.v
}
// String 将本次迭代的值解释为 string
func (it *Iterator) String() string {
return string(it.v)
}

42
reader_test.go Normal file
View File

@@ -0,0 +1,42 @@
package spb
import (
"bufio"
"fmt"
"os"
"testing"
)
func TestReader(t *testing.T) {
f, err := os.Open("dict.sp")
if err != nil {
t.Fatal(err)
}
defer f.Close()
ft, err := os.Open("dict.txt")
if err != nil {
t.Fatal(err)
}
defer ft.Close()
sc := bufio.NewScanner(ft)
var s Iterator
i := 1
for sc.Scan() {
s, err = NewReader(f)
if err != nil {
break
}
if !s.Next() {
t.Fatal("unexpected no next")
}
t0 := s.String()
if !s.Next() {
t.Fatal("unexpected no next")
}
t1 := s.String()
if fmt.Sprint(t0, "\t", t1) != sc.Text() {
t.Fatal("invalid text @ line", i)
}
i++
}
}

11
spb.go
View File

@@ -2,7 +2,7 @@ package spb
import "io"
func ReadNum(r io.Reader) (n uint32, cnt int, err error) {
func ReadNum(r io.Reader) (n uint32, cnt uint32, err error) {
var buf [1]byte
for cnt < 5 {
_, err = r.Read(buf[:])
@@ -43,7 +43,7 @@ type SimplePB struct {
}
func NewSimplePB(r io.Reader) (s SimplePB, err error) {
cnt := 0
cnt := uint32(0)
s.StructLen, cnt, err = ReadNum(r)
if err != nil {
s.RealLen = uint32(cnt)
@@ -55,7 +55,7 @@ func NewSimplePB(r io.Reader) (s SimplePB, err error) {
return
}
var offset, datalen uint32
n := 0
n := uint32(0)
for i := uint32(0); i < s.StructLen; i += offset {
offset, n, err = ReadNum(r)
cnt += n
@@ -75,8 +75,9 @@ func NewSimplePB(r io.Reader) (s SimplePB, err error) {
break
}
t := make([]byte, datalen)
n, err = r.Read(t)
cnt += n
x := 0
x, err = r.Read(t)
cnt += uint32(x)
if err != nil {
break
}