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, 11aeabc92eSBenno 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 { 17aeabc92eSBenno 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 32*d26732e5SBenno Lossin struct InitializerField { 33*d26732e5SBenno Lossin attrs: Vec<Attribute>, 34*d26732e5SBenno Lossin kind: InitializerKind, 35*d26732e5SBenno Lossin } 36*d26732e5SBenno Lossin 37*d26732e5SBenno Lossin enum InitializerKind { 384883830eSBenno Lossin Value { 394883830eSBenno Lossin ident: Ident, 404883830eSBenno Lossin value: Option<(Token![:], Expr)>, 414883830eSBenno Lossin }, 424883830eSBenno Lossin Init { 434883830eSBenno Lossin ident: Ident, 444883830eSBenno Lossin _left_arrow_token: Token![<-], 454883830eSBenno Lossin value: Expr, 464883830eSBenno Lossin }, 474883830eSBenno Lossin Code { 484883830eSBenno Lossin _underscore_token: Token![_], 494883830eSBenno Lossin _colon_token: Token![:], 504883830eSBenno Lossin block: Block, 514883830eSBenno Lossin }, 524883830eSBenno Lossin } 534883830eSBenno Lossin 54*d26732e5SBenno Lossin impl InitializerKind { 554883830eSBenno Lossin fn ident(&self) -> Option<&Ident> { 564883830eSBenno Lossin match self { 574883830eSBenno Lossin Self::Value { ident, .. } | Self::Init { ident, .. } => Some(ident), 584883830eSBenno Lossin Self::Code { .. } => None, 594883830eSBenno Lossin } 604883830eSBenno Lossin } 614883830eSBenno Lossin } 624883830eSBenno Lossin 63aeabc92eSBenno Lossin enum InitializerAttribute { 64aeabc92eSBenno Lossin DefaultError(DefaultErrorAttribute), 65aeabc92eSBenno Lossin } 66aeabc92eSBenno Lossin 67aeabc92eSBenno Lossin struct DefaultErrorAttribute { 68aeabc92eSBenno Lossin ty: Box<Type>, 69aeabc92eSBenno Lossin } 70aeabc92eSBenno Lossin 714883830eSBenno Lossin pub(crate) fn expand( 724883830eSBenno Lossin Initializer { 73aeabc92eSBenno Lossin attrs, 744883830eSBenno Lossin this, 754883830eSBenno Lossin path, 764883830eSBenno Lossin brace_token, 774883830eSBenno Lossin fields, 784883830eSBenno Lossin rest, 794883830eSBenno Lossin error, 804883830eSBenno Lossin }: Initializer, 814883830eSBenno Lossin default_error: Option<&'static str>, 824883830eSBenno Lossin pinned: bool, 834883830eSBenno Lossin dcx: &mut DiagCtxt, 844883830eSBenno Lossin ) -> Result<TokenStream, ErrorGuaranteed> { 854883830eSBenno Lossin let error = error.map_or_else( 864883830eSBenno Lossin || { 87aeabc92eSBenno Lossin if let Some(default_error) = attrs.iter().fold(None, |acc, attr| { 88aeabc92eSBenno Lossin #[expect(irrefutable_let_patterns)] 89aeabc92eSBenno Lossin if let InitializerAttribute::DefaultError(DefaultErrorAttribute { ty }) = attr { 90aeabc92eSBenno Lossin Some(ty.clone()) 91aeabc92eSBenno Lossin } else { 92aeabc92eSBenno Lossin acc 93aeabc92eSBenno Lossin } 94aeabc92eSBenno Lossin }) { 95aeabc92eSBenno Lossin default_error 96aeabc92eSBenno Lossin } else if let Some(default_error) = default_error { 974883830eSBenno Lossin syn::parse_str(default_error).unwrap() 984883830eSBenno Lossin } else { 994883830eSBenno Lossin dcx.error(brace_token.span.close(), "expected `? <type>` after `}`"); 1004883830eSBenno Lossin parse_quote!(::core::convert::Infallible) 1014883830eSBenno Lossin } 1024883830eSBenno Lossin }, 103aeabc92eSBenno Lossin |(_, err)| Box::new(err), 1044883830eSBenno Lossin ); 1054883830eSBenno Lossin let slot = format_ident!("slot"); 1064883830eSBenno Lossin let (has_data_trait, data_trait, get_data, init_from_closure) = if pinned { 1074883830eSBenno Lossin ( 1084883830eSBenno Lossin format_ident!("HasPinData"), 1094883830eSBenno Lossin format_ident!("PinData"), 1104883830eSBenno Lossin format_ident!("__pin_data"), 1114883830eSBenno Lossin format_ident!("pin_init_from_closure"), 1124883830eSBenno Lossin ) 1134883830eSBenno Lossin } else { 1144883830eSBenno Lossin ( 1154883830eSBenno Lossin format_ident!("HasInitData"), 1164883830eSBenno Lossin format_ident!("InitData"), 1174883830eSBenno Lossin format_ident!("__init_data"), 1184883830eSBenno Lossin format_ident!("init_from_closure"), 1194883830eSBenno Lossin ) 1204883830eSBenno Lossin }; 1214883830eSBenno Lossin let init_kind = get_init_kind(rest, dcx); 1224883830eSBenno Lossin let zeroable_check = match init_kind { 1234883830eSBenno Lossin InitKind::Normal => quote!(), 1244883830eSBenno Lossin InitKind::Zeroing => quote! { 1254883830eSBenno Lossin // The user specified `..Zeroable::zeroed()` at the end of the list of fields. 1264883830eSBenno Lossin // Therefore we check if the struct implements `Zeroable` and then zero the memory. 1274883830eSBenno Lossin // This allows us to also remove the check that all fields are present (since we 1284883830eSBenno Lossin // already set the memory to zero and that is a valid bit pattern). 1294883830eSBenno Lossin fn assert_zeroable<T: ?::core::marker::Sized>(_: *mut T) 1304883830eSBenno Lossin where T: ::pin_init::Zeroable 1314883830eSBenno Lossin {} 1324883830eSBenno Lossin // Ensure that the struct is indeed `Zeroable`. 1334883830eSBenno Lossin assert_zeroable(#slot); 1344883830eSBenno Lossin // SAFETY: The type implements `Zeroable` by the check above. 1354883830eSBenno Lossin unsafe { ::core::ptr::write_bytes(#slot, 0, 1) }; 1364883830eSBenno Lossin }, 1374883830eSBenno Lossin }; 1384883830eSBenno Lossin let this = match this { 1394883830eSBenno Lossin None => quote!(), 1404883830eSBenno Lossin Some(This { ident, .. }) => quote! { 1414883830eSBenno Lossin // Create the `this` so it can be referenced by the user inside of the 1424883830eSBenno Lossin // expressions creating the individual fields. 1434883830eSBenno Lossin let #ident = unsafe { ::core::ptr::NonNull::new_unchecked(slot) }; 1444883830eSBenno Lossin }, 1454883830eSBenno Lossin }; 1464883830eSBenno Lossin // `mixed_site` ensures that the data is not accessible to the user-controlled code. 1474883830eSBenno Lossin let data = Ident::new("__data", Span::mixed_site()); 1484883830eSBenno Lossin let init_fields = init_fields(&fields, pinned, &data, &slot); 1494883830eSBenno Lossin let field_check = make_field_check(&fields, init_kind, &path); 1504883830eSBenno Lossin Ok(quote! {{ 1514883830eSBenno Lossin // We do not want to allow arbitrary returns, so we declare this type as the `Ok` return 1524883830eSBenno Lossin // type and shadow it later when we insert the arbitrary user code. That way there will be 1534883830eSBenno Lossin // no possibility of returning without `unsafe`. 1544883830eSBenno Lossin struct __InitOk; 1554883830eSBenno Lossin 1564883830eSBenno Lossin // Get the data about fields from the supplied type. 1574883830eSBenno Lossin // SAFETY: TODO 1584883830eSBenno Lossin let #data = unsafe { 1594883830eSBenno Lossin use ::pin_init::__internal::#has_data_trait; 1604883830eSBenno Lossin // Can't use `<#path as #has_data_trait>::#get_data`, since the user is able to omit 1614883830eSBenno Lossin // generics (which need to be present with that syntax). 1624883830eSBenno Lossin #path::#get_data() 1634883830eSBenno Lossin }; 1644883830eSBenno Lossin // Ensure that `#data` really is of type `#data` and help with type inference: 1654883830eSBenno Lossin let init = ::pin_init::__internal::#data_trait::make_closure::<_, __InitOk, #error>( 1664883830eSBenno Lossin #data, 1674883830eSBenno Lossin move |slot| { 1684883830eSBenno Lossin { 1694883830eSBenno Lossin // Shadow the structure so it cannot be used to return early. 1704883830eSBenno Lossin struct __InitOk; 1714883830eSBenno Lossin #zeroable_check 1724883830eSBenno Lossin #this 1734883830eSBenno Lossin #init_fields 1744883830eSBenno Lossin #field_check 1754883830eSBenno Lossin } 1764883830eSBenno Lossin Ok(__InitOk) 1774883830eSBenno Lossin } 1784883830eSBenno Lossin ); 1794883830eSBenno Lossin let init = move |slot| -> ::core::result::Result<(), #error> { 1804883830eSBenno Lossin init(slot).map(|__InitOk| ()) 1814883830eSBenno Lossin }; 1824883830eSBenno Lossin // SAFETY: TODO 1834883830eSBenno Lossin let init = unsafe { ::pin_init::#init_from_closure::<_, #error>(init) }; 1844883830eSBenno Lossin init 1854883830eSBenno Lossin }}) 1864883830eSBenno Lossin } 1874883830eSBenno Lossin 1884883830eSBenno Lossin enum InitKind { 1894883830eSBenno Lossin Normal, 1904883830eSBenno Lossin Zeroing, 1914883830eSBenno Lossin } 1924883830eSBenno Lossin 1934883830eSBenno Lossin fn get_init_kind(rest: Option<(Token![..], Expr)>, dcx: &mut DiagCtxt) -> InitKind { 1944883830eSBenno Lossin let Some((dotdot, expr)) = rest else { 1954883830eSBenno Lossin return InitKind::Normal; 1964883830eSBenno Lossin }; 1974883830eSBenno Lossin match &expr { 1984883830eSBenno Lossin Expr::Call(ExprCall { func, args, .. }) if args.is_empty() => match &**func { 1994883830eSBenno Lossin Expr::Path(ExprPath { 2004883830eSBenno Lossin attrs, 2014883830eSBenno Lossin qself: None, 2024883830eSBenno Lossin path: 2034883830eSBenno Lossin Path { 2044883830eSBenno Lossin leading_colon: None, 2054883830eSBenno Lossin segments, 2064883830eSBenno Lossin }, 2074883830eSBenno Lossin }) if attrs.is_empty() 2084883830eSBenno Lossin && segments.len() == 2 2094883830eSBenno Lossin && segments[0].ident == "Zeroable" 2104883830eSBenno Lossin && segments[0].arguments.is_none() 2114883830eSBenno Lossin && segments[1].ident == "init_zeroed" 2124883830eSBenno Lossin && segments[1].arguments.is_none() => 2134883830eSBenno Lossin { 2144883830eSBenno Lossin return InitKind::Zeroing; 2154883830eSBenno Lossin } 2164883830eSBenno Lossin _ => {} 2174883830eSBenno Lossin }, 2184883830eSBenno Lossin _ => {} 2194883830eSBenno Lossin } 2204883830eSBenno Lossin dcx.error( 2214883830eSBenno Lossin dotdot.span().join(expr.span()).unwrap_or(expr.span()), 2224883830eSBenno Lossin "expected nothing or `..Zeroable::init_zeroed()`.", 2234883830eSBenno Lossin ); 2244883830eSBenno Lossin InitKind::Normal 2254883830eSBenno Lossin } 2264883830eSBenno Lossin 2274883830eSBenno Lossin /// Generate the code that initializes the fields of the struct using the initializers in `field`. 2284883830eSBenno Lossin fn init_fields( 2294883830eSBenno Lossin fields: &Punctuated<InitializerField, Token![,]>, 2304883830eSBenno Lossin pinned: bool, 2314883830eSBenno Lossin data: &Ident, 2324883830eSBenno Lossin slot: &Ident, 2334883830eSBenno Lossin ) -> TokenStream { 2344883830eSBenno Lossin let mut guards = vec![]; 235*d26732e5SBenno Lossin let mut guard_attrs = vec![]; 2364883830eSBenno Lossin let mut res = TokenStream::new(); 237*d26732e5SBenno Lossin for InitializerField { attrs, kind } in fields { 238*d26732e5SBenno Lossin let cfgs = { 239*d26732e5SBenno Lossin let mut cfgs = attrs.clone(); 240*d26732e5SBenno Lossin cfgs.retain(|attr| attr.path().is_ident("cfg")); 241*d26732e5SBenno Lossin cfgs 242*d26732e5SBenno Lossin }; 243*d26732e5SBenno Lossin let init = match kind { 244*d26732e5SBenno Lossin InitializerKind::Value { ident, value } => { 2454883830eSBenno Lossin let mut value_ident = ident.clone(); 2464883830eSBenno Lossin let value_prep = value.as_ref().map(|value| &value.1).map(|value| { 2474883830eSBenno Lossin // Setting the span of `value_ident` to `value`'s span improves error messages 2484883830eSBenno Lossin // when the type of `value` is wrong. 2494883830eSBenno Lossin value_ident.set_span(value.span()); 2504883830eSBenno Lossin quote!(let #value_ident = #value;) 2514883830eSBenno Lossin }); 2524883830eSBenno Lossin // Again span for better diagnostics 2534883830eSBenno Lossin let write = quote_spanned!(ident.span()=> ::core::ptr::write); 2544883830eSBenno Lossin let accessor = if pinned { 2554883830eSBenno Lossin let project_ident = format_ident!("__project_{ident}"); 2564883830eSBenno Lossin quote! { 2574883830eSBenno Lossin // SAFETY: TODO 2584883830eSBenno Lossin unsafe { #data.#project_ident(&mut (*#slot).#ident) } 2594883830eSBenno Lossin } 2604883830eSBenno Lossin } else { 2614883830eSBenno Lossin quote! { 2624883830eSBenno Lossin // SAFETY: TODO 2634883830eSBenno Lossin unsafe { &mut (*#slot).#ident } 2644883830eSBenno Lossin } 2654883830eSBenno Lossin }; 2664883830eSBenno Lossin quote! { 267*d26732e5SBenno Lossin #(#attrs)* 2684883830eSBenno Lossin { 2694883830eSBenno Lossin #value_prep 2704883830eSBenno Lossin // SAFETY: TODO 2714883830eSBenno Lossin unsafe { #write(::core::ptr::addr_of_mut!((*#slot).#ident), #value_ident) }; 2724883830eSBenno Lossin } 273*d26732e5SBenno Lossin #(#cfgs)* 2744883830eSBenno Lossin #[allow(unused_variables)] 2754883830eSBenno Lossin let #ident = #accessor; 2764883830eSBenno Lossin } 2774883830eSBenno Lossin } 278*d26732e5SBenno Lossin InitializerKind::Init { ident, value, .. } => { 2794883830eSBenno Lossin // Again span for better diagnostics 2804883830eSBenno Lossin let init = format_ident!("init", span = value.span()); 2814883830eSBenno Lossin if pinned { 2824883830eSBenno Lossin let project_ident = format_ident!("__project_{ident}"); 2834883830eSBenno Lossin quote! { 284*d26732e5SBenno Lossin #(#attrs)* 2854883830eSBenno Lossin { 2864883830eSBenno Lossin let #init = #value; 2874883830eSBenno Lossin // SAFETY: 2884883830eSBenno Lossin // - `slot` is valid, because we are inside of an initializer closure, we 2894883830eSBenno Lossin // return when an error/panic occurs. 2904883830eSBenno Lossin // - We also use `#data` to require the correct trait (`Init` or `PinInit`) 2914883830eSBenno Lossin // for `#ident`. 2924883830eSBenno Lossin unsafe { #data.#ident(::core::ptr::addr_of_mut!((*#slot).#ident), #init)? }; 2934883830eSBenno Lossin } 294*d26732e5SBenno Lossin #(#cfgs)* 2954883830eSBenno Lossin // SAFETY: TODO 2964883830eSBenno Lossin #[allow(unused_variables)] 2974883830eSBenno Lossin let #ident = unsafe { #data.#project_ident(&mut (*#slot).#ident) }; 2984883830eSBenno Lossin } 2994883830eSBenno Lossin } else { 3004883830eSBenno Lossin quote! { 301*d26732e5SBenno Lossin #(#attrs)* 3024883830eSBenno Lossin { 3034883830eSBenno Lossin let #init = #value; 3044883830eSBenno Lossin // SAFETY: `slot` is valid, because we are inside of an initializer 3054883830eSBenno Lossin // closure, we return when an error/panic occurs. 3064883830eSBenno Lossin unsafe { 3074883830eSBenno Lossin ::pin_init::Init::__init( 3084883830eSBenno Lossin #init, 3094883830eSBenno Lossin ::core::ptr::addr_of_mut!((*#slot).#ident), 3104883830eSBenno Lossin )? 3114883830eSBenno Lossin }; 3124883830eSBenno Lossin } 313*d26732e5SBenno Lossin #(#cfgs)* 3144883830eSBenno Lossin // SAFETY: TODO 3154883830eSBenno Lossin #[allow(unused_variables)] 3164883830eSBenno Lossin let #ident = unsafe { &mut (*#slot).#ident }; 3174883830eSBenno Lossin } 3184883830eSBenno Lossin } 3194883830eSBenno Lossin } 320*d26732e5SBenno Lossin InitializerKind::Code { block: value, .. } => quote! { 321*d26732e5SBenno Lossin #(#attrs)* 322*d26732e5SBenno Lossin #[allow(unused_braces)] 323*d26732e5SBenno Lossin #value 324*d26732e5SBenno Lossin }, 3254883830eSBenno Lossin }; 3264883830eSBenno Lossin res.extend(init); 327*d26732e5SBenno Lossin if let Some(ident) = kind.ident() { 3284883830eSBenno Lossin // `mixed_site` ensures that the guard is not accessible to the user-controlled code. 3294883830eSBenno Lossin let guard = format_ident!("__{ident}_guard", span = Span::mixed_site()); 3304883830eSBenno Lossin res.extend(quote! { 331*d26732e5SBenno Lossin #(#cfgs)* 3324883830eSBenno Lossin // Create the drop guard: 3334883830eSBenno Lossin // 3344883830eSBenno Lossin // We rely on macro hygiene to make it impossible for users to access this local 3354883830eSBenno Lossin // variable. 3364883830eSBenno Lossin // SAFETY: We forget the guard later when initialization has succeeded. 3374883830eSBenno Lossin let #guard = unsafe { 3384883830eSBenno Lossin ::pin_init::__internal::DropGuard::new( 3394883830eSBenno Lossin ::core::ptr::addr_of_mut!((*slot).#ident) 3404883830eSBenno Lossin ) 3414883830eSBenno Lossin }; 3424883830eSBenno Lossin }); 343*d26732e5SBenno Lossin guards.push(guard); 344*d26732e5SBenno Lossin guard_attrs.push(cfgs); 3454883830eSBenno Lossin } 3464883830eSBenno Lossin } 3474883830eSBenno Lossin quote! { 3484883830eSBenno Lossin #res 3494883830eSBenno Lossin // If execution reaches this point, all fields have been initialized. Therefore we can now 3504883830eSBenno Lossin // dismiss the guards by forgetting them. 351*d26732e5SBenno Lossin #( 352*d26732e5SBenno Lossin #(#guard_attrs)* 353*d26732e5SBenno Lossin ::core::mem::forget(#guards); 354*d26732e5SBenno Lossin )* 3554883830eSBenno Lossin } 3564883830eSBenno Lossin } 3574883830eSBenno Lossin 3584883830eSBenno Lossin /// Generate the check for ensuring that every field has been initialized. 3594883830eSBenno Lossin fn make_field_check( 3604883830eSBenno Lossin fields: &Punctuated<InitializerField, Token![,]>, 3614883830eSBenno Lossin init_kind: InitKind, 3624883830eSBenno Lossin path: &Path, 3634883830eSBenno Lossin ) -> TokenStream { 364*d26732e5SBenno Lossin let field_attrs = fields 365*d26732e5SBenno Lossin .iter() 366*d26732e5SBenno Lossin .filter_map(|f| f.kind.ident().map(|_| &f.attrs)); 367*d26732e5SBenno Lossin let field_name = fields.iter().filter_map(|f| f.kind.ident()); 3684883830eSBenno Lossin match init_kind { 3694883830eSBenno Lossin InitKind::Normal => quote! { 3704883830eSBenno Lossin // We use unreachable code to ensure that all fields have been mentioned exactly once, 3714883830eSBenno Lossin // this struct initializer will still be type-checked and complain with a very natural 3724883830eSBenno Lossin // error message if a field is forgotten/mentioned more than once. 3734883830eSBenno Lossin #[allow(unreachable_code, clippy::diverging_sub_expression)] 3744883830eSBenno Lossin // SAFETY: this code is never executed. 3754883830eSBenno Lossin let _ = || unsafe { 3764883830eSBenno Lossin ::core::ptr::write(slot, #path { 3774883830eSBenno Lossin #( 378*d26732e5SBenno Lossin #(#field_attrs)* 379*d26732e5SBenno Lossin #field_name: ::core::panic!(), 3804883830eSBenno Lossin )* 3814883830eSBenno Lossin }) 3824883830eSBenno Lossin }; 3834883830eSBenno Lossin }, 3844883830eSBenno Lossin InitKind::Zeroing => quote! { 3854883830eSBenno Lossin // We use unreachable code to ensure that all fields have been mentioned at most once. 3864883830eSBenno Lossin // Since the user specified `..Zeroable::zeroed()` at the end, all missing fields will 3874883830eSBenno Lossin // be zeroed. This struct initializer will still be type-checked and complain with a 3884883830eSBenno Lossin // very natural error message if a field is mentioned more than once, or doesn't exist. 3894883830eSBenno Lossin #[allow(unreachable_code, clippy::diverging_sub_expression, unused_assignments)] 3904883830eSBenno Lossin // SAFETY: this code is never executed. 3914883830eSBenno Lossin let _ = || unsafe { 3924883830eSBenno Lossin let mut zeroed = ::core::mem::zeroed(); 3934883830eSBenno Lossin // We have to use type inference here to make zeroed have the correct type. This 3944883830eSBenno Lossin // does not get executed, so it has no effect. 3954883830eSBenno Lossin ::core::ptr::write(slot, zeroed); 3964883830eSBenno Lossin zeroed = ::core::mem::zeroed(); 3974883830eSBenno Lossin ::core::ptr::write(slot, #path { 3984883830eSBenno Lossin #( 399*d26732e5SBenno Lossin #(#field_attrs)* 400*d26732e5SBenno Lossin #field_name: ::core::panic!(), 4014883830eSBenno Lossin )* 4024883830eSBenno Lossin ..zeroed 4034883830eSBenno Lossin }) 4044883830eSBenno Lossin }; 4054883830eSBenno Lossin }, 4064883830eSBenno Lossin } 4074883830eSBenno Lossin } 4084883830eSBenno Lossin 4094883830eSBenno Lossin impl Parse for Initializer { 4104883830eSBenno Lossin fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result<Self> { 411aeabc92eSBenno Lossin let attrs = input.call(Attribute::parse_outer)?; 4124883830eSBenno Lossin let this = input.peek(Token![&]).then(|| input.parse()).transpose()?; 4134883830eSBenno Lossin let path = input.parse()?; 4144883830eSBenno Lossin let content; 4154883830eSBenno Lossin let brace_token = braced!(content in input); 4164883830eSBenno Lossin let mut fields = Punctuated::new(); 4174883830eSBenno Lossin loop { 4184883830eSBenno Lossin let lh = content.lookahead1(); 4194883830eSBenno Lossin if lh.peek(End) || lh.peek(Token![..]) { 4204883830eSBenno Lossin break; 421*d26732e5SBenno Lossin } else if lh.peek(Ident) || lh.peek(Token![_]) || lh.peek(Token![#]) { 4224883830eSBenno Lossin fields.push_value(content.parse()?); 4234883830eSBenno Lossin let lh = content.lookahead1(); 4244883830eSBenno Lossin if lh.peek(End) { 4254883830eSBenno Lossin break; 4264883830eSBenno Lossin } else if lh.peek(Token![,]) { 4274883830eSBenno Lossin fields.push_punct(content.parse()?); 4284883830eSBenno Lossin } else { 4294883830eSBenno Lossin return Err(lh.error()); 4304883830eSBenno Lossin } 4314883830eSBenno Lossin } else { 4324883830eSBenno Lossin return Err(lh.error()); 4334883830eSBenno Lossin } 4344883830eSBenno Lossin } 4354883830eSBenno Lossin let rest = content 4364883830eSBenno Lossin .peek(Token![..]) 4374883830eSBenno Lossin .then(|| Ok::<_, syn::Error>((content.parse()?, content.parse()?))) 4384883830eSBenno Lossin .transpose()?; 4394883830eSBenno Lossin let error = input 4404883830eSBenno Lossin .peek(Token![?]) 4414883830eSBenno Lossin .then(|| Ok::<_, syn::Error>((input.parse()?, input.parse()?))) 4424883830eSBenno Lossin .transpose()?; 443aeabc92eSBenno Lossin let attrs = attrs 444aeabc92eSBenno Lossin .into_iter() 445aeabc92eSBenno Lossin .map(|a| { 446aeabc92eSBenno Lossin if a.path().is_ident("default_error") { 447aeabc92eSBenno Lossin a.parse_args::<DefaultErrorAttribute>() 448aeabc92eSBenno Lossin .map(InitializerAttribute::DefaultError) 449aeabc92eSBenno Lossin } else { 450aeabc92eSBenno Lossin Err(syn::Error::new_spanned(a, "unknown initializer attribute")) 451aeabc92eSBenno Lossin } 452aeabc92eSBenno Lossin }) 453aeabc92eSBenno Lossin .collect::<Result<Vec<_>, _>>()?; 4544883830eSBenno Lossin Ok(Self { 455aeabc92eSBenno Lossin attrs, 4564883830eSBenno Lossin this, 4574883830eSBenno Lossin path, 4584883830eSBenno Lossin brace_token, 4594883830eSBenno Lossin fields, 4604883830eSBenno Lossin rest, 4614883830eSBenno Lossin error, 4624883830eSBenno Lossin }) 4634883830eSBenno Lossin } 4644883830eSBenno Lossin } 4654883830eSBenno Lossin 466aeabc92eSBenno Lossin impl Parse for DefaultErrorAttribute { 467aeabc92eSBenno Lossin fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result<Self> { 468aeabc92eSBenno Lossin Ok(Self { ty: input.parse()? }) 469aeabc92eSBenno Lossin } 470aeabc92eSBenno Lossin } 471aeabc92eSBenno Lossin 4724883830eSBenno Lossin impl Parse for This { 4734883830eSBenno Lossin fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result<Self> { 4744883830eSBenno Lossin Ok(Self { 4754883830eSBenno Lossin _and_token: input.parse()?, 4764883830eSBenno Lossin ident: input.parse()?, 4774883830eSBenno Lossin _in_token: input.parse()?, 4784883830eSBenno Lossin }) 4794883830eSBenno Lossin } 4804883830eSBenno Lossin } 4814883830eSBenno Lossin 4824883830eSBenno Lossin impl Parse for InitializerField { 4834883830eSBenno Lossin fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result<Self> { 484*d26732e5SBenno Lossin let attrs = input.call(Attribute::parse_outer)?; 485*d26732e5SBenno Lossin Ok(Self { 486*d26732e5SBenno Lossin attrs, 487*d26732e5SBenno Lossin kind: input.parse()?, 488*d26732e5SBenno Lossin }) 489*d26732e5SBenno Lossin } 490*d26732e5SBenno Lossin } 491*d26732e5SBenno Lossin 492*d26732e5SBenno Lossin impl Parse for InitializerKind { 493*d26732e5SBenno Lossin fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result<Self> { 4944883830eSBenno Lossin let lh = input.lookahead1(); 4954883830eSBenno Lossin if lh.peek(Token![_]) { 4964883830eSBenno Lossin Ok(Self::Code { 4974883830eSBenno Lossin _underscore_token: input.parse()?, 4984883830eSBenno Lossin _colon_token: input.parse()?, 4994883830eSBenno Lossin block: input.parse()?, 5004883830eSBenno Lossin }) 5014883830eSBenno Lossin } else if lh.peek(Ident) { 5024883830eSBenno Lossin let ident = input.parse()?; 5034883830eSBenno Lossin let lh = input.lookahead1(); 5044883830eSBenno Lossin if lh.peek(Token![<-]) { 5054883830eSBenno Lossin Ok(Self::Init { 5064883830eSBenno Lossin ident, 5074883830eSBenno Lossin _left_arrow_token: input.parse()?, 5084883830eSBenno Lossin value: input.parse()?, 5094883830eSBenno Lossin }) 5104883830eSBenno Lossin } else if lh.peek(Token![:]) { 5114883830eSBenno Lossin Ok(Self::Value { 5124883830eSBenno Lossin ident, 5134883830eSBenno Lossin value: Some((input.parse()?, input.parse()?)), 5144883830eSBenno Lossin }) 5154883830eSBenno Lossin } else if lh.peek(Token![,]) || lh.peek(End) { 5164883830eSBenno Lossin Ok(Self::Value { ident, value: None }) 5174883830eSBenno Lossin } else { 5184883830eSBenno Lossin Err(lh.error()) 5194883830eSBenno Lossin } 5204883830eSBenno Lossin } else { 5214883830eSBenno Lossin Err(lh.error()) 5224883830eSBenno Lossin } 5234883830eSBenno Lossin } 5244883830eSBenno Lossin } 525