mirror of
https://github.com/wader/fq.git
synced 2024-12-28 08:02:28 +03:00
9b81d4d3ab
Preparation to make decoder use less memory and API more type safe. Now each scalar type has it's own struct type so it can store different things and enables to have a scalar interface. Also own types will enable experimenting with decode DLS designs like using chained methods that are type aware.
251 lines
6.3 KiB
Go
251 lines
6.3 KiB
Go
package scalar
|
|
|
|
// TODO: d.Pos check err
|
|
// TODO: fn for actual?
|
|
// TODO: dsl import .? own scalar package?
|
|
// TODO: better IOError op names
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"strconv"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/wader/fq/internal/bitioex"
|
|
"github.com/wader/fq/pkg/bitio"
|
|
)
|
|
|
|
//go:generate sh -c "cat scalar_gen.go.tmpl | go run ../../dev/tmpl.go ../decode/types.json | gofmt > scalar_gen.go"
|
|
|
|
type DisplayFormat int
|
|
|
|
const (
|
|
NumberDecimal DisplayFormat = iota
|
|
NumberBinary
|
|
NumberOctal
|
|
NumberHex
|
|
)
|
|
|
|
func (df DisplayFormat) FormatBase() int {
|
|
switch df {
|
|
case NumberDecimal:
|
|
return 10
|
|
case NumberBinary:
|
|
return 2
|
|
case NumberOctal:
|
|
return 8
|
|
case NumberHex:
|
|
return 16
|
|
default:
|
|
return 0
|
|
}
|
|
}
|
|
|
|
// TODO: todos
|
|
// rename raw?
|
|
// crc
|
|
//
|
|
//
|
|
// d.FieldU2("emphasis").
|
|
// MapSym().
|
|
// Actual
|
|
// Sym
|
|
// Value()
|
|
// Scalar()
|
|
|
|
var UintBin = UintFn(func(s Uint) (Uint, error) { s.DisplayFormat = NumberBinary; return s, nil })
|
|
var UintOct = UintFn(func(s Uint) (Uint, error) { s.DisplayFormat = NumberOctal; return s, nil })
|
|
var UintDec = UintFn(func(s Uint) (Uint, error) { s.DisplayFormat = NumberDecimal; return s, nil })
|
|
var UintHex = UintFn(func(s Uint) (Uint, error) { s.DisplayFormat = NumberHex; return s, nil })
|
|
var SintBin = SintFn(func(s Sint) (Sint, error) { s.DisplayFormat = NumberBinary; return s, nil })
|
|
var SintOct = SintFn(func(s Sint) (Sint, error) { s.DisplayFormat = NumberOctal; return s, nil })
|
|
var SintDec = SintFn(func(s Sint) (Sint, error) { s.DisplayFormat = NumberDecimal; return s, nil })
|
|
var SintHex = SintFn(func(s Sint) (Sint, error) { s.DisplayFormat = NumberHex; return s, nil })
|
|
var BigIntBin = BigIntFn(func(s BigInt) (BigInt, error) { s.DisplayFormat = NumberBinary; return s, nil })
|
|
var BigIntOct = BigIntFn(func(s BigInt) (BigInt, error) { s.DisplayFormat = NumberOctal; return s, nil })
|
|
var BigIntDec = BigIntFn(func(s BigInt) (BigInt, error) { s.DisplayFormat = NumberDecimal; return s, nil })
|
|
var BigIntHex = BigIntFn(func(s BigInt) (BigInt, error) { s.DisplayFormat = NumberHex; return s, nil })
|
|
|
|
func UintActualAdd(n int) UintActualFn {
|
|
// TODO: use math.Add/Sub?
|
|
return UintActualFn(func(a uint64) uint64 { return uint64(int64(a) + int64(n)) })
|
|
}
|
|
|
|
func SintActualAdd(n int) SintActualFn {
|
|
return SintActualFn(func(a int64) int64 { return a + int64(n) })
|
|
}
|
|
|
|
func StrActualTrim(cutset string) StrActualFn {
|
|
return StrActualFn(func(a string) string { return strings.Trim(a, cutset) })
|
|
}
|
|
|
|
var ActualTrimSpace = StrActualFn(strings.TrimSpace)
|
|
|
|
func strMapToSym(fn func(s string) (any, error), try bool) StrMapper {
|
|
return StrFn(func(s Str) (Str, error) {
|
|
ts := strings.TrimSpace(s.Actual)
|
|
n, err := fn(ts)
|
|
if err != nil {
|
|
if try {
|
|
return s, nil
|
|
}
|
|
return s, err
|
|
}
|
|
s.Sym = n
|
|
return s, nil
|
|
})
|
|
}
|
|
|
|
func TryStrSymParseUint(base int) StrMapper {
|
|
return strMapToSym(func(s string) (any, error) { return strconv.ParseUint(s, base, 64) }, true)
|
|
}
|
|
|
|
func TryStrSymParseInt(base int) StrMapper {
|
|
return strMapToSym(func(s string) (any, error) { return strconv.ParseInt(s, base, 64) }, true)
|
|
}
|
|
|
|
func TryStrSymParseFloat(base int) StrMapper {
|
|
return strMapToSym(func(s string) (any, error) { return strconv.ParseFloat(s, base) }, true)
|
|
}
|
|
|
|
func StrSymParseUint(base int) StrMapper {
|
|
return strMapToSym(func(s string) (any, error) { return strconv.ParseUint(s, base, 64) }, false)
|
|
}
|
|
|
|
func StrSymParseInt(base int) StrMapper {
|
|
return strMapToSym(func(s string) (any, error) { return strconv.ParseInt(s, base, 64) }, false)
|
|
}
|
|
|
|
func StrSymParseFloat(base int) StrMapper {
|
|
return strMapToSym(func(s string) (any, error) { return strconv.ParseFloat(s, base) }, false)
|
|
}
|
|
|
|
type URangeEntry struct {
|
|
Range [2]uint64
|
|
S Uint
|
|
}
|
|
|
|
// UintRangeToScalar maps uint64 ranges to a scalar, first in range is chosen
|
|
type UintRangeToScalar []URangeEntry
|
|
|
|
func (rs UintRangeToScalar) MapUint(s Uint) (Uint, error) {
|
|
n := s.Actual
|
|
for _, re := range rs {
|
|
if n >= re.Range[0] && n <= re.Range[1] {
|
|
ns := re.S
|
|
ns.Actual = s.Actual
|
|
s = ns
|
|
break
|
|
}
|
|
}
|
|
return s, nil
|
|
}
|
|
|
|
// SRangeToScalar maps ranges to a scalar, first in range is chosen
|
|
type SRangeEntry struct {
|
|
Range [2]int64
|
|
S Sint
|
|
}
|
|
|
|
// SRangeToScalar maps sint64 ranges to a scalar, first in range is chosen
|
|
type SRangeToScalar []SRangeEntry
|
|
|
|
func (rs SRangeToScalar) MapSint(s Sint) (Sint, error) {
|
|
n := s.Actual
|
|
for _, re := range rs {
|
|
if n >= re.Range[0] && n <= re.Range[1] {
|
|
ns := re.S
|
|
ns.Actual = s.Actual
|
|
s = ns
|
|
break
|
|
}
|
|
}
|
|
return s, nil
|
|
}
|
|
|
|
func RawSym(s BitBuf, nBytes int, fn func(b []byte) string) (BitBuf, error) {
|
|
br := s.Actual
|
|
brLen, err := bitioex.Len(br)
|
|
if err != nil {
|
|
return BitBuf{}, err
|
|
}
|
|
if nBytes < 0 {
|
|
nBytes = int(brLen) / 8
|
|
if brLen%8 != 0 {
|
|
nBytes++
|
|
}
|
|
}
|
|
if brLen < int64(nBytes)*8 {
|
|
return s, nil
|
|
}
|
|
// TODO: shared somehow?
|
|
b := make([]byte, nBytes)
|
|
if _, err := br.ReadBitsAt(b, int64(nBytes)*8, 0); err != nil {
|
|
return s, err
|
|
}
|
|
|
|
s.Sym = fn(b[0:nBytes])
|
|
|
|
return s, nil
|
|
}
|
|
|
|
var RawUUID = BitBufFn(func(s BitBuf) (BitBuf, error) {
|
|
return RawSym(s, -1, func(b []byte) string {
|
|
return fmt.Sprintf("%x-%x-%x-%x-%x", b[0:4], b[4:6], b[6:8], b[8:10], b[10:])
|
|
})
|
|
})
|
|
|
|
var RawHex = BitBufFn(func(s BitBuf) (BitBuf, error) {
|
|
return RawSym(s, -1, func(b []byte) string { return fmt.Sprintf("%x", b) })
|
|
})
|
|
|
|
type RawBytesMap []struct {
|
|
Bytes []byte
|
|
Scalar BitBuf
|
|
}
|
|
|
|
func (m RawBytesMap) MapBitBuf(s BitBuf) (BitBuf, error) {
|
|
rc, err := bitio.CloneReader(s.Actual)
|
|
if err != nil {
|
|
return s, err
|
|
}
|
|
bb := &bytes.Buffer{}
|
|
if _, err := bitioex.CopyBits(bb, rc); err != nil {
|
|
return s, err
|
|
}
|
|
for _, bs := range m {
|
|
if bytes.Equal(bb.Bytes(), bs.Bytes) {
|
|
ns := bs.Scalar
|
|
ns.Actual = s.Actual
|
|
s = ns
|
|
break
|
|
}
|
|
}
|
|
return s, nil
|
|
}
|
|
|
|
var unixTimeEpochDate = time.Date(1970, time.January, 1, 0, 0, 0, 0, time.UTC)
|
|
|
|
func UintActualDate(epoch time.Time, format string) UintFn {
|
|
return UintFn(func(s Uint) (Uint, error) {
|
|
s.Description = epoch.Add(time.Duration(s.Actual) * time.Second).Format(format)
|
|
return s, nil
|
|
})
|
|
}
|
|
|
|
func UintActualUnixTime(format string) UintFn {
|
|
return UintActualDate(unixTimeEpochDate, format)
|
|
}
|
|
|
|
func FltActualDate(epoch time.Time, format string) FltFn {
|
|
return FltFn(func(s Flt) (Flt, error) {
|
|
s.Description = epoch.Add(time.Duration(s.Actual) * time.Second).Format(format)
|
|
return s, nil
|
|
})
|
|
}
|
|
|
|
func FltActualUnixTime(format string) FltFn {
|
|
return FltActualDate(unixTimeEpochDate, format)
|
|
}
|