qubit-redact-derive 0.3.0

Derive macros for qubit-redact domain-object formatting
Documentation
qubit-redact-derive-0.3.0 has been yanked.

qubit-redact-derive

Rust CI Coverage Crates.io Rust License 中文文档

Qubit Redact Derive provides procedural macros for the qubit-redact runtime crate. Use them to define a deliberate redaction boundary for Rust domain objects: create safe borrowed diagnostic views with Redact, or explicitly replace logical values with RedactMut.

Why qubit-redact-derive

  • Field annotations make masking, omission, nested redaction, and map redaction reviewable at the domain-model boundary.
  • The macros support named, tuple, and unit structs, plus enums with all three variant shapes.
  • Optional Serde support serializes a redacted view without granting it deserialization or exposing an original-value escape hatch.
  • The generated code resolves a direct qubit-redact dependency, including a Cargo-renamed dependency, instead of relying on a fixed import spelling.

Quick Start

Add the runtime and derive crates together:

[dependencies]
qubit-redact = "0.3"
qubit-redact-derive = "0.3"
use qubit_redact::Redact as _;
use qubit_redact_derive::Redact;

#[derive(Redact)]
struct Credentials {
    user: String,
    #[redact(level = "secret")]
    password: String,
}

fn main() {
    let credentials = Credentials {
        user: "ada".to_owned(),
        password: "raw-password".to_owned(),
    };

    let output = format!("{:?}", credentials.redacted());
    assert!(output.contains("ada"));
    assert!(!output.contains("raw-password"));
}

Redact creates a borrowed view. The original Credentials value remains available to application logic.

Choose a Derive

Need Derive Result
Safely inspect or log a domain object without changing it Redact A borrowed Redacted<T> view.
Serialize an already-redacted object Redact with #[redact(serde)] An opt-in Serialize implementation for Redacted<T>.
Replace owned logical values before another boundary RedactMut An explicit redact_in_place() or redact_in_place_with(...) operation.
Make an original type format through the process default policy Redact with #[redact(debug)] or #[redact(display)] Generated Debug and/or Display for the original type.

Use Redact for diagnostics whenever possible. Choose RedactMut only when the next boundary requires a logically replaced value.

Attribute Overview

Field attributes select exactly one handling mode:

Attribute Effect
`#[redact(level = "low medium
#[redact(skip)] Omits the field from the redacted view.
#[redact(nested)] Delegates redaction to the nested value.
#[redact(map)] Redacts text-keyed map values using their keys and the complete runtime policy.
#[redact(json)] Redacts JSON stored in a String recursively by object key; invalid JSON is replaced opaquely.

Container attributes are opt-in controls:

Attribute Effect
#[redact(debug)] Generates redacted Debug for the original type.
#[redact(display)] Generates redacted Display for the original type.
#[redact(serde)] Generates serialization support for Redacted<T>.

Unmarked fields use their ordinary Debug representation. They are neither masked nor recursively traversed.

Dependencies and Features

The generated code requires qubit-redact to be a direct dependency. The derive crate discovers Cargo renames, so this also works:

[dependencies]
redaction = { package = "qubit-redact", version = "0.3" }
qubit-redact-derive = "0.3"

To use #[redact(serde)], enable the runtime crate's serde feature and declare serde directly:

[dependencies]
qubit-redact = { version = "0.3", features = ["serde"] }
qubit-redact-derive = "0.3"
serde = { version = "1", features = ["derive"] }
serde_json = "1"

#[redact(json)] requires the runtime crate's json feature. It formats a redacted JSON view, rewrites the string as compact redacted JSON for RedactMut, and serializes as a JSON string when combined with #[redact(serde)].

Safety Boundaries

  • The macros protect only the redacted view, generated formatting, or explicit in-place operation that you use. They cannot protect unrelated log calls or serialization paths.
  • An unmarked field uses its own Debug output. Mark every field whose representation can disclose sensitive data.
  • skip omits a value from the redacted representation; it does not erase the original value.
  • RedactMut performs logical replacement only. It does not erase released allocations, aliases, copies, or borrowed backing storage.
  • debug and display use the process-wide default policy. Use an explicit redacted_with boundary when a call site needs policy isolation.

Learn More

Testing

# Run tests with the default feature set
cargo test

# Run tests with all declared features
cargo test --all-features

# Project CI checks
./ci-check.sh

# Check code coverage
./coverage.sh

License

Copyright (c) 2025 - 2026. Haixing Hu. All rights reserved.

Licensed under the Apache License, Version 2.0. See LICENSE for the full license text.

Contributing

Contributions are welcome. Please follow the Rust API guidelines, keep public API documentation and tests current, and run ./align-ci.sh to format code and ./ci-check.sh to satisfy CI requirements before submitting a pull request.

Author

Haixing Hu - Qubit Co. Ltd.

Repository: https://github.com/qubit-ltd/rs-redact