pub struct MagicRule {
pub offset: OffsetSpec,
pub typ: TypeKind,
pub op: Operator,
pub value: Value,
pub message: String,
pub children: Vec<MagicRule>,
pub level: u32,
pub strength_modifier: Option<StrengthModifier>,
pub value_transform: Option<ValueTransform>,
}Expand description
Magic rule representation in the AST
Fields§
§offset: OffsetSpecOffset specification for where to read data
typ: TypeKindType of data to read and interpret
op: OperatorComparison operator to apply
value: ValueExpected value for comparison
message: StringHuman-readable message for this rule
children: Vec<MagicRule>Child rules that are evaluated if this rule matches
level: u32Indentation level for hierarchical rules
strength_modifier: Option<StrengthModifier>Optional strength modifier from !:strength directive
value_transform: Option<ValueTransform>Optional pre-comparison value transform from a magic-file
type-suffix like lelong+1 or ulequad/1073741824. When set,
the read value is transformed before op is evaluated and
before the message’s %-format substitution, so format
specifiers see the post-transform number.
#[serde(default)] keeps existing serialized AST snapshots
(which never had this field) round-tripping correctly: missing
fields deserialize to None, which means “no transform” –
the historical behavior.
Implementations§
Source§impl MagicRule
impl MagicRule
Sourcepub const MAX_LEVEL: u32 = 1000
pub const MAX_LEVEL: u32 = 1000
Hard structural ceiling on rule level.
This is a conservative upper bound enforced by
MagicRule::validate to keep the AST shape sane: real
magic files in the wild rarely exceed ~10 levels of nesting,
so rejecting rules with level > 1000 catches obviously
pathological input at construction time without constraining
any legitimate rule.
This ceiling is independent of the evaluator’s
EvaluationConfig::max_recursion_depth (default 20), which
is the runtime recursion guard applied during rule
evaluation. The evaluator limit is the first one that fires
in practice – a rule tree with 50 levels passes this
structural check but is aborted by the evaluator long before
reaching MAX_LEVEL. The two limits serve different purposes:
MAX_LEVEL is an AST-shape sanity check, and
max_recursion_depth is a per-evaluation resource bound.
Sourcepub fn new(
offset: OffsetSpec,
typ: TypeKind,
op: Operator,
value: Value,
message: String,
) -> Self
pub fn new( offset: OffsetSpec, typ: TypeKind, op: Operator, value: Value, message: String, ) -> Self
Construct a top-level rule with no children and no strength modifier.
This is the most common constructor for programmatically building
rules outside the parser. To add children, mutate
MagicRule::children directly, or use MagicRule::with_children.
To set a strength modifier, use
MagicRule::with_strength_modifier.
§Examples
use libmagic_rs::{MagicRule, OffsetSpec, Operator, TypeKind, Value};
let rule = MagicRule::new(
OffsetSpec::Absolute(0),
TypeKind::Byte { signed: false },
Operator::Equal,
Value::Uint(0x7f),
"ELF magic byte".to_string(),
);
assert_eq!(rule.level, 0);
assert!(rule.children.is_empty());
assert!(rule.validate().is_ok());Sourcepub fn with_children(self, children: Vec<MagicRule>) -> Self
pub fn with_children(self, children: Vec<MagicRule>) -> Self
Replace self.children with the given children and return the
modified rule. Builder-style for chaining.
Sourcepub const fn with_strength_modifier(self, modifier: StrengthModifier) -> Self
pub const fn with_strength_modifier(self, modifier: StrengthModifier) -> Self
Set self.strength_modifier to the given value and return the
modified rule. Builder-style for chaining.
Sourcepub const fn with_level(self, level: u32) -> Self
pub const fn with_level(self, level: u32) -> Self
Set self.level to the given value and return the modified rule.
Builder-style for chaining; typically used only when constructing
child rules programmatically.
Sourcepub fn validate(&self) -> Result<(), MagicRuleValidationError>
pub fn validate(&self) -> Result<(), MagicRuleValidationError>
Validate structural invariants of the rule.
This checks invariants that the parser enforces automatically but that programmatic constructors (especially via serde deserialize) can violate:
- Message must not be empty.
levelmust not exceedSelf::MAX_LEVEL.- Every child’s
levelmust be strictly greater thanself.level, and each child must recursively validate.
This does not validate that value is shape-compatible with
typ (e.g., a Value::Uint against a TypeKind::String); such
mismatches are coerced or rejected by the evaluator at match time.
§Errors
Returns MagicRuleValidationError describing the first
invariant violation encountered.
§Examples
use libmagic_rs::{MagicRule, OffsetSpec, Operator, TypeKind, Value};
let rule = MagicRule::new(
OffsetSpec::Absolute(0),
TypeKind::Byte { signed: false },
Operator::Equal,
Value::Uint(0),
"zero byte".to_string(),
);
assert!(rule.validate().is_ok());