Skip to main content

fack_macro/
lib.rs

1//! Procedural macro entry point for the `fack` derive language.
2//!
3//! This crate performs only compiler-token conversion and delegates parsing,
4//! semantic validation, and expansion to `fack-codegen`. The accepted helper
5//! attribute language is documented on the `Error` derive macro.
6
7use proc_macro::TokenStream;
8
9use fack_codegen::generate;
10
11/// Derive `Display` and `Error` implementations from `#[error(...)]`
12/// declarations.
13///
14/// A format string defines ordinary display behavior.
15///
16/// ```rust
17/// # use fack_macro::Error;
18/// #[derive(Error, Debug)]
19/// #[error("failed to read {path}")]
20/// struct ReadError {
21///     path: String,
22/// }
23/// ```
24///
25/// `source(field)` selects the ordinary error source.
26///
27/// ```rust
28/// # use fack_macro::Error;
29/// #[derive(Error, Debug)]
30/// #[error("network request failed")]
31/// #[error(source(io))]
32/// struct NetworkError {
33///     io: std::io::Error,
34/// }
35/// ```
36///
37/// `transparent(field)` selects one non-optional error field. Extra fields may
38/// retain context. Display forwards to the selected field and source chaining
39/// forwards through that field's own `Error::source` implementation.
40///
41/// ```rust
42/// # use fack_macro::Error;
43/// #[derive(Error, Debug)]
44/// #[error(transparent(inner))]
45/// struct Wrapper {
46///     context: u8,
47///     inner: std::io::Error,
48/// }
49/// ```
50///
51/// `from` requires exactly one field. It generates `From<T>` and selects that
52/// field as the ordinary source.
53///
54/// ```rust
55/// # use fack_macro::Error;
56/// #[derive(Error, Debug)]
57/// #[error("parse failed")]
58/// #[error(from)]
59/// struct ParseError(std::num::ParseIntError);
60/// ```
61///
62/// `display(path)` selects a custom formatter function.
63///
64/// ```rust
65/// # use fack_macro::Error;
66/// fn render(error: &Rendered, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
67///     let Rendered { code } = error;
68///     write!(f, "rendered {code}")
69/// }
70///
71/// #[derive(Error, Debug)]
72/// #[error(display(render))]
73/// struct Rendered {
74///     code: u8,
75/// }
76/// ```
77///
78/// Inline control is optional. Omitting it emits no explicit inline attribute.
79/// `inline` and `inline(neutral)` emit ordinary `#[inline]`. The `always` and
80/// `never` strategies emit the corresponding Rust attributes.
81///
82/// ```rust
83/// # use fack_macro::Error;
84/// #[derive(Error, Debug)]
85/// #[error(inline(never))]
86/// #[error("rare error")]
87/// struct RareError;
88/// ```
89///
90/// Generated paths use `::core` by default. `import(path)` selects a different
91/// root.
92///
93/// ```rust
94/// # use fack_macro::Error;
95/// #[derive(Error, Debug)]
96/// #[error(import(::std))]
97/// #[error("standard error")]
98/// struct StdError;
99/// ```
100#[proc_macro_derive(Error, attributes(error))]
101pub fn error(input: TokenStream) -> TokenStream {
102    let input = syn::parse_macro_input!(input as syn::DeriveInput);
103
104    match generate(&input) {
105        Ok(tokens) => TokenStream::from(tokens),
106        Err(error) => error.to_compile_error().into(),
107    }
108}