14883830eSBenno Lossin // SPDX-License-Identifier: Apache-2.0 OR MIT 24883830eSBenno Lossin 34883830eSBenno Lossin use proc_macro2::{Span, TokenStream}; 44883830eSBenno Lossin use quote::{format_ident, quote, quote_spanned}; 54883830eSBenno Lossin use syn::{ 64883830eSBenno Lossin braced, 74883830eSBenno Lossin parse::{End, Parse}, 84883830eSBenno Lossin parse_quote, 94883830eSBenno Lossin punctuated::Punctuated, 104883830eSBenno Lossin spanned::Spanned, 11*aeabc92eSBenno Lossin token, Attribute, Block, Expr, ExprCall, ExprPath, Ident, Path, Token, Type, 124883830eSBenno Lossin }; 134883830eSBenno Lossin 144883830eSBenno Lossin use crate::diagnostics::{DiagCtxt, ErrorGuaranteed}; 154883830eSBenno Lossin 164883830eSBenno Lossin pub(crate) struct Initializer { 17*aeabc92eSBenno Lossin attrs: Vec<InitializerAttribute>, 184883830eSBenno Lossin this: Option<This>, 194883830eSBenno Lossin path: Path, 204883830eSBenno Lossin brace_token: token::Brace, 214883830eSBenno Lossin fields: Punctuated<InitializerField, Token![,]>, 224883830eSBenno Lossin rest: Option<(Token![..], Expr)>, 234883830eSBenno Lossin error: Option<(Token![?], Type)>, 244883830eSBenno Lossin } 254883830eSBenno Lossin 264883830eSBenno Lossin struct This { 274883830eSBenno Lossin _and_token: Token![&], 284883830eSBenno Lossin ident: Ident, 294883830eSBenno Lossin _in_token: Token![in], 304883830eSBenno Lossin } 314883830eSBenno Lossin 324883830eSBenno Lossin enum InitializerField { 334883830eSBenno Lossin Value { 344883830eSBenno Lossin ident: Ident, 354883830eSBenno Lossin value: Option<(Token![:], Expr)>, 364883830eSBenno Lossin }, 374883830eSBenno Lossin Init { 384883830eSBenno Lossin ident: Ident, 394883830eSBenno Lossin _left_arrow_token: Token![<-], 404883830eSBenno Lossin value: Expr, 414883830eSBenno Lossin }, 424883830eSBenno Lossin Code { 434883830eSBenno Lossin _underscore_token: Token![_], 444883830eSBenno Lossin _colon_token: Token![:], 454883830eSBenno Lossin block: Block, 464883830eSBenno Lossin }, 474883830eSBenno Lossin } 484883830eSBenno Lossin 494883830eSBenno Lossin impl InitializerField { 504883830eSBenno Lossin fn ident(&self) -> Option<&Ident> { 514883830eSBenno Lossin match self { 524883830eSBenno Lossin Self::Value { ident, .. } | Self::Init { ident, .. } => Some(ident), 534883830eSBenno Lossin Self::Code { .. } => None, 544883830eSBenno Lossin } 554883830eSBenno Lossin } 564883830eSBenno Lossin } 574883830eSBenno Lossin 58*aeabc92eSBenno Lossin enum InitializerAttribute { 59*aeabc92eSBenno Lossin DefaultError(DefaultErrorAttribute), 60*aeabc92eSBenno Lossin } 61*aeabc92eSBenno Lossin 62*aeabc92eSBenno Lossin struct DefaultErrorAttribute { 63*aeabc92eSBenno Lossin ty: Box<Type>, 64*aeabc92eSBenno Lossin } 65*aeabc92eSBenno Lossin 664883830eSBenno Lossin pub(crate) fn expand( 674883830eSBenno Lossin Initializer { 68*aeabc92eSBenno Lossin attrs, 694883830eSBenno Lossin this, 704883830eSBenno Lossin path, 714883830eSBenno Lossin brace_token, 724883830eSBenno Lossin fields, 734883830eSBenno Lossin rest, 744883830eSBenno Lossin error, 754883830eSBenno Lossin }: Initializer, 764883830eSBenno Lossin default_error: Option<&'static str>, 774883830eSBenno Lossin pinned: bool, 784883830eSBenno Lossin dcx: &mut DiagCtxt, 794883830eSBenno Lossin ) -> Result<TokenStream, ErrorGuaranteed> { 804883830eSBenno Lossin let error = error.map_or_else( 814883830eSBenno Lossin || { 82*aeabc92eSBenno Lossin if let Some(default_error) = attrs.iter().fold(None, |acc, attr| { 83*aeabc92eSBenno Lossin #[expect(irrefutable_let_patterns)] 84*aeabc92eSBenno Lossin if let InitializerAttribute::DefaultError(DefaultErrorAttribute { ty }) = attr { 85*aeabc92eSBenno Lossin Some(ty.clone()) 86*aeabc92eSBenno Lossin } else { 87*aeabc92eSBenno Lossin acc 88*aeabc92eSBenno Lossin } 89*aeabc92eSBenno Lossin }) { 90*aeabc92eSBenno Lossin default_error 91*aeabc92eSBenno Lossin } else if let Some(default_error) = default_error { 924883830eSBenno Lossin syn::parse_str(default_error).unwrap() 934883830eSBenno Lossin } else { 944883830eSBenno Lossin dcx.error(brace_token.span.close(), "expected `? <type>` after `}`"); 954883830eSBenno Lossin parse_quote!(::core::convert::Infallible) 964883830eSBenno Lossin } 974883830eSBenno Lossin }, 98*aeabc92eSBenno Lossin |(_, err)| Box::new(err), 994883830eSBenno Lossin ); 1004883830eSBenno Lossin let slot = format_ident!("slot"); 1014883830eSBenno Lossin let (has_data_trait, data_trait, get_data, init_from_closure) = if pinned { 1024883830eSBenno Lossin ( 1034883830eSBenno Lossin format_ident!("HasPinData"), 1044883830eSBenno Lossin format_ident!("PinData"), 1054883830eSBenno Lossin format_ident!("__pin_data"), 1064883830eSBenno Lossin format_ident!("pin_init_from_closure"), 1074883830eSBenno Lossin ) 1084883830eSBenno Lossin } else { 1094883830eSBenno Lossin ( 1104883830eSBenno Lossin format_ident!("HasInitData"), 1114883830eSBenno Lossin format_ident!("InitData"), 1124883830eSBenno Lossin format_ident!("__init_data"), 1134883830eSBenno Lossin format_ident!("init_from_closure"), 1144883830eSBenno Lossin ) 1154883830eSBenno Lossin }; 1164883830eSBenno Lossin let init_kind = get_init_kind(rest, dcx); 1174883830eSBenno Lossin let zeroable_check = match init_kind { 1184883830eSBenno Lossin InitKind::Normal => quote!(), 1194883830eSBenno Lossin InitKind::Zeroing => quote! { 1204883830eSBenno Lossin // The user specified `..Zeroable::zeroed()` at the end of the list of fields. 1214883830eSBenno Lossin // Therefore we check if the struct implements `Zeroable` and then zero the memory. 1224883830eSBenno Lossin // This allows us to also remove the check that all fields are present (since we 1234883830eSBenno Lossin // already set the memory to zero and that is a valid bit pattern). 1244883830eSBenno Lossin fn assert_zeroable<T: ?::core::marker::Sized>(_: *mut T) 1254883830eSBenno Lossin where T: ::pin_init::Zeroable 1264883830eSBenno Lossin {} 1274883830eSBenno Lossin // Ensure that the struct is indeed `Zeroable`. 1284883830eSBenno Lossin assert_zeroable(#slot); 1294883830eSBenno Lossin // SAFETY: The type implements `Zeroable` by the check above. 1304883830eSBenno Lossin unsafe { ::core::ptr::write_bytes(#slot, 0, 1) }; 1314883830eSBenno Lossin }, 1324883830eSBenno Lossin }; 1334883830eSBenno Lossin let this = match this { 1344883830eSBenno Lossin None => quote!(), 1354883830eSBenno Lossin Some(This { ident, .. }) => quote! { 1364883830eSBenno Lossin // Create the `this` so it can be referenced by the user inside of the 1374883830eSBenno Lossin // expressions creating the individual fields. 1384883830eSBenno Lossin let #ident = unsafe { ::core::ptr::NonNull::new_unchecked(slot) }; 1394883830eSBenno Lossin }, 1404883830eSBenno Lossin }; 1414883830eSBenno Lossin // `mixed_site` ensures that the data is not accessible to the user-controlled code. 1424883830eSBenno Lossin let data = Ident::new("__data", Span::mixed_site()); 1434883830eSBenno Lossin let init_fields = init_fields(&fields, pinned, &data, &slot); 1444883830eSBenno Lossin let field_check = make_field_check(&fields, init_kind, &path); 1454883830eSBenno Lossin Ok(quote! {{ 1464883830eSBenno Lossin // We do not want to allow arbitrary returns, so we declare this type as the `Ok` return 1474883830eSBenno Lossin // type and shadow it later when we insert the arbitrary user code. That way there will be 1484883830eSBenno Lossin // no possibility of returning without `unsafe`. 1494883830eSBenno Lossin struct __InitOk; 1504883830eSBenno Lossin 1514883830eSBenno Lossin // Get the data about fields from the supplied type. 1524883830eSBenno Lossin // SAFETY: TODO 1534883830eSBenno Lossin let #data = unsafe { 1544883830eSBenno Lossin use ::pin_init::__internal::#has_data_trait; 1554883830eSBenno Lossin // Can't use `<#path as #has_data_trait>::#get_data`, since the user is able to omit 1564883830eSBenno Lossin // generics (which need to be present with that syntax). 1574883830eSBenno Lossin #path::#get_data() 1584883830eSBenno Lossin }; 1594883830eSBenno Lossin // Ensure that `#data` really is of type `#data` and help with type inference: 1604883830eSBenno Lossin let init = ::pin_init::__internal::#data_trait::make_closure::<_, __InitOk, #error>( 1614883830eSBenno Lossin #data, 1624883830eSBenno Lossin move |slot| { 1634883830eSBenno Lossin { 1644883830eSBenno Lossin // Shadow the structure so it cannot be used to return early. 1654883830eSBenno Lossin struct __InitOk; 1664883830eSBenno Lossin #zeroable_check 1674883830eSBenno Lossin #this 1684883830eSBenno Lossin #init_fields 1694883830eSBenno Lossin #field_check 1704883830eSBenno Lossin } 1714883830eSBenno Lossin Ok(__InitOk) 1724883830eSBenno Lossin } 1734883830eSBenno Lossin ); 1744883830eSBenno Lossin let init = move |slot| -> ::core::result::Result<(), #error> { 1754883830eSBenno Lossin init(slot).map(|__InitOk| ()) 1764883830eSBenno Lossin }; 1774883830eSBenno Lossin // SAFETY: TODO 1784883830eSBenno Lossin let init = unsafe { ::pin_init::#init_from_closure::<_, #error>(init) }; 1794883830eSBenno Lossin init 1804883830eSBenno Lossin }}) 1814883830eSBenno Lossin } 1824883830eSBenno Lossin 1834883830eSBenno Lossin enum InitKind { 1844883830eSBenno Lossin Normal, 1854883830eSBenno Lossin Zeroing, 1864883830eSBenno Lossin } 1874883830eSBenno Lossin 1884883830eSBenno Lossin fn get_init_kind(rest: Option<(Token![..], Expr)>, dcx: &mut DiagCtxt) -> InitKind { 1894883830eSBenno Lossin let Some((dotdot, expr)) = rest else { 1904883830eSBenno Lossin return InitKind::Normal; 1914883830eSBenno Lossin }; 1924883830eSBenno Lossin match &expr { 1934883830eSBenno Lossin Expr::Call(ExprCall { func, args, .. }) if args.is_empty() => match &**func { 1944883830eSBenno Lossin Expr::Path(ExprPath { 1954883830eSBenno Lossin attrs, 1964883830eSBenno Lossin qself: None, 1974883830eSBenno Lossin path: 1984883830eSBenno Lossin Path { 1994883830eSBenno Lossin leading_colon: None, 2004883830eSBenno Lossin segments, 2014883830eSBenno Lossin }, 2024883830eSBenno Lossin }) if attrs.is_empty() 2034883830eSBenno Lossin && segments.len() == 2 2044883830eSBenno Lossin && segments[0].ident == "Zeroable" 2054883830eSBenno Lossin && segments[0].arguments.is_none() 2064883830eSBenno Lossin && segments[1].ident == "init_zeroed" 2074883830eSBenno Lossin && segments[1].arguments.is_none() => 2084883830eSBenno Lossin { 2094883830eSBenno Lossin return InitKind::Zeroing; 2104883830eSBenno Lossin } 2114883830eSBenno Lossin _ => {} 2124883830eSBenno Lossin }, 2134883830eSBenno Lossin _ => {} 2144883830eSBenno Lossin } 2154883830eSBenno Lossin dcx.error( 2164883830eSBenno Lossin dotdot.span().join(expr.span()).unwrap_or(expr.span()), 2174883830eSBenno Lossin "expected nothing or `..Zeroable::init_zeroed()`.", 2184883830eSBenno Lossin ); 2194883830eSBenno Lossin InitKind::Normal 2204883830eSBenno Lossin } 2214883830eSBenno Lossin 2224883830eSBenno Lossin /// Generate the code that initializes the fields of the struct using the initializers in `field`. 2234883830eSBenno Lossin fn init_fields( 2244883830eSBenno Lossin fields: &Punctuated<InitializerField, Token![,]>, 2254883830eSBenno Lossin pinned: bool, 2264883830eSBenno Lossin data: &Ident, 2274883830eSBenno Lossin slot: &Ident, 2284883830eSBenno Lossin ) -> TokenStream { 2294883830eSBenno Lossin let mut guards = vec![]; 2304883830eSBenno Lossin let mut res = TokenStream::new(); 2314883830eSBenno Lossin for field in fields { 2324883830eSBenno Lossin let init = match field { 2334883830eSBenno Lossin InitializerField::Value { ident, value } => { 2344883830eSBenno Lossin let mut value_ident = ident.clone(); 2354883830eSBenno Lossin let value_prep = value.as_ref().map(|value| &value.1).map(|value| { 2364883830eSBenno Lossin // Setting the span of `value_ident` to `value`'s span improves error messages 2374883830eSBenno Lossin // when the type of `value` is wrong. 2384883830eSBenno Lossin value_ident.set_span(value.span()); 2394883830eSBenno Lossin quote!(let #value_ident = #value;) 2404883830eSBenno Lossin }); 2414883830eSBenno Lossin // Again span for better diagnostics 2424883830eSBenno Lossin let write = quote_spanned!(ident.span()=> ::core::ptr::write); 2434883830eSBenno Lossin let accessor = if pinned { 2444883830eSBenno Lossin let project_ident = format_ident!("__project_{ident}"); 2454883830eSBenno Lossin quote! { 2464883830eSBenno Lossin // SAFETY: TODO 2474883830eSBenno Lossin unsafe { #data.#project_ident(&mut (*#slot).#ident) } 2484883830eSBenno Lossin } 2494883830eSBenno Lossin } else { 2504883830eSBenno Lossin quote! { 2514883830eSBenno Lossin // SAFETY: TODO 2524883830eSBenno Lossin unsafe { &mut (*#slot).#ident } 2534883830eSBenno Lossin } 2544883830eSBenno Lossin }; 2554883830eSBenno Lossin quote! { 2564883830eSBenno Lossin { 2574883830eSBenno Lossin #value_prep 2584883830eSBenno Lossin // SAFETY: TODO 2594883830eSBenno Lossin unsafe { #write(::core::ptr::addr_of_mut!((*#slot).#ident), #value_ident) }; 2604883830eSBenno Lossin } 2614883830eSBenno Lossin #[allow(unused_variables)] 2624883830eSBenno Lossin let #ident = #accessor; 2634883830eSBenno Lossin } 2644883830eSBenno Lossin } 2654883830eSBenno Lossin InitializerField::Init { ident, value, .. } => { 2664883830eSBenno Lossin // Again span for better diagnostics 2674883830eSBenno Lossin let init = format_ident!("init", span = value.span()); 2684883830eSBenno Lossin if pinned { 2694883830eSBenno Lossin let project_ident = format_ident!("__project_{ident}"); 2704883830eSBenno Lossin quote! { 2714883830eSBenno Lossin { 2724883830eSBenno Lossin let #init = #value; 2734883830eSBenno Lossin // SAFETY: 2744883830eSBenno Lossin // - `slot` is valid, because we are inside of an initializer closure, we 2754883830eSBenno Lossin // return when an error/panic occurs. 2764883830eSBenno Lossin // - We also use `#data` to require the correct trait (`Init` or `PinInit`) 2774883830eSBenno Lossin // for `#ident`. 2784883830eSBenno Lossin unsafe { #data.#ident(::core::ptr::addr_of_mut!((*#slot).#ident), #init)? }; 2794883830eSBenno Lossin } 2804883830eSBenno Lossin // SAFETY: TODO 2814883830eSBenno Lossin #[allow(unused_variables)] 2824883830eSBenno Lossin let #ident = unsafe { #data.#project_ident(&mut (*#slot).#ident) }; 2834883830eSBenno Lossin } 2844883830eSBenno Lossin } else { 2854883830eSBenno Lossin quote! { 2864883830eSBenno Lossin { 2874883830eSBenno Lossin let #init = #value; 2884883830eSBenno Lossin // SAFETY: `slot` is valid, because we are inside of an initializer 2894883830eSBenno Lossin // closure, we return when an error/panic occurs. 2904883830eSBenno Lossin unsafe { 2914883830eSBenno Lossin ::pin_init::Init::__init( 2924883830eSBenno Lossin #init, 2934883830eSBenno Lossin ::core::ptr::addr_of_mut!((*#slot).#ident), 2944883830eSBenno Lossin )? 2954883830eSBenno Lossin }; 2964883830eSBenno Lossin } 2974883830eSBenno Lossin // SAFETY: TODO 2984883830eSBenno Lossin #[allow(unused_variables)] 2994883830eSBenno Lossin let #ident = unsafe { &mut (*#slot).#ident }; 3004883830eSBenno Lossin } 3014883830eSBenno Lossin } 3024883830eSBenno Lossin } 3034883830eSBenno Lossin InitializerField::Code { block: value, .. } => quote!(#[allow(unused_braces)] #value), 3044883830eSBenno Lossin }; 3054883830eSBenno Lossin res.extend(init); 3064883830eSBenno Lossin if let Some(ident) = field.ident() { 3074883830eSBenno Lossin // `mixed_site` ensures that the guard is not accessible to the user-controlled code. 3084883830eSBenno Lossin let guard = format_ident!("__{ident}_guard", span = Span::mixed_site()); 3094883830eSBenno Lossin guards.push(guard.clone()); 3104883830eSBenno Lossin res.extend(quote! { 3114883830eSBenno Lossin // Create the drop guard: 3124883830eSBenno Lossin // 3134883830eSBenno Lossin // We rely on macro hygiene to make it impossible for users to access this local 3144883830eSBenno Lossin // variable. 3154883830eSBenno Lossin // SAFETY: We forget the guard later when initialization has succeeded. 3164883830eSBenno Lossin let #guard = unsafe { 3174883830eSBenno Lossin ::pin_init::__internal::DropGuard::new( 3184883830eSBenno Lossin ::core::ptr::addr_of_mut!((*slot).#ident) 3194883830eSBenno Lossin ) 3204883830eSBenno Lossin }; 3214883830eSBenno Lossin }); 3224883830eSBenno Lossin } 3234883830eSBenno Lossin } 3244883830eSBenno Lossin quote! { 3254883830eSBenno Lossin #res 3264883830eSBenno Lossin // If execution reaches this point, all fields have been initialized. Therefore we can now 3274883830eSBenno Lossin // dismiss the guards by forgetting them. 3284883830eSBenno Lossin #(::core::mem::forget(#guards);)* 3294883830eSBenno Lossin } 3304883830eSBenno Lossin } 3314883830eSBenno Lossin 3324883830eSBenno Lossin /// Generate the check for ensuring that every field has been initialized. 3334883830eSBenno Lossin fn make_field_check( 3344883830eSBenno Lossin fields: &Punctuated<InitializerField, Token![,]>, 3354883830eSBenno Lossin init_kind: InitKind, 3364883830eSBenno Lossin path: &Path, 3374883830eSBenno Lossin ) -> TokenStream { 3384883830eSBenno Lossin let fields = fields.iter().filter_map(|f| f.ident()); 3394883830eSBenno Lossin match init_kind { 3404883830eSBenno Lossin InitKind::Normal => quote! { 3414883830eSBenno Lossin // We use unreachable code to ensure that all fields have been mentioned exactly once, 3424883830eSBenno Lossin // this struct initializer will still be type-checked and complain with a very natural 3434883830eSBenno Lossin // error message if a field is forgotten/mentioned more than once. 3444883830eSBenno Lossin #[allow(unreachable_code, clippy::diverging_sub_expression)] 3454883830eSBenno Lossin // SAFETY: this code is never executed. 3464883830eSBenno Lossin let _ = || unsafe { 3474883830eSBenno Lossin ::core::ptr::write(slot, #path { 3484883830eSBenno Lossin #( 3494883830eSBenno Lossin #fields: ::core::panic!(), 3504883830eSBenno Lossin )* 3514883830eSBenno Lossin }) 3524883830eSBenno Lossin }; 3534883830eSBenno Lossin }, 3544883830eSBenno Lossin InitKind::Zeroing => quote! { 3554883830eSBenno Lossin // We use unreachable code to ensure that all fields have been mentioned at most once. 3564883830eSBenno Lossin // Since the user specified `..Zeroable::zeroed()` at the end, all missing fields will 3574883830eSBenno Lossin // be zeroed. This struct initializer will still be type-checked and complain with a 3584883830eSBenno Lossin // very natural error message if a field is mentioned more than once, or doesn't exist. 3594883830eSBenno Lossin #[allow(unreachable_code, clippy::diverging_sub_expression, unused_assignments)] 3604883830eSBenno Lossin // SAFETY: this code is never executed. 3614883830eSBenno Lossin let _ = || unsafe { 3624883830eSBenno Lossin let mut zeroed = ::core::mem::zeroed(); 3634883830eSBenno Lossin // We have to use type inference here to make zeroed have the correct type. This 3644883830eSBenno Lossin // does not get executed, so it has no effect. 3654883830eSBenno Lossin ::core::ptr::write(slot, zeroed); 3664883830eSBenno Lossin zeroed = ::core::mem::zeroed(); 3674883830eSBenno Lossin ::core::ptr::write(slot, #path { 3684883830eSBenno Lossin #( 3694883830eSBenno Lossin #fields: ::core::panic!(), 3704883830eSBenno Lossin )* 3714883830eSBenno Lossin ..zeroed 3724883830eSBenno Lossin }) 3734883830eSBenno Lossin }; 3744883830eSBenno Lossin }, 3754883830eSBenno Lossin } 3764883830eSBenno Lossin } 3774883830eSBenno Lossin 3784883830eSBenno Lossin impl Parse for Initializer { 3794883830eSBenno Lossin fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result<Self> { 380*aeabc92eSBenno Lossin let attrs = input.call(Attribute::parse_outer)?; 3814883830eSBenno Lossin let this = input.peek(Token![&]).then(|| input.parse()).transpose()?; 3824883830eSBenno Lossin let path = input.parse()?; 3834883830eSBenno Lossin let content; 3844883830eSBenno Lossin let brace_token = braced!(content in input); 3854883830eSBenno Lossin let mut fields = Punctuated::new(); 3864883830eSBenno Lossin loop { 3874883830eSBenno Lossin let lh = content.lookahead1(); 3884883830eSBenno Lossin if lh.peek(End) || lh.peek(Token![..]) { 3894883830eSBenno Lossin break; 3904883830eSBenno Lossin } else if lh.peek(Ident) || lh.peek(Token![_]) { 3914883830eSBenno Lossin fields.push_value(content.parse()?); 3924883830eSBenno Lossin let lh = content.lookahead1(); 3934883830eSBenno Lossin if lh.peek(End) { 3944883830eSBenno Lossin break; 3954883830eSBenno Lossin } else if lh.peek(Token![,]) { 3964883830eSBenno Lossin fields.push_punct(content.parse()?); 3974883830eSBenno Lossin } else { 3984883830eSBenno Lossin return Err(lh.error()); 3994883830eSBenno Lossin } 4004883830eSBenno Lossin } else { 4014883830eSBenno Lossin return Err(lh.error()); 4024883830eSBenno Lossin } 4034883830eSBenno Lossin } 4044883830eSBenno Lossin let rest = content 4054883830eSBenno Lossin .peek(Token![..]) 4064883830eSBenno Lossin .then(|| Ok::<_, syn::Error>((content.parse()?, content.parse()?))) 4074883830eSBenno Lossin .transpose()?; 4084883830eSBenno Lossin let error = input 4094883830eSBenno Lossin .peek(Token![?]) 4104883830eSBenno Lossin .then(|| Ok::<_, syn::Error>((input.parse()?, input.parse()?))) 4114883830eSBenno Lossin .transpose()?; 412*aeabc92eSBenno Lossin let attrs = attrs 413*aeabc92eSBenno Lossin .into_iter() 414*aeabc92eSBenno Lossin .map(|a| { 415*aeabc92eSBenno Lossin if a.path().is_ident("default_error") { 416*aeabc92eSBenno Lossin a.parse_args::<DefaultErrorAttribute>() 417*aeabc92eSBenno Lossin .map(InitializerAttribute::DefaultError) 418*aeabc92eSBenno Lossin } else { 419*aeabc92eSBenno Lossin Err(syn::Error::new_spanned(a, "unknown initializer attribute")) 420*aeabc92eSBenno Lossin } 421*aeabc92eSBenno Lossin }) 422*aeabc92eSBenno Lossin .collect::<Result<Vec<_>, _>>()?; 4234883830eSBenno Lossin Ok(Self { 424*aeabc92eSBenno Lossin attrs, 4254883830eSBenno Lossin this, 4264883830eSBenno Lossin path, 4274883830eSBenno Lossin brace_token, 4284883830eSBenno Lossin fields, 4294883830eSBenno Lossin rest, 4304883830eSBenno Lossin error, 4314883830eSBenno Lossin }) 4324883830eSBenno Lossin } 4334883830eSBenno Lossin } 4344883830eSBenno Lossin 435*aeabc92eSBenno Lossin impl Parse for DefaultErrorAttribute { 436*aeabc92eSBenno Lossin fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result<Self> { 437*aeabc92eSBenno Lossin Ok(Self { ty: input.parse()? }) 438*aeabc92eSBenno Lossin } 439*aeabc92eSBenno Lossin } 440*aeabc92eSBenno Lossin 4414883830eSBenno Lossin impl Parse for This { 4424883830eSBenno Lossin fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result<Self> { 4434883830eSBenno Lossin Ok(Self { 4444883830eSBenno Lossin _and_token: input.parse()?, 4454883830eSBenno Lossin ident: input.parse()?, 4464883830eSBenno Lossin _in_token: input.parse()?, 4474883830eSBenno Lossin }) 4484883830eSBenno Lossin } 4494883830eSBenno Lossin } 4504883830eSBenno Lossin 4514883830eSBenno Lossin impl Parse for InitializerField { 4524883830eSBenno Lossin fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result<Self> { 4534883830eSBenno Lossin let lh = input.lookahead1(); 4544883830eSBenno Lossin if lh.peek(Token![_]) { 4554883830eSBenno Lossin Ok(Self::Code { 4564883830eSBenno Lossin _underscore_token: input.parse()?, 4574883830eSBenno Lossin _colon_token: input.parse()?, 4584883830eSBenno Lossin block: input.parse()?, 4594883830eSBenno Lossin }) 4604883830eSBenno Lossin } else if lh.peek(Ident) { 4614883830eSBenno Lossin let ident = input.parse()?; 4624883830eSBenno Lossin let lh = input.lookahead1(); 4634883830eSBenno Lossin if lh.peek(Token![<-]) { 4644883830eSBenno Lossin Ok(Self::Init { 4654883830eSBenno Lossin ident, 4664883830eSBenno Lossin _left_arrow_token: input.parse()?, 4674883830eSBenno Lossin value: input.parse()?, 4684883830eSBenno Lossin }) 4694883830eSBenno Lossin } else if lh.peek(Token![:]) { 4704883830eSBenno Lossin Ok(Self::Value { 4714883830eSBenno Lossin ident, 4724883830eSBenno Lossin value: Some((input.parse()?, input.parse()?)), 4734883830eSBenno Lossin }) 4744883830eSBenno Lossin } else if lh.peek(Token![,]) || lh.peek(End) { 4754883830eSBenno Lossin Ok(Self::Value { ident, value: None }) 4764883830eSBenno Lossin } else { 4774883830eSBenno Lossin Err(lh.error()) 4784883830eSBenno Lossin } 4794883830eSBenno Lossin } else { 4804883830eSBenno Lossin Err(lh.error()) 4814883830eSBenno Lossin } 4824883830eSBenno Lossin } 4834883830eSBenno Lossin } 484