qa 0.1.1

Requirements traceability for safety-critical Rust software
Documentation
#![cfg_attr(not(feature = "std"), no_std)]

#[cfg(feature = "std")]
mod matrix;
mod requirement;
mod trace;

pub use linkme;
#[cfg(feature = "std")]
pub use matrix::{Format, Matrix};
pub use qa_macros::traces;
pub use requirement::{REQUIREMENTS, Requirement, RequirementType};
pub use trace::{TRACES, TestTrace};

/// Define a single requirement as a static item with automatic registration.
///
/// `description` must be the first field. All other key-value pairs become
/// freeform metadata accessible via [`Requirement::get`].
///
/// ```rust,ignore
/// qa::requirement! {
///     pub REQ_VOID_TRACKING: Safety {
///         description: "Particles must be tracked through void regions",
///         source: "NRC Reg Guide 1.190",
///     }
/// }
/// ```
#[macro_export]
macro_rules! requirement {
    (
        $vis:vis $name:ident : $kind:path {
            description: $desc:expr,
            $($key:ident : $value:expr),* $(,)?
        }
    ) => {
        #[$crate::linkme::distributed_slice($crate::REQUIREMENTS)]
        $vis static $name: $crate::Requirement = $crate::Requirement {
            id: stringify!($name),
            kind: $kind,
            description: $desc,
            module: module_path!(),
            file: file!(),
            line: line!(),
            metadata: &[$(( stringify!($key), $value )),*],
        };
    };
    (
        $vis:vis $name:ident : $kind:path {
            description: $desc:expr $(,)?
        }
    ) => {
        $crate::requirement! {
            $vis $name : $kind {
                description: $desc,
            }
        }
    };
}

/// Define multiple requirements in a single block.
///
/// Delegates to [`requirement!`] for each entry.
///
/// ```rust,ignore
/// qa::requirements! {
///     pub REQ_A: Functional {
///         description: "First requirement",
///         source: "spec v1",
///     }
///
///     pub REQ_B: Safety {
///         description: "Second requirement",
///     }
/// }
/// ```
#[macro_export]
macro_rules! requirements {
    (
        $(
            $vis:vis $name:ident : $kind:path {
                description: $desc:expr
                $(, $key:ident : $value:expr)* $(,)?
            }
        )*
    ) => {
        $(
            $crate::requirement! {
                $vis $name : $kind {
                    description: $desc,
                    $($key : $value),*
                }
            }
        )*
    };
}