1
1
mirror of https://github.com/wader/fq.git synced 2024-12-01 19:12:34 +03:00
fq/pkg/scalar/scalar.go
Mattias Wadman bf7fa07c41 fq: Use go 1.20 and cleanup
Also rename *ex packages to *x
2024-04-01 19:14:10 +02:00

281 lines
7.2 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/bitiox"
"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 Scalarable interface {
ScalarActual() any
ScalarValue() any
ScalarSym() any
ScalarDescription() string
ScalarFlags() Flags
ScalarDisplayFormat() DisplayFormat
}
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
}
}
const (
FlagGap Flags = 1 << iota
FlagSynthetic
)
type Flags uint
func (f Flags) IsGap() bool { return f&FlagGap != 0 }
func (f Flags) IsSynthetic() bool { return f&FlagSynthetic != 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 := bitiox.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 := bitiox.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 UintActualDateDescription(epoch time.Time, unit time.Duration, format string) UintFn {
return UintFn(func(s Uint) (Uint, error) {
s.Description = epoch.Add(time.Duration(s.Actual) * unit).Format(format)
return s, nil
})
}
func UintActualUnixTimeDescription(unit time.Duration, format string) UintFn {
return UintActualDateDescription(unixTimeEpochDate, unit, format)
}
func SintActualDateDescription(epoch time.Time, unit time.Duration, format string) SintFn {
return SintFn(func(s Sint) (Sint, error) {
s.Description = epoch.Add(time.Duration(s.Actual) * unit).Format(format)
return s, nil
})
}
func SintActualUnixTimeDescription(unit time.Duration, format string) SintFn {
return SintActualDateDescription(unixTimeEpochDate, unit, format)
}
func FltActualDateDescription(epoch time.Time, unit time.Duration, format string) FltFn {
return FltFn(func(s Flt) (Flt, error) {
s.Description = epoch.Add(time.Duration(s.Actual) * unit).Format(format)
return s, nil
})
}
func FltActualUnixTimeDescription(unit time.Duration, format string) FltFn {
return FltActualDateDescription(unixTimeEpochDate, unit, format)
}