Skip to content

Conversation

@bradh
Copy link
Collaborator

@bradh bradh commented Jan 10, 2026

Replaces the remaining part of #92.

@coderabbitai
Copy link

coderabbitai bot commented Jan 10, 2026

Walkthrough

A new strict feature flag was added to the project. When enabled, error handling for unknown boxes in MP4 file parsing changes from logging a warning and continuing execution to logging an error and returning an error result. Documentation was updated to explain the strict parsing feature and its behavior regarding unknown boxes in ISO Base Media File Format files.

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The PR title clearly describes the main change: adding a strict mode feature and enabling it for tests, which aligns with the changeset modifications.
Description check ✅ Passed The PR description references PR #92 and indicates the change implements a strict mode feature, which is directly related to the changeset.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (3)
README.md (1)

105-115: Doc nits: feature naming + env var semantics should match implementation.

  • Line 105: “bytes features” → “bytes feature”.
  • Lines 109-110: since code treats “env var is present” as strict, consider clarifying “set MP4ATOM_STRICT (e.g. to 1)” to avoid implying it parses truthy/falsey values.
Proposed doc tweak
-There's also the `bytes` features which enables encoding for `Bytes` and `BytesMut` from the `bytes` crate, often used with tokio.
+There's also the `bytes` feature which enables encoding for `Bytes` and `BytesMut` from the `bytes` crate, often used with tokio.

 Enable using the `strict` feature, or by setting the `MP4ATOM_STRICT` environment variable.
+For example: `MP4ATOM_STRICT=1`.
src/error.rs (1)

72-80: Optional: Consider using var_os() for cleaner env handling.

The strict-mode logic is correct. If you add tests for MP4ATOM_STRICT environment variable mutation, use var_os("MP4ATOM_STRICT").is_some() instead of var(...).is_ok() to avoid UTF-8 validation and to more clearly express intent (presence enables strict, not a specific value). Extract this to a local variable to avoid repeated evaluation:

