790 lines
16 KiB
Go
790 lines
16 KiB
Go
/*
|
|
Copyright 2022 Alibaba Group Holding Limited.
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
you may not use this file except in compliance with the License.
|
|
You may obtain a copy of the License at
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
See the License for the specific language governing permissions and
|
|
limitations under the License.
|
|
*/
|
|
|
|
package layout
|
|
|
|
import (
|
|
"bytes"
|
|
"errors"
|
|
"fmt"
|
|
"io"
|
|
"math"
|
|
"unsafe"
|
|
|
|
"github.com/google/uuid"
|
|
"golang.org/x/exp/constraints"
|
|
|
|
"github.com/alibaba/polardbx-operator/pkg/binlogtool/bitmap"
|
|
"github.com/alibaba/polardbx-operator/pkg/binlogtool/utils"
|
|
)
|
|
|
|
var (
|
|
ErrNotEnoughBytes = errors.New("not enough bytes")
|
|
ErrNotNull = errors.New("not null")
|
|
)
|
|
|
|
type ExtractFrom interface {
|
|
FromBlock(data []byte) (int, error)
|
|
FromStream(r io.Reader) error
|
|
}
|
|
|
|
func checkDataSize(expect int, data []byte) error {
|
|
if len(data) < expect {
|
|
return ErrNotEnoughBytes
|
|
}
|
|
return nil
|
|
}
|
|
|
|
type FieldType uint8
|
|
|
|
const (
|
|
NullType FieldType = 0
|
|
BoolType FieldType = 1
|
|
NumberType FieldType = 2
|
|
PackedIntType FieldType = 3
|
|
BytesType FieldType = 4
|
|
BitSetType FieldType = 5
|
|
UUIDType FieldType = 6
|
|
AreaType FieldType = 7
|
|
RepeatType FieldType = 8
|
|
SkipType FieldType = 9
|
|
EOFType FieldType = 0xff
|
|
)
|
|
|
|
func FieldTypeName(t FieldType) string {
|
|
switch t {
|
|
case NullType:
|
|
return "Null"
|
|
case BoolType:
|
|
return "Bool"
|
|
case NumberType:
|
|
return "Number"
|
|
case PackedIntType:
|
|
return "PackedInt"
|
|
case BytesType:
|
|
return "Bytes"
|
|
case BitSetType:
|
|
return "BitSet"
|
|
case UUIDType:
|
|
return "UUID"
|
|
case AreaType:
|
|
return "Area"
|
|
case RepeatType:
|
|
return "Repeat"
|
|
case SkipType:
|
|
return "Skip"
|
|
case EOFType:
|
|
return "EOF"
|
|
default:
|
|
return "Unknown"
|
|
}
|
|
}
|
|
|
|
type Field interface {
|
|
ExtractFrom
|
|
|
|
Type() FieldType
|
|
IsVariant() bool
|
|
SizeRange() (int, int)
|
|
}
|
|
|
|
type NullField struct {
|
|
}
|
|
|
|
func (f NullField) FromBlock(data []byte) (int, error) {
|
|
if err := checkDataSize(1, data); err != nil {
|
|
return 0, err
|
|
}
|
|
if data[0] != 0 {
|
|
return 0, ErrNotNull
|
|
}
|
|
return 1, nil
|
|
}
|
|
|
|
func (f NullField) FromStream(r io.Reader) error {
|
|
buf := [1]byte{}
|
|
if _, err := io.ReadFull(r, buf[:]); err != nil {
|
|
return fmt.Errorf("unable to read: %w", err)
|
|
}
|
|
if buf[0] != 0 {
|
|
return ErrNotNull
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (f NullField) Type() FieldType {
|
|
return NullType
|
|
}
|
|
|
|
func (f NullField) IsVariant() bool {
|
|
return false
|
|
}
|
|
|
|
func (f NullField) SizeRange() (int, int) {
|
|
return 1, 1
|
|
}
|
|
|
|
type BoolField struct {
|
|
r *bool
|
|
}
|
|
|
|
func (f BoolField) FromBlock(data []byte) (int, error) {
|
|
if err := checkDataSize(1, data); err != nil {
|
|
return 0, err
|
|
}
|
|
*f.r = data[0] != 0
|
|
return 1, nil
|
|
}
|
|
|
|
func (f BoolField) FromStream(r io.Reader) error {
|
|
buf := [1]byte{}
|
|
if _, err := io.ReadFull(r, buf[:]); err != nil {
|
|
return fmt.Errorf("unable to read: %w", err)
|
|
}
|
|
*f.r = buf[0] != 0
|
|
return nil
|
|
}
|
|
|
|
func (f BoolField) Type() FieldType {
|
|
return BoolType
|
|
}
|
|
|
|
func (f BoolField) IsVariant() bool {
|
|
return false
|
|
}
|
|
|
|
func (f BoolField) SizeRange() (int, int) {
|
|
return 1, 1
|
|
}
|
|
|
|
type NumberField[N constraints.Integer | constraints.Float] struct {
|
|
r *N
|
|
}
|
|
|
|
func (f NumberField[N]) FromBlock(data []byte) (int, error) {
|
|
if err := checkDataSize(int(unsafe.Sizeof(N(0))), data); err != nil {
|
|
return 0, err
|
|
}
|
|
utils.ReadNumberLittleEndianHack(f.r, data)
|
|
return int(unsafe.Sizeof(N(0))), nil
|
|
}
|
|
|
|
func (f NumberField[N]) FromStream(r io.Reader) error {
|
|
buf := make([]byte, int(unsafe.Sizeof(N(0))))
|
|
if _, err := io.ReadFull(r, buf); err != nil {
|
|
return fmt.Errorf("unable to read: %w", err)
|
|
}
|
|
utils.ReadNumberLittleEndianHack(f.r, buf)
|
|
return nil
|
|
}
|
|
|
|
func (f NumberField[N]) Type() FieldType {
|
|
return NumberType
|
|
}
|
|
|
|
func (f NumberField[N]) IsVariant() bool {
|
|
return false
|
|
}
|
|
|
|
func (f NumberField[N]) SizeRange() (int, int) {
|
|
return int(unsafe.Sizeof(N(0))), int(unsafe.Sizeof(N(0)))
|
|
}
|
|
|
|
type PackedIntField struct {
|
|
r *uint64
|
|
}
|
|
|
|
func (f PackedIntField) FromBlock(bs []byte) (int, error) {
|
|
if len(bs) < 1 {
|
|
return 0, ErrNotEnoughBytes
|
|
}
|
|
firstByte := bs[0]
|
|
if firstByte <= 250 {
|
|
*f.r = uint64(firstByte)
|
|
return 1, nil
|
|
} else if firstByte == 252 {
|
|
if len(bs) < 3 {
|
|
return 0, ErrNotEnoughBytes
|
|
}
|
|
var v uint16
|
|
utils.ReadNumberLittleEndianHack(&v, bs[1:])
|
|
*f.r = uint64(v)
|
|
return 3, nil
|
|
} else if firstByte == 253 {
|
|
if len(bs) < 4 {
|
|
return 0, ErrNotEnoughBytes
|
|
}
|
|
v := uint32(bs[0]) + uint32(bs[1])<<8 + uint32(bs[2])<<16
|
|
*f.r = uint64(v)
|
|
return 4, nil
|
|
} else if firstByte == 254 {
|
|
if len(bs) < 9 {
|
|
return 0, ErrNotEnoughBytes
|
|
}
|
|
utils.ReadNumberLittleEndianHack(f.r, bs[1:])
|
|
return 9, nil
|
|
} else {
|
|
return 0, errors.New("packed int invalid")
|
|
}
|
|
}
|
|
|
|
func (f PackedIntField) FromStream(r io.Reader) error {
|
|
head := [1]byte{}
|
|
if _, err := io.ReadFull(r, head[:]); err != nil {
|
|
return fmt.Errorf("unable to read: %w", err)
|
|
}
|
|
|
|
firstByte := head[0]
|
|
if firstByte <= 250 {
|
|
*f.r = uint64(firstByte)
|
|
return nil
|
|
} else if firstByte == 252 {
|
|
bs := [2]byte{}
|
|
if _, err := io.ReadFull(r, bs[:]); err != nil {
|
|
return fmt.Errorf("unable to read: %w", err)
|
|
}
|
|
var v uint16
|
|
utils.ReadNumberLittleEndianHack(&v, bs[:])
|
|
*f.r = uint64(v)
|
|
return nil
|
|
} else if firstByte == 253 {
|
|
bs := [3]byte{}
|
|
if _, err := io.ReadFull(r, bs[:3]); err != nil {
|
|
return fmt.Errorf("unable to read: %w", err)
|
|
}
|
|
var v uint32
|
|
utils.ReadNumberLittleEndianHack(&v, bs[:])
|
|
*f.r = uint64(v)
|
|
return nil
|
|
} else if firstByte == 254 {
|
|
bs := [8]byte{}
|
|
if _, err := io.ReadFull(r, bs[:]); err != nil {
|
|
return fmt.Errorf("unable to read: %w", err)
|
|
}
|
|
utils.ReadNumberLittleEndianHack(f.r, bs[:])
|
|
return nil
|
|
} else {
|
|
return errors.New("packed int invalid")
|
|
}
|
|
}
|
|
|
|
func (f PackedIntField) Type() FieldType {
|
|
return PackedIntType
|
|
}
|
|
|
|
func (f PackedIntField) IsVariant() bool {
|
|
return true
|
|
}
|
|
|
|
func (f PackedIntField) SizeRange() (int, int) {
|
|
return 1, 5
|
|
}
|
|
|
|
type BytesField[N constraints.Integer, B ~[]byte] struct {
|
|
l *N
|
|
r *B
|
|
nullEnd bool
|
|
}
|
|
|
|
func (f BytesField[N, B]) FromBlock(data []byte) (int, error) {
|
|
// Copy to end
|
|
if f.l == nil {
|
|
*f.r = make([]byte, len(data))
|
|
copy(*f.r, data)
|
|
return len(data), nil
|
|
} else {
|
|
|
|
// Read length
|
|
l := int(*f.l)
|
|
if len(data) < l {
|
|
return 0, ErrNotEnoughBytes
|
|
}
|
|
|
|
// Copy
|
|
if !f.nullEnd {
|
|
*f.r = make([]byte, l)
|
|
copy(*f.r, data[:l])
|
|
} else {
|
|
if l == 0 {
|
|
return 0, ErrNotEnoughBytes
|
|
}
|
|
if data[l] != 0 {
|
|
return 0, ErrNotNull
|
|
}
|
|
*f.r = make([]byte, l-1)
|
|
copy(*f.r, data[:l-1])
|
|
}
|
|
|
|
return l, nil
|
|
}
|
|
}
|
|
|
|
func (f BytesField[N, B]) FromStream(r io.Reader) error {
|
|
// Copy to end
|
|
if f.l == nil {
|
|
var err error
|
|
*f.r, err = io.ReadAll(r)
|
|
if err != nil {
|
|
return fmt.Errorf("unable to read: %w", err)
|
|
}
|
|
return nil
|
|
} else {
|
|
|
|
// Read length
|
|
l := int(*f.l)
|
|
|
|
// Copy
|
|
if !f.nullEnd {
|
|
*f.r = make([]byte, l)
|
|
if _, err := io.ReadFull(r, *f.r); err != nil {
|
|
if err == io.ErrUnexpectedEOF {
|
|
return ErrNotEnoughBytes
|
|
}
|
|
return fmt.Errorf("unable to read: %w", err)
|
|
}
|
|
} else {
|
|
if l == 0 {
|
|
return ErrNotEnoughBytes
|
|
}
|
|
*f.r = make([]byte, l)
|
|
if _, err := io.ReadFull(r, *f.r); err != nil {
|
|
if err == io.ErrUnexpectedEOF {
|
|
return ErrNotEnoughBytes
|
|
}
|
|
return fmt.Errorf("unable to read: %w", err)
|
|
}
|
|
trailNull := [1]byte{}
|
|
if _, err := io.ReadFull(r, trailNull[:]); err != nil {
|
|
return fmt.Errorf("unable to read: %w", err)
|
|
}
|
|
if trailNull[0] != 0 {
|
|
return ErrNotNull
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
}
|
|
|
|
func (f BytesField[N, B]) Type() FieldType {
|
|
return BytesType
|
|
}
|
|
|
|
func (f BytesField[N, B]) IsVariant() bool {
|
|
return true
|
|
}
|
|
|
|
func (f BytesField[N, B]) SizeRange() (int, int) {
|
|
return 0, math.MaxInt
|
|
}
|
|
|
|
type BitSetField[N constraints.Integer] struct {
|
|
l *N
|
|
r *bitmap.Bitmap
|
|
}
|
|
|
|
func (f BitSetField[N]) FromBlock(data []byte) (int, error) {
|
|
// Read length
|
|
l := (int(*f.l) + 7) / 8
|
|
if len(data) < l {
|
|
return 0, ErrNotEnoughBytes
|
|
}
|
|
|
|
// Copy
|
|
buf := make([]byte, l)
|
|
copy(buf, data[:l])
|
|
*f.r = bitmap.NewBitmap(buf, int(*f.l))
|
|
|
|
return l, nil
|
|
}
|
|
|
|
func (f BitSetField[N]) FromStream(r io.Reader) error {
|
|
// Read length
|
|
l := (int(*f.l) + 7) / 8
|
|
|
|
// Copy
|
|
buf := make([]byte, l)
|
|
if _, err := io.ReadFull(r, buf); err != nil {
|
|
if err == io.ErrUnexpectedEOF {
|
|
return ErrNotEnoughBytes
|
|
}
|
|
return fmt.Errorf("unable to read: %w", err)
|
|
}
|
|
*f.r = bitmap.NewBitmap(buf, int(*f.l))
|
|
|
|
return nil
|
|
}
|
|
|
|
func (f BitSetField[N]) Type() FieldType {
|
|
return BitSetType
|
|
}
|
|
|
|
func (f BitSetField[N]) IsVariant() bool {
|
|
return true
|
|
}
|
|
|
|
func (f BitSetField[N]) SizeRange() (int, int) {
|
|
return 0, math.MaxInt
|
|
}
|
|
|
|
type UUIDField struct {
|
|
r *uuid.UUID
|
|
}
|
|
|
|
func (f UUIDField) FromBlock(data []byte) (int, error) {
|
|
if err := checkDataSize(16, data); err != nil {
|
|
return 0, err
|
|
}
|
|
copy((*f.r)[:], data)
|
|
return 16, nil
|
|
}
|
|
|
|
func (f UUIDField) FromStream(r io.Reader) error {
|
|
_, err := io.ReadFull(r, (*f.r)[:])
|
|
if err != nil {
|
|
return fmt.Errorf("unable to read: %w", err)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (f UUIDField) Type() FieldType {
|
|
return UUIDType
|
|
}
|
|
|
|
func (f UUIDField) IsVariant() bool {
|
|
return false
|
|
}
|
|
|
|
func (f UUIDField) SizeRange() (int, int) {
|
|
return 16, 16
|
|
}
|
|
|
|
type RepeatField[N constraints.Integer, T any] struct {
|
|
size *N
|
|
r *[]T
|
|
bind func(x *T) []Field
|
|
}
|
|
|
|
func (rf RepeatField[N, T]) FromBlock(data []byte) (int, error) {
|
|
if rf.size == nil {
|
|
sl, sr := rf.fieldsSizeRange()
|
|
if sl != sr {
|
|
return 0, errors.New("repeated fields are not in fixed size")
|
|
}
|
|
|
|
if err := rf.fromBytesInfinite(data, sl); err != nil {
|
|
return 0, err
|
|
}
|
|
return len(data), nil
|
|
} else {
|
|
buf := bytes.NewBuffer(data)
|
|
if err := rf.fromReaderFinite(buf); err != nil {
|
|
return 0, err
|
|
}
|
|
return len(data) - buf.Cap(), nil
|
|
}
|
|
}
|
|
|
|
func (rf *RepeatField[N, T]) fromReaderOne(r io.Reader, x *T, i int) error {
|
|
fields := rf.bind(x)
|
|
for fieldIndex, f := range fields {
|
|
if f == nil {
|
|
continue
|
|
}
|
|
err := f.FromStream(r)
|
|
if err != nil {
|
|
return fmt.Errorf("unable to extract field[%s, %d] of data[%d]: %w", FieldTypeName(f.Type()), fieldIndex, i, err)
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (rf *RepeatField[N, T]) fromReaderFinite(r io.Reader) error {
|
|
l := int(*rf.size)
|
|
rr := make([]T, l)
|
|
for i := 0; i < l; i++ {
|
|
if err := rf.fromReaderOne(r, &rr[i], i); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
*rf.r = rr
|
|
return nil
|
|
}
|
|
|
|
func (rf *RepeatField[N, T]) fieldsSizeRange() (int, int) {
|
|
var x T
|
|
fields := rf.bind(&x)
|
|
sl, sr := 0, 0
|
|
for _, f := range fields {
|
|
if f == nil {
|
|
continue
|
|
}
|
|
l, r := f.SizeRange()
|
|
sl += l
|
|
if sr == math.MaxInt || r == math.MaxInt {
|
|
sr = math.MaxInt
|
|
} else {
|
|
sr += r
|
|
}
|
|
}
|
|
return sl, sr
|
|
}
|
|
|
|
func (rf *RepeatField[N, T]) fromBytesInfinite(data []byte, oneSize int) error {
|
|
if len(data)%oneSize != 0 {
|
|
return fmt.Errorf("left data is not fit for repeated fields, left: %d, each: %d", len(data), oneSize)
|
|
}
|
|
|
|
buf := bytes.NewBuffer(data)
|
|
rr := make([]T, len(data)/oneSize)
|
|
for i := 0; i < len(data)/oneSize; i++ {
|
|
if err := rf.fromReaderOne(buf, &rr[i], i); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (rf *RepeatField[N, T]) fromReaderInfinite(r io.Reader) error {
|
|
sl, sr := rf.fieldsSizeRange()
|
|
if sl != sr {
|
|
return errors.New("repeated fields are not in fixed size")
|
|
}
|
|
|
|
data, err := io.ReadAll(r)
|
|
if err != nil {
|
|
return fmt.Errorf("unable to read: %w", err)
|
|
}
|
|
|
|
return rf.fromBytesInfinite(data, sl)
|
|
}
|
|
|
|
func (rf RepeatField[N, T]) FromStream(r io.Reader) error {
|
|
if rf.size == nil {
|
|
return rf.fromReaderInfinite(r)
|
|
} else {
|
|
return rf.fromReaderFinite(r)
|
|
}
|
|
}
|
|
|
|
func (rf RepeatField[N, T]) Type() FieldType {
|
|
return RepeatType
|
|
}
|
|
|
|
func (rf RepeatField[N, T]) IsVariant() bool {
|
|
return true
|
|
}
|
|
|
|
func (rf RepeatField[N, T]) SizeRange() (int, int) {
|
|
return 0, math.MaxInt
|
|
}
|
|
|
|
type SkipField[N constraints.Integer] struct {
|
|
l *N
|
|
}
|
|
|
|
func (s SkipField[N]) FromBlock(data []byte) (int, error) {
|
|
// Skip all
|
|
if s.l == nil {
|
|
return len(data), nil
|
|
} else {
|
|
|
|
// Skip to length
|
|
l := int(*s.l)
|
|
if err := checkDataSize(l, data); err != nil {
|
|
return 0, err
|
|
}
|
|
|
|
return l, nil
|
|
}
|
|
}
|
|
|
|
func (s SkipField[N]) FromStream(r io.Reader) error {
|
|
// Skip all
|
|
if s.l == nil {
|
|
_, err := io.Copy(io.Discard, r)
|
|
if err != nil {
|
|
return fmt.Errorf("unable to skip: %w", err)
|
|
}
|
|
return nil
|
|
} else {
|
|
// Skip to length
|
|
l := int(*s.l)
|
|
err := utils.SkipBytes(r, int64(l))
|
|
if err != nil {
|
|
if err == io.EOF {
|
|
return ErrNotEnoughBytes
|
|
}
|
|
return fmt.Errorf("unable to skip: %w", err)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
}
|
|
|
|
func (s SkipField[N]) Type() FieldType {
|
|
return SkipType
|
|
}
|
|
|
|
func (s SkipField[N]) IsVariant() bool {
|
|
return true
|
|
}
|
|
|
|
func (s SkipField[N]) SizeRange() (int, int) {
|
|
return 0, math.MaxInt
|
|
}
|
|
|
|
type BlockHandle func(data []byte) (int, error)
|
|
type StreamHandle func(r io.Reader) error
|
|
|
|
type Handler interface {
|
|
~func(data []byte) (int, error) | ~func(r io.Reader) error
|
|
}
|
|
|
|
func handleBlock[H Handler](block []byte, h H) (int, error) {
|
|
v := any(h)
|
|
if bh, ok := v.(func(data []byte) (int, error)); ok {
|
|
return bh(block)
|
|
}
|
|
if sh, ok := v.(func(r io.Reader) error); ok {
|
|
r := bytes.NewBuffer(block)
|
|
if err := sh(r); err != nil {
|
|
return 0, err
|
|
}
|
|
return len(block) - r.Len(), nil
|
|
}
|
|
panic("never reach here")
|
|
}
|
|
|
|
func handleStream[H Handler](r io.Reader, h H) error {
|
|
v := any(h)
|
|
if bh, ok := v.(func(data []byte) (int, error)); ok {
|
|
block, err := io.ReadAll(r)
|
|
if err != nil {
|
|
return fmt.Errorf("unable to read: %w", err)
|
|
}
|
|
_, err = bh(block)
|
|
return err
|
|
}
|
|
if sh, ok := v.(func(r io.Reader) error); ok {
|
|
return sh(r)
|
|
}
|
|
panic("never reach here")
|
|
}
|
|
|
|
type AreaField[N constraints.Integer, H Handler] struct {
|
|
l *N
|
|
h H
|
|
}
|
|
|
|
func (a AreaField[N, H]) FromBlock(data []byte) (int, error) {
|
|
if a.l == nil {
|
|
return handleBlock[H](data, a.h)
|
|
} else {
|
|
l := int(*a.l)
|
|
if err := checkDataSize(l, data); err != nil {
|
|
return 0, err
|
|
}
|
|
|
|
return handleBlock[H](data[:l], a.h)
|
|
}
|
|
}
|
|
|
|
func (a AreaField[N, H]) FromStream(r io.Reader) error {
|
|
if a.l == nil {
|
|
return handleStream[H](r, a.h)
|
|
} else {
|
|
l := int64(*a.l)
|
|
return handleStream(io.LimitReader(r, l), a.h)
|
|
}
|
|
}
|
|
|
|
func (a AreaField[N, H]) Type() FieldType {
|
|
return AreaType
|
|
}
|
|
|
|
func (a AreaField[N, H]) IsVariant() bool {
|
|
return true
|
|
}
|
|
|
|
func (a AreaField[N, H]) SizeRange() (int, int) {
|
|
return 0, math.MaxInt
|
|
}
|
|
|
|
// Declare helpers.
|
|
|
|
func Null() NullField {
|
|
return NullField{}
|
|
}
|
|
|
|
func Bool(r *bool) BoolField {
|
|
return BoolField{r: r}
|
|
}
|
|
|
|
func Number[N constraints.Integer | constraints.Float](r *N) NumberField[N] {
|
|
return NumberField[N]{r: r}
|
|
}
|
|
|
|
func PackedInt(r *uint64) PackedIntField {
|
|
return PackedIntField{r: r}
|
|
}
|
|
|
|
func Bytes[N constraints.Integer, B ~[]byte](l *N, r *B) BytesField[N, B] {
|
|
return BytesField[N, B]{l: l, r: r}
|
|
}
|
|
|
|
func BytesEndWithNull[N constraints.Integer, B ~[]byte](l *N, r *B) BytesField[N, B] {
|
|
return BytesField[N, B]{l: l, r: r, nullEnd: true}
|
|
}
|
|
|
|
func BitSet[N constraints.Integer](l *N, r *bitmap.Bitmap) BitSetField[N] {
|
|
if l == nil {
|
|
panic("infinite bitset field is not allowed")
|
|
}
|
|
return BitSetField[N]{l: l, r: r}
|
|
}
|
|
|
|
func UUID(r *uuid.UUID) UUIDField {
|
|
return UUIDField{r: r}
|
|
}
|
|
|
|
func Array[N constraints.Integer, T any](l *N, r *[]T, bind func(x *T) Field) RepeatField[N, T] {
|
|
return RepeatField[N, T]{size: l, r: r, bind: func(x *T) []Field {
|
|
return []Field{bind(x)}
|
|
}}
|
|
}
|
|
|
|
func Repeat[N constraints.Integer, T any](l *N, r *[]T, bind func(x *T) []Field) RepeatField[N, T] {
|
|
return RepeatField[N, T]{size: l, r: r, bind: bind}
|
|
}
|
|
|
|
func Const[T any](t T) *T {
|
|
return &t
|
|
}
|
|
|
|
func Infinite() *uint8 {
|
|
return nil
|
|
}
|
|
|
|
func Skip[T constraints.Integer](t *T) SkipField[T] {
|
|
return SkipField[T]{l: t}
|
|
}
|
|
|
|
func Area[T constraints.Integer, H Handler](l *T, h H) AreaField[T, H] {
|
|
return AreaField[T, H]{l: l, h: h}
|
|
}
|