feat(parser): implement quad 64-bit integer type with endian variants#133
Conversation
Signed-off-by: UncleSp1d3r <unclesp1d3r@evilbitlabs.io>
Signed-off-by: UncleSp1d3r <unclesp1d3r@evilbitlabs.io>
Signed-off-by: UncleSp1d3r <unclesp1d3r@evilbitlabs.io>
Signed-off-by: UncleSp1d3r <unclesp1d3r@evilbitlabs.io>
Signed-off-by: UncleSp1d3r <unclesp1d3r@evilbitlabs.io>
Signed-off-by: UncleSp1d3r <unclesp1d3r@evilbitlabs.io>
…-with-endian-variants
|
Caution Review failedThe pull request is closed. ℹ️ Recent review infoConfiguration used: Organization UI Review profile: CHILL Plan: Pro Disabled knowledge base sources:
📒 Files selected for processing (22)
Summary by CodeRabbit
WalkthroughAdds a 64-bit integer TypeKind::Quad { endian, signed }, refactors parser into grammar/types/codegen, moves built-in rules generation to parser::codegen for build-time codegen, updates evaluator (read/coerce/strength) for Quad, renames MatchResult→RuleMatch across API, and extends tests/docs for Quad support. Changes
Sequence Diagram(s)mermaid Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches
🧪 Generate unit tests (beta)
Comment |
Merge ProtectionsYour pull request matches the following merge protections and will not be merged until they are valid. 🟢 CI must passWonderful, this rule succeeded.All CI checks must pass. Release-plz PRs are exempt because they only bump versions and changelogs (code was already tested on main), and GITHUB_TOKEN-triggered force-pushes suppress CI.
🟢 Do not merge outdated PRsWonderful, this rule succeeded.Make sure PRs are within 10 commits of the base branch before merging
|
Signed-off-by: UncleSp1d3r <unclesp1d3r@evilbitlabs.io>
There was a problem hiding this comment.
Pull request overview
Adds first-class support for libmagic’s 64-bit integer types (quad / uquad) across parsing, AST/type system, evaluation, and strength scoring, with accompanying tests and documentation updates.
Changes:
- Extend the type system and parser to recognize
quad/uquadwith endian variants and full-width&maskparsing. - Implement safe 64-bit reads in the evaluator and integrate
Quadinto typed reads, coercion, and strength scoring. - Add/extend unit + integration tests and update roadmap/agent documentation to reflect completed quad support.
Reviewed changes
Copilot reviewed 11 out of 11 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| tests/property_tests.rs | Generates TypeKind::Quad and endianness variants for proptest coverage. |
| tests/integration_tests.rs | Adds end-to-end tests for lequad/bequad/signed quad and nested-rule offset behavior. |
| src/parser/grammar.rs | Adds unsigned numeric parsing for full u64 literal range; extends type parsing for quad + full-width &mask. |
| src/parser/ast.rs | Introduces TypeKind::Quad { endian, signed } and updates serialization tests. |
| src/evaluator/types.rs | Adds read_quad, strengthens bounds checks, wires quad into typed reads and coercion logic, adds tests. |
| src/evaluator/strength.rs | Assigns default strength for quad types and adds a targeted test. |
| src/build_helpers.rs | Updates build-time serialization helpers + tests for the new TypeKind::Quad variant. |
| build.rs | Mirrors TypeKind::Quad serialization for build-time rule compilation. |
| ROADMAP.md | Marks quad support as completed. |
| AGENTS.md | Documents quad support and updates process/merge-policy notes. |
|
Documentation Updates 11 document(s) were updated by changes in this PR: api-referenceView Changes@@ -369,9 +369,31 @@
| `timeout_ms()` | Get timeout value |
| `reset()` | Reset to initial state |
-### MatchResult (Evaluator)
-
-**Note**: This type was removed in v0.3.0. Match results are handled internally and exposed through the `output::MatchResult` type.
+### RuleMatch (Evaluator)
+
+Internal match result type used during rule evaluation. Renamed from `MatchResult` to `RuleMatch` in v0.3.0 to resolve a naming collision with `output::MatchResult`.
+
+```rust
+use libmagic_rs::RuleMatch;
+```
+
+#### Fields
+
+| Field | Type | Description |
+|-------|------|-------------|
+| `message` | `String` | Rule message |
+| `offset` | `usize` | Match offset |
+| `level` | `u32` | Rule nesting level |
+| `value` | `Value` | Matched value |
+| `confidence` | `f64` | Confidence score (0.0-1.0) |
+
+#### Methods
+
+| Method | Description |
+|--------|-------------|
+| `calculate_confidence(level)` | Calculate confidence from rule depth |
+
+**Note**: This type is used internally by the evaluator. User-facing code should use `output::MatchResult` for formatted output.
## Output Module
@@ -449,7 +471,7 @@
pub use parser::ast::{Endianness, MagicRule, OffsetSpec, Operator, StrengthModifier, TypeKind, Value};
// Evaluator types
-pub use evaluator::EvaluationContext;
+pub use evaluator::{EvaluationContext, RuleMatch};
// Error types
pub use error::{EvaluationError, LibmagicError, ParseError};
@@ -472,6 +494,7 @@
- `TypeKind::Quad` variant added to support 64-bit quad integer types (breaking change due to exhaustive enum)
- `TypeKind::String` discriminant changed from 3 to 4 due to insertion of `Quad` variant
+- `evaluator::MatchResult` renamed to `evaluator::RuleMatch` to resolve naming collision with `output::MatchResult`
### Breaking Changes in v0.2.0
Checked Arithmetic For Buffer Offset SafetyView Changes@@ -4,7 +4,7 @@
This pattern forms a critical component of libmagic-rs's [defense-in-depth security architecture](https://app.dosu.dev/documents/1fcbd1b5-e08c-4410-9892-4bc89593d6b5), which forbids unsafe code at the workspace level and requires that all library code handle errors gracefully without panicking. When processing potentially malicious file input, unchecked integer arithmetic in offset calculations could allow attackers to craft files that trigger overflow, wrapping offset values to bypass bounds checks and access arbitrary memory. By using `.get()` with range syntax, the pattern leverages Rust's built-in overflow protection—range construction saturates on overflow, creating invalid ranges that `.get()` rejects by returning `None`.
-The pattern applies to all [type-read functions in `src/evaluator/types.rs`](https://github.com/EvilBit-Labs/libmagic-rs/blob/b589ab10df11f7e4d2b14dcb176d561ae25c089d/src/evaluator/types.rs): `read_byte`, `read_short`, `read_long`, and `read_string`. It represents durable architectural knowledge that must be followed by all current and future type readers to maintain the project's memory safety guarantees.
+The pattern applies to all [type-read functions in `src/evaluator/types.rs`](https://github.com/EvilBit-Labs/libmagic-rs/blob/b589ab10df11f7e4d2b14dcb176d561ae25c089d/src/evaluator/types.rs): `read_byte`, `read_short`, `read_long`, `read_quad`, and `read_string`. It represents durable architectural knowledge that must be followed by all current and future type readers to maintain the project's memory safety guarantees.
## The Problem: Integer Overflow in Buffer Offset Arithmetic
@@ -55,7 +55,9 @@
### Core Pattern
-All type-read functions follow this pattern:
+Type-read functions use one of two patterns depending on implementation needs:
+
+**Pattern 1: Direct Range Construction (used by `read_short` and `read_long` before PR #133)**
```rust
pub fn read_short(
@@ -75,15 +77,50 @@
}
```
-The key safety properties:
-
-1. **Range saturation**: When `offset + 2` would overflow, Rust's range construction saturates, creating an invalid range (e.g., `usize::MAX..usize::MAX`)
+**Pattern 2: Explicit Checked Addition (used by `read_short`, `read_long`, and `read_quad`)**
+
+```rust
+pub fn read_quad(
+ buffer: &[u8],
+ offset: usize,
+ endian: Endianness,
+ signed: bool,
+) -> Result<Value, TypeReadError> {
+ let end = offset.checked_add(8).ok_or(TypeReadError::BufferOverrun {
+ offset,
+ buffer_len: buffer.len(),
+ })?;
+ let bytes = buffer
+ .get(offset..end)
+ .ok_or(TypeReadError::BufferOverrun {
+ offset,
+ buffer_len: buffer.len(),
+ })?;
+
+ // Endianness handling...
+}
+```
+
+Both patterns provide equivalent safety guarantees but differ in their approach:
+
+- **Pattern 1** relies on Rust's implicit range saturation: when `offset + N` overflows, the range constructor saturates, creating an invalid range that `.get()` rejects
+- **Pattern 2** uses explicit `checked_add()` to detect overflow before range construction, making the overflow check visible in the code
+
+Pattern 2 is preferred for clarity—it makes the overflow protection explicit rather than relying on implicit saturation behavior. The explicit check also satisfies the `arithmetic_side_effects` lint, which warns about potentially overflowing operations.
+
+The key safety properties (shared by both patterns):
+
+1. **Overflow protection**: Overflow is detected either through explicit `checked_add()` or implicit range saturation
2. **Bounds validation**: `.get()` checks whether the range is valid and within buffer bounds, returning `None` for invalid ranges
3. **Error conversion**: The pattern converts `None` to a structured [`TypeReadError::BufferOverrun`](https://github.com/EvilBit-Labs/libmagic-rs/blob/b589ab10df11f7e4d2b14dcb176d561ae25c089d/src/evaluator/types.rs#L20-L25) error
4. **No panics**: All error conditions return `Result` types, enabling [graceful error handling](https://app.dosu.dev/documents/e87d2c6e)
5. **No unsafe code**: The pattern operates entirely within Rust's safe subset
-### How Range Saturation Works
+### How Overflow Protection Works
+
+Both patterns protect against integer overflow, but through different mechanisms:
+
+**Implicit Range Saturation (Pattern 1)**
Rust's range expressions use [saturating arithmetic internally](https://doc.rust-lang.org/std/ops/struct.Range.html). When constructing `offset..offset + N`:
@@ -92,7 +129,14 @@
- Such ranges are empty by definition and invalid for indexing
- `.get()` recognizes the invalid range and returns `None`
-This behavior provides automatic overflow protection without explicit checked arithmetic calls.
+**Explicit Checked Addition (Pattern 2)**
+
+The `checked_add()` method explicitly checks for overflow:
+
+- `offset.checked_add(N)` returns `Some(end)` if the addition succeeds
+- Returns `None` if the addition would overflow
+- The overflow is caught before range construction
+- The explicit check makes the safety property visible in code and satisfies linter warnings
## Implementation in Type-Read Functions
@@ -133,8 +177,12 @@
endian: Endianness,
signed: bool,
) -> Result<Value, TypeReadError> {
+ let end = offset.checked_add(2).ok_or(TypeReadError::BufferOverrun {
+ offset,
+ buffer_len: buffer.len(),
+ })?;
let bytes = buffer
- .get(offset..offset + 2)
+ .get(offset..end)
.ok_or(TypeReadError::BufferOverrun {
offset,
buffer_len: buffer.len(),
@@ -154,7 +202,7 @@
}
```
-The pattern `offset..offset + 2` safely handles the case where `offset > usize::MAX - 2`, returning `None` instead of wrapping.
+The explicit `checked_add(2)` detects overflow before constructing the range, ensuring that `offset > usize::MAX - 2` is caught and converted to a `BufferOverrun` error.
### read_long: 32-bit Access
@@ -167,8 +215,12 @@
endian: Endianness,
signed: bool,
) -> Result<Value, TypeReadError> {
+ let end = offset.checked_add(4).ok_or(TypeReadError::BufferOverrun {
+ offset,
+ buffer_len: buffer.len(),
+ })?;
let bytes = buffer
- .get(offset..offset + 4)
+ .get(offset..end)
.ok_or(TypeReadError::BufferOverrun {
offset,
buffer_len: buffer.len(),
@@ -187,6 +239,45 @@
}
}
```
+
+### read_quad: 64-bit Access
+
+[`read_quad`](https://github.com/EvilBit-Labs/libmagic-rs/blob/b589ab10df11f7e4d2b14dcb176d561ae25c089d/src/evaluator/types.rs) reads eight bytes for 64-bit integer types:
+
+```rust
+pub fn read_quad(
+ buffer: &[u8],
+ offset: usize,
+ endian: Endianness,
+ signed: bool,
+) -> Result<Value, TypeReadError> {
+ let end = offset.checked_add(8).ok_or(TypeReadError::BufferOverrun {
+ offset,
+ buffer_len: buffer.len(),
+ })?;
+ let bytes = buffer
+ .get(offset..end)
+ .ok_or(TypeReadError::BufferOverrun {
+ offset,
+ buffer_len: buffer.len(),
+ })?;
+
+ let value = match endian {
+ Endianness::Little => LittleEndian::read_u64(bytes),
+ Endianness::Big => BigEndian::read_u64(bytes),
+ Endianness::Native => NativeEndian::read_u64(bytes),
+ };
+
+ if signed {
+ #[allow(clippy::cast_possible_wrap)]
+ Ok(Value::Int(value as i64))
+ } else {
+ Ok(Value::Uint(value))
+ }
+}
+```
+
+The quad reader uses the explicit `checked_add` pattern consistently with `read_short` and `read_long`. This two-stage approach—explicit overflow check followed by bounds-checked slice access—makes the safety properties clear and satisfies the `arithmetic_side_effects` lint.
### read_string: Variable-Length Access
@@ -296,27 +387,28 @@
## Future Applicability
-The checked arithmetic pattern represents a durable architectural requirement that must be followed by all type readers, including those not yet implemented. The [current `TypeKind` enum](https://github.com/EvilBit-Labs/libmagic-rs/blob/b589ab10df11f7e4d2b14dcb176d561ae25c089d/src/evaluator/types.rs#L364-L369) supports `Byte`, `Short`, `Long`, and `String` types, but future extensions will require additional readers.
+The checked arithmetic pattern represents a durable architectural requirement that must be followed by all type readers. The [current `TypeKind` enum](https://github.com/EvilBit-Labs/libmagic-rs/blob/b589ab10df11f7e4d2b14dcb176d561ae25c089d/src/evaluator/types.rs#L364-L369) supports `Byte`, `Short`, `Long`, `Quad`, and `String` types, with future extensions requiring additional readers.
### Planned Type Readers
Future type readers must follow the same pattern:
-- **64-bit integers (quad)**: Would use `buffer.get(offset..offset + 8)`
-- **Floating-point (float)**: Would use `buffer.get(offset..offset + 4)` for IEEE 754 single precision
-- **Double-precision (double)**: Would use `buffer.get(offset..offset + 8)` for IEEE 754 double precision
+- **Floating-point (float)**: Would use `checked_add(4)` for IEEE 754 single precision
+- **Double-precision (double)**: Would use `checked_add(8)` for IEEE 754 double precision
- **Date types**: Variable size depending on format, would follow `read_string` pattern
### Pattern Requirements
Any new type reader must:
-1. Use `.get()` with range expressions for multi-byte access
-2. Return `TypeReadError::BufferOverrun` on bounds check failure
-3. Avoid explicit checked arithmetic calls (let range construction handle overflow)
+1. Use explicit `checked_add()` for offset arithmetic (preferred) or rely on implicit range saturation
+2. Use `.get()` with range expressions for multi-byte access
+3. Return `TypeReadError::BufferOverrun` on bounds check failure
4. Return `Result<Value, TypeReadError>` for error handling
5. Include documentation of security guarantees
6. Avoid `unwrap()`, `expect()`, or panic calls
+
+The explicit `checked_add()` pattern (Pattern 2) is preferred for clarity and linter compatibility, as demonstrated by `read_quad`, `read_short`, and `read_long`.
### Enforcement
@@ -333,7 +425,7 @@
| File | Purpose | Key Elements |
|------|---------|--------------|
-| [`src/evaluator/types.rs`](https://github.com/EvilBit-Labs/libmagic-rs/blob/b589ab10df11f7e4d2b14dcb176d561ae25c089d/src/evaluator/types.rs) | Type-read functions | `read_byte`, `read_short`, `read_long`, `read_string`, `TypeReadError` enum |
+| [`src/evaluator/types.rs`](https://github.com/EvilBit-Labs/libmagic-rs/blob/b589ab10df11f7e4d2b14dcb176d561ae25c089d/src/evaluator/types.rs) | Type-read functions | `read_byte`, `read_short`, `read_long`, `read_quad`, `read_string`, `TypeReadError` enum |
| [`Cargo.toml` (lines 32-140)](https://github.com/EvilBit-Labs/libmagic-rs/blob/b589ab10df11f7e4d2b14dcb176d561ae25c089d/Cargo.toml#L32-L140) | Workspace lint enforcement | [`unsafe_code = "forbid"`](https://github.com/EvilBit-Labs/libmagic-rs/blob/b589ab10df11f7e4d2b14dcb176d561ae25c089d/Cargo.toml#L34), [`indexing_slicing`](https://github.com/EvilBit-Labs/libmagic-rs/blob/b589ab10df11f7e4d2b14dcb176d561ae25c089d/Cargo.toml#L51), [`arithmetic_side_effects`](https://github.com/EvilBit-Labs/libmagic-rs/blob/b589ab10df11f7e4d2b14dcb176d561ae25c089d/Cargo.toml#L52), [`panic = "deny"`](https://github.com/EvilBit-Labs/libmagic-rs/blob/b589ab10df11f7e4d2b14dcb176d561ae25c089d/Cargo.toml#L65), [`unwrap_used = "deny"`](https://github.com/EvilBit-Labs/libmagic-rs/blob/b589ab10df11f7e4d2b14dcb176d561ae25c089d/Cargo.toml#L66) |
## Related TopicsevaluatorView Changes@@ -49,12 +49,12 @@
- `timeout_ms()` - Query configured timeout
- `reset()` - Reset context state for reuse
-### MatchResult (`evaluator/mod.rs`)
+### RuleMatch (`evaluator/mod.rs`)
Represents a successful rule match:
```rust
-pub struct MatchResult {
+pub struct RuleMatch {
/// Human-readable description from the matched rule
pub message: String,
/// Offset where the match occurred
@@ -93,6 +93,7 @@
- **Byte**: Single byte values (signed or unsigned)
- **Short**: 16-bit integers with endianness
- **Long**: 32-bit integers with endianness
+- **Quad**: 64-bit integers with endianness
- **String**: Byte sequences with length limits
- **Bounds checking**: Prevents buffer overruns
@@ -165,7 +166,7 @@
pub fn evaluate_rules(
rules: &[MagicRule],
buffer: &[u8],
-) -> Result<Vec<MatchResult>, EvaluationError>
+) -> Result<Vec<RuleMatch>, EvaluationError>
```
**Algorithm:**
@@ -281,14 +282,14 @@
rules: &[MagicRule],
buffer: &[u8],
context: &mut EvaluationContext,
-) -> Result<Vec<MatchResult>, LibmagicError>;
+) -> Result<Vec<RuleMatch>, LibmagicError>;
/// Evaluate rules with custom configuration (creates context internally)
pub fn evaluate_rules_with_config(
rules: &[MagicRule],
buffer: &[u8],
config: &EvaluationConfig,
-) -> Result<Vec<MatchResult>, LibmagicError>;
+) -> Result<Vec<RuleMatch>, LibmagicError>;
/// Evaluate a single rule (used internally and for testing)
pub fn evaluate_single_rule(
@@ -346,7 +347,7 @@
- [x] Basic evaluation engine structure
- [x] Offset resolution (absolute, relative, from-end)
-- [x] Type reading with endianness support (Byte, Short, Long, String)
+- [x] Type reading with endianness support (Byte, Short, Long, Quad, String)
- [x] Operator application (Equal, NotEqual, LessThan, GreaterThan, LessEqual, GreaterEqual, BitwiseAnd, BitwiseAndMask)
- [x] Hierarchical rule processing with child evaluation
- [x] Error handling with graceful degradationGETTING_STARTEDView Changes@@ -24,7 +24,7 @@
libmagic-rs = "0.3.0"
```
-**Note:** Version 0.3.0 introduces breaking changes. If upgrading from 0.2.x, note that a new `TypeKind::Quad` enum variant was added for 64-bit quad integer types with endian variants, `TypeKind::String` variant discriminant changed from 3 to 4, and `MatchResult` struct was removed from `libmagic_rs::evaluator`. Exhaustive pattern matching on `TypeKind` requires updates.
+**Note:** Version 0.3.0 introduces breaking changes. If upgrading from 0.2.x, note that a new `TypeKind::Quad` enum variant was added for 64-bit quad integer types with endian variants, `TypeKind::String` variant discriminant changed from 3 to 4, and `evaluator::MatchResult` was renamed to `evaluator::RuleMatch` to resolve a naming collision with `output::MatchResult`. The public re-export is `RuleMatch`. Exhaustive pattern matching on `TypeKind` requires updates.
Version 0.2.0 introduced breaking changes from 0.1.x: `TypeKind::Byte` changed from a unit variant to a tuple variant, and the `Operator` enum gained new variants (`LessThan`, `GreaterThan`, `LessEqual`, `GreaterEqual`) for comparison operations.
library-apiView Changes@@ -146,7 +146,7 @@
pub description: String, // Human-readable file type (or "data" if unknown)
pub mime_type: Option<String>, // MIME type (only when enable_mime_types is true)
pub confidence: f64, // 0.0 to 1.0, based on match depth
- pub matches: Vec<MatchResult>, // Individual rule matches with offset/level/value
+ pub matches: Vec<RuleMatch>, // Individual rule matches with offset/level/value
pub metadata: EvaluationMetadata, // Diagnostics (timing, file size, etc.)
}
```magic-examplesView Changes@@ -35,6 +35,14 @@
0 string \x7fELF ELF
>16 leshort 2 executable
>18 leshort 62 x86-64
+
+# 64-bit file signature matching
+0 lequad 0x1234567890abcdef Custom format with 64-bit magic
+0 bequad 0xfeedface00000000 Mach-O universal binary signature
+
+# Large integer value checks
+512 uquad >0x8000000000000000 Large unsigned 64-bit value
+1024 quad 0xffffffffffffffff Signed 64-bit match
```
## Hierarchical Rules
@@ -79,14 +87,25 @@
# Little-endian integers
0 leshort 0x5a4d MS-DOS executable (little-endian short)
0 lelong 0x464c457f ELF (little-endian long)
+0 lequad 0x1234567890abcdef 64-bit little-endian value
# Big-endian integers
0 beshort 0x4d5a MS-DOS executable (big-endian short)
0 belong 0x7f454c46 ELF (big-endian long)
+0 bequad 0xfeedface00000000 64-bit big-endian value
# Native endian (system default)
0 short 0x5a4d MS-DOS executable (native endian)
0 long 0x464c457f ELF (native endian)
+0 quad 0xffffffffffffffff 64-bit native endian
+
+# Unsigned variants
+0 ubyte 0xff Unsigned byte
+0 ushort 0xffff Unsigned short
+0 ulong 0xffffffff Unsigned long
+0 uquad 0xffffffffffffffff Unsigned 64-bit value
+0 ulequad >0x8000000000000000 Unsigned little-endian quad
+0 ubequad >0x8000000000000000 Unsigned big-endian quad
```
### String Matchingmagic-formatView Changes@@ -101,6 +101,7 @@
- `.b` - byte (1 byte)
- `.s` - short (2 bytes)
- `.l` - long (4 bytes)
+- `.q` - quad (8 bytes)
### Relative Offset
@@ -126,12 +127,22 @@
| `long` | 4 bytes | native |
| `lelong` | 4 bytes | little-endian |
| `belong` | 4 bytes | big-endian |
+| `quad` | 8 bytes | native |
+| `lequad` | 8 bytes | little-endian |
+| `bequad` | 8 bytes | big-endian |
+
+All integer types have unsigned variants prefixed with `u`:
+- `ubyte`, `ushort`, `uleshort`, `ubeshort`
+- `ulong`, `ulelong`, `ubelong`
+- `uquad`, `ulequad`, `ubequad`
Examples:
```
0 byte 0x7f (byte match)
0 leshort 0x5a4d DOS MZ signature
0 belong 0xcafebabe Java class file
+0 lequad 0x1234567890abcdef (64-bit little-endian)
+8 uquad >0x8000000000000000 (unsigned 64-bit check)
```
### String Type
@@ -439,7 +450,7 @@
- Absolute offsets
- Relative offsets
- Indirect offsets (basic)
-- Byte, short, long types
+- Byte, short, long, quad types (8-bit, 16-bit, 32-bit, 64-bit integers)
- String type
- Comparison operators (equal, not-equal, less-than, greater-than, less-equal, greater-equal)
- Bitwise AND operator
@@ -451,12 +462,14 @@
- Regex patterns
- Date/time types
- Float types
+- 128-bit integer types
- Use/name directives
- Default rules
### Recently Added
- **Strength modifiers**: The `!:strength` directive for adjusting rule priority
+- **64-bit integers**: `quad` type family (`quad`, `uquad`, `lequad`, `ulequad`, `bequad`, `ubequad`)
## Troubleshooting
Nom Alt Combinator Branch Limit And Nesting PatternView Changes@@ -4,7 +4,7 @@
The **Nom Alt Combinator Branch Limit And Nesting Pattern** is an architectural design pattern used in parser implementation to address potential scaling constraints when using the [nom parser combinator library](https://github.com/Geal/nom). The pattern involves organizing parser alternatives into hierarchical groups (typically by type family or bit-width) and nesting `alt()` combinators to ensure each individual `alt()` call stays within nom's compile-time limitations while maintaining parser correctness through careful ordering conventions.
-In [libmagic-rs](https://github.com/EvilBit-Labs/libmagic-rs), this pattern was identified as a critical architectural consideration for the [parse_type_and_operator function (src/parser/grammar.rs:1549-1643)](https://github.com/EvilBit-Labs/libmagic-rs/blob/b589ab10df11f7e4d2b14dcb176d561ae25c089d/src/parser/grammar.rs#L1549-L1643) during planning for type system expansion. The current implementation uses [a single `alt()` with 17 type name branches](https://github.com/EvilBit-Labs/libmagic-rs/blob/b589ab10df11f7e4d2b14dcb176d561ae25c089d/src/parser/grammar.rs#L1552-L1570), but [the roadmap targets expansion to ~31 types by v1.0.0](https://github.com/EvilBit-Labs/libmagic-rs/blob/b589ab10df11f7e4d2b14dcb176d561ae25c089d/ROADMAP.md#L28-L37), which would require restructuring to avoid exceeding tuple size constraints.
+In [libmagic-rs](https://github.com/EvilBit-Labs/libmagic-rs), this pattern was identified as a critical architectural consideration during planning for type system expansion. The current implementation in [src/parser/types.rs](https://github.com/EvilBit-Labs/libmagic-rs/blob/b589ab10df11f7e4d2b14dcb176d561ae25c089d/src/parser/types.rs) uses nested `alt()` combinators with 23 type name tokens organized into 5 family groups (64-bit, 32-bit, 16-bit, 8-bit, and string), but [the roadmap targets expansion to ~31 types by v1.0.0](https://github.com/EvilBit-Labs/libmagic-rs/blob/b589ab10df11f7e4d2b14dcb176d561ae25c089d/ROADMAP.md#L28-L37), which would require adding additional family groups to avoid exceeding tuple size constraints.
The pattern emphasizes two ordering conventions: **longer prefixes before shorter** (to prevent premature matching, e.g., `lelong` before `long`) and **unsigned before signed** (for documentation clarity and consistent family grouping). These conventions ensure correct tokenization when type names share common prefixes and maintain logical organization within type families.
@@ -12,11 +12,10 @@
The nom parser combinator library implements `alt()` using Rust tuples, which have compile-time size limits based on trait implementations. While the exact limit varies by nom version and Rust compiler version, **practical limitations typically manifest around 21 alternatives** due to tuple trait bounds in the nom implementation.
-**Evidence in libmagic-rs**: No explicit documentation of hitting this limit exists in the current codebase. The [parse_type_and_operator function currently uses 17 branches](https://github.com/EvilBit-Labs/libmagic-rs/blob/b589ab10df11f7e4d2b14dcb176d561ae25c089d/src/parser/grammar.rs#L1552-L1570), and the [parse_operator function uses manual `if let` checks rather than `alt()`](https://github.com/EvilBit-Labs/libmagic-rs/blob/b589ab10df11f7e4d2b14dcb176d561ae25c089d/src/parser/grammar.rs#L173-L248), though this appears to be for explicit precedence control rather than to work around tuple limits.
+**Evidence in libmagic-rs**: No explicit documentation of hitting this limit exists in the current codebase. The type parsing implementation in [src/parser/types.rs uses nested `alt()` calls](https://github.com/EvilBit-Labs/libmagic-rs/blob/b589ab10df11f7e4d2b14dcb176d561ae25c089d/src/parser/types.rs#L43-L76) with 23 type name tokens organized into 5 family groups, and the [parse_operator function uses manual `if let` checks rather than `alt()`](https://github.com/EvilBit-Labs/libmagic-rs/blob/b589ab10df11f7e4d2b14dcb176d561ae25c089d/src/parser/grammar.rs#L173-L248), though this appears to be for explicit precedence control rather than to work around tuple limits.
The constraint becomes relevant when considering the [type system expansion roadmap](https://github.com/EvilBit-Labs/libmagic-rs/blob/b589ab10df11f7e4d2b14dcb176d561ae25c089d/ROADMAP.md#L28-L37):
-- **Current**: 4 type variants (Byte, Short, Long, String) expanding to 17 type name tokens
-- **v0.2.0**: Add Quad types (6 additional tokens)
+- **Current**: 5 type variants (Byte, Short, Long, Quad, String) expanding to 23 type name tokens
- **v0.3.0+**: Add Float, Double, Date, Pstring, Regex, Search types with endianness variants (20+ additional tokens)
- **Target**: ~31 of 33 libmagic types by v1.0.0
@@ -28,8 +27,8 @@
The nesting pattern groups types by **bit-width families** to create logical parser organization:
-**64-bit Family** (planned for v0.2.0):
-- [Quad types: `quad`, `lequad`, `bequad`, `uquad`, `ulequad`, `ubequad`](https://github.com/EvilBit-Labs/libmagic-rs/blob/b589ab10df11f7e4d2b14dcb176d561ae25c089d/ROADMAP.md#L28)
+**64-bit Family** (currently implemented):
+- [Quad types: `quad`, `lequad`, `bequad`, `uquad`, `ulequad`, `ubequad`](https://github.com/EvilBit-Labs/libmagic-rs/blob/b589ab10df11f7e4d2b14dcb176d561ae25c089d/src/parser/types.rs#L43-L52)
**32-bit Family** (currently implemented):
- [Long types: `long`, `lelong`, `belong`, `ulong`, `ulelong`, `ubelong`](https://github.com/EvilBit-Labs/libmagic-rs/blob/b589ab10df11f7e4d2b14dcb176d561ae25c089d/src/parser/grammar.rs#L1552-L1570)
@@ -51,35 +50,46 @@
### Current Implementation Structure
-The [current parse_type_and_operator implementation (lines 1549-1643)](https://github.com/EvilBit-Labs/libmagic-rs/blob/b589ab10df11f7e4d2b14dcb176d561ae25c089d/src/parser/grammar.rs#L1549-L1643) uses a flat structure:
+The current type parsing implementation (in [src/parser/types.rs](https://github.com/EvilBit-Labs/libmagic-rs/blob/b589ab10df11f7e4d2b14dcb176d561ae25c089d/src/parser/types.rs)) uses a nested structure with 23 type name tokens organized into family groups. The quad types (6 variants) were added as a nested `alt()` within the outer structure:
```rust
-let (input, type_name) = alt((
- // 32-bit unsigned
- tag("ubelong"),
- tag("ulelong"),
- tag("ulong"),
- // 16-bit unsigned
- tag("ubeshort"),
- tag("uleshort"),
- tag("ushort"),
- // 8-bit unsigned
- tag("ubyte"),
- // 32-bit signed
- tag("lelong"),
- tag("belong"),
- tag("long"),
- // 16-bit signed
- tag("leshort"),
- tag("beshort"),
- tag("short"),
- // 8-bit signed
- tag("byte"),
- // String
+alt((
+ // 64-bit types (6 branches)
+ alt((
+ tag("ubequad"),
+ tag("ulequad"),
+ tag("uquad"),
+ tag("bequad"),
+ tag("lequad"),
+ tag("quad"),
+ )),
+ // 32-bit types (6 branches)
+ alt((
+ tag("ubelong"),
+ tag("ulelong"),
+ tag("ulong"),
+ tag("belong"),
+ tag("lelong"),
+ tag("long"),
+ )),
+ // 16-bit types (6 branches)
+ alt((
+ tag("ubeshort"),
+ tag("uleshort"),
+ tag("ushort"),
+ tag("beshort"),
+ tag("leshort"),
+ tag("short"),
+ )),
+ // 8-bit types (2 branches)
+ alt((tag("ubyte"), tag("byte"))),
+ // String types (1 branch)
tag("string"),
))
-.parse(input)?;
-```
+.parse(input)
+```
+
+This structure demonstrates the nesting pattern in action: the 64-bit quad family was added as its own nested `alt()` group, keeping each inner `alt()` to 6 or fewer branches and the outer `alt()` to 5 families.
### Nested Pattern for Future Expansion
@@ -164,6 +174,8 @@
**Correct ordering**:
```
+ubequad (7 chars) → bequad (6 chars) → quad (4 chars)
+ulequad (7 chars) → lequad (6 chars) → quad (4 chars)
ubelong (7 chars) → belong (6 chars) → long (4 chars)
ulelong (7 chars) → lelong (6 chars) → long (4 chars)
ubeshort (8 chars) → beshort (7 chars) → short (5 chars)
@@ -172,7 +184,7 @@
### Unsigned Before Signed Within Families
-The current implementation [places unsigned variants (u-prefixed) before signed variants](https://github.com/EvilBit-Labs/libmagic-rs/blob/b589ab10df11f7e4d2b14dcb176d561ae25c089d/src/parser/grammar.rs#L1552-L1570) within each bit-width family. This convention provides:
+The current implementation [places unsigned variants (u-prefixed) before signed variants](https://github.com/EvilBit-Labs/libmagic-rs/blob/b589ab10df11f7e4d2b14dcb176d561ae25c089d/src/parser/types.rs#L43-L76) within each bit-width family. This convention provides:
1. **Consistent family grouping**: All unsigned variants for a bit-width appear together, then all signed variants
2. **Documentation clarity**: Readers can quickly identify all variants of each signedness
@@ -206,10 +218,10 @@
The nesting pattern interacts with the [Enum Extension And Exhaustive Match Synchronization pattern](https://app.dosu.dev/documents/e6db8e51-ec58-458f-893a-e0c04ea79829). When adding a new type variant:
1. **AST Definition**: [Add variant to `TypeKind` enum in src/parser/ast.rs](https://github.com/EvilBit-Labs/libmagic-rs/blob/b589ab10df11f7e4d2b14dcb176d561ae25c089d/src/parser/ast.rs#L80-L107)
-2. **Parser Grammar**: Add type name tokens to appropriate family's nested `alt()` in [src/parser/grammar.rs](https://github.com/EvilBit-Labs/libmagic-rs/blob/b589ab10df11f7e4d2b14dcb176d561ae25c089d/src/parser/grammar.rs#L1552-L1570), maintaining ordering conventions
+2. **Parser Grammar**: Add type name tokens to appropriate family's nested `alt()` in [src/parser/types.rs](https://github.com/EvilBit-Labs/libmagic-rs/blob/b589ab10df11f7e4d2b14dcb176d561ae25c089d/src/parser/types.rs#L43-L76), maintaining ordering conventions
3. **Type Reading**: Update [read_typed_value() dispatch in src/evaluator/types.rs](https://github.com/EvilBit-Labs/libmagic-rs/blob/b589ab10df11f7e4d2b14dcb176d561ae25c089d/src/evaluator/types.rs#L350-L361)
4. **Strength Scoring**: Update pattern match in `src/evaluator/strength.rs`
-5. **Build-Time Serialization**: Update both `build.rs` and `src/build_helpers.rs`
+5. **Build-Time Serialization**: Update serialization in `src/parser/codegen.rs`
6. **Property Tests**: Extend test strategies in `tests/property_tests.rs`
[Rust's exhaustive pattern matching and Clippy warnings catch missed updates at compile time](https://github.com/EvilBit-Labs/libmagic-rs/pull/58).
@@ -249,7 +261,7 @@
### Extensibility Without Refactoring
The nested pattern allows the type system to scale incrementally:
-- [Adding Quad types (v0.2.0)](https://github.com/EvilBit-Labs/libmagic-rs/blob/b589ab10df11f7e4d2b14dcb176d561ae25c089d/ROADMAP.md#L28) requires introducing the 64-bit family nested `alt()`
+- Quad types (64-bit) were added using the nested structure, creating a new family group without requiring a full parser refactor
- [Adding Float/Double types (v0.3.0)](https://github.com/EvilBit-Labs/libmagic-rs/blob/b589ab10df11f7e4d2b14dcb176d561ae25c089d/ROADMAP.md#L34) requires introducing the floating-point family nested `alt()`
- Each addition stays within the existing nested structure without requiring a full refactor
@@ -297,8 +309,8 @@
| File | Description | Key Lines |
|------|-------------|-----------|
-| [src/parser/grammar.rs](https://github.com/EvilBit-Labs/libmagic-rs/blob/b589ab10df11f7e4d2b14dcb176d561ae25c089d/src/parser/grammar.rs) | Type parsing implementation with current flat `alt()` structure | 1549-1643 |
-| [src/parser/ast.rs](https://github.com/EvilBit-Labs/libmagic-rs/blob/b589ab10df11f7e4d2b14dcb176d561ae25c089d/src/parser/ast.rs) | TypeKind enum definition with 4 current variants | 80-107 |
+| [src/parser/types.rs](https://github.com/EvilBit-Labs/libmagic-rs/blob/b589ab10df11f7e4d2b14dcb176d561ae25c089d/src/parser/types.rs) | Type parsing implementation with nested `alt()` structure | 43-76 |
+| [src/parser/ast.rs](https://github.com/EvilBit-Labs/libmagic-rs/blob/b589ab10df11f7e4d2b14dcb176d561ae25c089d/src/parser/ast.rs) | TypeKind enum definition with 5 current variants including Quad | 80-117 |
| [src/evaluator/types.rs](https://github.com/EvilBit-Labs/libmagic-rs/blob/b589ab10df11f7e4d2b14dcb176d561ae25c089d/src/evaluator/types.rs) | Type reading dispatch requiring exhaustive matches | 350-361 |
| [ROADMAP.md](https://github.com/EvilBit-Labs/libmagic-rs/blob/b589ab10df11f7e4d2b14dcb176d561ae25c089d/ROADMAP.md) | Type system expansion plan showing 31-type target | 28-37 |
| [docs/src/magic-format.md](https://github.com/EvilBit-Labs/libmagic-rs/blob/b589ab10df11f7e4d2b14dcb176d561ae25c089d/docs/src/magic-format.md) | Magic file format documentation listing not-yet-supported types | 449-456 |outputView Changes@@ -14,7 +14,7 @@
### `output::MatchResult`
-Represents a single magic rule match in the output layer. Created by converting from an evaluator-level `MatchResult`, with additional fields for structured output.
+Represents a single magic rule match in the output layer. Created by converting from an evaluator-level `RuleMatch`, with additional fields for structured output.
```rust
pub struct MatchResult {
@@ -32,7 +32,7 @@
- `MatchResult::new(message, offset, value)` -- Creates a match with default confidence of 50.
- `MatchResult::with_metadata(...)` -- Creates a fully specified match. Confidence is clamped to 100.
-- `MatchResult::from_evaluator_match(m, mime_type)` -- Converts from the evaluator's `MatchResult`. Scales confidence from 0.0--1.0 to 0--100 and extracts rule path tags using the shared `TagExtractor`.
+- `MatchResult::from_evaluator_match(m, mime_type)` -- Converts from the evaluator's `RuleMatch`. Scales confidence from 0.0--1.0 to 0--100 and extracts rule path tags using the shared `TagExtractor`.
### `output::EvaluationResult`
@@ -196,7 +196,7 @@
The full conversion pipeline from evaluation to output:
```text
-evaluator::MatchResult ──from_evaluator_match──> output::MatchResult
+evaluator::RuleMatch ──from_evaluator_match──> output::MatchResult
│
┌─────────────┼─────────────┐
v v vPerformance Optimization StrategyView Changes@@ -180,7 +180,7 @@
2. **Periodic timeout checking**: Check timeout every 16 rules (using bit manipulation for efficiency)
3. **Evaluate each rule**: Call `evaluate_single_rule` with graceful error handling
4. **On match found**:
- - Create `MatchResult` and add to matches vector
+ - Create `RuleMatch` and add to matches vector
- Recursively evaluate child rules if present
- Check early exit condition and break if enabled
5. **Continue to next rule**: If no match or early exit not triggered, proceed to next ruletestingView Changes@@ -65,8 +65,10 @@
- `test_type_kind_byte` - Single byte type handling with signedness
- `test_type_kind_short` - 16-bit integer types with endianness
- `test_type_kind_long` - 32-bit integer types with endianness
+- `test_type_kind_quad` - 64-bit integer types with endianness
- `test_type_kind_string` - String types with length limits
- `test_type_kind_serialization` - All type serialization including signed/unsigned variants
+- `test_serialize_type_kind_quad` - Quad type serialization (build_helpers.rs)
**Operator Tests:**
@@ -130,6 +132,43 @@
- `test_parse_value_edge_cases` - Boundary conditions
- `test_parse_value_invalid_input` - Error handling
+#### Evaluator Component Tests
+
+**Type Reading Tests:**
+
+- `test_read_byte` - Single byte reading with signedness
+- `test_read_short_endianness_and_signedness` - 16-bit reading with all endian/sign combinations
+- `test_read_short_extreme_values` - 16-bit boundary values
+- `test_read_long_endianness_and_signedness` - 32-bit reading with all endian/sign combinations
+- `test_read_long_buffer_overrun` - 32-bit buffer boundary checking
+- `test_read_quad_endianness_and_signedness` - 64-bit reading with all endian/sign combinations
+- `test_read_quad_buffer_overrun` - 64-bit buffer boundary checking
+- `test_read_quad_at_offset` - 64-bit reading at non-zero offsets
+- `test_read_string` - Null-terminated string reading
+- `test_read_typed_value` - Dispatch to correct type reader
+
+**Value Coercion Tests:**
+
+- `test_coerce_value_to_type` - Type conversion including quad overflow handling
+
+**Strength Calculation Tests:**
+
+- `test_strength_type_byte` - Byte type strength
+- `test_strength_type_short` - 16-bit type strength
+- `test_strength_type_long` - 32-bit type strength
+- `test_strength_type_quad` - 64-bit type strength
+- `test_strength_type_string` - String type strength with/without max_length
+- `test_strength_operator_equal` - Operator strength calculations
+
+#### Integration Tests
+
+**End-to-End Evaluation Tests:**
+
+- `test_quad_lequad_matches_little_endian_value` - LE quad pattern matching
+- `test_quad_bequad_matches_big_endian_value` - BE quad pattern matching
+- `test_quad_signed_negative_one` - Signed 64-bit negative value matching
+- `test_quad_nested_child_rule_with_offset` - Quad types in hierarchical rules
+
## Test Categories
### Unit Tests
@@ -335,6 +374,23 @@
}
```
+**Testing 64-bit Integer (Quad) Types:**
+
+```rust
+#[test]
+fn test_read_quad_endianness_and_signedness() {
+ // Little-endian unsigned
+ let buffer = &[0xef, 0xcd, 0xab, 0x90, 0x78, 0x56, 0x34, 0x12];
+ let result = read_quad(buffer, 0, Endianness::Little, false).unwrap();
+ assert_eq!(result, Value::Uint(0x1234_5678_90ab_cdef));
+
+ // Big-endian signed negative
+ let buffer = &[0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff];
+ let result = read_quad(buffer, 0, Endianness::Big, true).unwrap();
+ assert_eq!(result, Value::Int(-1));
+}
+```
+
### Test Data Management
**Test Fixtures:** |
🧪 CI InsightsHere's what we observed from your CI run for 3c3f8ed. 🟢 All jobs passed!But CI Insights is watching 👀 |
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
- Updated all references to MatchResult in the evaluator module - Adjusted related documentation and tests to reflect the new name - Ensured consistency across the codebase with the new naming convention Signed-off-by: UncleSp1d3r <unclesp1d3r@evilbitlabs.io>
Signed-off-by: UncleSp1d3r <unclesp1d3r@evilbitlabs.io>
Signed-off-by: UncleSp1d3r <unclesp1d3r@evilbitlabs.io>
Update documentation for #133 _Generated by [Dosu](https://dosu.dev)_ --------- Co-authored-by: dosubot[bot] <131922026+dosubot[bot]@users.noreply.github.com> Co-authored-by: UncleSp1d3r <unclesp1d3r@evilbitlabs.io>
| m: &crate::evaluator::MatchResult, | ||
| mime_type: Option<&str>, | ||
| ) -> Self { | ||
| pub fn from_evaluator_match(m: &crate::evaluator::RuleMatch, mime_type: Option<&str>) -> Self { |
There was a problem hiding this comment.
from_evaluator_match’s rustdoc still refers to an evaluator MatchResult, but the type has been renamed to RuleMatch. Update the documentation text so it matches the new API and keeps doctext accurate.
| m: &crate::evaluator::MatchResult, | ||
| mime_type: Option<&str>, | ||
| ) -> Self { | ||
| pub fn from_evaluator_match(m: &crate::evaluator::RuleMatch, mime_type: Option<&str>) -> Self { |
There was a problem hiding this comment.
from_evaluator_match hard-codes numeric match length to 4 bytes (Value::Uint/Value::Int). With the new quad (u64/i64) type, this metadata becomes incorrect for 64-bit matches. Consider carrying the matched width/type in RuleMatch (e.g., a value_len/type_kind field) so output length can be computed accurately (8 for quad, 4 for long, etc.).
|
|
||
| // Re-export evaluator types for convenience | ||
| pub use evaluator::{EvaluationContext, MatchResult}; | ||
| pub use evaluator::{EvaluationContext, RuleMatch}; |
There was a problem hiding this comment.
This PR renames the public evaluator match type from MatchResult to RuleMatch (and updates EvaluationResult.matches accordingly), which is a breaking API change. The PR description/title focus on quad support but don’t mention this rename; please call it out explicitly (or consider keeping a deprecated type alias for backwards compatibility).
…ut MatchResult Signed-off-by: UncleSp1d3r <unclesp1d3r@evilbitlabs.io>
## 🤖 New release
* `libmagic-rs`: 0.2.1 -> 0.3.0 (⚠ API breaking changes)
### ⚠ `libmagic-rs` breaking changes
```text
--- failure enum_no_repr_variant_discriminant_changed: enum variant had its discriminant change value ---
Description:
The enum's variant had its discriminant value change. This breaks downstream code that used its value via a numeric cast like `as isize`.
ref: https://doc.rust-lang.org/reference/items/enumerations.html#assigning-discriminant-values
impl: https://github.com/obi1kenobi/cargo-semver-checks/tree/v0.46.0/src/lints/enum_no_repr_variant_discriminant_changed.ron
Failed in:
variant TypeKind::String 3 -> 4 in /tmp/.tmp3M9g71/libmagic-rs/src/parser/ast.rs:119
variant TypeKind::String 3 -> 4 in /tmp/.tmp3M9g71/libmagic-rs/src/parser/ast.rs:119
variant TypeKind::String 3 -> 4 in /tmp/.tmp3M9g71/libmagic-rs/src/parser/ast.rs:119
--- failure enum_variant_added: enum variant added on exhaustive enum ---
Description:
A publicly-visible enum without #[non_exhaustive] has a new variant.
ref: https://doc.rust-lang.org/cargo/reference/semver.html#enum-variant-new
impl: https://github.com/obi1kenobi/cargo-semver-checks/tree/v0.46.0/src/lints/enum_variant_added.ron
Failed in:
variant TypeKind:Quad in /tmp/.tmp3M9g71/libmagic-rs/src/parser/ast.rs:112
variant TypeKind:Quad in /tmp/.tmp3M9g71/libmagic-rs/src/parser/ast.rs:112
variant TypeKind:Quad in /tmp/.tmp3M9g71/libmagic-rs/src/parser/ast.rs:112
--- failure struct_missing: pub struct removed or renamed ---
Description:
A publicly-visible struct cannot be imported by its prior path. A `pub use` may have been removed, or the struct itself may have been renamed or removed entirely.
ref: https://doc.rust-lang.org/cargo/reference/semver.html#item-remove
impl: https://github.com/obi1kenobi/cargo-semver-checks/tree/v0.46.0/src/lints/struct_missing.ron
Failed in:
struct libmagic_rs::evaluator::MatchResult, previously in file /tmp/.tmpp8oIWU/libmagic-rs/src/evaluator/mod.rs:207
struct libmagic_rs::MatchResult, previously in file /tmp/.tmpp8oIWU/libmagic-rs/src/evaluator/mod.rs:207
```
<details><summary><i><b>Changelog</b></i></summary><p>
<blockquote>
## [0.3.0] - 2026-03-02
### Features
- **parser**: Implement quad 64-bit integer type with endian variants
([#133](#133))
<!-- generated by git-cliff -->
</blockquote>
</p></details>
---
This PR was generated with
[release-plz](https://github.com/release-plz/release-plz/).
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Update documentation for #133 _Generated by [Dosu](https://dosu.dev)_ Signed-off-by: UncleSp1d3r <unclesp1d3r@evilbitlabs.io> Co-authored-by: dosubot[bot] <131922026+dosubot[bot]@users.noreply.github.com> Co-authored-by: UncleSp1d3r <unclesp1d3r@evilbitlabs.io>
This pull request adds support for 64-bit integer types (
quad/uquad) throughout the codebase, including parsing, evaluation, type system, and documentation. It also includes Phase 1 architecture refactoring from the architecture review.Breaking Changes
evaluator::MatchResultrenamed toevaluator::RuleMatch(issue refactor: rename evaluator::MatchResult to disambiguate from output::MatchResult #60): The internal evaluator match type was renamed to resolve the naming collision withoutput::MatchResult. The public re-export insrc/lib.rsis nowRuleMatch. The user-facingoutput::MatchResultis unchanged. This is a pre-1.0 breaking change.Quad (64-bit integer) type support
TypeKind::Quad { endian, signed }to the type system, enabling parsing and evaluation of 64-bit integers with endianness and signedness optionsread_quadfor safe reading of 64-bit integers from buffers with endianness and signedness supportArchitecture refactoring (Phase 1)
src/parser/types.rs): Moved type keyword parsing (parse_type_keyword) and type-to-kind conversion (type_keyword_to_kind) fromgrammar.rsinto a focused module, reducinggrammar.rscomplexitysrc/parser/codegen.rs): Consolidated 16 duplicated serialization functions frombuild.rsandbuild_helpers.rsinto a sharedcodegen.rsmodule, eliminating the need to update both files when adding enum variantsevaluator::MatchResulttoRuleMatch(issue refactor: rename evaluator::MatchResult to disambiguate from output::MatchResult #60): Resolved naming collision withoutput::MatchResultDocumentation and roadmap updates
AGENTS.mdto reflect quad type support, new module structure, and updated architecture constraintsOther improvements