pub(crate) fn decode_unknown(atom: &Any, parent: FourCC) -> Result<()> {
-    if std::env::var("MP4ATOM_STRICT").is_ok() || cfg!(feature = "strict") {
+    let strict = cfg!(feature = "strict") || std::env::var_os("MP4ATOM_STRICT").is_some();
+    if strict {
         tracing::error!(kind = %atom.kind(), parent = %parent, "unexpected box");
         return Err(Error::UnexpectedBox(atom.kind()));
     } else {
         tracing::warn!(kind = %atom.kind(), parent = %parent, "unexpected box");
     }
     Ok(())
 }
justfile (1)

5-8: MP4ATOM_STRICT is a top-level export affecting all recipes, but only has runtime impact on test. The environment variable controls strict parsing behavior in decode_unknown() (src/error.rs), turning warnings into hard errors. Since cargo check, cargo clippy, and cargo fmt are static analysis tools that don't execute decode logic, the export doesn't functionally affect the check and fix recipes. However, for clarity and to align with the documented use case ("useful... when testing mp4-atom itself"), consider scoping MP4ATOM_STRICT to only the test recipe:

Scope MP4ATOM_STRICT to test recipe
 export RUST_BACKTRACE := "1"
 export RUST_LOG := "info"
-export MP4ATOM_STRICT := "1"

 # Run any CI tests
 test:
+	MP4ATOM_STRICT=1 cargo test --all-targets
-	cargo test --all-targets
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between caa033a and 33704b4.

📒 Files selected for processing (4)
  • Cargo.toml
  • README.md
  • justfile
  • src/error.rs
🧰 Additional context used
📓 Path-based instructions (2)
**/*.rs

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.rs: Code must be clippy-clean (cargo clippy --all-targets --all-features -- -D warnings)
Code must be formatted with rustfmt (cargo fmt) and pass formatting checks (cargo fmt -- --check)
Write unit tests inline within modules using #[cfg(test)]

Files:

  • src/error.rs
src/**/*.rs

📄 CodeRabbit inference engine (CLAUDE.md)

src/**/*.rs: Each MP4 atom type must implement the Atom trait with KIND, decode_body(), and encode_body()
Use Header::read_from() to handle large atoms without loading entire contents into memory
All operations should return Result using custom error types defined in error.rs
Use the custom Buf/BufMut traits for contiguous byte slices instead of ad-hoc buffer handling

Files:

  • src/error.rs
🧠 Learnings (5)
📓 Common learnings
Learnt from: CR
Repo: kixelated/mp4-atom PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-08-31T04:06:57.364Z
Learning: Applies to src/**/*.rs : Each MP4 atom type must implement the Atom trait with KIND, decode_body(), and encode_body()
📚 Learning: 2025-08-31T04:06:57.364Z
Learnt from: CR
Repo: kixelated/mp4-atom PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-08-31T04:06:57.364Z
Learning: Applies to src/**/*.rs : Each MP4 atom type must implement the Atom trait with KIND, decode_body(), and encode_body()

Applied to files:

  • justfile
  • README.md
  • src/error.rs
📚 Learning: 2025-08-31T04:06:57.364Z
Learnt from: CR
Repo: kixelated/mp4-atom PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-08-31T04:06:57.364Z
Learning: Applies to src/**/*.rs : Use Header::read_from() to handle large atoms without loading entire contents into memory

Applied to files:

  • README.md
📚 Learning: 2025-08-31T04:06:57.364Z
Learnt from: CR
Repo: kixelated/mp4-atom PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-08-31T04:06:57.364Z
Learning: Applies to src/tokio/**/*.rs : For async IO (with the tokio feature), implement and use AsyncReadFrom and AsyncWriteTo traits

Applied to files:

  • README.md
📚 Learning: 2025-08-31T04:06:57.364Z
Learnt from: CR
Repo: kixelated/mp4-atom PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-08-31T04:06:57.364Z
Learning: Applies to src/any.rs : Register new atom types in the Any enum (src/any.rs) to enable flexible decoding

Applied to files:

  • src/error.rs
🔇 Additional comments (1)
Cargo.toml (1)

25-30: Feature flag addition looks correct.

strict = [] is a clean opt-in switch for cfg!(feature = "strict").

Copy link
Owner

@kixelated kixelated left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wouldn't do the env variable, but your call.

@bradh
Copy link
Collaborator Author

bradh commented Jan 11, 2026

I wouldn't do the env variable, but your call.

Actually I was a bit dubious about it, and only added it because of your comment "/// Either logs or returns an error depending on the environment/flag."

Will chop that and just keep the feature flag.

@bradh bradh force-pushed the strict_mode_2026-01-10 branch from 33704b4 to 88d5433 Compare January 11, 2026 08:43
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (1)
README.md (1)

105-105: Minor grammar issue: subject-verb disagreement.

Line 105 has "features" (plural) paired with "enables" (singular). Consider revising to either "feature which enables" or "features which enable" for grammatical consistency.

📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 33704b4 and 88d5433.

📒 Files selected for processing (4)
  • Cargo.toml
  • README.md
  • justfile
  • src/error.rs
🚧 Files skipped from review as they are similar to previous changes (3)
  • justfile
  • src/error.rs
  • Cargo.toml
🧰 Additional context used
🧠 Learnings (4)
📚 Learning: 2025-08-31T04:06:57.364Z
Learnt from: CR
Repo: kixelated/mp4-atom PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-08-31T04:06:57.364Z
Learning: Applies to src/**/*.rs : Each MP4 atom type must implement the Atom trait with KIND, decode_body(), and encode_body()

Applied to files:

  • README.md
📚 Learning: 2025-08-31T04:06:57.364Z
Learnt from: CR
Repo: kixelated/mp4-atom PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-08-31T04:06:57.364Z
Learning: Applies to src/tokio/**/*.rs : For async IO (with the tokio feature), implement and use AsyncReadFrom and AsyncWriteTo traits

Applied to files:

  • README.md
📚 Learning: 2025-08-31T04:06:57.364Z
Learnt from: CR
Repo: kixelated/mp4-atom PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-08-31T04:06:57.364Z
Learning: Applies to src/**/*.rs : Use Header::read_from() to handle large atoms without loading entire contents into memory

Applied to files:

  • README.md
📚 Learning: 2025-08-31T04:06:57.364Z
Learnt from: CR
Repo: kixelated/mp4-atom PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-08-31T04:06:57.364Z
Learning: Applies to src/any.rs : Register new atom types in the Any enum (src/any.rs) to enable flexible decoding

Applied to files:

  • README.md
🔇 Additional comments (1)
README.md (1)

107-115: New Strict parsing section is clear and well-documented.

The new "Strict parsing" section effectively explains the feature: what it does (treats unknown boxes as hard errors), why it's generally undesirable (ISO/IMBF tolerance for unknown boxes), and practical use cases (testing). The documentation follows the established pattern used for other features (e.g., tokio, bytes) and aligns with the implementation described in the PR.

@kixelated
Copy link
Owner

kixelated commented Jan 11, 2026

I wouldn't do the env variable, but your call.

Actually I was a bit dubious about it, and only added it because of your comment "/// Either logs or returns an error depending on the environment/flag."

Will chop that and just keep the feature flag.

Ah yeah, by environment I meant #[cfg(test)]. That's the way to always enable it for unit tests.

@bradh
Copy link
Collaborator Author

bradh commented Jan 11, 2026

Ah yeah, by environment I meant #[cfg(test)]. That's the way to always enable it for unit tests.

OK.

I thought it might be worth running the tests in both modes (i.e. with and without the strict feature enabled) to check it still works for the common case.

Would you prefer I did:

diff --git a/justfile b/justfile
index 8233478..2284785 100644
--- a/justfile
+++ b/justfile
@@ -19,7 +19,6 @@ check:
 # Run any CI tests
 test:
        cargo test --all-targets
-       cargo test --all-targets --features strict
 
 # Automatically fix some issues.
 fix:
diff --git a/src/error.rs b/src/error.rs
index 99344ee..0973864 100644
--- a/src/error.rs
+++ b/src/error.rs
@@ -71,7 +71,7 @@ pub type Result<T> = std::result::Result<T, Error>;
 
 /// Either logs or returns an error depending on the strict feature flag.
 pub(crate) fn decode_unknown(atom: &Any, parent: FourCC) -> Result<()> {
-    if cfg!(feature = "strict") {
+    if cfg!(feature = "strict") || cfg!(test) {
         tracing::error!(kind = %atom.kind(), parent = %parent, "unexpected box");
         return Err(Error::UnexpectedBox(atom.kind()));
     } else {

(relative to the current PR configuration)

@kixelated
Copy link
Owner

Ah yeah, by environment I meant #[cfg(test)]. That's the way to always enable it for unit tests.

OK.

I thought it might be worth running the tests in both modes (i.e. with and without the strict feature enabled) to check it still works for the common case.

Would you prefer I did:

diff --git a/justfile b/justfile
index 8233478..2284785 100644
--- a/justfile
+++ b/justfile
@@ -19,7 +19,6 @@ check:
 # Run any CI tests
 test:
        cargo test --all-targets
-       cargo test --all-targets --features strict
 
 # Automatically fix some issues.
 fix:
diff --git a/src/error.rs b/src/error.rs
index 99344ee..0973864 100644
--- a/src/error.rs
+++ b/src/error.rs
@@ -71,7 +71,7 @@ pub type Result<T> = std::result::Result<T, Error>;
 
 /// Either logs or returns an error depending on the strict feature flag.
 pub(crate) fn decode_unknown(atom: &Any, parent: FourCC) -> Result<()> {
-    if cfg!(feature = "strict") {
+    if cfg!(feature = "strict") || cfg!(test) {
         tracing::error!(kind = %atom.kind(), parent = %parent, "unexpected box");
         return Err(Error::UnexpectedBox(atom.kind()));
     } else {

(relative to the current PR configuration)

Yeah, I had something like:

pub(crate) fn decode_unknown(atom: &Any, parent: FourCC) -> Result<()> {
    #[cfg(any(feature = "strict", test))]
    return Err(Error::UnexpectedBox(atom.kind()));
    #[cfg(not(any(feature = "strict", test)))]
    {
        tracing::warn!(kind = %atom.kind(), parent = %parent, "unexpected box");
        return Ok(())
    }
}

@coderabbitai Can you show the correct syntax? It's probably wrong, just from memory.

It's probably the same result as yours because the compiler will be smart enough inline the if true || false { resulting from the cfg! macro.

@coderabbitai
Copy link

coderabbitai bot commented Jan 12, 2026

Tip

For best results, initiate chat on the files or code changes.

@kixelated, here's the corrected syntax using #[cfg(...)] attributes:

pub(crate) fn decode_unknown(atom: &Any, parent: FourCC) -> Result<()> {
    #[cfg(any(feature = "strict", test))]
    {
        tracing::error!(kind = %atom.kind(), parent = %parent, "unexpected box");
        return Err(Error::UnexpectedBox(atom.kind()));
    }
    
    #[cfg(not(any(feature = "strict", test)))]
    {
        tracing::warn!(kind = %atom.kind(), parent = %parent, "unexpected box");
        Ok(())
    }
}

The key fix is wrapping the tracing::error! call inside the cfg-gated block (you had only the return statement in there).

Alternative: bradh's approach using runtime checks is also valid and simpler:

pub(crate) fn decode_unknown(atom: &Any, parent: FourCC) -> Result<()> {
    if cfg!(feature = "strict") || cfg!(test) {
        tracing::error!(kind = %atom.kind(), parent = %parent, "unexpected box");
        Err(Error::UnexpectedBox(atom.kind()))
    } else {
        tracing::warn!(kind = %atom.kind(), parent = %parent, "unexpected box");
        Ok(())
    }
}

You're correct that the compiler should optimize both to the same machine code since the conditions are known at compile time. The #[cfg(...)] approach is more explicit about compile-time branching, while the cfg!() approach is more readable. Either works fine!


🧠 Learnings used
Learnt from: CR
Repo: kixelated/mp4-atom PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-08-31T04:06:57.364Z
Learning: Applies to **/*.rs : Write unit tests inline within modules using #[cfg(test)]

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (1)
src/error.rs (1)

72-81: Implementation looks correct; consider updating doc comment for completeness.

The use of cfg!(feature = "strict") || cfg!(test) correctly provides compile-time conditional behavior. The logic properly returns an error in strict/test mode while only warning in non-strict mode.

Minor suggestion: The doc comment mentions only the "strict feature flag" but the function also enables strict behavior during tests via cfg!(test). Consider updating for clarity:

📝 Suggested doc comment update
-/// Either logs or returns an error depending on the strict feature flag.
+/// Either logs or returns an error depending on the strict feature flag or test mode.
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 88d5433 and 9cd848c.

📒 Files selected for processing (1)
  • src/error.rs
🧰 Additional context used
📓 Path-based instructions (2)
**/*.rs

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.rs: Code must be clippy-clean (cargo clippy --all-targets --all-features -- -D warnings)
Code must be formatted with rustfmt (cargo fmt) and pass formatting checks (cargo fmt -- --check)
Write unit tests inline within modules using #[cfg(test)]

Files:

  • src/error.rs
src/**/*.rs

📄 CodeRabbit inference engine (CLAUDE.md)

src/**/*.rs: Each MP4 atom type must implement the Atom trait with KIND, decode_body(), and encode_body()
Use Header::read_from() to handle large atoms without loading entire contents into memory
All operations should return Result using custom error types defined in error.rs
Use the custom Buf/BufMut traits for contiguous byte slices instead of ad-hoc buffer handling

Files:

  • src/error.rs
🧠 Learnings (3)
📚 Learning: 2025-08-31T04:06:57.364Z
Learnt from: CR
Repo: kixelated/mp4-atom PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-08-31T04:06:57.364Z
Learning: Applies to src/any.rs : Register new atom types in the Any enum (src/any.rs) to enable flexible decoding

Applied to files:

  • src/error.rs
📚 Learning: 2025-08-31T04:06:57.364Z
Learnt from: CR
Repo: kixelated/mp4-atom PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-08-31T04:06:57.364Z
Learning: Applies to src/**/*.rs : Each MP4 atom type must implement the Atom trait with KIND, decode_body(), and encode_body()

Applied to files:

  • src/error.rs
📚 Learning: 2025-08-31T04:06:57.364Z
Learnt from: CR
Repo: kixelated/mp4-atom PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-08-31T04:06:57.364Z
Learning: Applies to src/**/*.rs : All operations should return Result<T> using custom error types defined in error.rs

Applied to files:

  • src/error.rs
🧬 Code graph analysis (1)
src/error.rs (1)
src/atom.rs (1)
  • decode_unknown (13-15)

@bradh bradh merged commit d09f478 into kixelated:main Jan 14, 2026
1 check passed
@bradh bradh deleted the strict_mode_2026-01-10 branch January 14, 2026 00:11
@github-actions github-actions bot mentioned this pull request Jan 12, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants