Skip to content

chore: release v0.6.0#240

Merged
unclesp1d3r merged 1 commit into
mainfrom
release-plz-2026-04-25T20-36-06Z
Apr 25, 2026
Merged

chore: release v0.6.0#240
unclesp1d3r merged 1 commit into
mainfrom
release-plz-2026-04-25T20-36-06Z

Conversation

@github-actions
Copy link
Copy Markdown
Contributor

🤖 New release

  • libmagic-rs: 0.5.0 -> 0.6.0 (⚠ API breaking changes)

libmagic-rs breaking changes

--- failure constructible_struct_adds_field: externally-constructible struct adds field ---

Description:
A pub struct constructible with a struct literal has a new pub field. Existing struct literals must be updated to include the new field.
        ref: https://doc.rust-lang.org/reference/expressions/struct-expr.html
       impl: https://github.com/obi1kenobi/cargo-semver-checks/tree/v0.46.0/src/lints/constructible_struct_adds_field.ron

Failed in:
  field MagicRule.value_transform in /tmp/.tmpwFvgw1/libmagic-rs/src/parser/ast.rs:1189
  field MagicRule.value_transform in /tmp/.tmpwFvgw1/libmagic-rs/src/parser/ast.rs:1189
  field MagicRule.value_transform in /tmp/.tmpwFvgw1/libmagic-rs/src/parser/ast.rs:1189

--- failure copy_impl_added: type now implements Copy ---

Description:
A public type now implements Copy, causing non-move closures to capture it by reference instead of moving it.
        ref: https://github.com/rust-lang/rust/issues/100905
       impl: https://github.com/obi1kenobi/cargo-semver-checks/tree/v0.46.0/src/lints/copy_impl_added.ron

Failed in:
  libmagic_rs::mime::MimeMapper in /tmp/.tmpwFvgw1/libmagic-rs/src/mime.rs:98

--- failure enum_marked_non_exhaustive: enum marked #[non_exhaustive] ---

Description:
A public enum has been marked #[non_exhaustive]. Pattern-matching on it outside of its crate must now include a wildcard pattern like `_`, or it will fail to compile.
        ref: https://doc.rust-lang.org/cargo/reference/semver.html#attr-adding-non-exhaustive
       impl: https://github.com/obi1kenobi/cargo-semver-checks/tree/v0.46.0/src/lints/enum_marked_non_exhaustive.ron

Failed in:
  enum OffsetSpec in /tmp/.tmpwFvgw1/libmagic-rs/src/parser/ast.rs:198
  enum OffsetSpec in /tmp/.tmpwFvgw1/libmagic-rs/src/parser/ast.rs:198
  enum OffsetSpec in /tmp/.tmpwFvgw1/libmagic-rs/src/parser/ast.rs:198
  enum LibmagicError in /tmp/.tmpwFvgw1/libmagic-rs/src/error.rs:15
  enum LibmagicError in /tmp/.tmpwFvgw1/libmagic-rs/src/error.rs:15
  enum IoError in /tmp/.tmpwFvgw1/libmagic-rs/src/io/mod.rs:26
  enum Operator in /tmp/.tmpwFvgw1/libmagic-rs/src/parser/ast.rs:838
  enum Operator in /tmp/.tmpwFvgw1/libmagic-rs/src/parser/ast.rs:838
  enum Operator in /tmp/.tmpwFvgw1/libmagic-rs/src/parser/ast.rs:838
  enum TypeReadError in /tmp/.tmpwFvgw1/libmagic-rs/src/evaluator/types/mod.rs:56
  enum ParseError in /tmp/.tmpwFvgw1/libmagic-rs/src/error.rs:74
  enum ParseError in /tmp/.tmpwFvgw1/libmagic-rs/src/error.rs:74
  enum Value in /tmp/.tmpwFvgw1/libmagic-rs/src/parser/ast.rs:965
  enum Value in /tmp/.tmpwFvgw1/libmagic-rs/src/parser/ast.rs:965
  enum Value in /tmp/.tmpwFvgw1/libmagic-rs/src/parser/ast.rs:965
  enum TypeKind in /tmp/.tmpwFvgw1/libmagic-rs/src/parser/ast.rs:398
  enum TypeKind in /tmp/.tmpwFvgw1/libmagic-rs/src/parser/ast.rs:398
  enum TypeKind in /tmp/.tmpwFvgw1/libmagic-rs/src/parser/ast.rs:398
  enum EvaluationError in /tmp/.tmpwFvgw1/libmagic-rs/src/error.rs:148
  enum EvaluationError in /tmp/.tmpwFvgw1/libmagic-rs/src/error.rs:148

