policy-engine/pkg/chain/marshal.go
Dmitrii Stepanov 58386edf58 [#1] chain: Add binary marshal/unmarshal
Signed-off-by: Dmitrii Stepanov <d.stepanov@yadro.com>
2024-01-24 11:04:03 +03:00

257 lines
6.1 KiB
Go

package chain
import (
"encoding"
"fmt"
"git.frostfs.info/TrueCloudLab/policy-engine/pkg/marshal"
)
const (
ChainMarshalVersion uint8 = 0 // increase if breaking change
)
var (
_ encoding.BinaryMarshaler = (*Chain)(nil)
_ encoding.BinaryUnmarshaler = (*Chain)(nil)
)
func (c *Chain) MarshalBinary() ([]byte, error) {
s := marshal.UInt8Size // Marshaller version
s += marshal.UInt8Size // Chain version
s += marshal.StringSize(string(c.ID))
s += marshal.SliceSize(c.Rules, ruleSize)
s += marshal.UInt8Size // MatchType
buf := make([]byte, s)
var offset int
var err error
offset, err = marshal.UInt8Marshal(buf, offset, marshal.Version)
if err != nil {
return nil, err
}
offset, err = marshal.UInt8Marshal(buf, offset, ChainMarshalVersion)
if err != nil {
return nil, err
}
offset, err = marshal.StringMarshal(buf, offset, string(c.ID))
if err != nil {
return nil, err
}
offset, err = marshal.SliceMarshal(buf, offset, c.Rules, marshalRule)
if err != nil {
return nil, err
}
offset, err = marshal.UInt8Marshal(buf, offset, uint8(c.MatchType))
if err != nil {
return nil, err
}
if err := marshal.VerifyMarshal(buf, offset); err != nil {
return nil, err
}
return buf, nil
}
func (c *Chain) UnmarshalBinary(data []byte) error {
var offset int
marshallerVersion, offset, err := marshal.UInt8Unmarshal(data, offset)
if err != nil {
return err
}
if marshallerVersion != marshal.Version {
return fmt.Errorf("unsupported marshaller version %d", marshallerVersion)
}
chainVersion, offset, err := marshal.UInt8Unmarshal(data, offset)
if err != nil {
return err
}
if chainVersion != ChainMarshalVersion {
return fmt.Errorf("unsupported chain version %d", chainVersion)
}
idStr, offset, err := marshal.StringUnmarshal(data, offset)
if err != nil {
return err
}
c.ID = ID(idStr)
c.Rules, offset, err = marshal.SliceUnmarshal(data, offset, unmarshalRule)
if err != nil {
return err
}
matchTypeV, offset, err := marshal.UInt8Unmarshal(data, offset)
if err != nil {
return err
}
c.MatchType = MatchType(matchTypeV)
return marshal.VerifyUnmarshal(data, offset)
}
func ruleSize(r Rule) int {
s := marshal.ByteSize // Status
s += actionsSize(r.Actions)
s += resourcesSize(r.Resources)
s += marshal.BoolSize // Any
s += marshal.SliceSize(r.Condition, conditionSize)
return s
}
func marshalRule(buf []byte, offset int, r Rule) (int, error) {
offset, err := marshal.ByteMarshal(buf, offset, byte(r.Status))
if err != nil {
return 0, err
}
offset, err = marshalActions(buf, offset, r.Actions)
if err != nil {
return 0, err
}
offset, err = marshalResources(buf, offset, r.Resources)
if err != nil {
return 0, err
}
offset, err = marshal.BoolMarshal(buf, offset, r.Any)
if err != nil {
return 0, err
}
return marshal.SliceMarshal(buf, offset, r.Condition, marshalCondition)
}
func unmarshalRule(buf []byte, offset int) (Rule, int, error) {
var r Rule
statusV, offset, err := marshal.ByteUnmarshal(buf, offset)
if err != nil {
return Rule{}, 0, err
}
r.Status = Status(statusV)
r.Actions, offset, err = unmarshalActions(buf, offset)
if err != nil {
return Rule{}, 0, err
}
r.Resources, offset, err = unmarshalResources(buf, offset)
if err != nil {
return Rule{}, 0, err
}
r.Any, offset, err = marshal.BoolUnmarshal(buf, offset)
if err != nil {
return Rule{}, 0, err
}
r.Condition, offset, err = marshal.SliceUnmarshal(buf, offset, unmarshalCondition)
if err != nil {
return Rule{}, 0, err
}
return r, offset, nil
}
func actionsSize(a Actions) int {
return marshal.BoolSize + // Inverted
marshal.SliceSize(a.Names, marshal.StringSize)
}
func marshalActions(buf []byte, offset int, a Actions) (int, error) {
offset, err := marshal.BoolMarshal(buf, offset, a.Inverted)
if err != nil {
return 0, err
}
return marshal.SliceMarshal(buf, offset, a.Names, marshal.StringMarshal)
}
func unmarshalActions(buf []byte, offset int) (Actions, int, error) {
var a Actions
var err error
a.Inverted, offset, err = marshal.BoolUnmarshal(buf, offset)
if err != nil {
return Actions{}, 0, err
}
a.Names, offset, err = marshal.SliceUnmarshal(buf, offset, marshal.StringUnmarshal)
if err != nil {
return Actions{}, 0, err
}
return a, offset, nil
}
func resourcesSize(r Resources) int {
return marshal.BoolSize + // Inverted
marshal.SliceSize(r.Names, marshal.StringSize)
}
func marshalResources(buf []byte, offset int, r Resources) (int, error) {
offset, err := marshal.BoolMarshal(buf, offset, r.Inverted)
if err != nil {
return 0, err
}
return marshal.SliceMarshal(buf, offset, r.Names, marshal.StringMarshal)
}
func unmarshalResources(buf []byte, offset int) (Resources, int, error) {
var r Resources
var err error
r.Inverted, offset, err = marshal.BoolUnmarshal(buf, offset)
if err != nil {
return Resources{}, 0, err
}
r.Names, offset, err = marshal.SliceUnmarshal(buf, offset, marshal.StringUnmarshal)
if err != nil {
return Resources{}, 0, err
}
return r, offset, nil
}
func conditionSize(c Condition) int {
return marshal.ByteSize + // Op
marshal.ByteSize + // Object
marshal.StringSize(c.Key) +
marshal.StringSize(c.Value)
}
func marshalCondition(buf []byte, offset int, c Condition) (int, error) {
offset, err := marshal.ByteMarshal(buf, offset, byte(c.Op))
if err != nil {
return 0, err
}
offset, err = marshal.ByteMarshal(buf, offset, byte(c.Object))
if err != nil {
return 0, err
}
offset, err = marshal.StringMarshal(buf, offset, c.Key)
if err != nil {
return 0, err
}
return marshal.StringMarshal(buf, offset, c.Value)
}
func unmarshalCondition(buf []byte, offset int) (Condition, int, error) {
var c Condition
opV, offset, err := marshal.ByteUnmarshal(buf, offset)
if err != nil {
return Condition{}, 0, err
}
c.Op = ConditionType(opV)
obV, offset, err := marshal.ByteUnmarshal(buf, offset)
if err != nil {
return Condition{}, 0, err
}
c.Object = ObjectType(obV)
c.Key, offset, err = marshal.StringUnmarshal(buf, offset)
if err != nil {
return Condition{}, 0, err
}
c.Value, offset, err = marshal.StringUnmarshal(buf, offset)
if err != nil {
return Condition{}, 0, err
}
return c, offset, nil
}