1use super::framework::*;
29
30use indexmap::IndexMap;
31
32use Usage as U;
33
34#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
38#[derive(AsRefStr, EnumString, EnumIter)]
39#[rustfmt::skip]
40pub enum Scope {
41 #[strum(serialize = "tmeta")] T,
43 #[strum(serialize = "vmeta")] V,
44 #[strum(serialize = "fmeta")] F,
45}
46
47#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)] #[derive(strum::Display, EnumIter)]
53#[strum(serialize_all = "snake_case")]
54pub enum SuppliedScope {
55 Struct,
56 Enum,
57 Variant,
58 Field,
59}
60
61impl SuppliedScope {
62 fn recog_search(self) -> impl Iterator<Item = Scope> {
63 use Scope as S;
64 use SuppliedScope as SS;
65 match self {
66 SS::Struct => &[S::T, S::V] as &[_],
67 SS::Enum => &[S::T],
68 SS::Variant => &[S::V],
69 SS::Field => &[S::F],
70 }
71 .iter()
72 .copied()
73 }
74}
75
76#[derive(Debug, Clone, Eq, PartialEq, Hash)]
80pub struct Label {
81 pub lpaths: Vec<syn::Path>,
84}
85
86#[derive(Debug, Clone, Eq, PartialEq, Hash)]
89pub struct Desig {
90 pub scope: Scope,
91 pub label: Label,
92}
93
94#[derive(Hash)]
95struct BorrowedDesig<'p> {
97 pub scope: Scope,
98 pub lpaths: &'p [&'p syn::Path],
99}
100
101#[derive(Debug)]
104pub struct SubstMeta<O: SubstParseContext> {
105 pub desig: Desig,
106 pub as_: Option<SubstAs<O>>,
107 pub default: Option<(Argument<O>, O::NotInBool, beta::Enabled)>,
108}
109
110#[derive(Debug, Clone, AsRefStr, Display)]
111#[allow(non_camel_case_types)] pub enum SubstAs<O: SubstParseContext> {
113 expr(O::NotInBool, AllowTokens<O>, SubstAsSupported<ValueExpr>),
114 ident(O::NotInBool),
115 items(O::NotInBool, AllowTokens<O>, SubstAsSupported<ValueItems>),
116 path(O::NotInBool),
117 str(O::NotInBool),
118 token_stream(O::NotInBool, AllowTokens<O>),
119 ty(O::NotInBool),
120}
121
122#[derive(Debug)]
126pub struct PreprocessedValueList {
127 pub content: Punctuated<PreprocessedTree, token::Comma>,
128}
129
130pub type PreprocessedMetas = Vec<PreprocessedValueList>;
132
133#[derive(Debug)]
138pub struct PreprocessedTree {
139 pub path: syn::Path,
140 pub value: PreprocessedValue,
141 pub used: Cell<Usage>,
142}
143
144#[derive(Debug)]
150pub enum PreprocessedValue {
151 Unit,
153 Value { value: syn::Lit },
155 List(PreprocessedValueList),
157}
158
159#[derive(Debug)]
163pub struct FoundNode<'l> {
164 kind: FoundNodeKind<'l>,
165 path_span: Span,
166 ptree: &'l PreprocessedTree,
167}
168
169#[derive(Debug)]
171pub enum FoundNodeKind<'l> {
172 Unit,
173 Lit(&'l syn::Lit),
174}
175
176#[derive(Debug)]
181pub struct FoundNearbyNode<'l> {
182 pub kind: FoundNearbyNodeKind,
183 pub path_span: Span,
185 pub ptree: &'l PreprocessedTree,
186}
187
188#[derive(Debug)]
190pub enum FoundNearbyNodeKind {
191 Unit,
193 Lit,
195 List,
197}
198
199pub use FoundNearbyNodeKind as FNNK;
200pub use FoundNodeKind as FNK;
201
202#[derive(Default, Debug, Clone, Copy, Eq, PartialEq)]
205pub struct UsageInfo<M> {
206 unit: Option<M>,
207 value: Option<M>,
208}
209
210pub type Usage = UsageInfo<IsUsed>;
211
212impl Usage {
213 pub const BOOL_ONLY: Usage = UsageInfo {
214 unit: Some(IsUsed),
215 value: None,
216 };
217 pub const VALUE_ONLY: Usage = UsageInfo {
218 unit: None,
219 value: Some(IsUsed),
220 };
221 pub const VALUE: Usage = UsageInfo {
222 unit: Some(IsUsed),
223 value: Some(IsUsed),
224 };
225 pub const NONE: Usage = UsageInfo {
226 unit: None,
227 value: None,
228 };
229}
230
231#[derive(Debug, Clone, Copy, Eq, PartialEq, strum::EnumIter)]
232pub enum UsageMode {
233 Unit,
234 Value,
235}
236
237impl<M> UsageInfo<M> {
238 pub fn get(&self, mode: UsageMode) -> Option<&M> {
239 match mode {
240 UsageMode::Unit => self.unit.as_ref(),
241 UsageMode::Value => self.value.as_ref(),
242 }
243 }
244 pub fn get_mut(&mut self, mode: UsageMode) -> &mut Option<M> {
245 match mode {
246 UsageMode::Unit => &mut self.unit,
247 UsageMode::Value => &mut self.value,
248 }
249 }
250}
251
252impl std::ops::BitOr for Usage {
253 type Output = Usage;
254 fn bitor(self, other: Usage) -> Usage {
255 let mut out = self;
256 for mode in UsageMode::iter() {
257 let ent = out.get_mut(mode);
258 *ent = cmp::max(*ent, other.get(mode).copied());
259 }
260 out
261 }
262}
263
264#[derive(Default, Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd)]
265pub struct IsUsed;
266
267#[derive(Debug)]
269pub struct UsedGroup {
270 pub content: TokenStream,
271}
272
273#[derive(Debug, Clone)]
275pub enum CheckUsed<T> {
276 Check(T),
278 Unchecked,
280}
281
282#[derive(Debug, Default)]
284pub struct Accum {
285 pub recog: Recognised,
286 pub used: Vec<UsedGroup>,
287}
288
289#[derive(Default, Debug, Clone)]
290pub struct Recognised {
291 map: IndexMap<Desig, Usage>,
292}
293
294pub trait FindRecogMetas {
295 fn find_recog_metas(&self, acc: &mut Recognised);
300}
301
302impl<O: SubstParseContext> SubstMeta<O> {
307 fn span_whole(&self, scope_span: Span) -> Span {
308 spans_join(chain!(
309 [scope_span], self.desig.label.spans(),
311 ))
312 .unwrap()
313 }
314}
315
316impl Label {
317 pub fn spans(&self) -> impl Iterator<Item = Span> + '_ {
319 self.lpaths.iter().map(|path| path.span())
320 }
321}
322
323impl<O: SubstParseContext> SubstAs<O> {
324 fn parse(input: ParseStream, nb: O::NotInBool) -> syn::Result<Self> {
325 let kw: IdentAny = input.parse()?;
326 let from_sma = |sma: SubstAs<_>| Ok(sma);
327
328 macro_rules! keyword { { $($args:tt)* } => {
330 keyword_general! { kw from_sma SubstAs; $($args)* }
331 } }
332
333 let allow_tokens = || O::allow_tokens(&kw);
334 fn supported<P>(kw: &IdentAny) -> syn::Result<SubstAsSupported<P>>
335 where
336 P: SubstAsSupportStatus,
337 {
338 SubstAsSupportStatus::new(&kw)
339 }
340
341 keyword! { expr(nb, allow_tokens()?, supported(&kw)?) }
342 keyword! { ident(nb) }
343 keyword! { items(nb, allow_tokens()?, supported(&kw)?) }
344 keyword! { path(nb) }
345 keyword! { str(nb) }
346 keyword! { token_stream(nb, allow_tokens()?) }
347 keyword! { ty(nb) }
348
349 Err(kw.error("unknown derive-deftly 'as' syntax type keyword"))
350 }
351}
352
353impl<O: SubstParseContext> SubstMeta<O> {
354 pub fn parse(
355 input: ParseStream,
356 kw_span: Span,
357 scope: Scope,
358 ) -> syn::Result<Self> {
359 if input.is_empty() {
360 O::missing_keyword_arguments(kw_span)?;
361 }
362
363 let label: Label = input.parse()?;
364
365 fn store<V>(
366 kw: Span,
367 already: &mut Option<(Span, V)>,
368 call: impl FnOnce() -> syn::Result<V>,
369 ) -> syn::Result<()> {
370 if let Some((already, _)) = already {
371 return Err([(*already, "first"), (kw, "second")]
372 .error("`${Xmeta ..}` option repeated"));
373 }
374 let v = call()?;
375 *already = Some((kw, v));
376 Ok(())
377 }
378
379 let mut as_ = None::<(Span, SubstAs<O>)>;
380 let mut default = None;
381
382 while !O::IS_BOOL && !input.is_empty() {
383 let keyword = Ident::parse_any(input)?;
384 let kw_span = keyword.span();
385 let nb = O::not_in_bool(&kw_span).expect("checked already");
386 let ue = || beta::Enabled::new_for_syntax(kw_span);
387 if keyword == "as" {
388 store(kw_span, &mut as_, || SubstAs::parse(input, nb))?;
389 } else if keyword == "default" {
390 store(kw_span, &mut default, || {
391 Ok((input.parse()?, nb, ue()?))
392 })?;
393 } else {
394 return Err(keyword.error("unknown option in `${Xmeta }`"));
395 }
396 if input.is_empty() {
397 break;
398 }
399 let _: Token![,] = input.parse()?;
400 }
401
402 macro_rules! ret { { $( $f:ident )* } => {
403 SubstMeta {
404 desig: Desig { label, scope },
405 $( $f: $f.map(|(_span, v)| v), )*
406 }
407 } }
408
409 Ok(ret! {
410 as_
411 default
412 })
413 }
414}
415
416impl PreprocessedValueList {
419 fn parse_outer(input: ParseStream) -> syn::Result<Self> {
420 let meta;
421 let _paren = parenthesized!(meta in input);
422 Self::parse_inner(&meta)
423 }
424}
425
426impl PreprocessedValueList {
427 pub fn parse_inner(input: ParseStream) -> syn::Result<Self> {
428 let content = Punctuated::parse_terminated(input)?;
429 Ok(PreprocessedValueList { content })
430 }
431}
432
433impl Parse for PreprocessedTree {
434 fn parse(input: ParseStream) -> syn::Result<Self> {
435 use PreprocessedValue as PV;
436
437 let path = input.call(syn::Path::parse_mod_style)?;
438 let la = input.lookahead1();
439 let value = if la.peek(Token![=]) {
440 let _: Token![=] = input.parse()?;
441 let value = input.parse()?;
442 PV::Value { value }
443 } else if la.peek(token::Paren) {
444 let list = input.call(PreprocessedValueList::parse_outer)?;
445 PV::List(list)
446 } else if la.peek(Token![,]) || input.is_empty() {
447 PV::Unit
448 } else {
449 return Err(la.error());
450 };
451 let used = Usage::default().into(); Ok(PreprocessedTree { path, value, used })
453 }
454}
455
456impl Parse for Label {
457 fn parse(outer: ParseStream) -> syn::Result<Self> {
458 fn recurse(
459 lpaths: &mut Vec<syn::Path>,
460 outer: ParseStream,
461 ) -> syn::Result<()> {
462 let input;
463 let paren = parenthesized!(input in outer);
464 let path = input.call(syn::Path::parse_mod_style)?;
465 if path.segments.is_empty() {
466 return Err(paren
467 .span
468 .error("`deftly` attribute must have nonempty path"));
469 }
470
471 lpaths.push(path);
472 if !input.is_empty() {
473 recurse(lpaths, &input)?;
474 }
475 Ok(())
476 }
477
478 let mut lpaths = vec![];
479 recurse(&mut lpaths, outer)?;
480
481 Ok(Label { lpaths })
482 }
483}
484
485impl Label {
488 pub fn search<'a, F, G, E>(
490 &self,
491 pmetas: &'a [PreprocessedValueList],
492 f: &mut F,
493 g: &mut G,
494 ) -> Result<(), E>
495 where
496 F: FnMut(FoundNode<'a>) -> Result<(), E>,
497 G: FnMut(FoundNearbyNode<'a>) -> Result<(), E>,
498 {
499 for m in pmetas {
500 for l in &m.content {
501 Self::search_1(&self.lpaths, l, &mut *f, &mut *g)?;
502 }
503 }
504 Ok(())
505 }
506
507 fn search_1<'a, E, F, G>(
508 lpaths: &[syn::Path],
510 ptree: &'a PreprocessedTree,
511 f: &mut F,
512 g: &mut G,
513 ) -> Result<(), E>
514 where
515 F: FnMut(FoundNode<'a>) -> Result<(), E>,
516 G: FnMut(FoundNearbyNode<'a>) -> Result<(), E>,
517 {
518 use PreprocessedValue as PV;
519
520 if ptree.path != lpaths[0] {
521 return Ok(());
522 }
523
524 let path_span = ptree.path.span();
525
526 let mut nearby = |kind| {
527 g(FoundNearbyNode {
528 kind,
529 path_span,
530 ptree,
531 })
532 };
533
534 let deeper = if lpaths.len() <= 1 {
535 None
536 } else {
537 Some(&lpaths[1..])
538 };
539
540 match (deeper, &ptree.value) {
541 (None, PV::Unit) => f(FoundNode {
542 path_span,
543 kind: FNK::Unit,
544 ptree,
545 })?,
546 (None, PV::List(_)) => nearby(FNNK::List)?,
547 (None, PV::Value { value, .. }) => f(FoundNode {
548 path_span,
549 kind: FNK::Lit(value),
550 ptree,
551 })?,
552 (Some(_), PV::Value { .. }) => nearby(FNNK::Lit)?,
553 (Some(_), PV::Unit) => nearby(FNNK::Unit)?,
554 (Some(d), PV::List(l)) => {
555 for m in l.content.iter() {
556 Self::search_1(d, m, &mut *f, &mut *g)?;
557 }
558 }
559 }
560
561 Ok(())
562 }
563}
564
565impl Label {
566 pub fn search_eval_bool(
567 &self,
568 pmetas: &PreprocessedMetas,
569 ) -> Result<(), Found> {
570 let found = |ptree: &PreprocessedTree| {
571 ptree.update_used(Usage::BOOL_ONLY);
572 Err(Found)
573 };
574 self.search(
575 pmetas,
576 &mut |av| found(av.ptree),
577 &mut |nearby| match nearby.kind {
578 FNNK::List => found(nearby.ptree),
579 FNNK::Unit => Ok(()),
580 FNNK::Lit => Ok(()),
581 },
582 )
583 }
584}
585
586impl<O> SubstMeta<O>
589where
590 O: SubstParseContext,
591{
592 pub fn repeat_over(&self) -> Option<RepeatOver> {
593 match self.desig.scope {
594 Scope::T => None,
595 Scope::V => Some(RO::Variants),
596 Scope::F => Some(RO::Fields),
597 }
598 }
599}
600
601impl<O> SubstMeta<O>
602where
603 O: SubstParseContext,
604{
605 pub fn pmetas<'c>(
606 &self,
607 ctx: &'c Context<'c>,
608 kw_span: Span,
609 ) -> syn::Result<&'c PreprocessedMetas> {
610 Ok(match self.desig.scope {
611 Scope::T => &ctx.pmetas,
612 Scope::V => &ctx.variant(&kw_span)?.pmetas,
613 Scope::F => &ctx.field(&kw_span)?.pfield.pmetas,
614 })
615 }
616}
617
618impl ToTokens for Label {
619 fn to_tokens(&self, out: &mut TokenStream) {
620 let mut lpaths = self.lpaths.iter().rev();
621 let mut current =
622 lpaths.next().expect("empty path!").to_token_stream();
623 let r = loop {
624 let group = group_new_with_span(
625 Delimiter::Parenthesis,
626 current.span(),
627 current,
628 );
629 let wrap = if let Some(y) = lpaths.next() {
630 y
631 } else {
632 break group;
633 };
634 current = quote! { #wrap #group };
635 };
636 r.to_tokens(out);
637 }
638}
639
640impl Desig {
641 fn to_tokens(&self, scope_span: Span, out: &mut TokenStream) {
642 let scope: &str = self.scope.as_ref();
643 Ident::new(scope, scope_span).to_tokens(out);
644 self.label.to_tokens(out);
645 }
646}
647
648impl Parse for Desig {
649 fn parse(input: ParseStream) -> syn::Result<Self> {
650 let scope: syn::Ident = input.parse()?;
651 let scope = scope
652 .to_string()
653 .parse()
654 .map_err(|_| scope.error("invalid meta keyword/level"))?;
655 let label = input.parse()?;
656 Ok(Self { scope, label })
657 }
658}
659
660impl indexmap::Equivalent<Desig> for BorrowedDesig<'_> {
661 fn equivalent(&self, desig: &Desig) -> bool {
662 let BorrowedDesig { scope, lpaths } = self;
663 *scope == desig.scope
664 && itertools::equal(lpaths.iter().copied(), &desig.label.lpaths)
665 }
666}
667
668struct DisplayAsIfSpecified<'r> {
670 lpaths: &'r [&'r syn::Path],
671 inside_after: &'r str,
673}
674impl Display for DisplayAsIfSpecified<'_> {
675 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
676 write!(f, "#[deftly")?;
677 for p in self.lpaths {
678 write!(f, "({}", p.to_token_stream())?;
679 }
680 write!(f, "{}", self.inside_after)?;
681 for _ in self.lpaths {
682 write!(f, ")")?;
683 }
684 Ok(())
685 }
686}
687
688#[test]
690fn check_borrowed_desig() {
691 use super::*;
692 use indexmap::Equivalent;
693 use itertools::iproduct;
694 use std::hash::{Hash, Hasher};
695
696 #[derive(PartialEq, Eq, Debug, Default)]
697 struct TrackingHasher(Vec<Vec<u8>>);
698 impl Hasher for TrackingHasher {
699 fn write(&mut self, bytes: &[u8]) {
700 self.0.push(bytes.to_owned());
701 }
702 fn finish(&self) -> u64 {
703 unreachable!()
704 }
705 }
706 impl TrackingHasher {
707 fn hash(t: impl Hash) -> Self {
708 let mut self_ = Self::default();
709 t.hash(&mut self_);
710 self_
711 }
712 }
713
714 type Case = (Scope, &'static [&'static str]);
715 const TEST_CASES: &[Case] = &[
716 (Scope::T, &["path"]),
717 (Scope::T, &["r#path"]),
718 (Scope::V, &["path", "some::path"]),
719 (Scope::V, &["r#struct", "with_generics::<()>"]),
720 (Scope::F, &[]), ];
722
723 struct Desigs<'b> {
724 owned: Desig,
725 borrowed: BorrowedDesig<'b>,
726 }
727 impl Desigs<'_> {
728 fn with((scope, lpaths): &Case, f: impl FnOnce(Desigs<'_>)) {
729 let scope = *scope;
730 let lpaths = lpaths
731 .iter()
732 .map(|l| syn::parse_str(l).expect(l))
733 .collect_vec();
734 let owned = {
735 let label = Label {
736 lpaths: lpaths.clone(),
737 };
738 Desig { scope, label }
739 };
740 let lpaths_borrowed;
741 let borrowed = {
742 lpaths_borrowed = lpaths.iter().collect_vec();
743 BorrowedDesig {
744 scope,
745 lpaths: &*lpaths_borrowed,
746 }
747 };
748 f(Desigs { owned, borrowed })
749 }
750 }
751
752 for case in TEST_CASES {
756 Desigs::with(case, |d| {
757 assert!(d.borrowed.equivalent(&d.owned));
758 assert_eq!(
759 TrackingHasher::hash(&d.owned),
760 TrackingHasher::hash(&d.borrowed),
761 );
762 });
763 }
764
765 for (case0, case1) in iproduct!(TEST_CASES, TEST_CASES) {
772 Desigs::with(case0, |d0| {
773 Desigs::with(case1, |d1| {
774 let equal = d0.owned == d1.owned;
775 assert_eq!(equal, d0.borrowed.equivalent(&d1.owned));
776 assert_eq!(equal, d1.borrowed.equivalent(&d0.owned));
777 if equal {
778 let hash = TrackingHasher::hash(&d0.owned);
779 assert_eq!(hash, TrackingHasher::hash(&d1.owned));
780 assert_eq!(hash, TrackingHasher::hash(&d0.borrowed));
781 assert_eq!(hash, TrackingHasher::hash(&d1.borrowed));
782 }
783 });
784 });
785 }
786}
787
788#[cfg(feature = "meta-as-expr")]
791pub type ValueExpr = syn::Expr;
792#[cfg(not(feature = "meta-as-expr"))]
793pub type ValueExpr = MetaUnsupported;
794
795#[cfg(feature = "meta-as-items")]
796pub type ValueItems = Concatenated<syn::Item>;
797#[cfg(not(feature = "meta-as-items"))]
798pub type ValueItems = MetaUnsupported;
799
800#[derive(Debug, Copy, Clone)]
802#[allow(dead_code)] pub struct MetaUnsupported(Void);
804
805#[derive(Debug, Copy, Clone)]
806pub struct SubstAsSupported<P: SubstAsSupportStatus>(P::Marker);
807
808pub trait SubstAsSupportStatus: Sized {
810 type Marker;
811 type Parsed: Parse + ToTokens;
812 fn new(kw: &IdentAny) -> syn::Result<SubstAsSupported<Self>>;
813}
814
815impl<P: SubstAsSupportStatus> SubstAsSupported<P> {
816 fn infer_type(&self, _parsed: &P::Parsed) {}
817}
818
819impl<T: Parse + ToTokens> SubstAsSupportStatus for T {
820 type Marker = ();
821 type Parsed = T;
822 fn new(_kw: &IdentAny) -> syn::Result<SubstAsSupported<Self>> {
823 Ok(SubstAsSupported(()))
824 }
825}
826
827impl SubstAsSupportStatus for MetaUnsupported {
828 type Marker = MetaUnsupported;
829 type Parsed = TokenStream;
830 fn new(kw: &IdentAny) -> syn::Result<SubstAsSupported<Self>> {
831 Err(kw.error(format_args!(
832 "${{Xmeta as {}}} used but cargo feature meta-as-{} disabled",
835 **kw, **kw,
836 )))
837 }
838}
839
840impl ToTokens for MetaUnsupported {
841 fn to_tokens(&self, _out: &mut TokenStream) {
842 void::unreachable(self.0)
843 }
844}
845
846impl<O> SubstMeta<O>
849where
850 O: ExpansionOutput,
851 TemplateElement<O>: Expand<O>,
852{
853 pub fn expand(
854 &self,
855 ctx: &Context,
856 kw_span: Span,
857 out: &mut O,
858 pmetas: &PreprocessedMetas,
859 ) -> syn::Result<()> {
860 let SubstMeta {
861 desig,
862 as_,
863 default,
864 } = self;
865 let mut found = None::<FoundNode>;
866 let mut hint = None::<FoundNearbyNode>;
867 let span_whole = self.span_whole(kw_span);
868 let self_loc = || (span_whole, "expansion");
869 let error_loc = || [ctx.error_loc(), self_loc()];
870
871 desig.label.search(
872 pmetas,
873 &mut |av: FoundNode| {
874 if let Some(first) = &found {
875 return Err([(first.path_span, "first occurrence"),
876 (av.path_span, "second occurrence"),
877 self_loc()].error(
878 "tried to expand just attribute value, but it was specified multiple times"
879 ));
880 }
881 found = Some(av);
882 Ok(())
883 },
884 &mut |nearby| {
885 hint.get_or_insert(nearby);
886 Ok(())
887 },
888 )?;
889
890 if let Some((def, ..)) = default {
891 if match found {
892 None => true,
893 Some(FoundNode {
894 kind: FNK::Unit,
895 ptree,
896 ..
897 }) => {
898 ptree.update_used(Usage::VALUE_ONLY);
901 true
902 }
903 _ => false,
904 } {
905 return Ok(def.expand(ctx.as_general(), out));
906 }
907 }
908
909 let found = found.ok_or_else(|| {
910 if let Some(hint) = hint {
911 let hint_msg = match hint.kind {
912 FNNK::Unit =>
913 "expected a list with sub-attributes, found a unit",
914 FNNK::Lit =>
915 "expected a list with sub-attributes, found a simple value",
916 FNNK::List =>
917 "expected a leaf node, found a list with sub-attributes",
918 };
919 let mut err = hint.path_span.error(hint_msg);
920 err.combine(error_loc().error(
921 "attribute value expanded, but no suitable value in data structure definition"
922 ));
923 err
924 } else {
925 error_loc().error(
926 "attribute value expanded, but no value in data structure definition"
927 )
928 }
929 })?;
930
931 found.ptree.update_used(Usage::VALUE);
932 found.expand(span_whole, as_, out)?;
933
934 Ok(())
935 }
936}
937
938fn metavalue_spans(tspan: Span, vspan: Span) -> [ErrorLoc<'static>; 2] {
939 [(vspan, "attribute value"), (tspan, "template")]
940}
941
942fn metavalue_litstr<'l>(
947 lit: &'l syn::Lit,
948 tspan: Span,
949 msg: fmt::Arguments<'_>,
950) -> syn::Result<&'l syn::LitStr> {
951 match lit {
952 syn::Lit::Str(s) => Ok(s),
953 _ => Err(metavalue_spans(tspan, lit.span()).error(msg)),
956 }
957}
958
959pub fn metavalue_lit_as<T>(
963 lit: &syn::Lit,
964 tspan: Span,
965 into_what: &dyn Display,
966) -> syn::Result<T>
967where
968 T: Parse + ToTokens,
969{
970 let s = metavalue_litstr(
971 lit,
972 tspan,
973 format_args!(
974 "expected string literal, for conversion to {}",
975 into_what,
976 ),
977 )?;
978
979 let t: TokenStream = s.parse().map_err(|e| {
980 match (|| {
991 let _: String = (&e).into_iter().next()?.span().source_text()?;
992 Some(())
993 })() {
994 Some(()) => e,
995 None => lit.span().error(e.to_string()),
996 }
997 })?;
998
999 let thing: T = syn::parse2(t)?;
1000 Ok(thing)
1001}
1002
1003impl<'l> FoundNode<'l> {
1004 fn expand<O>(
1005 &self,
1006 tspan: Span,
1007 as_: &Option<SubstAs<O>>,
1008 out: &mut O,
1009 ) -> syn::Result<()>
1010 where
1011 O: ExpansionOutput,
1012 {
1013 let spans = |vspan| metavalue_spans(tspan, vspan);
1014
1015 let lit = match self.kind {
1016 FNK::Unit => return Err(spans(self.path_span).error(
1017 "tried to expand attribute which is just a unit, not a literal"
1018 )),
1019 FNK::Lit(lit) => lit,
1020 };
1021
1022 use SubstAs as SA;
1023
1024 let default_buf;
1025 let as_ = match as_ {
1026 Some(as_) => as_,
1027 None => {
1028 default_buf = O::default_subst_meta_as(tspan)?;
1029 &default_buf
1030 }
1031 };
1032
1033 match as_ {
1034 as_ @ SA::expr(.., at, supported) => {
1035 let expr = metavalue_lit_as(lit, tspan, as_)?;
1036 supported.infer_type(&expr);
1037 let span = expr.span();
1038 out.append_tokens(at, Grouping::Parens.surround(span, expr))?;
1039 }
1040 as_ @ SA::ident(..) => {
1041 let ident: IdentAny = metavalue_lit_as(lit, tspan, as_)?;
1042 out.append_identfrag_toks(&*ident)?;
1043 }
1044 SA::items(_, np, supported) => {
1045 let items = metavalue_lit_as(lit, tspan, &"items")?;
1046 supported.infer_type(&items);
1047 out.append_tokens(np, items)?;
1048 }
1049 as_ @ SA::path(..) => out.append_syn_type(
1050 tspan,
1051 syn::Type::Path(metavalue_lit_as(lit, tspan, as_)?),
1052 Grouping::Invisible,
1053 ),
1054 SA::str(..) => {
1055 let s = metavalue_litstr(
1056 lit,
1057 tspan,
1058 format_args!("expected string literal, for meta value",),
1059 )?;
1060 out.append_syn_litstr(s);
1061 }
1062 as_ @ SA::ty(..) => out.append_syn_type(
1063 tspan,
1064 metavalue_lit_as(lit, tspan, as_)?,
1065 Grouping::Invisible,
1066 ),
1067 SA::token_stream(_, np) => {
1068 let tokens: TokenStream =
1069 metavalue_lit_as(lit, tspan, &"tokens")?;
1070 out.append_tokens(np, tokens)?;
1071 }
1072 }
1073 Ok(())
1074 }
1075}
1076
1077impl Parse for CheckUsed<UsedGroup> {
1080 fn parse(input: ParseStream) -> syn::Result<Self> {
1081 let la = input.lookahead1();
1082 Ok(if la.peek(Token![*]) {
1083 let _star: Token![*] = input.parse()?;
1084 mCU::Unchecked
1085 } else if la.peek(token::Bracket) {
1086 let group: proc_macro2::Group = input.parse()?;
1087 let content = group.stream();
1088 mCU::Check(UsedGroup { content })
1089 } else {
1090 return Err(la.error());
1091 })
1092 }
1093}
1094
1095impl Recognised {
1096 pub fn update(&mut self, k: Desig, v: Usage) {
1098 let ent = self.map.entry(k).or_insert(v);
1099 *ent = *ent | v
1100 }
1101}
1102
1103impl ToTokens for Recognised {
1104 fn to_tokens(&self, out: &mut TokenStream) {
1105 for (desig, allow) in &self.map {
1106 match *allow {
1107 Usage::BOOL_ONLY => out.extend(quote! { ? }),
1108 Usage::VALUE_ONLY => out.extend(quote! { + }),
1109 Usage::VALUE => {}
1110 Usage::NONE => panic!("should be impossible!"),
1111 }
1112 desig.to_tokens(Span::call_site(), out);
1113 }
1114 }
1115}
1116
1117impl PreprocessedTree {
1118 pub fn update_used(&self, ra: Usage) {
1119 self.used.set(self.used.get() | ra);
1120 }
1121}
1122
1123impl PreprocessedValueList {
1126 fn decode_update_used(&self, input: ParseStream) -> syn::Result<()> {
1127 use PreprocessedValue as PV;
1128
1129 for ptree in &self.content {
1130 if input.is_empty() {
1131 return Ok(());
1132 }
1133 if !input.peek(Token![,]) {
1134 let path = input.call(syn::Path::parse_mod_style)?;
1135 if path != ptree.path {
1136 return Err([
1137 (path.span(), "found"),
1138 (ptree.path.span(), "expected"),
1139 ].error(
1140 "mismatch (desynchronised) incorporating previous expansions' used metas"
1141 ));
1142 }
1143 let used = if input.peek(Token![=]) {
1144 let _: Token![=] = input.parse()?;
1145 Some(Usage::VALUE)
1146 } else if input.peek(Token![?]) {
1147 let _: Token![?] = input.parse()?;
1148 Some(Usage::BOOL_ONLY)
1149 } else if input.peek(Token![+]) {
1150 let _: Token![+] = input.parse()?;
1151 Some(Usage::VALUE_ONLY)
1152 } else {
1153 None
1154 };
1155 if let Some(used) = used {
1156 ptree.update_used(used);
1157 }
1158 if input.peek(token::Paren) {
1159 let inner;
1160 let paren = parenthesized!(inner in input);
1161 let sub_list = match &ptree.value {
1162 PV::Unit | PV::Value { .. } => return Err([
1163 (paren.span.open(), "found"),
1164 (ptree.path.span(), "defined"),
1165 ].error(
1166 "mismatch (tree vs terminal) incorporating previous expansions' used metas"
1167 )),
1168 PV::List(l) => l,
1169 };
1170 sub_list.decode_update_used(&inner)?;
1171 }
1172 }
1173 if input.is_empty() {
1174 return Ok(());
1175 }
1176 let _: Token![,] = input.parse()?;
1177 }
1178 Ok(())
1179 }
1180}
1181
1182impl<'c> Context<'c> {
1183 pub fn decode_update_metas_used(
1184 &self,
1185 input: ParseStream,
1186 ) -> syn::Result<()> {
1187 #[derive(Default)]
1188 struct Intended {
1189 variant: Option<syn::Ident>,
1190 field: Option<Either<syn::Ident, u32>>,
1191 attr_i: usize,
1192 }
1193 let mut intended = Intended::default();
1194
1195 let mut visit =
1196 |pmetas: &PreprocessedMetas,
1197 current_variant: Option<&syn::Ident>,
1198 current_field: Option<Either<&syn::Ident, &u32>>| {
1199 loop {
1200 let la = input.lookahead1();
1201 if input.is_empty() {
1202 return Ok(());
1204 } else if la.peek(Token![::]) {
1205 let _: Token![::] = input.parse()?;
1206 intended = Intended {
1207 variant: Some(input.parse()?),
1208 field: None,
1209 attr_i: 0,
1210 };
1211 } else if la.peek(Token![.]) {
1212 let _: Token![.] = input.parse()?;
1213 intended.field = Some(match input.parse()? {
1214 syn::Member::Named(n) => Either::Left(n),
1215 syn::Member::Unnamed(i) => Either::Right(i.index),
1216 });
1217 intended.attr_i = 0;
1218 } else if {
1219 let intended_field_refish = intended
1220 .field
1221 .as_ref()
1222 .map(|some: &Either<_, _>| some.as_ref());
1223
1224 !(current_variant == intended.variant.as_ref()
1225 && current_field == intended_field_refish)
1226 } {
1227 return Ok(());
1229 } else if la.peek(token::Paren) {
1230 let i = intended.attr_i;
1232 intended.attr_i += 1;
1233 let m = pmetas.get(i).ok_or_else(|| {
1234 input.error("more used metas, out of range!")
1235 })?;
1236 let r;
1237 let _ = parenthesized!(r in input);
1238 m.decode_update_used(&r)?;
1239 } else {
1240 return Err(la.error());
1241 }
1242 }
1243 };
1244
1245 visit(&self.pmetas, None, None)?;
1246
1247 WithinVariant::for_each(self, |ctx, wv| {
1248 let current_variant = wv.variant.map(|wv| &wv.ident);
1249
1250 if !wv.is_struct_toplevel_as_variant() {
1251 visit(&wv.pmetas, current_variant, None)?;
1252 }
1253
1254 WithinField::for_each(ctx, |_ctx, wf| {
1255 let current_field = if let Some(ref ident) = wf.field.ident {
1256 Either::Left(ident)
1257 } else {
1258 Either::Right(&wf.index)
1259 };
1260
1261 visit(&wf.pfield.pmetas, current_variant, Some(current_field))
1262 })
1263 })
1264
1265 }
1268}
1269
1270impl PreprocessedTree {
1273 fn encode_useds(
1275 list: &PreprocessedValueList,
1276 ) -> Option<proc_macro2::Group> {
1277 let preamble = syn::parse::Nothing;
1278 let sep = Token);
1279 let mut ts = TokenStream::new();
1280 let mut ot = TokenOutputTrimmer::new(&mut ts, &preamble, &sep);
1281 for t in &list.content {
1282 t.encode_used(&mut ot);
1283 ot.push_sep();
1284 }
1285 if ts.is_empty() {
1286 None
1287 } else {
1288 Some(proc_macro2::Group::new(Delimiter::Parenthesis, ts))
1289 }
1290 }
1291
1292 fn encode_used(&self, out: &mut TokenOutputTrimmer) {
1294 use PreprocessedValue as PV;
1295
1296 struct OutputTrimmerWrapper<'or, 'o, 't, 'p> {
1297 path: Option<&'p syn::Path>,
1299 out: &'or mut TokenOutputTrimmer<'t, 'o>,
1300 }
1301
1302 let mut out = OutputTrimmerWrapper {
1303 path: Some(&self.path),
1304 out,
1305 };
1306
1307 impl OutputTrimmerWrapper<'_, '_, '_, '_> {
1308 fn push_reified(&mut self, t: &dyn ToTokens) {
1309 if let Some(path) = self.path.take() {
1310 self.out.push_reified(path);
1311 }
1312 self.out.push_reified(t);
1313 }
1314 }
1315
1316 let tspan = Span::call_site();
1317
1318 match self.used.get() {
1319 Usage::BOOL_ONLY => out.push_reified(&Token),
1320 Usage::VALUE => out.push_reified(&Token),
1321 Usage::VALUE_ONLY => out.push_reified(&Token),
1322 Usage::NONE => {}
1323 }
1324
1325 match &self.value {
1326 PV::Unit | PV::Value { .. } => {}
1327 PV::List(l) => {
1328 if let Some(group) = PreprocessedTree::encode_useds(l) {
1329 out.push_reified(&group);
1330 }
1331 }
1332 }
1333 }
1334}
1335
1336impl<'c> Context<'c> {
1337 pub fn encode_metas_used(&self) -> proc_macro2::Group {
1339 let parenthesize =
1340 |ts| proc_macro2::Group::new(Delimiter::Parenthesis, ts);
1341 let an_empty = parenthesize(TokenStream::new());
1342
1343 let mut ts = TokenStream::new();
1344
1345 struct Preamble<'p> {
1346 variant: Option<&'p syn::Variant>,
1347 field: Option<&'p WithinField<'p>>,
1348 }
1349 impl ToTokens for Preamble<'_> {
1350 fn to_tokens(&self, out: &mut TokenStream) {
1351 let span = Span::call_site();
1352 if let Some(v) = self.variant {
1353 Token.to_tokens(out);
1354 v.ident.to_tokens(out);
1355 }
1356 if let Some(f) = self.field {
1357 Token.to_tokens(out);
1358 f.fname(span).to_tokens(out);
1359 }
1360 }
1361 }
1362
1363 let mut last_variant: *const syn::Variant = ptr::null();
1364 let mut last_field: *const syn::Field = ptr::null();
1365
1366 fn ptr_of_ref<'i, InDi>(r: Option<&'i InDi>) -> *const InDi {
1367 r.map(|r| r as _).unwrap_or_else(ptr::null)
1368 }
1369
1370 let mut encode = |pmetas: &PreprocessedMetas,
1371 wv: Option<&WithinVariant>,
1372 wf: Option<&WithinField>| {
1373 let now_variant: *const syn::Variant =
1374 ptr_of_ref(wv.map(|wv| wv.variant).flatten());
1375 let now_field: *const syn::Field =
1376 ptr_of_ref(wf.map(|wf| wf.field));
1377
1378 let preamble = Preamble {
1379 variant: (!ptr::eq(last_variant, now_variant)).then(|| {
1380 last_field = ptr::null();
1381 let v = wv.expect("had WithinVariant, now not");
1382 v.variant.expect("variant was syn::Variant, now not")
1383 }),
1384 field: (!ptr::eq(last_field, now_field)).then(|| {
1385 wf.expect("had WithinField (Field), now not") }),
1387 };
1388 let mut ot =
1389 TokenOutputTrimmer::new(&mut ts, &preamble, &an_empty);
1390 for m in pmetas {
1391 if let Some(group) = PreprocessedTree::encode_useds(m) {
1392 ot.push_reified(group);
1393 } else {
1394 ot.push_sep();
1395 }
1396 }
1397 if ot.did_preamble().is_some() {
1398 last_variant = now_variant;
1399 last_field = now_field;
1400 }
1401
1402 Ok::<_, Void>(())
1403 };
1404
1405 encode(&self.pmetas, None, None).void_unwrap();
1406 WithinVariant::for_each(self, |ctx, wv| {
1407 if !wv.is_struct_toplevel_as_variant() {
1408 encode(&wv.pmetas, Some(wv), None)?;
1409 }
1410 WithinField::for_each(ctx, |_ctx, wf| {
1411 encode(&wf.pfield.pmetas, Some(wv), Some(wf))
1412 })
1413 })
1414 .void_unwrap();
1415
1416 proc_macro2::Group::new(Delimiter::Bracket, ts)
1417 }
1418}
1419
1420struct UsedChecker<'c, 'e> {
1423 current: Vec<&'c syn::Path>,
1424 reported: &'e mut HashSet<Label>,
1425 recog: &'c Recognised,
1426 supplied_scope: SuppliedScope,
1427 errors: &'e mut ErrorAccumulator,
1428}
1429
1430impl PreprocessedTree {
1431 fn check_used<'c>(&'c self, checker: &mut UsedChecker<'c, '_>) {
1432 checker.current.push(&self.path);
1433
1434 let mut err = |err| {
1435 let lpaths = checker.current.iter().copied().cloned().collect();
1436 if checker.reported.insert(Label { lpaths }) {
1437 checker.errors.push(err);
1438 }
1439 };
1440
1441 let mut need = |supplied_mode| {
1442 let used = self.used.get();
1443 match used.get(supplied_mode) {
1444 Some(IsUsed) => {}
1445 None => err(unrecognised_error(
1446 checker.recog,
1447 checker.supplied_scope,
1448 supplied_mode,
1449 self.path.span(),
1450 used,
1451 &checker.current,
1452 )
1453 .void_unwrap_err()),
1454 }
1455 };
1456
1457 match &self.value {
1458 PreprocessedValue::Unit => need(UsageMode::Unit),
1459 PreprocessedValue::Value { .. } => need(UsageMode::Value),
1460 PreprocessedValue::List(l) => {
1461 if l.content.is_empty() {
1462 err(self.path.error(
1463 "empty nested list in #[deftly], is not useable by any template"
1464 ));
1465 }
1466 for subtree in &l.content {
1467 subtree.check_used(checker);
1468 }
1469 }
1470 }
1471
1472 checker
1473 .current
1474 .pop()
1475 .expect("pushed earlier, but can't pop?");
1476 }
1477}
1478
1479impl<'c> Context<'c> {
1480 pub(crate) fn check_metas_used(
1481 &self,
1482 errors: &mut ErrorAccumulator,
1483 recog: &Recognised,
1484 ) {
1485 use SuppliedScope as SS;
1486
1487 let mut reported = HashSet::new();
1488
1489 let mut chk_pmetas = |supplied_scope, pmetas: &PreprocessedMetas| {
1490 let mut checker = UsedChecker {
1491 reported: &mut reported,
1492 current: vec![],
1493 recog,
1494 errors,
1495 supplied_scope,
1496 };
1497
1498 for a in pmetas {
1499 for l in &a.content {
1500 l.check_used(&mut checker);
1501 }
1502 }
1503
1504 Ok::<_, Void>(())
1505 };
1506
1507 chk_pmetas(
1508 match &self.top.data {
1509 syn::Data::Struct(_) | syn::Data::Union(_) => SS::Struct,
1510 syn::Data::Enum(_) => SS::Enum,
1511 },
1512 &self.pmetas,
1513 )
1514 .void_unwrap();
1515
1516 WithinVariant::for_each(self, |ctx, wv| {
1517 if !wv.is_struct_toplevel_as_variant() {
1521 chk_pmetas(SS::Variant, &wv.pmetas)?;
1522 }
1523 WithinField::for_each(ctx, |_ctx, wf| {
1524 chk_pmetas(SS::Field, &wf.pfield.pmetas)
1525 })
1526 })
1527 .void_unwrap();
1528 }
1529}
1530
1531fn unrecognised_error(
1532 recog: &Recognised,
1533 supplied_scope: SuppliedScope,
1534 supplied_mode: UsageMode,
1535 supplied_span: Span,
1536 used: Usage,
1537 lpaths: &[&syn::Path],
1538) -> Result<Void, syn::Error> {
1539 let try_case = |e: Option<_>| e.map(Err).unwrap_or(Ok(()));
1543 let some_err = |m: &dyn Display| Some(supplied_span.error(m));
1544
1545 try_case((|| {
1548 let recog_allow = supplied_scope
1549 .recog_search()
1550 .map(|scope| {
1551 recog
1552 .map
1553 .get(&BorrowedDesig { scope, lpaths })
1554 .copied()
1555 .unwrap_or_default()
1556 })
1557 .reduce(std::ops::BitOr::bitor)
1558 .unwrap_or_default();
1559
1560 let _: &IsUsed = recog_allow.get(supplied_mode)?;
1562
1563 match used {
1564 U::NONE => some_err(
1565 &"meta attribute provided, and (conditionally) recognised; but not used in these particular circumstances"
1566 ),
1567 U::BOOL_ONLY => some_err(
1568 &"meta attribute provided with value, and (conditionally) recognised with value; but in these particular circumstances only used as a boolean"
1569 ),
1570 U::VALUE_ONLY => some_err(
1571 &"meta attribute provided as a unit, and (conditionally) recognised as such; but in these particular circumstances only used in contexts with a default value, so the unit is ignored"
1572 ),
1573 U::VALUE => unreachable!(),
1574 }
1575 })())?;
1576
1577 try_case((|| {
1582 (supplied_mode == UsageMode::Value).then(|| ())?;
1583 let _: IsUsed = used.unit?;
1584 some_err(
1585 &"meta attribute value provided, but is used only as a boolean",
1586 )
1587 })())?;
1588
1589 try_case((|| {
1591 (supplied_mode == UsageMode::Unit).then(|| ())?;
1592 let _: IsUsed = used.value?;
1593 some_err(
1594 &"meta attribute provided as unit (flag), but is used only with default values, so the unit is ignored"
1595 )
1596 })())?;
1597
1598 try_case((|| {
1602 let y_scopes = Scope::iter()
1603 .filter(|&scope| {
1604 recog.map.contains_key(&BorrowedDesig { scope, lpaths })
1605 })
1606 .collect_vec();
1607
1608 if y_scopes.is_empty() {
1609 return None;
1610 }
1611 let y_ss = SuppliedScope::iter()
1612 .filter(|ss| ss.recog_search().any(|s| y_scopes.contains(&s)))
1613 .map(|ss| ss.to_string())
1614 .join("/");
1615 let y_scopes = y_scopes.iter().map(|s| s.as_ref()).join("/");
1616 some_err(&format_args!(
1617 "meta attribute provided for {}, but recognised by template only for {} ({})",
1618 supplied_scope,
1619 y_ss,
1620 y_scopes,
1621 ))
1622 })())?;
1623
1624 try_case((|| {
1627 let (upper, recog) =
1628 supplied_scope.recog_search().find_map(|scope| {
1629 let upper = BorrowedDesig {
1630 scope,
1631 lpaths: lpaths.split_last()?.1,
1632 };
1633 let recog = recog.map.get(&upper)?;
1634 Some((upper, recog))
1635 })?;
1636 let _: IsUsed = recog.value?;
1637 some_err(&format_args!(
1638 "nested meta provided and not recognised; but, template would recognise {}",
1639 DisplayAsIfSpecified {
1640 lpaths: upper.lpaths,
1641 inside_after: " = ..",
1642 },
1643 ))
1644 })())?;
1645
1646 try_case((|| {
1649 recog.map.keys().find_map(|desig| {
1650 if !itertools::equal(
1652 lpaths.iter().copied(),
1653 desig.label.lpaths.iter().take(lpaths.len()),
1654 ) {
1655 return None;
1656 }
1657 Some(())
1658 })?;
1659 some_err(&format_args!(
1660 "meta attribute provided, but not recognised; template only uses it as a container"
1661 ))
1662 })())?;
1663
1664 Err(supplied_span
1665 .error("meta attribute provided, but not recognised by template"))
1666}
1667
1668impl<O: SubstParseContext> FindRecogMetas for Template<O> {
1671 fn find_recog_metas(&self, acc: &mut Recognised) {
1672 for e in &self.elements {
1673 e.find_recog_metas(acc)
1674 }
1675 }
1676}
1677
1678impl<O: SubstParseContext> FindRecogMetas for TemplateElement<O> {
1679 fn find_recog_metas(&self, acc: &mut Recognised) {
1680 match self {
1681 TE::Ident(..)
1682 | TE::LitStr(_)
1683 | TE::Literal(..)
1684 | TE::Punct(..) => {}
1685 TE::Group { template, .. } => template.find_recog_metas(acc),
1686 TE::Subst(n) => n.find_recog_metas(acc),
1687 TE::Repeat(n) => n.find_recog_metas(acc),
1688 }
1689 }
1690}
1691
1692impl<O: SubstParseContext> FindRecogMetas for RepeatedTemplate<O> {
1693 fn find_recog_metas(&self, acc: &mut Recognised) {
1694 self.template.find_recog_metas(acc);
1695 self.whens.find_recog_metas(acc);
1696 }
1697}
1698
1699impl<O: SubstParseContext> FindRecogMetas for Subst<O> {
1700 fn find_recog_metas(&self, acc: &mut Recognised) {
1701 self.sd.find_recog_metas(acc);
1702 }
1703}
1704
1705macro_rules! impL_find_recog_metas_via_iter { {
1706 ( $($gens:tt)* ), $i:ty
1707} => {
1708 impl<T: FindRecogMetas, $($gens)*> FindRecogMetas for $i {
1709 fn find_recog_metas(&self, acc: &mut Recognised) {
1710 #[allow(for_loops_over_fallibles)]
1711 for item in self {
1712 item.find_recog_metas(acc)
1713 }
1714 }
1715 }
1716} }
1717impL_find_recog_metas_via_iter!((), [T]);
1718impL_find_recog_metas_via_iter!((), Option<T>);
1719impL_find_recog_metas_via_iter!((U), Punctuated<T, U>);
1720
1721macro_rules! impL_find_recog_metas_via_deref { {
1722 ( $($gens:tt)* ), $i:ty
1723} => {
1724 impl<$($gens)*> FindRecogMetas for $i {
1725 fn find_recog_metas(&self, acc: &mut Recognised) {
1726 (**self).find_recog_metas(acc)
1727 }
1728 }
1729} }
1730impL_find_recog_metas_via_deref!((O: SubstParseContext), Argument<O>);
1731impL_find_recog_metas_via_deref!((T: FindRecogMetas), Box<T>);
1732
1733impl<O: SubstParseContext> FindRecogMetas for SubstDetails<O> {
1734 fn find_recog_metas(&self, acc: &mut Recognised) {
1735 use SD::*;
1736
1737 match self {
1738 Xmeta(v) => v.find_recog_metas(acc),
1739 vpat(v, _, _) => v.find_recog_metas(acc),
1740 vtype(v, _, _) => v.find_recog_metas(acc),
1741 tdefvariants(v, _, _) => v.find_recog_metas(acc),
1742 fdefine(v, _, _) => v.find_recog_metas(acc),
1743 vdefbody(a, b, _, _) => {
1744 a.find_recog_metas(acc);
1745 b.find_recog_metas(acc);
1746 }
1747 paste(v, _) => v.find_recog_metas(acc),
1748 paste_spanned(_span, content, ..) => {
1749 content.find_recog_metas(acc);
1750 }
1751 ChangeCase(v, _, _) => v.find_recog_metas(acc),
1752 concat(v, ..) => v.find_recog_metas(acc),
1753
1754 when(v, _) => v.find_recog_metas(acc),
1755 define(v, _) => v.find_recog_metas(acc),
1756 defcond(v, _) => v.find_recog_metas(acc),
1757
1758 not(v, _) => v.find_recog_metas(acc),
1759 any(v, _) | all(v, _) => v.find_recog_metas(acc),
1760 is_empty(_, v) => v.find_recog_metas(acc),
1761 approx_equal(_, v) => v.find_recog_metas(acc),
1762
1763 For(v, _) => v.find_recog_metas(acc),
1764 If(v, _) | select1(v, _) => v.find_recog_metas(acc),
1765 ignore(v, _) => v.find_recog_metas(acc),
1766 dbg(v) => v.content_parsed.find_recog_metas(acc),
1767
1768 tname(_)
1769 | ttype(_)
1770 | tdeftype(_)
1771 | vname(_)
1772 | fname(_)
1773 | ftype(_)
1774 | fpatname(_)
1775 | vindex(..)
1776 | findex(..)
1777 | tdefkwd(_)
1778 | Vis(_, _)
1779 | tattrs(_, _, _)
1780 | vattrs(_, _, _)
1781 | fattrs(_, _, _)
1782 | tgens(_)
1783 | tdefgens(_, _)
1784 | tgnames(_, _)
1785 | twheres(_, _)
1786 | UserDefined(_)
1787 | False(_)
1788 | True(_)
1789 | is_struct(_)
1790 | is_enum(_)
1791 | is_union(_)
1792 | v_is_unit(_)
1793 | v_is_tuple(_)
1794 | v_is_named(_)
1795 | error(..)
1796 | require_beta(..)
1797 | dbg_all_keywords(_)
1798 | Crate(_, _) => {}
1799 }
1800 }
1801}
1802
1803impl<O: SubstParseContext> FindRecogMetas for SubstMeta<O> {
1804 fn find_recog_metas(&self, acc: &mut Recognised) {
1805 let recog = O::meta_recog_usage(self);
1806 acc.update(self.desig.clone(), recog);
1807 }
1808}
1809
1810impl FindRecogMetas for SubstVType {
1811 fn find_recog_metas(&self, acc: &mut Recognised) {
1812 let Self { self_, vname } = self;
1813 self_.find_recog_metas(acc);
1814 vname.find_recog_metas(acc);
1815 }
1816}
1817
1818impl FindRecogMetas for SubstVPat {
1819 fn find_recog_metas(&self, acc: &mut Recognised) {
1820 let Self { vtype, fprefix } = self;
1821 vtype.find_recog_metas(acc);
1822 fprefix.find_recog_metas(acc);
1823 }
1824}
1825
1826impl<B: FindRecogMetas> FindRecogMetas for Definition<B> {
1827 fn find_recog_metas(&self, acc: &mut Recognised) {
1828 let Self {
1829 name: _,
1830 body_span: _,
1831 body,
1832 } = self;
1833 body.find_recog_metas(acc);
1834 }
1835}
1836
1837impl FindRecogMetas for DefinitionBody {
1838 fn find_recog_metas(&self, acc: &mut Recognised) {
1839 match self {
1840 DefinitionBody::Normal(v) => v.find_recog_metas(acc),
1841 DefinitionBody::Paste(v) => v.find_recog_metas(acc),
1842 DefinitionBody::Concat(v) => v.find_recog_metas(acc),
1843 }
1844 }
1845}
1846
1847impl<O: SubstParseContext> FindRecogMetas for SubstIf<O> {
1848 fn find_recog_metas(&self, acc: &mut Recognised) {
1849 let Self {
1850 tests,
1851 otherwise,
1852 kw_span: _,
1853 } = self;
1854 for (if_, then) in tests {
1855 if_.find_recog_metas(acc);
1856 then.find_recog_metas(acc);
1857 }
1858 otherwise.find_recog_metas(acc);
1859 }
1860}