--- failure enum_struct_variant_field_added: pub enum struct variant field added ---

Description:
An enum's exhaustive struct variant has a new field, which has to be included when constructing or matching on this variant.
        ref: https://doc.rust-lang.org/reference/attributes/type_system.html#the-non_exhaustive-attribute
       impl: https://github.com/obi1kenobi/cargo-semver-checks/tree/v0.46.0/src/lints/enum_struct_variant_field_added.ron

Failed in:
  field base_relative of variant OffsetSpec::Indirect in /tmp/.tmpwFvgw1/libmagic-rs/src/parser/ast.rs:251
  field adjustment_op of variant OffsetSpec::Indirect in /tmp/.tmpwFvgw1/libmagic-rs/src/parser/ast.rs:266
  field result_relative of variant OffsetSpec::Indirect in /tmp/.tmpwFvgw1/libmagic-rs/src/parser/ast.rs:272
  field base_relative of variant OffsetSpec::Indirect in /tmp/.tmpwFvgw1/libmagic-rs/src/parser/ast.rs:251
  field adjustment_op of variant OffsetSpec::Indirect in /tmp/.tmpwFvgw1/libmagic-rs/src/parser/ast.rs:266
  field result_relative of variant OffsetSpec::Indirect in /tmp/.tmpwFvgw1/libmagic-rs/src/parser/ast.rs:272
  field base_relative of variant OffsetSpec::Indirect in /tmp/.tmpwFvgw1/libmagic-rs/src/parser/ast.rs:251
  field adjustment_op of variant OffsetSpec::Indirect in /tmp/.tmpwFvgw1/libmagic-rs/src/parser/ast.rs:266
  field result_relative of variant OffsetSpec::Indirect in /tmp/.tmpwFvgw1/libmagic-rs/src/parser/ast.rs:272

--- failure function_missing: pub fn removed or renamed ---

Description:
A publicly-visible function cannot be imported by its prior path. A `pub use` may have been removed, or the function 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/function_missing.ron

Failed in:
  function libmagic_rs::parser::grammar::is_empty_line, previously in file /tmp/.tmphvgzOh/libmagic-rs/src/parser/grammar/mod.rs:1025
  function libmagic_rs::parser::grammar::parse_strength_directive, previously in file /tmp/.tmphvgzOh/libmagic-rs/src/parser/grammar/mod.rs:846
  function libmagic_rs::parser::grammar::parse_type_and_operator, previously in file /tmp/.tmphvgzOh/libmagic-rs/src/parser/grammar/mod.rs:683
  function libmagic_rs::parser::grammar::parse_offset, previously in file /tmp/.tmphvgzOh/libmagic-rs/src/parser/grammar/mod.rs:179
  function libmagic_rs::parser::parse_offset, previously in file /tmp/.tmphvgzOh/libmagic-rs/src/parser/grammar/mod.rs:179
  function libmagic_rs::parser::grammar::parse_comment, previously in file /tmp/.tmphvgzOh/libmagic-rs/src/parser/grammar/mod.rs:1004
  function libmagic_rs::parser::grammar::parse_message, previously in file /tmp/.tmphvgzOh/libmagic-rs/src/parser/grammar/mod.rs:810
  function libmagic_rs::parser::grammar::parse_value, previously in file /tmp/.tmphvgzOh/libmagic-rs/src/parser/grammar/mod.rs:633
  function libmagic_rs::parser::grammar::parse_number, previously in file /tmp/.tmphvgzOh/libmagic-rs/src/parser/grammar/mod.rs:133
  function libmagic_rs::parser::parse_number, previously in file /tmp/.tmphvgzOh/libmagic-rs/src/parser/grammar/mod.rs:133
  function libmagic_rs::parser::grammar::has_continuation, previously in file /tmp/.tmphvgzOh/libmagic-rs/src/parser/grammar/mod.rs:1060
  function libmagic_rs::parser::grammar::parse_magic_rule, previously in file /tmp/.tmphvgzOh/libmagic-rs/src/parser/grammar/mod.rs:946
  function libmagic_rs::parser::grammar::parse_rule_offset, previously in file /tmp/.tmphvgzOh/libmagic-rs/src/parser/grammar/mod.rs:779
  function libmagic_rs::parser::grammar::is_comment_line, previously in file /tmp/.tmphvgzOh/libmagic-rs/src/parser/grammar/mod.rs:1042
  function libmagic_rs::parser::grammar::is_strength_directive, previously in file /tmp/.tmphvgzOh/libmagic-rs/src/parser/grammar/mod.rs:902
  function libmagic_rs::parser::grammar::parse_type, previously in file /tmp/.tmphvgzOh/libmagic-rs/src/parser/grammar/mod.rs:749
  function libmagic_rs::parser::grammar::parse_operator, previously in file /tmp/.tmphvgzOh/libmagic-rs/src/parser/grammar/mod.rs:227

--- failure function_parameter_count_changed: pub fn parameter count changed ---

Description:
A publicly-visible function now takes a different number of parameters.
        ref: https://doc.rust-lang.org/cargo/reference/semver.html#fn-change-arity
       impl: https://github.com/obi1kenobi/cargo-semver-checks/tree/v0.46.0/src/lints/function_parameter_count_changed.ron

Failed in:
  libmagic_rs::evaluator::evaluate_single_rule now takes 3 parameters instead of 2, in /tmp/.tmpwFvgw1/libmagic-rs/src/evaluator/engine/mod.rs:196

--- failure inherent_method_missing: pub method removed or renamed ---

Description:
A publicly-visible method or associated fn is no longer available under its prior name. It 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/inherent_method_missing.ron

Failed in:
  FileBuffer::create_symlink, previously in file /tmp/.tmphvgzOh/libmagic-rs/src/io/mod.rs:326
  EvaluationContext::increment_recursion_depth, previously in file /tmp/.tmphvgzOh/libmagic-rs/src/evaluator/mod.rs:114
  EvaluationContext::decrement_recursion_depth, previously in file /tmp/.tmphvgzOh/libmagic-rs/src/evaluator/mod.rs:130
  EvaluationContext::increment_recursion_depth, previously in file /tmp/.tmphvgzOh/libmagic-rs/src/evaluator/mod.rs:114
  EvaluationContext::decrement_recursion_depth, previously in file /tmp/.tmphvgzOh/libmagic-rs/src/evaluator/mod.rs:130

--- failure module_missing: pub module removed or renamed ---

Description:
A publicly-visible module cannot be imported by its prior path. A `pub use` may have been removed, or the module may have been renamed, removed, or made non-public.
        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/module_missing.ron

Failed in:
  mod libmagic_rs::parser::grammar, previously in file /tmp/.tmphvgzOh/libmagic-rs/src/parser/grammar/mod.rs:4

--- failure struct_marked_non_exhaustive: struct marked #[non_exhaustive] ---

Description:
A public struct has been marked #[non_exhaustive], which will prevent it from being constructed using a struct literal outside of its crate. It previously had no private fields, so a struct literal could be used to construct it outside its crate.
        ref: https://doc.rust-lang.org/cargo/reference/semver.html#attr-adding-non-exhaustive
       impl: https://github.com/obi1kenobi/cargo-semver-checks/tree/v0.46.0/src/lints/struct_marked_non_exhaustive.ron

Failed in:
  struct EvaluationConfig in /tmp/.tmpwFvgw1/libmagic-rs/src/config.rs:42
Changelog

[0.6.0] - 2026-04-25

