Browse Source

Refactor tag encoder to optimize buffer reuse, simplify tag marshaling, and improve event handling; enhance tests with additional coverage and example validation.

main
mleku 5 months ago
parent
commit
7d20a51508
No known key found for this signature in database
  1. 31
      pkg/encoders/event/event.go
  2. 41
      pkg/encoders/event/event_test.go
  3. 6
      pkg/encoders/ints/ints.go
  4. 3
      pkg/encoders/tag/tag.go
  5. 14
      pkg/encoders/tag/tags.go
  6. 1
      pkg/utils/bufpool/bufpool.go

31
pkg/encoders/event/event.go

@ -111,27 +111,11 @@ func (ev *E) MarshalJSON() (b []byte, err error) {
b = ints.New(ev.Kind).Marshal(b) b = ints.New(ev.Kind).Marshal(b)
b = append(b, `,"`...) b = append(b, `,"`...)
b = append(b, jTags...) b = append(b, jTags...)
b = append(b, `":[`...) b = append(b, `":`...)
if ev.Tags != nil { if ev.Tags != nil {
lts := len(*ev.Tags) - 1 b = ev.Tags.Marshal(b)
for i, tt := range *ev.Tags {
b = append(b, '[')
lt := len(tt.T) - 1
for j, t := range tt.T {
b = append(b, '"')
b = append(b, t...)
b = append(b, '"')
if j < lt {
b = append(b, ',')
}
}
b = append(b, ']')
if i < lts {
b = append(b, ',')
}
}
} }
b = append(b, `],"`...) b = append(b, `,"`...)
b = append(b, jContent...) b = append(b, jContent...)
b = append(b, `":"`...) b = append(b, `":"`...)
// it can happen the slice has insufficient capacity to hold the content AND // it can happen the slice has insufficient capacity to hold the content AND
@ -175,6 +159,7 @@ func (ev *E) UnmarshalJSON(b []byte) (err error) {
goto BetweenKeys goto BetweenKeys
} }
} }
log.I.F("start")
goto eof goto eof
BetweenKeys: BetweenKeys:
for ; len(b) > 0; b = b[1:] { for ; len(b) > 0; b = b[1:] {
@ -187,6 +172,7 @@ BetweenKeys:
goto InKey goto InKey
} }
} }
log.I.F("BetweenKeys")
goto eof goto eof
InKey: InKey:
for ; len(b) > 0; b = b[1:] { for ; len(b) > 0; b = b[1:] {
@ -196,6 +182,7 @@ InKey:
} }
key = append(key, b[0]) key = append(key, b[0])
} }
log.I.F("InKey")
goto eof goto eof
InKV: InKV:
for ; len(b) > 0; b = b[1:] { for ; len(b) > 0; b = b[1:] {
@ -208,6 +195,7 @@ InKV:
goto InVal goto InVal
} }
} }
log.I.F("InKV")
goto eof goto eof
InVal: InVal:
// Skip whitespace before value // Skip whitespace before value
@ -298,9 +286,11 @@ InVal:
if !utils.FastEqual(jCreatedAt, key) { if !utils.FastEqual(jCreatedAt, key) {
goto invalid goto invalid
} }
if b, err = ints.New(0).Unmarshal(b); chk.T(err) { i := ints.New(0)
if b, err = i.Unmarshal(b); chk.T(err) {
return return
} }
ev.CreatedAt = i.Int64()
goto BetweenKV goto BetweenKV
} else { } else {
goto invalid goto invalid
@ -315,7 +305,6 @@ BetweenKV:
if isWhitespace(b[0]) { if isWhitespace(b[0]) {
continue continue
} }
switch { switch {
case len(b) == 0: case len(b) == 0:
return return

41
pkg/encoders/event/event_test.go

@ -1,16 +1,21 @@
package event package event
import ( import (
"bufio"
"bytes"
"encoding/json" "encoding/json"
"testing" "testing"
"time" "time"
"lol.mleku.dev/chk" "lol.mleku.dev/chk"
"lol.mleku.dev/log"
"lukechampine.com/frand" "lukechampine.com/frand"
"next.orly.dev/pkg/encoders/event/examples"
"next.orly.dev/pkg/encoders/hex" "next.orly.dev/pkg/encoders/hex"
"next.orly.dev/pkg/encoders/tag" "next.orly.dev/pkg/encoders/tag"
"next.orly.dev/pkg/utils" "next.orly.dev/pkg/utils"
"next.orly.dev/pkg/utils/bufpool" "next.orly.dev/pkg/utils/bufpool"
"next.orly.dev/pkg/utils/units"
) )
func TestMarshalJSONUnmarshalJSON(t *testing.T) { func TestMarshalJSONUnmarshalJSON(t *testing.T) {
@ -35,13 +40,12 @@ func TestMarshalJSONUnmarshalJSON(t *testing.T) {
`) `)
ev.Sig = frand.Bytes(64) ev.Sig = frand.Bytes(64)
// log.I.S(ev) // log.I.S(ev)
b, err := ev.MarshalJSON() // b, err := ev.MarshalJSON()
var err error
var b []byte
if b, err = json.Marshal(ev); chk.E(err) { if b, err = json.Marshal(ev); chk.E(err) {
t.Fatal(err) t.Fatal(err)
} }
if err != nil {
t.Fatal(err)
}
var bc []byte var bc []byte
bc = append(bc, b...) bc = append(bc, b...)
ev2 := New() ev2 := New()
@ -49,7 +53,7 @@ func TestMarshalJSONUnmarshalJSON(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
var b2 []byte var b2 []byte
if b2, err = ev.MarshalJSON(); err != nil { if b2, err = json.Marshal(ev2); err != nil {
t.Fatal(err) t.Fatal(err)
} }
if !utils.FastEqual(bc, b2) { if !utils.FastEqual(bc, b2) {
@ -65,5 +69,30 @@ func TestMarshalJSONUnmarshalJSON(t *testing.T) {
} }
func TestExamplesCache(t *testing.T) { func TestExamplesCache(t *testing.T) {
scanner := bufio.NewScanner(bytes.NewBuffer(examples.Cache))
scanner.Buffer(make([]byte, 0, 4*units.Mb), 4*units.Mb)
var err error
for scanner.Scan() {
b := scanner.Bytes()
c := bufpool.Get()
c = c[:0]
c = append(c, b...)
ev := New()
if err = ev.UnmarshalJSON(b); chk.E(err) {
t.Fatal(err)
}
var b2 []byte
if b2, err = ev.MarshalJSON(); err != nil {
t.Fatal(err)
}
if !utils.FastEqual(c, b2) {
log.I.F("\n%s\n%s", c, b2)
t.Fatalf("failed to re-marshal back original")
}
ev.Free()
// Don't return scanner.Bytes() to the pool as it's not a buffer we own
// bufpool.PutBytes(b)
bufpool.PutBytes(b2)
bufpool.PutBytes(c)
}
} }

6
pkg/encoders/ints/ints.go

@ -109,6 +109,7 @@ func (n *T) Unmarshal(b []byte) (r []byte, err error) {
break break
} }
} }
// log.I.F("%s", b)
if len(b) == 0 { if len(b) == 0 {
err = io.EOF err = io.EOF
return return
@ -116,6 +117,7 @@ func (n *T) Unmarshal(b []byte) (r []byte, err error) {
// count the digits // count the digits
for ; sLen < len(b) && b[sLen] >= zero && b[sLen] <= nine && b[sLen] != ','; sLen++ { for ; sLen < len(b) && b[sLen] >= zero && b[sLen] <= nine && b[sLen] != ','; sLen++ {
} }
// log.I.F("%s", b[:sLen])
if sLen == 0 { if sLen == 0 {
err = errorf.E("zero length number") err = errorf.E("zero length number")
return return
@ -127,9 +129,13 @@ func (n *T) Unmarshal(b []byte) (r []byte, err error) {
// the length of the string found // the length of the string found
r = b[sLen:] r = b[sLen:]
b = b[:sLen] b = b[:sLen]
// log.I.F("\n%s\n%s", b, r)
n.N = uint64(b[0]) - zero
b = b[1:]
for _, ch := range b { for _, ch := range b {
ch -= zero ch -= zero
n.N = n.N*10 + uint64(ch) n.N = n.N*10 + uint64(ch)
} }
// log.I.F("%d", n.N)
return return
} }

3
pkg/encoders/tag/tag.go

@ -33,8 +33,7 @@ func (t *T) Free() {
// Marshal encodes a tag.T as standard minified JSON array of strings. // Marshal encodes a tag.T as standard minified JSON array of strings.
// //
// Call bufpool.PutBytes(b) to return the buffer to the bufpool after use. // Call bufpool.PutBytes(b) to return the buffer to the bufpool after use.
func (t *T) Marshal() (b []byte) { func (t *T) Marshal(dst []byte) (b []byte) {
dst := t.b
dst = append(dst, '[') dst = append(dst, '[')
for i, s := range t.T { for i, s := range t.T {
dst = text.AppendQuote(dst, s, text.NostrEscape) dst = text.AppendQuote(dst, s, text.NostrEscape)

14
pkg/encoders/tag/tags.go

@ -16,7 +16,19 @@ func (s *S) MarshalJSON() (b []byte, err error) {
b = bufpool.Get() b = bufpool.Get()
b = append(b, '[') b = append(b, '[')
for i, ss := range *s { for i, ss := range *s {
b = append(b, ss.Marshal()...) b = ss.Marshal(b)
if i < len(*s)-1 {
b = append(b, ',')
}
}
b = append(b, ']')
return
}
func (s *S) Marshal(dst []byte) (b []byte) {
b = append(dst, '[')
for i, ss := range *s {
b = ss.Marshal(b)
if i < len(*s)-1 { if i < len(*s)-1 {
b = append(b, ',') b = append(b, ',')
} }

1
pkg/utils/bufpool/bufpool.go

@ -74,5 +74,6 @@ func PutBytes(b []byte) {
return fmt.Sprintf("returning bytes to buffer: %p", ptr) return fmt.Sprintf("returning bytes to buffer: %p", ptr)
}, },
) )
b = b[:0]
Put(b) Put(b)
} }

Loading…
Cancel
Save