1pub mod call;
23pub mod composite;
24pub mod config;
25pub mod error;
26pub mod event;
27pub mod extra_constants;
28pub mod genesis_build;
29pub mod genesis_config;
30pub mod helper;
31pub mod hooks;
32pub mod inherent;
33pub mod origin;
34pub mod pallet_struct;
35pub mod storage;
36pub mod tasks;
37pub mod type_value;
38pub mod validate_unsigned;
39
40#[cfg(test)]
41pub mod tests;
42
43use composite::{keyword::CompositeKeyword, CompositeDef};
44use frame_support_procedural_tools::generate_access_from_frame_or_crate;
45use quote::ToTokens;
46use syn::spanned::Spanned;
47
48pub struct Def {
50 pub item: syn::ItemMod,
53 pub config: config::ConfigDef,
54 pub pallet_struct: pallet_struct::PalletStructDef,
55 pub hooks: Option<hooks::HooksDef>,
56 pub call: Option<call::CallDef>,
57 pub tasks: Option<tasks::TasksDef>,
58 pub task_enum: Option<tasks::TaskEnumDef>,
59 pub storages: Vec<storage::StorageDef>,
60 pub error: Option<error::ErrorDef>,
61 pub event: Option<event::EventDef>,
62 pub origin: Option<origin::OriginDef>,
63 pub inherent: Option<inherent::InherentDef>,
64 pub genesis_config: Option<genesis_config::GenesisConfigDef>,
65 pub genesis_build: Option<genesis_build::GenesisBuildDef>,
66 pub validate_unsigned: Option<validate_unsigned::ValidateUnsignedDef>,
67 pub extra_constants: Option<extra_constants::ExtraConstantsDef>,
68 pub composites: Vec<composite::CompositeDef>,
69 pub type_values: Vec<type_value::TypeValueDef>,
70 pub frame_system: syn::Path,
71 pub frame_support: syn::Path,
72 pub dev_mode: bool,
73}
74
75impl Def {
76 pub fn try_from(mut item: syn::ItemMod, dev_mode: bool) -> syn::Result<Self> {
77 let frame_system = generate_access_from_frame_or_crate("frame-system")?;
78 let frame_support = generate_access_from_frame_or_crate("frame-support")?;
79 let item_span = item.span();
80 let items = &mut item
81 .content
82 .as_mut()
83 .ok_or_else(|| {
84 let msg = "Invalid pallet definition, expected mod to be inlined.";
85 syn::Error::new(item_span, msg)
86 })?
87 .1;
88
89 let mut config = None;
90 let mut pallet_struct = None;
91 let mut hooks = None;
92 let mut call = None;
93 let mut tasks = None;
94 let mut task_enum = None;
95 let mut error = None;
96 let mut event = None;
97 let mut origin = None;
98 let mut inherent = None;
99 let mut genesis_config = None;
100 let mut genesis_build = None;
101 let mut validate_unsigned = None;
102 let mut extra_constants = None;
103 let mut storages = vec![];
104 let mut type_values = vec![];
105 let mut composites: Vec<CompositeDef> = vec![];
106
107 for (index, item) in items.iter_mut().enumerate() {
108 let pallet_attr: Option<PalletAttr> = helper::take_first_item_pallet_attr(item)?;
109
110 match pallet_attr {
111 Some(PalletAttr::Config(_, with_default)) if config.is_none() =>
112 config = Some(config::ConfigDef::try_from(
113 &frame_system,
114 index,
115 item,
116 with_default,
117 )?),
118 Some(PalletAttr::Pallet(span)) if pallet_struct.is_none() => {
119 let p = pallet_struct::PalletStructDef::try_from(span, index, item)?;
120 pallet_struct = Some(p);
121 },
122 Some(PalletAttr::Hooks(span)) if hooks.is_none() => {
123 let m = hooks::HooksDef::try_from(span, item)?;
124 hooks = Some(m);
125 },
126 Some(PalletAttr::RuntimeCall(cw, span)) if call.is_none() =>
127 call = Some(call::CallDef::try_from(span, index, item, dev_mode, cw)?),
128 Some(PalletAttr::Tasks(_)) if tasks.is_none() => {
129 let item_tokens = item.to_token_stream();
130 tasks = Some(syn::parse2::<tasks::TasksDef>(quote::quote! {
133 #[pallet::tasks_experimental]
134 #item_tokens
135 })?);
136
137 *item = syn::Item::Verbatim(quote::quote!());
139 }
140 Some(PalletAttr::TaskCondition(span)) => return Err(syn::Error::new(
141 span,
142 "`#[pallet::task_condition]` can only be used on items within an `impl` statement."
143 )),
144 Some(PalletAttr::TaskIndex(span)) => return Err(syn::Error::new(
145 span,
146 "`#[pallet::task_index]` can only be used on items within an `impl` statement."
147 )),
148 Some(PalletAttr::TaskList(span)) => return Err(syn::Error::new(
149 span,
150 "`#[pallet::task_list]` can only be used on items within an `impl` statement."
151 )),
152 Some(PalletAttr::RuntimeTask(_)) if task_enum.is_none() =>
153 task_enum = Some(syn::parse2::<tasks::TaskEnumDef>(item.to_token_stream())?),
154 Some(PalletAttr::Error(span)) if error.is_none() =>
155 error = Some(error::ErrorDef::try_from(span, index, item)?),
156 Some(PalletAttr::RuntimeEvent(span)) if event.is_none() =>
157 event = Some(event::EventDef::try_from(span, index, item)?),
158 Some(PalletAttr::GenesisConfig(_)) if genesis_config.is_none() => {
159 let g = genesis_config::GenesisConfigDef::try_from(index, item)?;
160 genesis_config = Some(g);
161 },
162 Some(PalletAttr::GenesisBuild(span)) if genesis_build.is_none() => {
163 let g = genesis_build::GenesisBuildDef::try_from(span, item)?;
164 genesis_build = Some(g);
165 },
166 Some(PalletAttr::RuntimeOrigin(_)) if origin.is_none() =>
167 origin = Some(origin::OriginDef::try_from(item)?),
168 Some(PalletAttr::Inherent(_)) if inherent.is_none() =>
169 inherent = Some(inherent::InherentDef::try_from(item)?),
170 Some(PalletAttr::Storage(span)) =>
171 storages.push(storage::StorageDef::try_from(span, index, item, dev_mode)?),
172 Some(PalletAttr::ValidateUnsigned(_)) if validate_unsigned.is_none() => {
173 let v = validate_unsigned::ValidateUnsignedDef::try_from(item)?;
174 validate_unsigned = Some(v);
175 },
176 Some(PalletAttr::TypeValue(span)) =>
177 type_values.push(type_value::TypeValueDef::try_from(span, index, item)?),
178 Some(PalletAttr::ExtraConstants(_)) =>
179 extra_constants =
180 Some(extra_constants::ExtraConstantsDef::try_from(item)?),
181 Some(PalletAttr::Composite(span)) => {
182 let composite =
183 composite::CompositeDef::try_from(span, &frame_support, item)?;
184 if composites.iter().any(|def| {
185 match (&def.composite_keyword, &composite.composite_keyword) {
186 (
187 CompositeKeyword::FreezeReason(_),
188 CompositeKeyword::FreezeReason(_),
189 ) |
190 (CompositeKeyword::HoldReason(_), CompositeKeyword::HoldReason(_)) |
191 (CompositeKeyword::LockId(_), CompositeKeyword::LockId(_)) |
192 (
193 CompositeKeyword::SlashReason(_),
194 CompositeKeyword::SlashReason(_),
195 ) => true,
196 _ => false,
197 }
198 }) {
199 let msg = format!(
200 "Invalid duplicated `{}` definition",
201 composite.composite_keyword
202 );
203 return Err(syn::Error::new(composite.composite_keyword.span(), &msg))
204 }
205 composites.push(composite);
206 },
207 Some(attr) => {
208 let msg = "Invalid duplicated attribute";
209 return Err(syn::Error::new(attr.span(), msg))
210 },
211 None => (),
212 }
213 }
214
215 if genesis_config.is_some() != genesis_build.is_some() {
216 let msg = format!(
217 "`#[pallet::genesis_config]` and `#[pallet::genesis_build]` attributes must be \
218 either both used or both not used, instead genesis_config is {} and genesis_build \
219 is {}",
220 genesis_config.as_ref().map_or("unused", |_| "used"),
221 genesis_build.as_ref().map_or("unused", |_| "used"),
222 );
223 return Err(syn::Error::new(item_span, msg));
224 }
225
226 Self::resolve_tasks(&item_span, &mut tasks, &mut task_enum, items)?;
227
228 let def = Def {
229 item,
230 config: config
231 .ok_or_else(|| syn::Error::new(item_span, "Missing `#[pallet::config]`"))?,
232 pallet_struct: pallet_struct
233 .ok_or_else(|| syn::Error::new(item_span, "Missing `#[pallet::pallet]`"))?,
234 hooks,
235 call,
236 tasks,
237 task_enum,
238 extra_constants,
239 genesis_config,
240 genesis_build,
241 validate_unsigned,
242 error,
243 event,
244 origin,
245 inherent,
246 storages,
247 composites,
248 type_values,
249 frame_system,
250 frame_support,
251 dev_mode,
252 };
253
254 def.check_instance_usage()?;
255 def.check_event_usage()?;
256
257 Ok(def)
258 }
259
260 fn resolve_tasks(
262 item_span: &proc_macro2::Span,
263 tasks: &mut Option<tasks::TasksDef>,
264 task_enum: &mut Option<tasks::TaskEnumDef>,
265 items: &mut Vec<syn::Item>,
266 ) -> syn::Result<()> {
267 Self::resolve_manual_tasks_impl(tasks, task_enum, items)?;
269
270 Self::resolve_manual_task_enum(tasks, task_enum, items)?;
272
273 match (&task_enum, &tasks) {
275 (Some(_), None) =>
276 return Err(syn::Error::new(
277 *item_span,
278 "Missing `#[pallet::tasks_experimental]` impl",
279 )),
280 (None, Some(tasks)) =>
281 if tasks.tasks_attr.is_none() {
282 return Err(syn::Error::new(
283 tasks.item_impl.impl_token.span(),
284 "A `#[pallet::tasks_experimental]` attribute must be attached to your `Task` impl if the \
285 task enum has been omitted",
286 ));
287 } else {
288 },
289 _ => (),
290 }
291
292 Ok(())
293 }
294
295 fn resolve_manual_task_enum(
298 tasks: &Option<tasks::TasksDef>,
299 task_enum: &mut Option<tasks::TaskEnumDef>,
300 items: &mut Vec<syn::Item>,
301 ) -> syn::Result<()> {
302 let (None, Some(tasks)) = (&task_enum, &tasks) else { return Ok(()) };
303 let syn::Type::Path(type_path) = &*tasks.item_impl.self_ty else { return Ok(()) };
304 let type_path = type_path.path.segments.iter().collect::<Vec<_>>();
305 let (Some(seg), None) = (type_path.get(0), type_path.get(1)) else { return Ok(()) };
306 let mut result = None;
307 for item in items {
308 let syn::Item::Enum(item_enum) = item else { continue };
309 if item_enum.ident == seg.ident {
310 result = Some(syn::parse2::<tasks::TaskEnumDef>(item_enum.to_token_stream())?);
311 *item = syn::Item::Verbatim(quote::quote!());
315 break;
316 }
317 }
318 *task_enum = result;
319 Ok(())
320 }
321
322 pub fn resolve_manual_tasks_impl(
325 tasks: &mut Option<tasks::TasksDef>,
326 task_enum: &Option<tasks::TaskEnumDef>,
327 items: &Vec<syn::Item>,
328 ) -> syn::Result<()> {
329 let None = tasks else { return Ok(()) };
330 let mut result = None;
331 for item in items {
332 let syn::Item::Impl(item_impl) = item else { continue };
333 let Some((_, path, _)) = &item_impl.trait_ else { continue };
334 let Some(trait_last_seg) = path.segments.last() else { continue };
335 let syn::Type::Path(target_path) = &*item_impl.self_ty else { continue };
336 let target_path = target_path.path.segments.iter().collect::<Vec<_>>();
337 let (Some(target_ident), None) = (target_path.get(0), target_path.get(1)) else {
338 continue;
339 };
340 let matches_task_enum = match task_enum {
341 Some(task_enum) => task_enum.item_enum.ident == target_ident.ident,
342 None => true,
343 };
344 if trait_last_seg.ident == "Task" && matches_task_enum {
345 result = Some(syn::parse2::<tasks::TasksDef>(item_impl.to_token_stream())?);
346 break;
347 }
348 }
349 *tasks = result;
350 Ok(())
351 }
352
353 fn check_event_usage(&self) -> syn::Result<()> {
356 match (self.config.has_event_type, self.event.is_some()) {
357 (true, false) => {
358 let msg = "Invalid usage of RuntimeEvent, `Config` contains associated type `RuntimeEvent`, \
359 but enum `Event` is not declared (i.e. no use of `#[pallet::event]`). \
360 Note that type `RuntimeEvent` in trait is reserved to work alongside pallet event.";
361 Err(syn::Error::new(proc_macro2::Span::call_site(), msg))
362 },
363 (false, true) => {
364 let msg = "Invalid usage of RuntimeEvent, `Config` contains no associated type \
365 `RuntimeEvent`, but enum `Event` is declared (in use of `#[pallet::event]`). \
366 An RuntimeEvent associated type must be declare on trait `Config`.";
367 Err(syn::Error::new(proc_macro2::Span::call_site(), msg))
368 },
369 _ => Ok(()),
370 }
371 }
372
373 fn check_instance_usage(&self) -> syn::Result<()> {
376 let mut instances = vec![];
377 instances.extend_from_slice(&self.pallet_struct.instances[..]);
378 instances.extend(&mut self.storages.iter().flat_map(|s| s.instances.clone()));
379 if let Some(call) = &self.call {
380 instances.extend_from_slice(&call.instances[..]);
381 }
382 if let Some(hooks) = &self.hooks {
383 instances.extend_from_slice(&hooks.instances[..]);
384 }
385 if let Some(event) = &self.event {
386 instances.extend_from_slice(&event.instances[..]);
387 }
388 if let Some(error) = &self.error {
389 instances.extend_from_slice(&error.instances[..]);
390 }
391 if let Some(inherent) = &self.inherent {
392 instances.extend_from_slice(&inherent.instances[..]);
393 }
394 if let Some(origin) = &self.origin {
395 instances.extend_from_slice(&origin.instances[..]);
396 }
397 if let Some(genesis_config) = &self.genesis_config {
398 instances.extend_from_slice(&genesis_config.instances[..]);
399 }
400 if let Some(genesis_build) = &self.genesis_build {
401 genesis_build.instances.as_ref().map(|i| instances.extend_from_slice(&i));
402 }
403 if let Some(extra_constants) = &self.extra_constants {
404 instances.extend_from_slice(&extra_constants.instances[..]);
405 }
406
407 let mut errors = instances.into_iter().filter_map(|instances| {
408 if instances.has_instance == self.config.has_instance {
409 return None;
410 }
411 let msg = if self.config.has_instance {
412 "Invalid generic declaration, trait is defined with instance but generic use none"
413 } else {
414 "Invalid generic declaration, trait is defined without instance but generic use \
415 some"
416 };
417 Some(syn::Error::new(instances.span, msg))
418 });
419
420 if let Some(mut first_error) = errors.next() {
421 for error in errors {
422 first_error.combine(error)
423 }
424 Err(first_error)
425 } else {
426 Ok(())
427 }
428 }
429
430 pub fn type_impl_generics(&self, span: proc_macro2::Span) -> proc_macro2::TokenStream {
434 if self.config.has_instance {
435 quote::quote_spanned!(span => T: Config<I>, I: 'static)
436 } else {
437 quote::quote_spanned!(span => T: Config)
438 }
439 }
440
441 pub fn type_decl_bounded_generics(&self, span: proc_macro2::Span) -> proc_macro2::TokenStream {
445 if self.config.has_instance {
446 quote::quote_spanned!(span => T: Config<I>, I: 'static = ())
447 } else {
448 quote::quote_spanned!(span => T: Config)
449 }
450 }
451
452 pub fn type_decl_generics(&self, span: proc_macro2::Span) -> proc_macro2::TokenStream {
456 if self.config.has_instance {
457 quote::quote_spanned!(span => T, I = ())
458 } else {
459 quote::quote_spanned!(span => T)
460 }
461 }
462
463 pub fn trait_use_generics(&self, span: proc_macro2::Span) -> proc_macro2::TokenStream {
468 if self.config.has_instance {
469 quote::quote_spanned!(span => <I>)
470 } else {
471 quote::quote_spanned!(span => )
472 }
473 }
474
475 pub fn type_use_generics(&self, span: proc_macro2::Span) -> proc_macro2::TokenStream {
479 if self.config.has_instance {
480 quote::quote_spanned!(span => T, I)
481 } else {
482 quote::quote_spanned!(span => T)
483 }
484 }
485}
486
487pub enum GenericKind {
490 None,
491 Config,
492 ConfigAndInstance,
493}
494
495impl GenericKind {
496 pub fn from_gens(has_config: bool, has_instance: bool) -> Result<Self, ()> {
498 match (has_config, has_instance) {
499 (false, false) => Ok(GenericKind::None),
500 (true, false) => Ok(GenericKind::Config),
501 (true, true) => Ok(GenericKind::ConfigAndInstance),
502 (false, true) => Err(()),
503 }
504 }
505
506 pub fn type_use_gen(&self, span: proc_macro2::Span) -> proc_macro2::TokenStream {
510 match self {
511 GenericKind::None => quote::quote!(),
512 GenericKind::Config => quote::quote_spanned!(span => T),
513 GenericKind::ConfigAndInstance => quote::quote_spanned!(span => T, I),
514 }
515 }
516
517 pub fn type_impl_gen(&self, span: proc_macro2::Span) -> proc_macro2::TokenStream {
519 match self {
520 GenericKind::None => quote::quote!(),
521 GenericKind::Config => quote::quote_spanned!(span => T: Config),
522 GenericKind::ConfigAndInstance => {
523 quote::quote_spanned!(span => T: Config<I>, I: 'static)
524 },
525 }
526 }
527
528 pub fn is_generic(&self) -> bool {
530 match self {
531 GenericKind::None => false,
532 GenericKind::Config | GenericKind::ConfigAndInstance => true,
533 }
534 }
535}
536
537mod keyword {
539 syn::custom_keyword!(origin);
540 syn::custom_keyword!(call);
541 syn::custom_keyword!(tasks_experimental);
542 syn::custom_keyword!(task_enum);
543 syn::custom_keyword!(task_list);
544 syn::custom_keyword!(task_condition);
545 syn::custom_keyword!(task_index);
546 syn::custom_keyword!(weight);
547 syn::custom_keyword!(event);
548 syn::custom_keyword!(config);
549 syn::custom_keyword!(with_default);
550 syn::custom_keyword!(hooks);
551 syn::custom_keyword!(inherent);
552 syn::custom_keyword!(error);
553 syn::custom_keyword!(storage);
554 syn::custom_keyword!(genesis_build);
555 syn::custom_keyword!(genesis_config);
556 syn::custom_keyword!(validate_unsigned);
557 syn::custom_keyword!(type_value);
558 syn::custom_keyword!(pallet);
559 syn::custom_keyword!(extra_constants);
560 syn::custom_keyword!(composite_enum);
561}
562
563enum PalletAttr {
566 Config(proc_macro2::Span, bool),
567 Pallet(proc_macro2::Span),
568 Hooks(proc_macro2::Span),
569 RuntimeCall(Option<InheritedCallWeightAttr>, proc_macro2::Span),
607 Error(proc_macro2::Span),
608 Tasks(proc_macro2::Span),
609 TaskList(proc_macro2::Span),
610 TaskCondition(proc_macro2::Span),
611 TaskIndex(proc_macro2::Span),
612 RuntimeTask(proc_macro2::Span),
613 RuntimeEvent(proc_macro2::Span),
614 RuntimeOrigin(proc_macro2::Span),
615 Inherent(proc_macro2::Span),
616 Storage(proc_macro2::Span),
617 GenesisConfig(proc_macro2::Span),
618 GenesisBuild(proc_macro2::Span),
619 ValidateUnsigned(proc_macro2::Span),
620 TypeValue(proc_macro2::Span),
621 ExtraConstants(proc_macro2::Span),
622 Composite(proc_macro2::Span),
623}
624
625impl PalletAttr {
626 fn span(&self) -> proc_macro2::Span {
627 match self {
628 Self::Config(span, _) => *span,
629 Self::Pallet(span) => *span,
630 Self::Hooks(span) => *span,
631 Self::Tasks(span) => *span,
632 Self::TaskCondition(span) => *span,
633 Self::TaskIndex(span) => *span,
634 Self::TaskList(span) => *span,
635 Self::Error(span) => *span,
636 Self::RuntimeTask(span) => *span,
637 Self::RuntimeCall(_, span) => *span,
638 Self::RuntimeEvent(span) => *span,
639 Self::RuntimeOrigin(span) => *span,
640 Self::Inherent(span) => *span,
641 Self::Storage(span) => *span,
642 Self::GenesisConfig(span) => *span,
643 Self::GenesisBuild(span) => *span,
644 Self::ValidateUnsigned(span) => *span,
645 Self::TypeValue(span) => *span,
646 Self::ExtraConstants(span) => *span,
647 Self::Composite(span) => *span,
648 }
649 }
650}
651
652impl syn::parse::Parse for PalletAttr {
653 fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
654 input.parse::<syn::Token![#]>()?;
655 let content;
656 syn::bracketed!(content in input);
657 content.parse::<keyword::pallet>()?;
658 content.parse::<syn::Token![::]>()?;
659
660 let lookahead = content.lookahead1();
661 if lookahead.peek(keyword::config) {
662 let span = content.parse::<keyword::config>()?.span();
663 let with_default = content.peek(syn::token::Paren);
664 if with_default {
665 let inside_config;
666 let _paren = syn::parenthesized!(inside_config in content);
667 inside_config.parse::<keyword::with_default>()?;
668 }
669 Ok(PalletAttr::Config(span, with_default))
670 } else if lookahead.peek(keyword::pallet) {
671 Ok(PalletAttr::Pallet(content.parse::<keyword::pallet>()?.span()))
672 } else if lookahead.peek(keyword::hooks) {
673 Ok(PalletAttr::Hooks(content.parse::<keyword::hooks>()?.span()))
674 } else if lookahead.peek(keyword::call) {
675 let span = content.parse::<keyword::call>().expect("peeked").span();
676 let attr = match content.is_empty() {
677 true => None,
678 false => Some(InheritedCallWeightAttr::parse(&content)?),
679 };
680 Ok(PalletAttr::RuntimeCall(attr, span))
681 } else if lookahead.peek(keyword::tasks_experimental) {
682 Ok(PalletAttr::Tasks(content.parse::<keyword::tasks_experimental>()?.span()))
683 } else if lookahead.peek(keyword::task_enum) {
684 Ok(PalletAttr::RuntimeTask(content.parse::<keyword::task_enum>()?.span()))
685 } else if lookahead.peek(keyword::task_condition) {
686 Ok(PalletAttr::TaskCondition(content.parse::<keyword::task_condition>()?.span()))
687 } else if lookahead.peek(keyword::task_index) {
688 Ok(PalletAttr::TaskIndex(content.parse::<keyword::task_index>()?.span()))
689 } else if lookahead.peek(keyword::task_list) {
690 Ok(PalletAttr::TaskList(content.parse::<keyword::task_list>()?.span()))
691 } else if lookahead.peek(keyword::error) {
692 Ok(PalletAttr::Error(content.parse::<keyword::error>()?.span()))
693 } else if lookahead.peek(keyword::event) {
694 Ok(PalletAttr::RuntimeEvent(content.parse::<keyword::event>()?.span()))
695 } else if lookahead.peek(keyword::origin) {
696 Ok(PalletAttr::RuntimeOrigin(content.parse::<keyword::origin>()?.span()))
697 } else if lookahead.peek(keyword::inherent) {
698 Ok(PalletAttr::Inherent(content.parse::<keyword::inherent>()?.span()))
699 } else if lookahead.peek(keyword::storage) {
700 Ok(PalletAttr::Storage(content.parse::<keyword::storage>()?.span()))
701 } else if lookahead.peek(keyword::genesis_config) {
702 Ok(PalletAttr::GenesisConfig(content.parse::<keyword::genesis_config>()?.span()))
703 } else if lookahead.peek(keyword::genesis_build) {
704 Ok(PalletAttr::GenesisBuild(content.parse::<keyword::genesis_build>()?.span()))
705 } else if lookahead.peek(keyword::validate_unsigned) {
706 Ok(PalletAttr::ValidateUnsigned(content.parse::<keyword::validate_unsigned>()?.span()))
707 } else if lookahead.peek(keyword::type_value) {
708 Ok(PalletAttr::TypeValue(content.parse::<keyword::type_value>()?.span()))
709 } else if lookahead.peek(keyword::extra_constants) {
710 Ok(PalletAttr::ExtraConstants(content.parse::<keyword::extra_constants>()?.span()))
711 } else if lookahead.peek(keyword::composite_enum) {
712 Ok(PalletAttr::Composite(content.parse::<keyword::composite_enum>()?.span()))
713 } else {
714 Err(lookahead.error())
715 }
716 }
717}
718
719#[derive(Clone)]
721pub struct InheritedCallWeightAttr {
722 pub typename: syn::Type,
723}
724
725impl syn::parse::Parse for InheritedCallWeightAttr {
726 fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
728 let content;
729 syn::parenthesized!(content in input);
730 content.parse::<keyword::weight>()?;
731 let lookahead = content.lookahead1();
732
733 let buffer = if lookahead.peek(syn::token::Paren) {
734 let inner;
735 syn::parenthesized!(inner in content);
736 inner
737 } else if lookahead.peek(syn::Token![=]) {
738 content.parse::<syn::Token![=]>().expect("peeked");
739 content
740 } else {
741 return Err(lookahead.error());
742 };
743
744 Ok(Self { typename: buffer.parse()? })
745 }
746}