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.SliceSize(c.ID, func(byte) int { return marshal.ByteSize }) 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.SliceMarshal(buf, offset, c.ID, marshal.ByteMarshal) 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) } idBytes, offset, err := marshal.SliceUnmarshal(data, offset, marshal.ByteUnmarshal) if err != nil { return err } c.ID = ID(idBytes) 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 }