1use crate::{attr, private, ty};
2use proc_macro2::{Span, TokenStream, TokenTree};
3use quote::{format_ident, quote, quote_spanned};
4use syn::parse::{Error, Parse, ParseStream, Result};
5use syn::punctuated::Punctuated;
6use syn::{
7 braced, parenthesized, parse_quote, Abi, Attribute, BareFnArg, BoundLifetimes, GenericParam,
8 Generics, Ident, Path, ReturnType, Token, Type, TypeBareFn, Visibility, WhereClause,
9};
10
11pub struct Element {
12 attrs: Vec<Attribute>,
13 vis: Visibility,
14 ident: Ident,
15 ty: Type,
16 expr: TokenStream,
17 orig_item: Option<TokenStream>,
18 start_span: Span,
19 end_span: Span,
20}
21
22impl Parse for Element {
23 fn parse(input: ParseStream) -> Result<Self> {
24 let attrs = input.call(Attribute::parse_outer)?;
25 let item = input.cursor();
26 let vis: Visibility = input.parse()?;
27 let static_token: Option<Token![static]> = input.parse()?;
28 if static_token.is_some() {
29 let mut_token: Option<Token![mut]> = input.parse()?;
30 if let Some(mut_token) = mut_token {
31 return Err(Error::new_spanned(
32 mut_token,
33 "static mut is not supported by distributed_slice",
34 ));
35 }
36 let ident: Ident = input.parse()?;
37 input.parse::<Token![:]>()?;
38 let start_span = input.span();
39 let ty: Type = input.parse()?;
40 let end_span = {
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&ty, &mut _s);
_s
}quote!(#ty).into_iter().last().unwrap().span();
41 input.parse::<Token![=]>()?;
42 let mut expr_semi = Vec::from_iter(input.parse::<TokenStream>()?);
43 if let Some(tail) = expr_semi.pop() {
44 syn::parse2::<Token![;]>(TokenStream::from(tail))?;
45 }
46 let expr = TokenStream::from_iter(expr_semi);
47 Ok(Element {
48 attrs,
49 vis,
50 ident,
51 ty,
52 expr,
53 orig_item: None,
54 start_span,
55 end_span,
56 })
57 } else {
58 let constness: Option<Token![const]> = input.parse()?;
59 let asyncness: Option<Token![async]> = input.parse()?;
60 let unsafety: Option<Token![unsafe]> = input.parse()?;
61 let abi: Option<Abi> = input.parse()?;
62 let fn_token: Token![fn] = input.parse().map_err(|_| {
63 Error::new_spanned(
64 item.token_stream(),
65 "distributed element must be either static or function item",
66 )
67 })?;
68 let ident: Ident = input.parse()?;
69 let generics: Generics = input.parse()?;
70
71 let content;
72 let paren_token = match ::syn::__private::parse_parens(&input) {
::syn::__private::Ok(parens) => { content = parens.content; parens.token }
::syn::__private::Err(error) => { return ::syn::__private::Err(error); }
}parenthesized!(content in input);
73 let mut inputs = Punctuated::new();
74 while !content.is_empty() {
75 content.parse::<Option<Token![mut]>>()?;
76 let ident = if let Some(wild) = content.parse::<Option<Token![_]>>()? {
77 Ident::from(wild)
78 } else {
79 content.parse()?
80 };
81 let colon_token: Token![:] = content.parse()?;
82 let ty: Type = content.parse()?;
83 inputs.push_value(BareFnArg {
84 attrs: Vec::new(),
85 name: Some((ident, colon_token)),
86 ty,
87 });
88 if !content.is_empty() {
89 let comma: Token![,] = content.parse()?;
90 inputs.push_punct(comma);
91 }
92 }
93
94 let output: ReturnType = input.parse()?;
95 let where_clause: Option<WhereClause> = input.parse()?;
96
97 let content;
98 match ::syn::__private::parse_braces(&input) {
::syn::__private::Ok(braces) => { content = braces.content; braces.token }
::syn::__private::Err(error) => { return ::syn::__private::Err(error); }
};braced!(content in input);
99 content.parse::<TokenStream>()?;
100
101 if let Some(constness) = constness {
102 return Err(Error::new_spanned(
103 constness,
104 "const fn distributed slice element is not supported",
105 ));
106 }
107
108 if let Some(asyncness) = asyncness {
109 return Err(Error::new_spanned(
110 asyncness,
111 "async fn distributed slice element is not supported",
112 ));
113 }
114
115 let lifetimes = if generics.params.is_empty() {
116 None
117 } else {
118 let mut bound = BoundLifetimes {
119 for_token: ::syn::token::ForToken.span),
120 lt_token: generics.lt_token.unwrap(),
121 lifetimes: Punctuated::new(),
122 gt_token: generics.gt_token.unwrap(),
123 };
124 for param in generics.params.into_pairs() {
125 let (param, punct) = param.into_tuple();
126 if let GenericParam::Lifetime(_) = param {
127 bound.lifetimes.push_value(param);
128 if let Some(punct) = punct {
129 bound.lifetimes.push_punct(punct);
130 }
131 } else {
132 return Err(Error::new_spanned(
133 param,
134 "cannot have generic parameters on distributed slice element",
135 ));
136 }
137 }
138 Some(bound)
139 };
140
141 if let Some(where_clause) = where_clause {
142 return Err(Error::new_spanned(
143 where_clause,
144 "where-clause is not allowed on distributed slice elements",
145 ));
146 }
147
148 let start_span = item.span();
149 let end_span = {
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&output, &mut _s);
_s
}quote!(#output)
150 .into_iter()
151 .last()
152 .as_ref()
153 .map_or(paren_token.span.close(), TokenTree::span);
154 let mut original_attrs = attrs;
155 let linkme_path = attr::linkme_path(&mut original_attrs)?;
156
157 let attrs = <[_]>::into_vec(::alloc::boxed::box_new([::syn::__private::parse_quote({
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_pound(&mut _s);
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Bracket,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "allow");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s,
"non_upper_case_globals");
_s
});
_s
});
_s
}),
::syn::__private::parse_quote({
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_pound(&mut _s);
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Bracket,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "linkme");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "crate");
::quote::__private::push_eq(&mut _s);
::quote::ToTokens::to_tokens(&linkme_path, &mut _s);
_s
});
_s
});
_s
})]))vec![
158 parse_quote! {
159 #[allow(non_upper_case_globals)]
160 },
161 parse_quote! {
162 #[linkme(crate = #linkme_path)]
163 },
164 ];
165 let vis = Visibility::Inherited;
166 let expr = ::syn::__private::parse_quote({
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&ident, &mut _s);
_s
})parse_quote!(#ident);
167 let ty = Type::BareFn(TypeBareFn {
168 lifetimes,
169 unsafety,
170 abi,
171 fn_token,
172 paren_token,
173 inputs,
174 variadic: None,
175 output,
176 });
177 let ident = match ::quote::__private::IdentFragmentAdapter(&ident) {
arg =>
::quote::__private::mk_ident(&::alloc::__export::must_use({
::alloc::fmt::format(format_args!("_LINKME_ELEMENT_{0}",
arg))
}), ::quote::__private::Option::None.or(arg.span())),
}format_ident!("_LINKME_ELEMENT_{}", ident);
178 let item = item.token_stream();
179 let orig_item = Some({
let mut _s = ::quote::__private::TokenStream::new();
{
use ::quote::__private::ext::*;
let has_iter = ::quote::__private::ThereIsNoIteratorInRepetition;
#[allow(unused_mut)]
let (mut original_attrs, i) = original_attrs.quote_into_iter();
let has_iter = has_iter | i;
let _: ::quote::__private::HasIterator = has_iter;
while true {
let original_attrs =
match original_attrs.next() {
Some(_x) => ::quote::__private::RepInterp(_x),
None => break,
};
::quote::ToTokens::to_tokens(&original_attrs, &mut _s);
}
}
::quote::ToTokens::to_tokens(&item, &mut _s);
_s
}quote!(
180 #(#original_attrs)*
181 #item
182 ));
183
184 Ok(Element {
185 attrs,
186 vis,
187 ident,
188 ty,
189 expr,
190 orig_item,
191 start_span,
192 end_span,
193 })
194 }
195 }
196}
197
198pub fn expand(path: Path, pos: impl Into<Option<usize>>, input: Element) -> TokenStream {
199 let pos = pos.into();
200 do_expand(path, pos, input)
201}
202
203fn do_expand(path: Path, pos: Option<usize>, input: Element) -> TokenStream {
204 let mut attrs = input.attrs;
205 let vis = input.vis;
206 let ident = input.ident;
207 let mut ty = input.ty;
208 let expr = input.expr;
209 let orig_item = input.orig_item;
210
211 ty::populate_static_lifetimes(&mut ty);
212
213 let linkme_path = match attr::linkme_path(&mut attrs) {
214 Ok(path) => path,
215 Err(err) => return err.to_compile_error(),
216 };
217
218 let sort_key = pos.into_iter().map(|pos| ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0:04}", pos))
})format!("{:04}", pos));
219
220 let factory = {
let mut _s = ::quote::__private::TokenStream::new();
let _span: ::quote::__private::Span =
::quote::__private::get_span(input.start_span).__into_span();
::quote::__private::push_ident_spanned(&mut _s, _span, "__new");
_s
}quote_spanned!(input.start_span=> __new);
221 let get = {
let mut _s = ::quote::__private::TokenStream::new();
let _span: ::quote::__private::Span =
::quote::__private::get_span(input.end_span).__into_span();
::quote::ToTokens::to_tokens(&factory, &mut _s);
::quote::__private::push_group_spanned(&mut _s, _span,
::quote::__private::Delimiter::Parenthesis,
{
let _: ::quote::__private::Span =
::quote::__private::get_span(_span).__into_span();
::quote::__private::TokenStream::new()
});
_s
}quote_spanned!(input.end_span=> #factory());
222
223 {
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&path, &mut _s);
::quote::__private::push_bang(&mut _s);
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Brace,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_pound(&mut _s);
::quote::__private::push_bang(&mut _s);
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Bracket,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "linkme_macro");
::quote::__private::push_eq(&mut _s);
::quote::ToTokens::to_tokens(&path, &mut _s);
_s
});
{
use ::quote::__private::ext::*;
let has_iter =
::quote::__private::ThereIsNoIteratorInRepetition;
#[allow(unused_mut)]
let (mut sort_key, i) = sort_key.quote_into_iter();
let has_iter = has_iter | i;
let _: ::quote::__private::HasIterator = has_iter;
while true {
let sort_key =
match sort_key.next() {
Some(_x) => ::quote::__private::RepInterp(_x),
None => break,
};
::quote::__private::push_pound(&mut _s);
::quote::__private::push_bang(&mut _s);
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Bracket,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "linkme_sort_key");
::quote::__private::push_eq(&mut _s);
::quote::ToTokens::to_tokens(&sort_key, &mut _s);
_s
});
}
}
{
use ::quote::__private::ext::*;
let has_iter =
::quote::__private::ThereIsNoIteratorInRepetition;
#[allow(unused_mut)]
let (mut attrs, i) = attrs.quote_into_iter();
let has_iter = has_iter | i;
let _: ::quote::__private::HasIterator = has_iter;
while true {
let attrs =
match attrs.next() {
Some(_x) => ::quote::__private::RepInterp(_x),
None => break,
};
::quote::ToTokens::to_tokens(&attrs, &mut _s);
}
}
::quote::ToTokens::to_tokens(&vis, &mut _s);
::quote::__private::push_ident(&mut _s, "static");
::quote::ToTokens::to_tokens(&ident, &mut _s);
::quote::__private::push_colon(&mut _s);
::quote::ToTokens::to_tokens(&ty, &mut _s);
::quote::__private::push_eq(&mut _s);
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Brace,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_pound(&mut _s);
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Bracket,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "allow");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "clippy");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s,
"no_effect_underscore_binding");
_s
});
_s
});
::quote::__private::push_ident(&mut _s, "unsafe");
::quote::__private::push_ident(&mut _s, "fn");
::quote::__private::push_ident(&mut _s, "__typecheck");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_underscore(&mut _s);
::quote::__private::push_colon(&mut _s);
::quote::ToTokens::to_tokens(&linkme_path, &mut _s);
::quote::__private::push_colon2(&mut _s);
::quote::ToTokens::to_tokens(&private, &mut _s);
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "Void");
_s
});
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Brace,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_pound(&mut _s);
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Bracket,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "allow");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "clippy");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "ref_option_ref");
_s
});
_s
});
::quote::__private::push_ident(&mut _s, "let");
::quote::ToTokens::to_tokens(&factory, &mut _s);
::quote::__private::push_eq(&mut _s);
::quote::__private::push_or_or(&mut _s);
::quote::__private::push_rarrow(&mut _s);
::quote::__private::push_ident(&mut _s, "fn");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
::quote::__private::TokenStream::new());
::quote::__private::push_rarrow(&mut _s);
::quote::__private::push_and(&mut _s);
::quote::__private::push_lifetime(&mut _s, "\'static");
::quote::ToTokens::to_tokens(&ty, &mut _s);
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Brace,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_or_or(&mut _s);
::quote::__private::push_and(&mut _s);
::quote::ToTokens::to_tokens(&ident, &mut _s);
_s
});
::quote::__private::push_semi(&mut _s);
::quote::__private::push_ident(&mut _s, "unsafe");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Brace,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&linkme_path, &mut _s);
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "DistributedSlice");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s,
"private_typecheck");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&path, &mut _s);
::quote::__private::push_comma(&mut _s);
::quote::ToTokens::to_tokens(&get, &mut _s);
_s
});
::quote::__private::push_semi(&mut _s);
_s
});
_s
});
::quote::ToTokens::to_tokens(&expr, &mut _s);
_s
});
::quote::__private::push_semi(&mut _s);
_s
});
::quote::ToTokens::to_tokens(&orig_item, &mut _s);
_s
}quote! {
224 #path ! {
225 #![linkme_macro = #path]
226 #(
227 #![linkme_sort_key = #sort_key]
228 )*
229 #(#attrs)*
230 #vis static #ident : #ty = {
231 #[allow(clippy::no_effect_underscore_binding)]
232 unsafe fn __typecheck(_: #linkme_path::#private::Void) {
233 #[allow(clippy::ref_option_ref)]
234 let #factory = || -> fn() -> &'static #ty { || &#ident };
235 unsafe {
236 #linkme_path::DistributedSlice::private_typecheck(#path, #get);
237 }
238 }
239
240 #expr
241 };
242 }
243
244 #orig_item
245 }
246}