fuller implementation of chunk and unmarshal
This commit is contained in:
parent
3004475000
commit
9514f9c374
|
@ -7,7 +7,7 @@ func Map[T, V any](c Vector[T], f func(T) V) Vector[V] {
|
||||||
out[index] = f(c[index])
|
out[index] = f(c[index])
|
||||||
}
|
}
|
||||||
|
|
||||||
return From(out)
|
return From(out...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func Filter[T any](v Vector[T], f func(T) bool) Vector[T] {
|
func Filter[T any](v Vector[T], f func(T) bool) Vector[T] {
|
||||||
|
@ -27,7 +27,7 @@ func Take[T any](v Vector[T], howMany int) Vector[T] {
|
||||||
if len(v) < howMany {
|
if len(v) < howMany {
|
||||||
howMany = len(v)
|
howMany = len(v)
|
||||||
}
|
}
|
||||||
return From(v[:howMany-1])
|
return From(v[:howMany-1]...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func Any[T any](v Vector[T], f func(T) bool) bool {
|
func Any[T any](v Vector[T], f func(T) bool) bool {
|
||||||
|
@ -39,6 +39,15 @@ func Any[T any](v Vector[T], f func(T) bool) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func AnyOf[T comparable](v Vector[T], t T) bool {
|
||||||
|
for _, vT := range v {
|
||||||
|
if vT == t {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
type numeric interface {
|
type numeric interface {
|
||||||
~int | ~int8 | ~int16 | ~int32 | ~int64 | ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~float32 | ~float64
|
~int | ~int8 | ~int16 | ~int32 | ~int64 | ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~float32 | ~float64
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,7 @@ func WithCap[T any](capacity int) Vector[T] {
|
||||||
return make(Vector[T], 0, capacity)
|
return make(Vector[T], 0, capacity)
|
||||||
}
|
}
|
||||||
|
|
||||||
func From[T any](v []T) Vector[T] {
|
func From[T any](v ...T) Vector[T] {
|
||||||
return Vector[T](v)
|
return Vector[T](v)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -45,7 +45,7 @@ func (v Vector[T]) Append(t ...T) Vector[T] {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v Vector[T]) Remove(index int) Vector[T] {
|
func (v Vector[T]) Remove(index int) Vector[T] {
|
||||||
return From(append(v[:index], v[index+1:]...))
|
return From(append(v[:index], v[index+1:]...)...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Faster remove function that can be used on vectors where ordering doesn't matter
|
// Faster remove function that can be used on vectors where ordering doesn't matter
|
||||||
|
@ -110,12 +110,12 @@ func (v Vector[T]) Sub(start, end int) Vector[T] {
|
||||||
v.panicIndex(end)
|
v.panicIndex(end)
|
||||||
}
|
}
|
||||||
if start < 0 {
|
if start < 0 {
|
||||||
return From(v[:end])
|
return From(v[:end]...)
|
||||||
}
|
}
|
||||||
if end < 0 {
|
if end < 0 {
|
||||||
return From(v[start:])
|
return From(v[start:]...)
|
||||||
}
|
}
|
||||||
return From(v[start:end])
|
return From(v[start:end]...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v Vector[T]) Filter(f func(T) bool) Vector[T] {
|
func (v Vector[T]) Filter(f func(T) bool) Vector[T] {
|
||||||
|
|
|
@ -59,18 +59,18 @@ func TestVector(t *testing.T) {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"append": func(that *require.Assertions) {
|
"append": func(that *require.Assertions) {
|
||||||
v := coll.From([]int{1, 2, 3}).Append(4, 5, 6)
|
v := coll.From([]int{1, 2, 3}...).Append(4, 5, 6)
|
||||||
that.Equal(6, len(v))
|
that.Equal(6, len(v))
|
||||||
that.EqualValues([]int{1, 2, 3, 4, 5, 6}, v)
|
that.EqualValues([]int{1, 2, 3, 4, 5, 6}, v)
|
||||||
},
|
},
|
||||||
"getsoft": func(that *require.Assertions) {
|
"getsoft": func(that *require.Assertions) {
|
||||||
v := coll.From([]int{1, 2, 3})
|
v := coll.From([]int{1, 2, 3}...)
|
||||||
that.Equal(2, v.GetSoft(1))
|
that.Equal(2, v.GetSoft(1))
|
||||||
that.Zero(v.GetSoft(-1000))
|
that.Zero(v.GetSoft(-1000))
|
||||||
that.Zero(v.GetSoft(1000))
|
that.Zero(v.GetSoft(1000))
|
||||||
},
|
},
|
||||||
"get": func(that *require.Assertions) {
|
"get": func(that *require.Assertions) {
|
||||||
v := coll.From([]int{1, 2, 3})
|
v := coll.From([]int{1, 2, 3}...)
|
||||||
that.Equal(2, v.Get(1))
|
that.Equal(2, v.Get(1))
|
||||||
that.Panics(func() {
|
that.Panics(func() {
|
||||||
v.Get(-1000)
|
v.Get(-1000)
|
||||||
|
@ -80,7 +80,7 @@ func TestVector(t *testing.T) {
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
"clone": func(that *require.Assertions) {
|
"clone": func(that *require.Assertions) {
|
||||||
v := coll.From([]int{1, 2, 3})
|
v := coll.From([]int{1, 2, 3}...)
|
||||||
|
|
||||||
v1 := v.Clone().Set(1, 1)
|
v1 := v.Clone().Set(1, 1)
|
||||||
that.Equal(3, len(v1))
|
that.Equal(3, len(v1))
|
||||||
|
@ -88,7 +88,7 @@ func TestVector(t *testing.T) {
|
||||||
that.EqualValues([]int{1, 2, 3}, v)
|
that.EqualValues([]int{1, 2, 3}, v)
|
||||||
},
|
},
|
||||||
"set": func(that *require.Assertions) {
|
"set": func(that *require.Assertions) {
|
||||||
v := coll.From([]int{1, 2, 3})
|
v := coll.From([]int{1, 2, 3}...)
|
||||||
|
|
||||||
v1 := v.Clone().Set(1, 1)
|
v1 := v.Clone().Set(1, 1)
|
||||||
that.Equal(3, len(v1))
|
that.Equal(3, len(v1))
|
||||||
|
@ -110,7 +110,7 @@ func TestVector(t *testing.T) {
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
"sub": func(that *require.Assertions) {
|
"sub": func(that *require.Assertions) {
|
||||||
v := coll.From([]int{0, 1, 2, 3, 4, 5, 6})
|
v := coll.From([]int{0, 1, 2, 3, 4, 5, 6}...)
|
||||||
|
|
||||||
v1 := v.Clone().Sub(2, 4)
|
v1 := v.Clone().Sub(2, 4)
|
||||||
that.Equal(2, len(v1))
|
that.Equal(2, len(v1))
|
||||||
|
@ -139,13 +139,13 @@ func TestVector(t *testing.T) {
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
"filter": func(that *require.Assertions) {
|
"filter": func(that *require.Assertions) {
|
||||||
v := coll.From([]int{1, 2, 3, 4, 5, 6})
|
v := coll.From([]int{1, 2, 3, 4, 5, 6}...)
|
||||||
v = v.Filter(func(i int) bool { return i%2 == 0 })
|
v = v.Filter(func(i int) bool { return i%2 == 0 })
|
||||||
that.Len(v, 3)
|
that.Len(v, 3)
|
||||||
},
|
},
|
||||||
"any": func(that *require.Assertions) {
|
"any": func(that *require.Assertions) {
|
||||||
that.True(coll.From([]int{1, 2, 3, 4, 5, 6}).Any(func(i int) bool { return i == 3 }))
|
that.True(coll.From([]int{1, 2, 3, 4, 5, 6}...).Any(func(i int) bool { return i == 3 }))
|
||||||
that.False(coll.From([]int{1, 2, 3, 4, 5, 6}).Any(func(i int) bool { return i == 666 }))
|
that.False(coll.From([]int{1, 2, 3, 4, 5, 6}...).Any(func(i int) bool { return i == 666 }))
|
||||||
},
|
},
|
||||||
"take": func(that *require.Assertions) {
|
"take": func(that *require.Assertions) {
|
||||||
that.EqualValues([]int{1, 2, 3}, coll.From([]int{1, 2, 3, 4, 5, 6}).Take(3))
|
that.EqualValues([]int{1, 2, 3}, coll.From([]int{1, 2, 3, 4, 5, 6}).Take(3))
|
||||||
|
|
|
@ -3,16 +3,22 @@ package chunk
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"unicode"
|
|
||||||
"unicode/utf8"
|
|
||||||
|
|
||||||
"sectorinf.com/emilis/flabk/pkg/coll"
|
"sectorinf.com/emilis/flabk/pkg/coll"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
escapeChar = '\\'
|
||||||
|
unicodeEscape = 'u'
|
||||||
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
ErrNoMatch = errors.New("no matching")
|
ErrNoMatch = errors.New("no matching")
|
||||||
ErrMapMemberNotString = errors.New("map member not a string")
|
ErrMapMemberNotString = errors.New("map member not a string")
|
||||||
ErrUnexpectedSymbol = errors.New("unexpected symbol")
|
ErrUnexpectedSymbol = errors.New("unexpected symbol")
|
||||||
|
ErrMissingValue = errors.New("missing value")
|
||||||
|
ErrEscapeAtEnd = errors.New("escape character at the end of value")
|
||||||
|
ErrIncompleteEscape = errors.New("incomplete unicode escape sequence")
|
||||||
)
|
)
|
||||||
|
|
||||||
type Chunk struct {
|
type Chunk struct {
|
||||||
|
@ -24,72 +30,120 @@ type Chunk struct {
|
||||||
globRight int
|
globRight int
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c Chunk) LeftByte() byte {
|
||||||
|
return c.vector[c.posLeft]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c Chunk) Null() bool {
|
||||||
|
return (c.posRight+1)-c.posLeft >= 4 && c.vector[c.posLeft] == 'n' && c.vector[c.posLeft+1] == 'u' && c.vector[c.posLeft+2] == 'l' && c.vector[c.posLeft+3] == 'l'
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c Chunk) LeftPosf(format string, args ...any) error {
|
||||||
|
return fmt.Errorf(fmt.Sprintf("[%d] %s", c.globLeft, format), args...)
|
||||||
|
}
|
||||||
|
|
||||||
// Match finds the matching closer to the symbol at the left position and sets the
|
// Match finds the matching closer to the symbol at the left position and sets the
|
||||||
// right position to this index
|
// right position to this index
|
||||||
func (c Chunk) Match() (Chunk, error) {
|
func (c Chunk) Match() (Chunk, error) {
|
||||||
s, ok := matchers[c.vector[c.posLeft]]
|
start := c.vector[c.posLeft]
|
||||||
|
matcher, ok := matchers[start]
|
||||||
if !ok {
|
if !ok {
|
||||||
panic(fmt.Sprintf("Match called on %c with no matcher defined", c.vector[c.posLeft]))
|
panic(fmt.Sprintf("Match called on %c with no matcher defined", c.vector[c.posLeft]))
|
||||||
}
|
}
|
||||||
if s.StartFromRight {
|
|
||||||
for c.posRight > 0 {
|
for index := c.posLeft + 1; index < len(c.vector); index++ {
|
||||||
if c.vector[c.posRight] == s.MatchByte {
|
if start != '"' && c.vector[index] == start {
|
||||||
return c, nil
|
sub, err := c.Child(index, len(c.vector)).Match()
|
||||||
|
if err != nil {
|
||||||
|
return c, fmt.Errorf("[%d] child %w", c.globLeft+(c.posLeft-index), err)
|
||||||
}
|
}
|
||||||
c.posRight--
|
index += sub.posRight
|
||||||
c.globRight--
|
continue
|
||||||
}
|
}
|
||||||
} else {
|
if c.vector[index] == escapeChar {
|
||||||
for index := c.posLeft + 1; index < len(c.vector); index++ {
|
if index+1 == len(c.vector) {
|
||||||
if c.vector[index] == s.MatchByte {
|
return c, fmt.Errorf("[%d] %w", c.globLeft+(c.posLeft-index), ErrEscapeAtEnd)
|
||||||
c.posRight = index
|
|
||||||
c.globRight += (c.posLeft + 1) - index
|
|
||||||
return c, nil
|
|
||||||
}
|
}
|
||||||
|
if c.vector[index+1] == unicodeEscape {
|
||||||
|
if index+6 >= len(c.vector) {
|
||||||
|
return c, fmt.Errorf("[%d] %w", c.globLeft+(c.posLeft+index), ErrIncompleteEscape)
|
||||||
|
}
|
||||||
|
index += 5
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
index++
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if c.vector[index] == matcher {
|
||||||
|
c.globRight -= c.posRight - index
|
||||||
|
c.posRight = index
|
||||||
|
return c, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return c, fmt.Errorf("%w %c", ErrNoMatch, c.vector[c.posLeft])
|
return c, c.LeftPosf("%w %c", ErrNoMatch, c.vector[c.posLeft])
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c Chunk) Copy() Chunk {
|
func (c Chunk) Copy() Chunk {
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c Chunk) Left() byte {
|
|
||||||
return c.vector[c.posLeft]
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sub returns an inclusive subchunk of [left;right]
|
// Sub returns an inclusive subchunk of [left;right]
|
||||||
func (c Chunk) Sub() Chunk {
|
func (c Chunk) Sub() Chunk {
|
||||||
return New(c.vector[c.posLeft : c.posRight+1])
|
c = c.Child(c.posLeft, c.posRight+1)
|
||||||
|
// To be inclusive we incremented posRight above, so
|
||||||
|
// to restore the original position, we must decrement
|
||||||
|
// it here before returning. Only if we have room to decrement it
|
||||||
|
if c.posRight > 0 {
|
||||||
|
c.posRight--
|
||||||
|
c.globRight--
|
||||||
|
}
|
||||||
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
// CookieCutter returns a subchunk of (left;right)
|
// CookieCutter returns a subchunk of (left;right)
|
||||||
func (c Chunk) CookieCutter() Chunk {
|
func (c Chunk) CookieCutter() Chunk {
|
||||||
return New(c.vector[c.posLeft+1 : c.posRight])
|
return c.Child(c.posLeft+1, c.posRight)
|
||||||
|
}
|
||||||
|
|
||||||
|
func spaceAtIndex(v coll.Vector[byte], index int) bool {
|
||||||
|
return v[index] == 0x9 || v[index] == 0xa || v[index] == 0xd || v[index] == 0x20
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c Chunk) AtSpace() bool {
|
func (c Chunk) AtSpace() bool {
|
||||||
r, _ := utf8.DecodeRune(c.vector[c.posLeft:])
|
return spaceAtIndex(c.vector, c.posLeft)
|
||||||
return unicode.IsSpace(r)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c Chunk) Seek() Chunk {
|
func (c Chunk) Seek() Chunk {
|
||||||
for c.posLeft < len(c.vector) && c.AtSpace() {
|
for c.posLeft < len(c.vector) && c.AtSpace() {
|
||||||
|
c.globLeft++
|
||||||
c.posLeft++
|
c.posLeft++
|
||||||
}
|
}
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Step increments the left position by 1 if b
|
||||||
|
// is the byte at the current left position
|
||||||
|
func (c Chunk) StepIf(b byte) Chunk {
|
||||||
|
if c.vector[c.posLeft] != b {
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
c.posLeft++
|
||||||
|
c.globLeft++
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
func (c Chunk) ValueEnd() (Chunk, error) {
|
func (c Chunk) ValueEnd() (Chunk, error) {
|
||||||
switch c.vector[c.posLeft] {
|
switch c.vector[c.posLeft] {
|
||||||
case '"', '{', '[':
|
case '"', '{', '[':
|
||||||
return c.Match()
|
return c.Match()
|
||||||
default:
|
default:
|
||||||
for index := c.posLeft; index <= c.posRight; index++ {
|
for index := c.posLeft; index <= c.posRight; index++ {
|
||||||
if c.vector[index] == ',' {
|
if c.vector[index] == ',' || spaceAtIndex(c.vector, index) {
|
||||||
return New(c.vector[c.posLeft:index]), nil
|
if index == c.posLeft {
|
||||||
|
return c, c.LeftPosf("%w", ErrMissingValue)
|
||||||
|
}
|
||||||
|
return c.Child(c.posLeft, index), nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return c, nil
|
return c, nil
|
||||||
|
@ -100,6 +154,7 @@ func (c Chunk) ValueEnd() (Chunk, error) {
|
||||||
func (c Chunk) Skip() Chunk {
|
func (c Chunk) Skip() Chunk {
|
||||||
if c.posLeft+1 < len(c.vector) {
|
if c.posLeft+1 < len(c.vector) {
|
||||||
c.posLeft++
|
c.posLeft++
|
||||||
|
c.globLeft++
|
||||||
}
|
}
|
||||||
return c.Seek()
|
return c.Seek()
|
||||||
}
|
}
|
||||||
|
@ -110,18 +165,10 @@ type MatchRule struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
matchers = map[byte]MatchRule{
|
matchers = map[byte]byte{
|
||||||
'{': {
|
'{': '}',
|
||||||
MatchByte: '}',
|
'[': ']',
|
||||||
StartFromRight: true,
|
'"': '"',
|
||||||
},
|
|
||||||
'[': {
|
|
||||||
MatchByte: ']',
|
|
||||||
StartFromRight: true,
|
|
||||||
},
|
|
||||||
'"': {
|
|
||||||
MatchByte: '"',
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -131,9 +178,10 @@ func New(v []byte) Chunk {
|
||||||
posRight = 0
|
posRight = 0
|
||||||
}
|
}
|
||||||
return Chunk{
|
return Chunk{
|
||||||
vector: coll.Vector[byte](v),
|
vector: coll.Vector[byte](v),
|
||||||
posLeft: 0,
|
posLeft: 0,
|
||||||
posRight: posRight,
|
posRight: posRight,
|
||||||
|
globRight: posRight,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -142,31 +190,14 @@ func (c Chunk) Child(left, right int) Chunk {
|
||||||
return Chunk{
|
return Chunk{
|
||||||
vector: sub,
|
vector: sub,
|
||||||
posLeft: 0,
|
posLeft: 0,
|
||||||
posRight: len(sub),
|
posRight: len(sub) - 1,
|
||||||
globLeft: (c.globLeft - c.posLeft) + left,
|
globLeft: (c.globLeft - c.posLeft) + left,
|
||||||
globRight: (c.globRight - c.posRight) + right,
|
globRight: (c.globRight - c.posRight) + (right - 1),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type ParseFunc[T any] func(T) (T, error)
|
type ParseFunc[T any] func(T) (T, error)
|
||||||
|
|
||||||
func Parse[T any](c Chunk) ParseFunc[T] {
|
|
||||||
switch c.vector[c.posLeft] {
|
|
||||||
case '{':
|
|
||||||
return ParseMap[T](c.CookieCutter())
|
|
||||||
default:
|
|
||||||
panic("not implemented")
|
|
||||||
}
|
|
||||||
// return can be:
|
|
||||||
// * {}
|
|
||||||
// * []
|
|
||||||
// * ""
|
|
||||||
// * 123
|
|
||||||
// * true
|
|
||||||
// * false
|
|
||||||
// * null
|
|
||||||
}
|
|
||||||
|
|
||||||
type Row struct {
|
type Row struct {
|
||||||
Name string
|
Name string
|
||||||
Value Chunk
|
Value Chunk
|
||||||
|
@ -177,47 +208,47 @@ func (c Chunk) String() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c Chunk) Row() (Row, error) {
|
func (c Chunk) Row() (Row, error) {
|
||||||
c = c.Seek()
|
|
||||||
if c.vector[c.posLeft] != '"' {
|
if c.vector[c.posLeft] != '"' {
|
||||||
return Row{}, fmt.Errorf("%w: %c", ErrMapMemberNotString, c.vector[c.posLeft])
|
return Row{}, c.LeftPosf("%w: %c", ErrMapMemberNotString, c.vector[c.posLeft])
|
||||||
}
|
}
|
||||||
name, err := c.Match()
|
name, err := c.Match()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return Row{}, fmt.Errorf("match: %w", err)
|
return Row{}, c.LeftPosf("match: %w", err)
|
||||||
}
|
}
|
||||||
postName := c.Copy()
|
postName := c.Copy()
|
||||||
postName.posLeft = name.posRight
|
postName.posLeft = name.posRight
|
||||||
|
postName.globLeft = name.globRight
|
||||||
postName = postName.Skip()
|
postName = postName.Skip()
|
||||||
// Next we must get a :
|
// Next we must get a :
|
||||||
if postName.vector[postName.posLeft] != ':' {
|
if postName.vector[postName.posLeft] != ':' {
|
||||||
return Row{}, fmt.Errorf("%w '%c', expected ':'", ErrUnexpectedSymbol, postName.vector[postName.posLeft])
|
return Row{}, postName.LeftPosf("%w '%c', expected ':'", ErrUnexpectedSymbol, postName.vector[postName.posLeft])
|
||||||
}
|
}
|
||||||
value, err := postName.Skip().ValueEnd()
|
value, err := postName.Skip().ValueEnd()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return Row{}, fmt.Errorf("value: %w", err)
|
return Row{}, postName.LeftPosf("value: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return Row{
|
return Row{
|
||||||
Name: name.String(),
|
Name: name.String()[1 : name.posRight-name.posLeft],
|
||||||
Value: value,
|
Value: value,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// After returns the chunk with its left position, if possible,
|
||||||
|
// right after the global right position of v
|
||||||
func (c Chunk) After(v Chunk) Chunk {
|
func (c Chunk) After(v Chunk) Chunk {
|
||||||
c.posLeft = v.posLeft
|
// Add two, as one is for dealing with right side being exclusive
|
||||||
|
// in slice indexes, and another one to go on to the next
|
||||||
|
offset := (v.globRight - c.globLeft) + 1
|
||||||
|
// Then, make sure we don't go too far
|
||||||
|
if c.posLeft+offset >= len(c.vector) {
|
||||||
|
offset--
|
||||||
|
}
|
||||||
|
c.posLeft += offset
|
||||||
|
c.globLeft += offset
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
func ParseMap[T any](c Chunk) ParseFunc[T] {
|
func (c Chunk) EOF() bool {
|
||||||
return func(t T) (T, error) {
|
return c.posLeft >= len(c.vector)-1
|
||||||
// mapper := parse.GetMap(t)
|
|
||||||
// for {
|
|
||||||
// row, err := c.Row()
|
|
||||||
// if err != nil {
|
|
||||||
// return t, err
|
|
||||||
// }
|
|
||||||
|
|
||||||
// }
|
|
||||||
panic("todo")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,37 +1,108 @@
|
||||||
package chunk_test
|
package chunk
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
"sectorinf.com/emilis/flabk/pkg/ld/internal/parse/chunk"
|
"sectorinf.com/emilis/flabk/pkg/coll"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestSpace(t *testing.T) {
|
func TestSpace(t *testing.T) {
|
||||||
|
tests := []byte{0x9, 0xa, 0xd, 0x20}
|
||||||
|
|
||||||
that := require.New(t)
|
that := require.New(t)
|
||||||
ch := chunk.New([]byte(" hello world"))
|
for _, test := range tests {
|
||||||
that.True(ch.AtSpace())
|
b := []byte("xhello world")
|
||||||
|
b[0] = test
|
||||||
|
that.True(New(b).AtSpace())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestParseMap(t *testing.T) {
|
func TestAlign(t *testing.T) {
|
||||||
type Hello struct {
|
tests := map[string]struct {
|
||||||
Hello string
|
c func() Chunk
|
||||||
|
v func(Chunk) Chunk
|
||||||
|
}{
|
||||||
|
"same-size": {
|
||||||
|
c: func() Chunk {
|
||||||
|
c := New(coll.Vector[byte](`{"heres some test data": "hi mom"}`))
|
||||||
|
c.posLeft = 15
|
||||||
|
c.globLeft = 15
|
||||||
|
return c
|
||||||
|
},
|
||||||
|
v: func(c Chunk) Chunk {
|
||||||
|
c.posLeft = 20
|
||||||
|
c.globLeft = 20
|
||||||
|
c.globRight = 22
|
||||||
|
c.posRight = 22
|
||||||
|
return c
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"cookie-cutter": {
|
||||||
|
c: func() Chunk {
|
||||||
|
c := New(coll.Vector[byte](`{"heres some test data": "hi mom"}`))
|
||||||
|
c.posLeft = 15
|
||||||
|
c.globLeft = 15
|
||||||
|
return c
|
||||||
|
},
|
||||||
|
v: func(c Chunk) Chunk {
|
||||||
|
return c.CookieCutter().CookieCutter()
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"no-change": {
|
||||||
|
c: func() Chunk {
|
||||||
|
c := New(coll.Vector[byte](`{"heres some test data": "hi mom"}`))
|
||||||
|
c.posLeft = 15
|
||||||
|
c.globLeft = 15
|
||||||
|
return c
|
||||||
|
},
|
||||||
|
v: func(c Chunk) Chunk {
|
||||||
|
c.posRight = 15
|
||||||
|
c.globRight = 15
|
||||||
|
return c.Sub()
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"contains": {
|
||||||
|
c: func() Chunk {
|
||||||
|
return New(coll.Vector[byte](`0123456789`))
|
||||||
|
},
|
||||||
|
v: func(c Chunk) Chunk {
|
||||||
|
return c.Child(5, 8)
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
ch := chunk.New([]byte(`"Hello": "world"`))
|
|
||||||
h, err := chunk.ParseMap[Hello](ch)(Hello{})
|
for name, test := range tests {
|
||||||
if err != nil {
|
test := test
|
||||||
panic(err)
|
t.Run(name, func(tt *testing.T) {
|
||||||
|
that := require.New(tt)
|
||||||
|
c := test.c()
|
||||||
|
v := test.v(c)
|
||||||
|
out := c.After(v)
|
||||||
|
that.Equal(v.globRight+1, out.globLeft)
|
||||||
|
that.Equal(string(c.vector[v.globRight+1]), string(out.LeftByte()))
|
||||||
|
})
|
||||||
}
|
}
|
||||||
fmt.Println(h)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestChild(t *testing.T) {
|
func TestRow(t *testing.T) {
|
||||||
type Hello struct {
|
c := New(coll.Vector[byte](`{
|
||||||
Hello string
|
"heres some test data": "hi mom",
|
||||||
}
|
"another field": "get it right",
|
||||||
ch := chunk.New([]byte(`"Hello": "world"`))
|
"integer": -12345
|
||||||
child := ch.Child(5, 10)
|
}`))
|
||||||
|
that := require.New(t)
|
||||||
fmt.Println(child)
|
row, err := c.CookieCutter().Seek().Row()
|
||||||
|
that.NoError(err)
|
||||||
|
that.Equal("heres some test data", row.Name)
|
||||||
|
that.Equal(`"hi mom"`, row.Value.String())
|
||||||
|
row, err = c.After(row.Value).StepIf(',').Seek().Row()
|
||||||
|
that.NoError(err)
|
||||||
|
that.Equal("another field", row.Name)
|
||||||
|
that.Equal(`"get it right"`, row.Value.String())
|
||||||
|
row, err = c.After(row.Value).StepIf(',').Seek().Row()
|
||||||
|
that.NoError(err)
|
||||||
|
that.Equal("integer", row.Name)
|
||||||
|
that.Equal("-12345", row.Value.String())
|
||||||
|
that.True(c.After(row.Value).Seek().EOF())
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,54 +1,200 @@
|
||||||
package parse
|
package parse
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"reflect"
|
"reflect"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
|
||||||
|
|
||||||
|
"sectorinf.com/emilis/flabk/pkg/coll"
|
||||||
"sectorinf.com/emilis/flabk/pkg/ld/internal/consts"
|
"sectorinf.com/emilis/flabk/pkg/ld/internal/consts"
|
||||||
|
"sectorinf.com/emilis/flabk/pkg/ld/internal/parse/chunk"
|
||||||
)
|
)
|
||||||
|
|
||||||
type LazyMapFunc func(name string, value string)
|
const (
|
||||||
|
memberSeparator = ','
|
||||||
|
)
|
||||||
|
|
||||||
func GetMap(v any) LazyMapFunc {
|
var (
|
||||||
val := reflect.ValueOf(v)
|
ErrNotArray = errors.New("value is not an array")
|
||||||
// typ := reflect.TypeOf(v)
|
ErrNotMap = errors.New("value is not a map")
|
||||||
switch val.Kind() {
|
)
|
||||||
case reflect.Map:
|
|
||||||
return func(name string, value string) {
|
var (
|
||||||
// val.SetMapIndex(reflect.ValueOf(name), value)
|
boolVals = map[string]bool{
|
||||||
}
|
"true": true,
|
||||||
case reflect.Struct:
|
"false": false,
|
||||||
// fields := GetStructFields(val, typ)
|
|
||||||
return func(name, value string) {
|
|
||||||
// val, ok := fields[name]
|
|
||||||
// if ok {
|
|
||||||
// val.Set(value)
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
panic("wrong")
|
|
||||||
}
|
}
|
||||||
|
determineMap = func() map[byte]coll.Vector[reflect.Kind] {
|
||||||
|
m := map[byte]coll.Vector[reflect.Kind]{
|
||||||
|
'"': coll.From(reflect.String),
|
||||||
|
'[': coll.From(reflect.Array, reflect.Slice),
|
||||||
|
'{': coll.From(reflect.Map, reflect.Struct),
|
||||||
|
'-': coll.From(reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64),
|
||||||
|
't': coll.From(reflect.Bool),
|
||||||
|
'f': coll.From(reflect.Bool),
|
||||||
|
}
|
||||||
|
numbers := coll.From(
|
||||||
|
reflect.Int,
|
||||||
|
reflect.Int8,
|
||||||
|
reflect.Int16,
|
||||||
|
reflect.Int32,
|
||||||
|
reflect.Int64,
|
||||||
|
reflect.Uint,
|
||||||
|
reflect.Uint64,
|
||||||
|
reflect.Uint32,
|
||||||
|
reflect.Uint16,
|
||||||
|
reflect.Uint8,
|
||||||
|
reflect.Float32,
|
||||||
|
reflect.Float64,
|
||||||
|
)
|
||||||
|
for index := byte('0'); index <= '9'; index++ {
|
||||||
|
m[index] = numbers
|
||||||
|
}
|
||||||
|
|
||||||
|
return m
|
||||||
|
}()
|
||||||
|
sizes = map[reflect.Kind]int{
|
||||||
|
// Int and Uint values stolen from the [math] package, as the intSize
|
||||||
|
// constant is unexported
|
||||||
|
reflect.Int: 32 << (^uint(0) >> 63), // 32 or 64
|
||||||
|
reflect.Uint: 32 << (^uint(0) >> 63), // 32 or 64
|
||||||
|
reflect.Int64: 64,
|
||||||
|
reflect.Int32: 32,
|
||||||
|
reflect.Int16: 16,
|
||||||
|
reflect.Int8: 8,
|
||||||
|
reflect.Uint64: 64,
|
||||||
|
reflect.Uint32: 32,
|
||||||
|
reflect.Uint16: 16,
|
||||||
|
reflect.Uint8: 8,
|
||||||
|
reflect.Float32: 32,
|
||||||
|
reflect.Float64: 64,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
func SetMap(val reflect.Value, typ reflect.Type, c chunk.Chunk) error {
|
||||||
|
if c.LeftByte() != '{' {
|
||||||
|
return c.LeftPosf("%w", ErrNotMap)
|
||||||
|
}
|
||||||
|
fields := GetStructFields(val, typ)
|
||||||
|
c = c.CookieCutter().Seek()
|
||||||
|
for !c.EOF() {
|
||||||
|
row, err := c.Row()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("row: %w", err)
|
||||||
|
}
|
||||||
|
field, ok := fields[row.Name]
|
||||||
|
if ok {
|
||||||
|
if err := SetValue(field, field.Type(), row.Value); err != nil {
|
||||||
|
return fmt.Errorf("set: %w", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Shift c
|
||||||
|
c = c.After(row.Value).StepIf(memberSeparator).Seek()
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func ParseAsValue(v string, valType reflect.Type) (any, error) {
|
func SetArray(val reflect.Value, typ reflect.Type, c chunk.Chunk) error {
|
||||||
// Might not be necessary to trim
|
if c.LeftByte() != '[' {
|
||||||
v = strings.TrimSpace(v)
|
return c.LeftPosf("%w", ErrNotArray)
|
||||||
switch valType.Kind() {
|
|
||||||
case reflect.String:
|
|
||||||
return v[1 : len(v)-1], nil
|
|
||||||
case reflect.Bool:
|
|
||||||
b, err := strconv.ParseBool(strings.ToLower(v))
|
|
||||||
if err != nil {
|
|
||||||
fmt.Errorf("boolean: %w", err)
|
|
||||||
}
|
|
||||||
return b, nil
|
|
||||||
case reflect.Struct, reflect.Map:
|
|
||||||
panic("todo")
|
|
||||||
default:
|
|
||||||
panic("todo")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
c = c.CookieCutter().Seek()
|
||||||
|
elems := coll.New[chunk.Chunk]()
|
||||||
|
for !c.EOF() {
|
||||||
|
element, err := c.ValueEnd()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("getting array elem: %w", err)
|
||||||
|
}
|
||||||
|
elems = elems.Push(element)
|
||||||
|
c = c.After(element).StepIf(memberSeparator).Seek()
|
||||||
|
}
|
||||||
|
elementType := typ.Elem()
|
||||||
|
arrayType := reflect.ArrayOf(len(elems), elementType)
|
||||||
|
array := reflect.New(arrayType).Elem()
|
||||||
|
for index, elem := range elems {
|
||||||
|
if err := SetValue(array.Index(index), elementType, elem); err != nil {
|
||||||
|
return fmt.Errorf("%w at array index [%d]", err, index)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if val.Kind() == reflect.Slice {
|
||||||
|
array = array.Slice(0, len(elems))
|
||||||
|
}
|
||||||
|
val.Set(array)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Determines what [reflect.Kind] of object the given [chunk.Chunk] is
|
||||||
|
func Determine(c chunk.Chunk) coll.Vector[reflect.Kind] {
|
||||||
|
k, ok := determineMap[c.LeftByte()]
|
||||||
|
if !ok {
|
||||||
|
return coll.From(reflect.Invalid)
|
||||||
|
}
|
||||||
|
return k
|
||||||
|
}
|
||||||
|
|
||||||
|
func SetValue(val reflect.Value, typ reflect.Type, c chunk.Chunk) error {
|
||||||
|
if c.Null() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if val.Kind() == reflect.Pointer {
|
||||||
|
if val.IsNil() {
|
||||||
|
val.Set(reflect.New(typ.Elem()))
|
||||||
|
}
|
||||||
|
return SetValue(val.Elem(), typ.Elem(), c)
|
||||||
|
}
|
||||||
|
|
||||||
|
kinds := Determine(c)
|
||||||
|
if !coll.AnyOf(kinds, val.Kind()) {
|
||||||
|
return fmt.Errorf("kind %s not found in appropriate list %s for value [%s]", val.Kind(), kinds, c)
|
||||||
|
}
|
||||||
|
|
||||||
|
switch val.Kind() {
|
||||||
|
case reflect.Map, reflect.Struct:
|
||||||
|
return SetMap(val, typ, c)
|
||||||
|
case reflect.String:
|
||||||
|
val.SetString(Escape(c.CookieCutter()))
|
||||||
|
case reflect.Bool:
|
||||||
|
b, ok := boolVals[c.String()]
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("value [%s] is not a boolean", c.String())
|
||||||
|
}
|
||||||
|
val.SetBool(b)
|
||||||
|
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||||
|
i, err := strconv.ParseInt(c.String(), 10, sizes[val.Kind()])
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("value [%s] is not an %s", c.String(), val.Kind().String())
|
||||||
|
}
|
||||||
|
val.SetInt(i)
|
||||||
|
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
||||||
|
u, err := strconv.ParseUint(c.String(), 10, sizes[val.Kind()])
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("value [%s] is not an %s", c.String(), val.Kind().String())
|
||||||
|
}
|
||||||
|
val.SetUint(u)
|
||||||
|
case reflect.Float32, reflect.Float64:
|
||||||
|
f, err := strconv.ParseFloat(c.String(), sizes[val.Kind()])
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("value [%s] is not an %s", c.String(), val.Kind().String())
|
||||||
|
}
|
||||||
|
val.SetFloat(f)
|
||||||
|
case reflect.Array, reflect.Slice:
|
||||||
|
return SetArray(val, typ, c)
|
||||||
|
default:
|
||||||
|
fmt.Println(val.Kind().String())
|
||||||
|
panic("unsupported")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func Escape(v chunk.Chunk) string {
|
||||||
|
// TODO: string escaping
|
||||||
|
return v.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetStructFields(val reflect.Value, typ reflect.Type) map[string]reflect.Value {
|
func GetStructFields(val reflect.Value, typ reflect.Type) map[string]reflect.Value {
|
||||||
|
|
|
@ -1 +1,17 @@
|
||||||
package ld
|
package ld
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"reflect"
|
||||||
|
|
||||||
|
"sectorinf.com/emilis/flabk/pkg/ld/internal/parse"
|
||||||
|
"sectorinf.com/emilis/flabk/pkg/ld/internal/parse/chunk"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Unmarshal[T any](v []byte) (T, error) {
|
||||||
|
ptr := new(T)
|
||||||
|
if err := parse.SetValue(reflect.ValueOf(ptr), reflect.TypeOf(ptr), chunk.New(v)); err != nil {
|
||||||
|
return *ptr, fmt.Errorf("unmarshal: %w", err)
|
||||||
|
}
|
||||||
|
return *ptr, nil
|
||||||
|
}
|
||||||
|
|
|
@ -1,192 +1,192 @@
|
||||||
package ld_test
|
package ld_test
|
||||||
|
|
||||||
// import (
|
import (
|
||||||
// "encoding/json"
|
"encoding/json"
|
||||||
// "fmt"
|
"fmt"
|
||||||
// "math"
|
"math"
|
||||||
// "testing"
|
"testing"
|
||||||
// "time"
|
"time"
|
||||||
|
|
||||||
// "sectorinf.com/emilis/flabk/pkg/asld"
|
"github.com/stretchr/testify/require"
|
||||||
// "sectorinf.com/emilis/flabk/pkg/epk"
|
"sectorinf.com/emilis/flabk/pkg/epk"
|
||||||
// "github.com/stretchr/testify/require"
|
"sectorinf.com/emilis/flabk/pkg/ld"
|
||||||
// )
|
)
|
||||||
|
|
||||||
// type testObj struct {
|
type testObj struct {
|
||||||
// String string `asld:"string" json:"string"`
|
String string `ld:"string" json:"string"`
|
||||||
// NoTag string
|
NoTag string
|
||||||
// Int int
|
Int int
|
||||||
// Int8 int8
|
Int8 int8
|
||||||
// Int16 int16
|
Int16 int16
|
||||||
// Int32 int32
|
Int32 int32
|
||||||
// Int64 int64
|
Int64 int64
|
||||||
// Uint uint
|
Uint uint
|
||||||
// Uint8 uint8
|
Uint8 uint8
|
||||||
// Uint16 uint16
|
Uint16 uint16
|
||||||
// Uint32 uint32
|
Uint32 uint32
|
||||||
// Uint64 uint64
|
Uint64 uint64
|
||||||
// Float32 float32
|
Float32 float32
|
||||||
// Float64 float64
|
Float64 float64
|
||||||
// // Complex64 complex64
|
// Complex64 complex64
|
||||||
// // Complex128 complex128
|
// Complex128 complex128
|
||||||
// IntPtr *int
|
IntPtr *int
|
||||||
// Int8Ptr *int8
|
Int8Ptr *int8
|
||||||
// Int16Ptr *int16
|
Int16Ptr *int16
|
||||||
// Int32Ptr *int32
|
Int32Ptr *int32
|
||||||
// Int64Ptr *int64
|
Int64Ptr *int64
|
||||||
// UintPtr *uint
|
UintPtr *uint
|
||||||
// Uint8Ptr *uint8
|
Uint8Ptr *uint8
|
||||||
// Uint16Ptr *uint16
|
Uint16Ptr *uint16
|
||||||
// Uint32Ptr *uint32
|
Uint32Ptr *uint32
|
||||||
// Uint64Ptr *uint64
|
Uint64Ptr *uint64
|
||||||
// Float32Ptr *float32
|
Float32Ptr *float32
|
||||||
// Float64Ptr *float64
|
Float64Ptr *float64
|
||||||
// // Complex64Ptr *complex64
|
// Complex64Ptr *complex64
|
||||||
// // Complex128Ptr *complex128
|
// Complex128Ptr *complex128
|
||||||
// TestPtr *testObj
|
TestPtr *testObj
|
||||||
// TestArray []testObj
|
TestArray []testObj
|
||||||
// }
|
}
|
||||||
|
|
||||||
// func TestUnmarshal(t *testing.T) {
|
func TestUnmarshal(t *testing.T) {
|
||||||
// tests := map[string]struct {
|
tests := map[string]struct {
|
||||||
// obj testObj
|
obj testObj
|
||||||
// errCheck epk.ErrorTest
|
errCheck epk.ErrorTest
|
||||||
// }{
|
}{
|
||||||
// "string children": {
|
"string children": {
|
||||||
// obj: testObj{
|
obj: testObj{
|
||||||
// String: "hello",
|
String: "hello",
|
||||||
// NoTag: "no_tag",
|
NoTag: "no_tag",
|
||||||
// Int: math.MaxInt,
|
Int: math.MaxInt,
|
||||||
// Int8: math.MaxInt8,
|
Int8: math.MaxInt8,
|
||||||
// Int16: math.MaxInt16,
|
Int16: math.MaxInt16,
|
||||||
// Int32: math.MaxInt32,
|
Int32: math.MaxInt32,
|
||||||
// Int64: math.MaxInt64,
|
Int64: math.MaxInt64,
|
||||||
// Uint: math.MaxUint,
|
Uint: math.MaxUint,
|
||||||
// Uint8: math.MaxUint8,
|
Uint8: math.MaxUint8,
|
||||||
// Uint16: math.MaxUint16,
|
Uint16: math.MaxUint16,
|
||||||
// Uint32: math.MaxUint32,
|
Uint32: math.MaxUint32,
|
||||||
// Uint64: math.MaxUint64,
|
Uint64: math.MaxUint64,
|
||||||
// Float32: math.MaxFloat32,
|
Float32: math.MaxFloat32,
|
||||||
// Float64: math.MaxFloat64,
|
Float64: math.MaxFloat64,
|
||||||
// TestPtr: &testObj{
|
TestPtr: &testObj{
|
||||||
// String: "hello2",
|
String: "hello2",
|
||||||
// },
|
},
|
||||||
// TestArray: []testObj{
|
TestArray: []testObj{
|
||||||
// {
|
{
|
||||||
// String: "hello3",
|
String: "hello3",
|
||||||
// },
|
},
|
||||||
// {
|
{
|
||||||
// String: "hello4",
|
String: "hello4",
|
||||||
// TestPtr: &testObj{
|
TestPtr: &testObj{
|
||||||
// TestArray: []testObj{
|
TestArray: []testObj{
|
||||||
// {
|
{
|
||||||
// String: "hello5",
|
String: "hello5",
|
||||||
// },
|
},
|
||||||
// },
|
},
|
||||||
// },
|
},
|
||||||
// },
|
},
|
||||||
// },
|
},
|
||||||
// // Complex64: complex(math.MaxFloat32, math.MaxFloat32),
|
// Complex64: complex(math.MaxFloat32, math.MaxFloat32),
|
||||||
// // Complex128: complex(math.MaxFloat64, math.MaxFloat64),
|
// Complex128: complex(math.MaxFloat64, math.MaxFloat64),
|
||||||
// },
|
},
|
||||||
// },
|
},
|
||||||
// }
|
}
|
||||||
|
|
||||||
// for name, test := range tests {
|
for name, test := range tests {
|
||||||
// test := test
|
test := test
|
||||||
// t.Run(name, func(tt *testing.T) {
|
t.Run(name, func(tt *testing.T) {
|
||||||
// that := require.New(tt)
|
that := require.New(tt)
|
||||||
// objJSON, err := json.MarshalIndent(test.obj, "", " ")
|
objJSON, err := json.MarshalIndent(test.obj, "", " ")
|
||||||
// that.NoError(err)
|
that.NoError(err)
|
||||||
// result, err := asld.Unmarshal[testObj](objJSON)
|
result, err := ld.Unmarshal[testObj](objJSON)
|
||||||
// that.NoError(err)
|
that.NoError(err)
|
||||||
// that.Equal(test.obj, result)
|
that.Equal(test.obj, result)
|
||||||
// })
|
})
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
|
|
||||||
// func TestBench(t *testing.T) {
|
func TestBench(t *testing.T) {
|
||||||
// obj := testObj{
|
obj := testObj{
|
||||||
// String: "hello",
|
String: "hello",
|
||||||
// NoTag: "no_tag",
|
NoTag: "no_tag",
|
||||||
// Int: math.MaxInt,
|
Int: math.MaxInt,
|
||||||
// Int8: math.MaxInt8,
|
Int8: math.MaxInt8,
|
||||||
// Int16: math.MaxInt16,
|
Int16: math.MaxInt16,
|
||||||
// Int32: math.MaxInt32,
|
Int32: math.MaxInt32,
|
||||||
// Int64: math.MaxInt64,
|
Int64: math.MaxInt64,
|
||||||
// Uint: math.MaxUint,
|
Uint: math.MaxUint,
|
||||||
// Uint8: math.MaxUint8,
|
Uint8: math.MaxUint8,
|
||||||
// Uint16: math.MaxUint16,
|
Uint16: math.MaxUint16,
|
||||||
// Uint32: math.MaxUint32,
|
Uint32: math.MaxUint32,
|
||||||
// Uint64: math.MaxUint64,
|
Uint64: math.MaxUint64,
|
||||||
// Float32: math.MaxFloat32,
|
Float32: math.MaxFloat32,
|
||||||
// Float64: math.MaxFloat64,
|
Float64: math.MaxFloat64,
|
||||||
// // Complex64: complex(math.MaxFloat32, math.MaxFloat32),
|
// Complex64: complex(math.MaxFloat32, math.MaxFloat32),
|
||||||
// // Complex128: complex(math.MaxFloat64, math.MaxFloat64),
|
// Complex128: complex(math.MaxFloat64, math.MaxFloat64),
|
||||||
// }
|
}
|
||||||
// that := require.New(t)
|
that := require.New(t)
|
||||||
// asldTotal := int64(0)
|
asldTotal := int64(0)
|
||||||
// jsonTotal := int64(0)
|
jsonTotal := int64(0)
|
||||||
|
|
||||||
// jsonMax := int64(0)
|
jsonMax := int64(0)
|
||||||
// jsonMin := math.MaxInt64
|
jsonMin := math.MaxInt64
|
||||||
|
|
||||||
// asldMax := int64(0)
|
asldMax := int64(0)
|
||||||
// asldMin := math.MaxInt64
|
asldMin := math.MaxInt64
|
||||||
|
|
||||||
// count := int64(1 << 20)
|
count := int64(1 << 20)
|
||||||
// for index := int64(0); index < count; index++ {
|
for index := int64(0); index < count; index++ {
|
||||||
// objJSON, err := json.Marshal(obj)
|
objJSON, err := json.Marshal(obj)
|
||||||
// that.NoError(err)
|
that.NoError(err)
|
||||||
|
|
||||||
// asldStart := time.Now()
|
asldStart := time.Now()
|
||||||
// _, err = asld.Unmarshal[testObj](objJSON)
|
_, err = ld.Unmarshal[testObj](objJSON)
|
||||||
// asldDur := time.Since(asldStart)
|
asldDur := time.Since(asldStart)
|
||||||
// asldTotal += int64(asldDur)
|
asldTotal += int64(asldDur)
|
||||||
// if asldDur < time.Duration(asldMin) {
|
if asldDur < time.Duration(asldMin) {
|
||||||
// asldMin = int(asldDur)
|
asldMin = int(asldDur)
|
||||||
// }
|
}
|
||||||
// if asldDur > time.Duration(asldMax) {
|
if asldDur > time.Duration(asldMax) {
|
||||||
// asldMax = int64(asldDur)
|
asldMax = int64(asldDur)
|
||||||
// }
|
}
|
||||||
|
|
||||||
// that.NoError(err)
|
that.NoError(err)
|
||||||
// a := testObj{}
|
a := testObj{}
|
||||||
|
|
||||||
// jsonStart := time.Now()
|
jsonStart := time.Now()
|
||||||
// err = json.Unmarshal(objJSON, &a)
|
err = json.Unmarshal(objJSON, &a)
|
||||||
// jsonDur := time.Since(jsonStart)
|
jsonDur := time.Since(jsonStart)
|
||||||
// jsonTotal += int64(jsonDur)
|
jsonTotal += int64(jsonDur)
|
||||||
|
|
||||||
// if jsonDur < time.Duration(jsonMin) {
|
if jsonDur < time.Duration(jsonMin) {
|
||||||
// jsonMin = int(jsonDur)
|
jsonMin = int(jsonDur)
|
||||||
// }
|
}
|
||||||
// if jsonDur > time.Duration(jsonMax) {
|
if jsonDur > time.Duration(jsonMax) {
|
||||||
// jsonMax = int64(jsonDur)
|
jsonMax = int64(jsonDur)
|
||||||
// }
|
}
|
||||||
|
|
||||||
// that.NoError(err)
|
that.NoError(err)
|
||||||
// }
|
}
|
||||||
// fmt.Println(count, "runs")
|
fmt.Println(count, "runs")
|
||||||
// fmt.Printf("json avg (%s), min (%s), max (%s)\n", time.Duration(jsonTotal/count), time.Duration(jsonMin), time.Duration(jsonMax))
|
fmt.Printf("json avg (%s), min (%s), max (%s)\n", time.Duration(jsonTotal/count), time.Duration(jsonMin), time.Duration(jsonMax))
|
||||||
// fmt.Printf("asld avg (%s), min (%s), max (%s)\n", time.Duration(asldTotal/count), time.Duration(asldMin), time.Duration(asldMax))
|
fmt.Printf("asld avg (%s), min (%s), max (%s)\n", time.Duration(asldTotal/count), time.Duration(asldMin), time.Duration(asldMax))
|
||||||
// }
|
}
|
||||||
// func jsonElemList[T any](that *require.Assertions, a any) [][]byte {
|
func jsonElemList[T any](that *require.Assertions, a any) [][]byte {
|
||||||
// that.NotNil(a)
|
that.NotNil(a)
|
||||||
// v, ok := a.([]T)
|
v, ok := a.([]T)
|
||||||
// that.True(ok)
|
that.True(ok)
|
||||||
// fields := make([][]byte, len(v))
|
fields := make([][]byte, len(v))
|
||||||
// for index, field := range v {
|
for index, field := range v {
|
||||||
// jsonField, err := json.Marshal(field)
|
jsonField, err := json.Marshal(field)
|
||||||
// that.NoError(err)
|
that.NoError(err)
|
||||||
// fields[index] = jsonField
|
fields[index] = jsonField
|
||||||
// }
|
}
|
||||||
// return fields
|
return fields
|
||||||
// }
|
}
|
||||||
|
|
||||||
// type hello struct {
|
type hello struct {
|
||||||
// Hello string
|
Hello string
|
||||||
// }
|
}
|
||||||
|
|
||||||
// func TestArrayMembers(t *testing.T) {
|
// func TestArrayMembers(t *testing.T) {
|
||||||
// tests := map[string]struct {
|
// tests := map[string]struct {
|
||||||
|
|
Loading…
Reference in New Issue