Skip to content

Commit b7a3f00

Browse files
committed
rust: pin-init: add #[default_error(<type>)] attribute to initializer macros
The `#[default_error(<type>)]` attribute can be used to supply a default type as the error used for the `[pin_]init!` macros. This way one can easily define custom `try_[pin_]init!` variants that default to your project specific error type. Just write the following declarative macro: macro_rules! try_init { ($($args:tt)*) => { ::pin_init::init!( #[default_error(YourCustomErrorType)] $($args)* ) } } Signed-off-by: Benno Lossin <lossin@kernel.org>
1 parent 5dff229 commit b7a3f00

1 file changed

Lines changed: 40 additions & 2 deletions

File tree

rust/pin-init/internal/src/init.rs

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,11 @@ use syn::{
88
parse_quote,
99
punctuated::Punctuated,
1010
spanned::Spanned,
11-
token, Block, Error, Expr, ExprCall, ExprPath, Ident, Path, Token, Type,
11+
token, Attribute, Block, Error, Expr, ExprCall, ExprPath, Ident, Path, Token, Type,
1212
};
1313

1414
pub(crate) struct Initializer {
15+
attrs: Vec<InitializerAttribute>,
1516
this: Option<This>,
1617
path: Path,
1718
brace_token: token::Brace,
@@ -52,8 +53,17 @@ impl InitializerField {
5253
}
5354
}
5455

56+
enum InitializerAttribute {
57+
DefaultError(DefaultErrorAttribute),
58+
}
59+
60+
struct DefaultErrorAttribute {
61+
ty: Type,
62+
}
63+
5564
pub(crate) fn expand(
5665
Initializer {
66+
attrs,
5767
this,
5868
path,
5969
brace_token,
@@ -67,7 +77,16 @@ pub(crate) fn expand(
6777
let mut macro_error = crate::Error::none();
6878
let error = error.map_or_else(
6979
|| {
70-
if let Some(default_error) = default_error {
80+
if let Some(default_error) = attrs.iter().fold(None, |acc, attr| {
81+
#[expect(irrefutable_let_patterns)]
82+
if let InitializerAttribute::DefaultError(DefaultErrorAttribute { ty }) = attr {
83+
Some(ty.clone())
84+
} else {
85+
acc
86+
}
87+
}) {
88+
default_error
89+
} else if let Some(default_error) = default_error {
7190
syn::parse_str(default_error).unwrap()
7291
} else {
7392
macro_error.combine(Error::new(
@@ -360,6 +379,7 @@ fn make_field_check(
360379

361380
impl Parse for Initializer {
362381
fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result<Self> {
382+
let attrs = input.call(Attribute::parse_outer)?;
363383
let this = input.peek(Token![&]).then(|| input.parse()).transpose()?;
364384
let path = input.parse()?;
365385
let content;
@@ -391,7 +411,19 @@ impl Parse for Initializer {
391411
.peek(Token![?])
392412
.then(|| Ok::<_, syn::Error>((input.parse()?, input.parse()?)))
393413
.transpose()?;
414+
let attrs = attrs
415+
.into_iter()
416+
.map(|a| {
417+
if a.path().is_ident("default_error") {
418+
a.parse_args::<DefaultErrorAttribute>()
419+
.map(InitializerAttribute::DefaultError)
420+
} else {
421+
Err(syn::Error::new_spanned(a, "unknown initializer attribute"))
422+
}
423+
})
424+
.collect::<Result<Vec<_>, _>>()?;
394425
Ok(Self {
426+
attrs,
395427
this,
396428
path,
397429
brace_token,
@@ -402,6 +434,12 @@ impl Parse for Initializer {
402434
}
403435
}
404436

437+
impl Parse for DefaultErrorAttribute {
438+
fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result<Self> {
439+
Ok(Self { ty: input.parse()? })
440+
}
441+
}
442+
405443
impl Parse for This {
406444
fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result<Self> {
407445
Ok(Self {

0 commit comments

Comments
 (0)