Features

  • parser: Add Date and QDate types with serialization support (#165)
  • parser: Implement pstring (Pascal string) type (#170)
  • parser: Implement pstring multi-byte length prefix variants (/B, /H, /h, /L, /l, /J) (#183)
  • evaluator: Add debug-level tracing for skipped rules (#184)
  • evaluator: Implement indirect offset resolution (#37) (#199)
  • evaluator: Implement relative offset resolution (#38) (#211)
  • deps: Add new skills to actionbook/rust-skills and trailofbits/skills
  • evaluator: Regex and search types (closes Parser: implement regex and search types #39) (#214)
  • Implement libmagic meta-type directives and format substitution (#42) (#230)

Bug Fixes

Documentation

  • gotchas: Clarify requirements for adding TypeKind variants

Miscellaneous Tasks

  • Rename .coderabbitai.yaml to .coderabbit.yaml
  • Mergify: Configuration update (#173)
  • Update .gitignore to exclude local AI assistant files
  • mergify: Upgrade configuration to current format (#205)
  • Resolve all pending TODO items (#212)
  • mergify: Upgrade configuration to current format (#231)

Security

  • io: Close TOCTOU race in FileBuffer::new metadata validation (CWE-367). validate_file_metadata now uses File::metadata() on the open descriptor instead of re-canonicalizing the path, so an attacker cannot swap the path between open_file and validation. Error paths now report the caller-supplied path rather than the canonicalized variant.
  • cli: Remove relative-path fallbacks from default_magic_file_path (CWE-426). ./missing.magic, ./third_party/magic.mgc, and the CI/GITHUB_ACTIONS env-var branch no longer resolve against the process cwd. CI pipelines must pass --magic <path> explicitly.
  • evaluator: build_regex now bounds size_limit and dfa_size_limit to 1 MiB (REGEX_COMPILE_SIZE_LIMIT) to reject compile-time DoS patterns (CWE-1333) from adversarial magic files.

Features

  • parser: Implement meta-type directives: name/use subroutines, default/clear per-level fallback, and indirect re-evaluation. parse_text_magic_file now returns ParsedMagic { rules, name_table } (breaking change from Vec<MagicRule>). Named subroutines are hoisted into NameTable at load time and dispatched via RuleEnvironment in the evaluator. Recursion is bounded by EvaluationConfig::max_recursion_depth. Resolves #42.
  • evaluator: Thread-local regex compile cache eliminates the double-compile paid by every successful regex match. regex_bytes_consumed now reuses the compiled Regex from read_regex instead of recompiling the pattern to derive the anchor advance. The cache is reset at the start of every evaluate_rules_with_config call, bounding memory to one evaluation.
  • config: EvaluationConfig is now #[non_exhaustive]; new builder-style setters (with_max_recursion_depth, with_max_string_length, with_stop_at_first_match, with_mime_types, with_timeout_ms) let external crates construct configurations without struct literals.
  • parser: MagicRule::new() smart constructor with ::with_children(), ::with_strength_modifier(), ::with_level() builder methods and a ::validate() method enforcing structural invariants (non-empty message, level <= MAX_LEVEL, children nested strictly deeper than parent). New MagicRuleValidationError error type.
  • parser: RegexFlags::with_case_insensitive() and ::with_start_offset() builder methods.

Refactor

  • engine: Extract evaluate_pattern_rule() and evaluate_value_rule() helpers from evaluate_single_rule_with_anchor's 90-line body. Dispatch is now a two-arm type-category split; each helper has focused rustdoc on semantics and invariants.
  • types: Replace the _ => catch-all in bytes_consumed_with_pattern with an explicit listing of the fixed-width TypeKind variants. Adding a new variable-width variant without updating this match is now a compile error instead of a silent relative-offset anchor corruption in release builds.
  • parser: Split the 185-line type_keyword_to_kind match into per-family helpers (byte_family, short_family, long_family, quad_family, float_family, double_family, date_family, qdate_family, string_family). Drops the #[allow(clippy::too_many_lines)] attribute.
  • main: main() returns std::process::ExitCode instead of calling process::exit, so destructors run on the happy path. Ctrl-C AtomicBool flag uses Ordering::Relaxed instead of SeqCst.
  • grammar: parse_strength_directive uses nom 8's preceded + Parser::map instead of the legacy map(pair(char(...), parse_number), |(_, n)| ...) pattern.
  • output: Add #[serde(skip_serializing_if = "Option::is_none", default)] to public Option<T> fields so JSON output no longer emits "field": null for unset optional values.

Documentation

  • lib: Add # Security sections to MagicDatabase::with_builtin_rules, ::with_builtin_rules_and_config, ::load_from_file, and ::load_from_file_with_config warning about the unbounded default timeout and recommending EvaluationConfig::performance() for untrusted input.
  • lib: Document MagicDatabase: Send + Sync for parallel scanning.
  • README: Update TypeKind enum example to match the current AST, add regex and search/N to the supported types table, add pre-1.0 API stability warning, correct the roadmap to mark v0.2-v0.4 as shipped.
  • AGENTS.md: Relabel "Currently Implemented (v0.1.0)" and "Current Limitations (v0.1.0)" to v0.5.0 and rewrite the Development Phases section to reflect actual shipped scope.

Testing

  • Security regression tests for S-H1 (planted-magic-file in cwd), S-H2 (TOCTOU path-swap contract), S-M2 (pathological regex bounded runtime), S-L2 (codegen message escape round-trip), and GOTCHAS S13.1 (EvaluationConfig::default() unbounded timeout invariant).
  • Backspace message concatenation regression tests for first-match, consecutive, and empty-rest edge cases.
  • MagicRule::validate() tests covering empty message, child level invariant, and max-depth rejection.
  • RegexCache population/clear/reuse tests.

Breaking Changes

  • parser: parse_text_magic_file return type changed from Result<Vec<MagicRule>, ParseError> to Result<ParsedMagic, ParseError>. Callers must destructure ParsedMagic { rules, name_table }. Low-level callers that only need the rule list can use parsed.rules. load_magic_file and load_magic_directory return the same new type.


This PR was generated with release-plz.

@dosubot dosubot Bot added size:M This PR changes 30-99 lines, ignoring generated files. rust Rust language features and idioms labels Apr 25, 2026
@mergify
Copy link
Copy Markdown
Contributor

mergify Bot commented Apr 25, 2026

Merge Protections

Your pull request matches the following merge protections and will not be merged until they are valid.

🟢 Do not merge outdated PRs

Wonderful, this rule succeeded.

Make sure PRs are within 10 commits of the base branch before merging

  • #commits-behind <= 10

@unclesp1d3r unclesp1d3r self-assigned this Apr 25, 2026
@unclesp1d3r unclesp1d3r merged commit 7e08f98 into main Apr 25, 2026
7 checks passed
@unclesp1d3r unclesp1d3r deleted the release-plz-2026-04-25T20-36-06Z branch April 25, 2026 20:39
@dosubot
Copy link
Copy Markdown
Contributor

dosubot Bot commented Apr 25, 2026

Documentation Updates

4 document(s) were updated by changes in this PR:

api-reference
View Changes
@@ -45,12 +45,10 @@
 let result = db.evaluate_file("sample.bin")?;
 println!("Type: {}", result.description);
 
-// With custom configuration
-let config = EvaluationConfig {
-    timeout_ms: Some(5000),
-    enable_mime_types: true,
-    ..Default::default()
-};
+// With custom configuration (v0.6.0: use builder methods)
+let config = EvaluationConfig::default()
+    .with_timeout_ms(5000)
+    .with_mime_types(true);
 let db = MagicDatabase::with_builtin_rules_and_config(config)?;
 
 // From file
@@ -133,11 +131,10 @@
 #### Validation
 
 ```rust
-let config = EvaluationConfig {
-    max_recursion_depth: 25,
-    max_string_length: 16384,
-    ..Default::default()
-};
+// v0.6.0: Use builder methods instead of struct literals
+let config = EvaluationConfig::default()
+    .with_max_recursion_depth(25)
+    .with_max_string_length(16384);
 
 // Validate configuration
 config.validate()?;
@@ -553,7 +550,19 @@
 - **Minimum Rust Version**: 1.85
 - **Edition**: 2024
 - **License**: Apache-2.0
-- **Current Version**: 0.5.0
+- **Current Version**: 0.6.0
+
+### Breaking Changes in v0.6.0
+
+- `MagicRule` struct now has an additional public field `value_transform`, requiring updates to any code that constructs `MagicRule` instances using struct literal syntax. Prefer using the `MagicRule::new()` constructor and builder methods (`with_children()`, `with_strength_modifier()`, etc.) for forward compatibility.
+- `EvaluationConfig` struct is now marked `#[non_exhaustive]`. Existing struct literals must switch to builder methods (`EvaluationConfig::default().with_max_recursion_depth(n).with_timeout_ms(ms)`) or the provided preset constructors (`::performance()`, `::comprehensive()`).
+- Several public enums (`OffsetSpec`, `LibmagicError`, `IoError`, `Operator`, `TypeReadError`, `ParseError`, `Value`, `TypeKind`, `EvaluationError`) are now marked `#[non_exhaustive]`. Pattern matching on these enums outside the crate must include a wildcard arm (`_ =>`).
+- `OffsetSpec::Indirect` struct variant has three new fields (`base_relative`, `adjustment_op`, `result_relative`). Existing pattern matches and struct literal constructions must be updated.
+- `MimeMapper` now implements `Copy` trait, changing closure capture semantics in non-move closures.
+- `FileBuffer::create_symlink` method removed.
+- `EvaluationContext::increment_recursion_depth` and `::decrement_recursion_depth` methods removed from the public API.
+- `libmagic_rs::parser::grammar` module is no longer public. Several grammar parsing functions previously exported (`parse_offset`, `parse_number`, `parse_magic_rule`, etc.) are now internal only.
+- `evaluate_single_rule` now takes 3 parameters instead of 2.
 
 ### Breaking Changes in v0.5.0
 
API_REFERENCE
View Changes
@@ -336,6 +336,7 @@
 | `typ`               | `TypeKind`                 | Type of data to read                                   |
 | `op`                | `Operator`                 | Comparison operator                                    |
 | `value`             | `Value`                    | Expected value                                         |
+| `value_transform`   | `Option<ValueTransform>`   | Optional transformation applied to matched value       |
 | `message`           | `String`                   | Description message                                    |
 | `children`          | `Vec<MagicRule>`           | Nested rules                                           |
 | `level`             | `u32`                      | Indentation level                                      |
@@ -657,3 +658,9 @@
 - `MagicDatabase` struct now includes internal fields `root_rules: Arc<[MagicRule]>` and `name_table: Arc<NameTable>` to support meta-type evaluation.
 - Printf-style format substitution (`%d`, `%x`, `%s`, etc.) is applied to the `message` field in `MatchResult`. Messages containing literal `%` characters that were previously passed through verbatim will now be interpreted as format specifiers. Escape literal `%` as `%%`.
 - `TypeKind::Meta(MetaType)` enum added with variants `Default`, `Clear`, `Name`, `Use`, `Indirect`, `Offset`.
+
+### v0.6.0
+
+**MagicRule struct adds public field**:
+
+- `MagicRule` now has a new public field `value_transform: Option<ValueTransform>`. Existing code that constructs `MagicRule` with struct literals must include this field or use alternative construction patterns (such as the `MagicRule::new()` builder or `Default` trait). Code that only reads or pattern-matches on `MagicRule` without constructing it is unaffected.
GETTING_STARTED
View Changes
@@ -21,10 +21,12 @@
 
 ```toml
 [dependencies]
-libmagic-rs = "0.5.0"
-```
-
-**Note:** Version 0.5.0 introduces breaking changes. If upgrading from 0.4.x, the `RuleMatch` struct has a new `type_kind` field that must be included in struct literals, the `Value` enum no longer derives the `Eq` trait (affecting comparison operations), and the `TypeKind` enum gained two new variants (`Float`, `Double`) for floating-point types with endian variants, causing the `TypeKind::String` variant discriminant to change from 4 to 6. Exhaustive pattern matching on `TypeKind` and struct literals for `RuleMatch` require updates.
+libmagic-rs = "0.6.0"
+```
+
+**Note:** Version 0.6.0 introduces breaking changes. If upgrading from 0.5.x, see the [migration guide](MIGRATION_GUIDE.md) for details on the `MagicRule.value_transform` field addition, `Copy` trait implementation for `MimeMapper`, newly `#[non_exhaustive]` enums (`OffsetSpec`, `LibmagicError`, `IoError`, `Operator`, `TypeReadError`, `ParseError`, `Value`, `TypeKind`, `EvaluationError`) and structs (`EvaluationConfig`), additional fields on `OffsetSpec::Indirect`, and other API changes.
+
+Version 0.5.0 introduces breaking changes. If upgrading from 0.4.x, the `RuleMatch` struct has a new `type_kind` field that must be included in struct literals, the `Value` enum no longer derives the `Eq` trait (affecting comparison operations), and the `TypeKind` enum gained two new variants (`Float`, `Double`) for floating-point types with endian variants, causing the `TypeKind::String` variant discriminant to change from 4 to 6. Exhaustive pattern matching on `TypeKind` and struct literals for `RuleMatch` require updates.
 
 Version 0.4.0 introduces breaking changes. If upgrading from 0.3.x, the `Operator` enum gained three new variants (`BitwiseXor`, `BitwiseNot`, `AnyValue`) for bitwise and any-value operations. Exhaustive pattern matching on `Operator` requires updates.
 
@@ -69,7 +71,7 @@
 
 ```toml
 [dependencies]
-libmagic-rs = "0.5.0"
+libmagic-rs = "0.6.0"
 ```
 
 #### Step 3: Write Code
migration
View Changes
@@ -576,6 +576,277 @@
 
 **Recommendation:** Avoid relying on enum discriminant values. Use pattern matching or the `std::mem::discriminant` function instead.
 
+## Migrating from v0.5.x to v0.6.0
+
+Version 0.6.0 introduces multiple breaking changes to the AST, parser API, and evaluator. These changes enable advanced features like indirect offsets, named subroutines, and meta-type directives.
+
+### MagicRule Struct Field Addition
+
+The `MagicRule` struct gained a new `value_transform` field. Code constructing `MagicRule` instances with struct literals must add this field or use the `..Default::default()` syntax to fill in missing fields.
+
+**Before (v0.5.x):**
+
+```rust,ignore
+use libmagic_rs::parser::ast::MagicRule;
+
+let rule = MagicRule {
+    level: 0,
+    offset_spec: OffsetSpec::Direct(0),
+    type_spec: TypeSpec { kind: TypeKind::Byte { signed: false }, operator: Some(Operator::Equal) },
+    value: Value::Uint(0x7f),
+    message: "ELF magic".to_string(),
+    strength_modifier: None,
+    children: vec![],
+};
+```
+
+**After (v0.6.0):**
+
+```rust,ignore
+use libmagic_rs::parser::ast::MagicRule;
+
+let rule = MagicRule {
+    level: 0,
+    offset_spec: OffsetSpec::Direct(0),
+    type_spec: TypeSpec { kind: TypeKind::Byte { signed: false }, operator: Some(Operator::Equal) },
+    value: Value::Uint(0x7f),
+    message: "ELF magic".to_string(),
+    strength_modifier: None,
+    children: vec![],
+    value_transform: None,  // New field
+};
+```
+
+**Alternative with default values:**
+
+```rust,ignore
+let rule = MagicRule {
+    level: 0,
+    offset_spec: OffsetSpec::Direct(0),
+    type_spec: TypeSpec { kind: TypeKind::Byte { signed: false }, operator: Some(Operator::Equal) },
+    value: Value::Uint(0x7f),
+    message: "ELF magic".to_string(),
+    ..Default::default()  // Fills in missing fields with defaults
+};
+```
+
+### OffsetSpec Enum Changes
+
+Multiple changes to the `OffsetSpec` enum affect pattern matching and construction:
+
+**Marked #[non_exhaustive]:**
+
+The `OffsetSpec` enum is now marked `#[non_exhaustive]`. Exhaustive pattern matches must include a wildcard pattern.
+
+```rust,ignore
+use libmagic_rs::parser::ast::OffsetSpec;
+
+// Before (v0.5.x) - exhaustive match
+match offset_spec {
+    OffsetSpec::Direct(offset) => { /* ... */ }
+    OffsetSpec::Indirect { /* ... */ } => { /* ... */ }
+}
+
+// After (v0.6.0) - wildcard required
+match offset_spec {
+    OffsetSpec::Direct(offset) => { /* ... */ }
+    OffsetSpec::Indirect { /* ... */ } => { /* ... */ }
+    _ => { /* handle future variants */ }
+}
+```
+
+**Indirect Variant Field Additions:**
+
+The `OffsetSpec::Indirect` variant gained three new fields:
+
+- `base_relative: bool` - Whether base offset is relative
+- `adjustment_op: Option<AdjustmentOp>` - Optional offset adjustment
+- `result_relative: bool` - Whether result offset is relative
+
+**Before (v0.5.x):**
+
+```rust,ignore
+let indirect = OffsetSpec::Indirect {
+    base_offset: 4,
+    read_type: TypeKind::Long { endian: Endianness::Big, signed: false },
+};
+```
+
+**After (v0.6.0):**
+
+```rust,ignore
+let indirect = OffsetSpec::Indirect {
+    base_offset: 4,
+    read_type: TypeKind::Long { endian: Endianness::Big, signed: false },
+    base_relative: false,
+    adjustment_op: None,
+    result_relative: false,
+};
+```
+
+### Parser API Changes
+
+The parser API changed to support named subroutines and meta-type directives.
+
+**parse_text_magic_file Return Type:**
+
+The return type changed from `Result<Vec<MagicRule>, ParseError>` to `Result<ParsedMagic, ParseError>`.
+
+**Before (v0.5.x):**
+
+```rust,ignore
+use libmagic_rs::parser::parse_text_magic_file;
+
+let rules = parse_text_magic_file("magic.mgc")?;
+for rule in rules {
+    // Process rule
+}
+```
+
+**After (v0.6.0):**
+
+```rust,ignore
+use libmagic_rs::parser::parse_text_magic_file;
+
+let parsed = parse_text_magic_file("magic.mgc")?;
+for rule in parsed.rules {
+    // Process rule
+}
+// Access name table for named subroutines
+let name_table = parsed.name_table;
+```
+
+**Removed Functions:**
+
+The following parser functions were removed or renamed:
+
+- `libmagic_rs::parser::grammar` module is no longer public
+- Individual parser functions like `parse_offset`, `parse_number` moved to internal grammar module
+- Use high-level `parse_text_magic_file` or `parse_magic_rule` instead
+
+### Evaluator API Changes
+
+**evaluate_single_rule Parameter Count:**
+
+The `evaluate_single_rule` function signature changed from 2 to 3 parameters to accept a `RuleEnvironment`.
+
+**Before (v0.5.x):**
+
+```rust,ignore
+use libmagic_rs::evaluator::evaluate_single_rule;
+
+let result = evaluate_single_rule(&rule, &buffer)?;
+```
+
+**After (v0.6.0):**
+
+```rust,ignore
+use libmagic_rs::evaluator::evaluate_single_rule;
+use libmagic_rs::evaluator::RuleEnvironment;
+
+let env = RuleEnvironment::new();  // Or pass existing environment
+let result = evaluate_single_rule(&rule, &buffer, &env)?;
+```
+
+**EvaluationContext Method Removals:**
+
+The following methods were removed from `EvaluationContext`:
+
+- `increment_recursion_depth` - Recursion tracking moved to internal implementation
+- `decrement_recursion_depth` - Recursion tracking moved to internal implementation
+
+If your code directly managed recursion tracking, use the high-level `evaluate_rules_with_config` API instead.
+
+### EvaluationConfig Struct Changes
+
+The `EvaluationConfig` struct is now marked `#[non_exhaustive]`. Code constructing `EvaluationConfig` with struct literals must use builder methods instead.
+
+**Before (v0.5.x):**
+
+```rust,ignore
+use libmagic_rs::config::EvaluationConfig;
+
+let config = EvaluationConfig {
+    enable_mime_types: true,
+    stop_at_first_match: false,
+    max_string_length: 1024,
+    timeout_ms: None,
+};
+```
+
+**After (v0.6.0):**
+
+```rust,ignore
+use libmagic_rs::config::EvaluationConfig;
+
+let config = EvaluationConfig::default()
+    .with_mime_types(true)
+    .with_stop_at_first_match(false)
+    .with_max_string_length(1024);
+    // .with_timeout_ms(5000)  // Optional timeout
+```
+
+Use `EvaluationConfig::performance()` for untrusted input with bounded timeout:
+
+```rust,ignore
+let config = EvaluationConfig::performance();  // Includes timeout, bounded recursion
+```
+
+### Enum #[non_exhaustive] Markers
+
+Multiple enums gained the `#[non_exhaustive]` attribute. Exhaustive matches must add wildcard patterns:
+
+- `LibmagicError`
+- `ParseError`
+- `EvaluationError`
+- `IoError`
+- `TypeReadError`
+- `Operator`
+- `Value`
+- `TypeKind`
+
+**Pattern:**
+
+```rust,ignore
+match error {
+    LibmagicError::ParseError(e) => { /* ... */ }
+    LibmagicError::EvaluationError(e) => { /* ... */ }
+    _ => { /* handle future error variants */ }
+}
+```
+
+### MimeMapper Now Implements Copy
+
+The `MimeMapper` type now implements `Copy`. Non-move closures capture it by reference instead of by value.
+
+**Before (v0.5.x):**
+
+```rust,ignore
+let mapper = MimeMapper::new();
+let closure = move || {
+    // mapper moved into closure
+    mapper.map("text/plain")
+};
+```
+
+**After (v0.6.0):**
+
+```rust,ignore
+let mapper = MimeMapper::new();
+let closure = || {
+    // mapper copied into closure, original still available
+    mapper.map("text/plain")
+};
+```
+
+If move semantics are required, explicitly move the mapper into the closure.
+
+### FileBuffer API Changes
+
+The `FileBuffer::create_symlink` method was removed. Symlink creation is not part of the file buffer abstraction.
+
+If your code created symlinks through `FileBuffer`, use `std::os::unix::fs::symlink` or `std::os::windows::fs::symlink_file` directly.
+
 ## Getting Help
 
 If you encounter migration issues:

How did I do? Any feedback?

mergify Bot pushed a commit that referenced this pull request Apr 25, 2026
)

Update documentation for
#240

Added comprehensive getting started guide with installation, quick
start, library usage, CLI examples, and common patterns. Expanded API
reference with complete type documentation, error handling, and thread
safety information. Added migration guide covering transition from C
libmagic and detailed v0.6.0 breaking changes. These updates provide
users with clear entry points for learning the library and upgrading
between versions.

_Generated by [Dosu](https://dosu.dev)_

Co-authored-by: dosubot[bot] <131922026+dosubot[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

rust Rust language features and idioms size:M This PR changes 30-99 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Parser: implement default, clear, name, use, and indirect meta-types Parser: implement regex and search types

1 participant