150 lines
4 KiB
Go
150 lines
4 KiB
Go
package parse
|
|
|
|
import (
|
|
"bytes"
|
|
"errors"
|
|
"fmt"
|
|
|
|
"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-lens/schema/parse/types"
|
|
cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
|
|
objectSDK "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object"
|
|
oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id"
|
|
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/user"
|
|
"github.com/nspcc-dev/neo-go/pkg/io"
|
|
)
|
|
|
|
type Parser func(init []byte) (result Result, next []byte, err error)
|
|
|
|
func Prefix(prefix types.Prefix) Parser {
|
|
return func(init []byte) (result Result, next []byte, err error) {
|
|
init, found := bytes.CutPrefix(init, []byte{byte(prefix)})
|
|
if !found {
|
|
return nil, init, fmt.Errorf("expected prefix %d", prefix)
|
|
}
|
|
return prefix, init, nil
|
|
}
|
|
}
|
|
|
|
func CID(init []byte) (result Result, next []byte, err error) {
|
|
if len(init) < 32 {
|
|
return nil, init, errors.New("can't parse CID, not enough data")
|
|
}
|
|
id := new(cid.ID)
|
|
err = id.Decode(init[:32])
|
|
if err != nil {
|
|
return nil, init, fmt.Errorf("can't parse CID: %w", err)
|
|
}
|
|
return &types.CID{ID: *id}, init[32:], nil
|
|
}
|
|
|
|
func OID(init []byte) (result Result, next []byte, err error) {
|
|
if len(init) < 32 {
|
|
return nil, init, errors.New("can't parse OID, not enough data")
|
|
}
|
|
id := new(oid.ID)
|
|
err = id.Decode(init[:32])
|
|
if err != nil {
|
|
return nil, init, fmt.Errorf("can't parse OID: %w", err)
|
|
}
|
|
return &types.OID{ID: *id}, init[32:], nil
|
|
}
|
|
|
|
func UID(init []byte) (result Result, next []byte, err error) {
|
|
id := new(user.ID)
|
|
if err = id.DecodeString(string(init)); err != nil {
|
|
return nil, init, fmt.Errorf("can't parse UID: %w", err)
|
|
}
|
|
return &types.UID{ID: *id}, nil, nil
|
|
}
|
|
|
|
func Checksum(init []byte) (result Result, next []byte, err error) {
|
|
if len(init) < 32 {
|
|
return nil, init, errors.New("can't parse checksum, not enough data")
|
|
}
|
|
return &types.Checksum{Value: init[:32]}, init[32:], nil
|
|
}
|
|
|
|
func Object(init []byte) (result Result, next []byte, err error) {
|
|
obj := objectSDK.New()
|
|
if err = obj.Unmarshal(init); err != nil {
|
|
return nil, init, fmt.Errorf("can't parse object: %w", err)
|
|
}
|
|
return &types.Object{Obj: obj}, nil, nil
|
|
}
|
|
|
|
func StorageID(init []byte) (result Result, next []byte, err error) {
|
|
if len(init) == 0 {
|
|
return nil, init, errors.New("can't parse storage id, unexpected EOF")
|
|
}
|
|
return &resultFromString{string(init)}, nil, nil
|
|
}
|
|
|
|
func Attribute(init []byte) (result Result, next []byte, err error) {
|
|
if len(init) == 0 {
|
|
return nil, init, errors.New("can't parse attribute, unexpected EOF")
|
|
}
|
|
return &resultFromString{string(init)}, nil, nil
|
|
}
|
|
|
|
func OIDsList(init []byte) (result Result, next []byte, err error) {
|
|
r := io.NewBinReaderFromBuf(init)
|
|
|
|
size := r.ReadVarUint()
|
|
oids := make([]Result, size)
|
|
|
|
var i uint64
|
|
for ; i < size; i++ {
|
|
id := new(oid.ID)
|
|
if err = id.Decode(r.ReadVarBytes()); err != nil {
|
|
return nil, init, fmt.Errorf("can't parse list of OIDs: %w", err)
|
|
}
|
|
oids[i] = types.OID{ID: *id}
|
|
}
|
|
return &resultUnion{oids}, nil, nil
|
|
}
|
|
|
|
func Skip(_ []byte) (result Result, next []byte, err error) {
|
|
return &resultFromString{}, nil, nil
|
|
}
|
|
|
|
func EOF(init []byte) (result Result, next []byte, err error) {
|
|
if len(init) != 0 {
|
|
return nil, init, fmt.Errorf("expected EOF but got %v", init)
|
|
}
|
|
return &resultFromString{}, nil, err
|
|
}
|
|
|
|
func Any(parsers ...Parser) Parser {
|
|
return func(init []byte) (result Result, next []byte, err error) {
|
|
var errs error
|
|
for _, parser := range parsers {
|
|
result, next, err = parser(init)
|
|
if err == nil {
|
|
return result, next, nil
|
|
}
|
|
errs = errors.Join(errs, err)
|
|
}
|
|
return nil, init, errs
|
|
}
|
|
}
|
|
|
|
func Chain(parsers ...Parser) Parser {
|
|
return func(init []byte) (result Result, next []byte, err error) {
|
|
var results []Result
|
|
|
|
current := init
|
|
for _, parser := range parsers {
|
|
result, current, err = parser(current)
|
|
if err != nil {
|
|
return nil, init, err
|
|
}
|
|
results = append(results, result)
|
|
}
|
|
|
|
return &resultUnion{results}, current, nil
|
|
}
|
|
}
|
|
|
|
func ChainWithEOF(parsers ...Parser) Parser {
|
|
return Chain(Chain(parsers...), EOF)
|
|
}
|