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

feat: add writer

This commit is contained in:
源文雨
2024-02-26 04:28:37 +09:00
parent 6c9102f75f
commit 83dfd6288b
6 changed files with 144 additions and 36 deletions

View File

@@ -1,4 +1,3 @@
# go-simple-protobuf
> Note: Only supports reading.
Golang implementation of [simple-protobuf](https://github.com/fumiama/simple-protobuf)

View File

@@ -65,3 +65,13 @@ func (it *Iterator) Bytes() []byte {
func (it *Iterator) String() string {
return string(it.v)
}
// Cap structlen 结构体带 padding 的长度
func (it *Iterator) Cap() uint32 {
return it.structlen
}
// Len reallen (迭代器目前迭代到的实值总长, 不带 padding)
func (it *Iterator) Len() uint32 {
return it.reallen
}

35
spb.go
View File

@@ -2,41 +2,6 @@ package spb
import "io"
func ReadNum(r io.Reader) (n uint32, cnt uint32, err error) {
var buf [1]byte
for cnt < 5 {
_, err = r.Read(buf[:])
if err != nil {
return
}
n |= uint32(buf[0]&0x7f) << (7 * cnt)
cnt++
if buf[0]&0x80 == 0 {
break
}
}
return
}
/*
func WriteNum(w io.Writer, n uint32) (cnt int, err error) {
var buf [1]byte
for n > 0 {
buf[0] = uint8(n & 0x7f)
if n>>7 > 0 {
buf[0] |= 0x80
}
_, err = w.Write(buf[:])
if err != nil {
return
}
n >>= 7
cnt++
}
return
}
*/
type SimplePB struct {
StructLen, RealLen uint32
Target [][]byte

36
utils.go Normal file
View File

@@ -0,0 +1,36 @@
package spb
import "io"
func ReadNum(r io.Reader) (n uint32, cnt uint32, err error) {
var buf [1]byte
for cnt < 5 {
_, err = r.Read(buf[:])
if err != nil {
return
}
n |= uint32(buf[0]&0x7f) << (7 * cnt)
cnt++
if buf[0]&0x80 == 0 {
break
}
}
return
}
func WriteNum(w io.Writer, n uint32) (cnt uint32, err error) {
var buf [1]byte
for n > 0 {
buf[0] = uint8(n & 0x7f)
if n>>7 > 0 {
buf[0] |= 0x80
}
_, err = w.Write(buf[:])
if err != nil {
return
}
n >>= 7
cnt++
}
return
}

62
writer.go Normal file
View File

@@ -0,0 +1,62 @@
package spb
import (
"bytes"
"io"
)
type Constructor struct {
structlen, reallen uint32
body bytes.Buffer
}
// NewWriter 新的写入构造器
func NewWriter(buf []byte) (c Constructor) {
c.body = *bytes.NewBuffer(buf)
return
}
// WriteString 按字符串写入一项
func (c *Constructor) WriteString(s string, cap uint32) error {
if int(cap) < len(s) {
return ErrInvalidDataLen
}
cnt, err := WriteNum(&c.body, cap)
if err != nil {
return err
}
c.structlen += cap
c.reallen += cnt
cnt, err = WriteNum(&c.body, uint32(len(s)))
if err != nil {
return err
}
c.reallen += cnt
_, err = c.body.WriteString(s)
if err != nil {
return err
}
c.reallen += uint32(len(s))
return nil
}
// Cap structlen 目前写入的总长, 带 padding
func (c *Constructor) Cap() uint32 {
return c.structlen
}
// Len reallen 目前写入的实值总长, 不带 padding
func (c *Constructor) Len() uint32 {
return c.reallen
}
// WriteTo 将当前结果写出, 返回写入的实际长度
func (c *Constructor) WriteTo(w io.Writer) (int64, error) {
cnt, err := WriteNum(w, c.structlen)
if err != nil {
return int64(cnt), err
}
n, err := w.Write(c.body.Bytes())
cnt += uint32(n)
return int64(cnt), err
}

36
writer_test.go Normal file
View File

@@ -0,0 +1,36 @@
package spb
import (
"bufio"
"bytes"
"os"
"strings"
"testing"
)
func TestWriter(t *testing.T) {
f := bytes.NewBuffer(make([]byte, 0, 65536))
ft, err := os.Open("dict.txt")
if err != nil {
t.Fatal(err)
}
defer ft.Close()
sc := bufio.NewScanner(ft)
for sc.Scan() {
c := Constructor{}
for _, s := range strings.Split(sc.Text(), "\t") {
err = c.WriteString(s, 127)
if err != nil {
t.Fatal(err)
}
}
c.WriteTo(f)
}
real, err := os.ReadFile("dict.sp")
if err != nil {
t.Fatal(err)
}
if !bytes.Equal(real, f.Bytes()) {
t.Fail()
}
}