1
1
mirror of https://github.com/wader/fq.git synced 2024-11-23 18:56:52 +03:00
fq/pkg/scalar/scalar.go
Mattias Wadman 9b81d4d3ab decode: More type safe API and split scalar into multiple types
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.
2022-12-14 16:23:58 +01:00

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)
}