1#![cfg_attr(nightly, feature(doc_cfg))]
2
3use std::borrow::Cow;
6use std::collections::HashMap;
7
8pub use unsynn;
9use unsynn::*;
10
11mod functions;
12#[cfg(test)]
13mod tests;
14mod vis;
15
16pub use self::functions::{Function, NativeFun};
17pub use self::vis::Visibility;
18
19pub fn sanitize_for_tokenizer(content: &str) -> String {
28 let regex = raw_ident_regex();
29 let mut lines = content.lines().map(|line| {
30 if !line.trim_start().starts_with("//") {
32 regex.replace(line, "$1")
33 } else {
34 Cow::Borrowed(line)
35 }
36 });
37 lines.next().map_or_else(String::new, |line| {
38 let mut sanitized = String::with_capacity(content.len());
39 sanitized.push_str(&line);
40 for line in lines {
41 sanitized.push('\n');
42 sanitized.push_str(&line);
43 }
44 sanitized
45 })
46}
47
48fn raw_ident_regex() -> regex::Regex {
49 regex::Regex::new("`([[:alnum:]_]+)`").expect("Valid regex")
50}
51
52pub mod kw {
53 use unsynn::*;
55
56 unsynn! {
57 pub keyword Struct = "struct";
58 pub keyword Phantom = "phantom";
59 pub keyword Public = "public";
60 pub keyword Has = "has";
61 pub keyword Copy = "copy";
62 pub keyword Drop = "drop";
63 pub keyword Key = "key";
64 pub keyword Store = "store";
65 pub keyword Module = "module";
66 pub keyword Package = "package";
67 pub keyword Friend = "friend";
68 pub keyword Use = "use";
69 pub keyword Fun = "fun";
70 pub keyword As = "as";
71 pub keyword Const = "const";
72 pub keyword Mut = "mut";
73 pub keyword Entry = "entry";
74 pub keyword Native = "native";
75 pub keyword Macro = "macro";
76 pub keyword Vector = "vector";
77 pub keyword Enum = "enum";
78 }
79}
80
81unsynn! {
82 pub enum File {
83 ModuleLabel(LabeledModule),
85 Legacy(Vec<Module>),
87 }
88
89 pub struct LabeledModule {
93 attrs: Vec<Attribute>,
94 keyword: kw::Module,
95 named_address: Ident,
96 path_sep: PathSep,
97 ident: Ident,
98 semicolon: Semicolon,
99 contents: Vec<Item>,
100 }
101
102 pub struct Module {
104 pub attrs: Vec<Attribute>,
105 keyword: kw::Module,
106 pub named_address: Ident,
107 path_sep: PathSep,
108 pub ident: Ident,
109 contents: BraceGroupContaining<Vec<Item>>,
110 }
111
112 pub struct Item {
114 pub attrs: Vec<Attribute>,
115 vis: Option<Vis>,
116 pub kind: ItemKind,
117 }
118
119 #[derive(Clone)]
123 pub struct Attribute {
124 pound: Pound,
125 contents: BracketGroupContaining<DelimitedVec<Meta, Comma, TrailingDelimiter::Optional>>,
126 }
127
128 #[derive(Clone)]
137 enum Meta {
138 Doc(Cons<DocKw, Assign, LiteralString>),
140 For(ForKw),
141 Other {
142 ident: Ident,
143 sub: Option<SubMeta>,
144 }
145 }
146
147 keyword DocKw = "doc";
148 keyword ForKw = "for";
149
150 #[derive(Clone)]
151 enum SubMeta {
152 Eq(Cons<Assign, AttributeValue>),
153 List(ParenthesisGroupContaining<DelimitedVec<Box<Meta>, Comma, TrailingDelimiter::Optional>>),
154 }
155
156 #[derive(Clone)]
163 enum AttributeValue {
164 Lit(Literal),
165 NameAccessChain {
169 leading_name_access: Either<SyntaxIdent, Ident>,
172 path: DelimitedVec<PathSep, Ident, TrailingDelimiter::Forbidden>,
175 },
176 }
177
178 #[derive(Clone)]
184 struct Vis {
185 public: kw::Public,
186 modifier: Option<ParenthesisGroupContaining<VisibilityModifier>>,
187 }
188
189 #[derive(Clone)]
195 enum VisibilityModifier {
196 Package(kw::Package),
197 Friend(kw::Friend)
198 }
199
200 #[non_exhaustive]
204 pub enum ItemKind {
205 Struct(Struct),
206 Enum(Enum),
207 Import(Import),
208 UseFun(UseFun),
209 Const(Const),
210 Function(Function),
211 MacroFun(MacroFun),
212 NativeFun(NativeFun)
213 }
214
215 pub struct UseFun {
217 keyword: kw::Use,
218 fun_kw: kw::Fun,
219 fun_path: ItemPath,
221 as_kw: kw::As,
222 ty: Ident,
223 dot: Dot,
224 method: Ident,
225 semicolon: Semicolon,
226 }
227
228 pub struct Const {
231 const_kw: kw::Const,
233 ident: Ident,
235 colon: Colon,
237 ty: Type,
239 assign: Assign,
241 expr: Vec<Cons<Except<Semicolon>, TokenTree>>,
243 semicolon: Semicolon,
245 }
246
247 pub struct Import {
250 keyword: kw::Use,
251 named_address: Ident,
252 path_sep: PathSep,
253 module: ImportModule,
254 semicolon: Semicolon,
255 }
256
257 enum ImportModule {
259 One(ModuleOrItems),
260 Many(BraceGroupContaining<CommaDelimitedVec<ModuleOrItems>>),
261 }
262
263 #[derive(Clone)]
264 struct ModuleOrItems {
265 ident: Ident,
266 next: Option<AliasOrItems>,
267 }
268
269 #[derive(Clone)]
270 enum AliasOrItems {
271 Alias {
272 as_kw: kw::As,
273 alias: Ident,
274 },
275 Items {
276 sep: PathSep,
277 item: ImportItem,
278 }
279 }
280
281 #[derive(Clone)]
282 enum ImportItem {
283 One(MaybeAliased),
284 Many(BraceGroupContaining<CommaDelimitedVec<MaybeAliased>>)
285 }
286
287 #[derive(Clone)]
288 struct MaybeAliased {
289 ident: Ident,
290 alias: Option<Cons<kw::As, Ident>>,
291 }
292
293 #[derive(Clone)]
297 pub struct Struct {
298 keyword: kw::Struct,
299 pub ident: Ident,
300 pub generics: Option<Generics>,
301 pub kind: StructKind,
302 }
303
304 #[derive(Clone)]
306 pub enum StructKind {
307 Braced(BracedStruct),
308 Tuple(TupleStruct),
309 }
310
311 #[derive(Clone)]
313 pub struct BracedStruct {
314 abilities: Option<Abilities>,
315 pub fields: NamedFields,
316 }
317
318 #[derive(Clone)]
321 pub struct TupleStruct {
322 pub fields: PositionalFields,
323 abilities: Option<Cons<Abilities, Semicolon>>
324 }
325
326 #[derive(Clone)]
329 pub struct Enum {
330 keyword: kw::Enum,
331 pub ident: Ident,
332 pub generics: Option<Generics>,
333 abilities: Option<Abilities>,
334 content: BraceGroupContaining<CommaDelimitedVec<EnumVariant>>,
335 }
336
337 #[derive(Clone)]
338 pub struct EnumVariant {
339 pub attrs: Vec<Attribute>,
340 pub ident: Ident,
341 pub fields: Option<FieldsKind>
343 }
344
345 #[derive(Clone)]
347 pub enum FieldsKind {
348 Positional(PositionalFields),
349 Named(NamedFields),
350 }
351
352 #[derive(Clone)]
356 pub struct PositionalFields(ParenthesisGroupContaining<DelimitedVec<UnnamedField, Comma>>);
357
358 #[derive(Clone)]
360 pub struct NamedFields(BraceGroupContaining<DelimitedVec<NamedField, Comma>>);
361
362 #[derive(Clone)]
364 pub struct NamedField {
365 pub attrs: Vec<Attribute>,
366 pub ident: Ident,
367 colon: Colon,
368 pub ty: Type,
369 }
370
371 #[derive(Clone)]
373 pub struct UnnamedField {
374 pub attrs: Vec<Attribute>,
375 pub ty: Type,
376 }
377
378 #[derive(Clone)]
385 pub struct Generics {
386 lt_token: Lt,
387 type_args: DelimitedVec<Generic, Comma>,
388 gt_token: Gt,
389 }
390
391 #[derive(Clone)]
399 pub struct Generic {
400 pub phantom: Option<kw::Phantom>,
401 pub ident: Ident,
402 bounds: Option<GenericBounds>
403 }
404
405 #[derive(Clone)]
409 struct GenericBounds {
410 colon: Colon,
411 abilities: Many<Ability, Plus, TrailingDelimiter::Forbidden>,
412 }
413
414 #[derive(Clone)]
420 struct Abilities {
421 has: kw::Has,
422 keywords: Many<Ability, Comma, TrailingDelimiter::Forbidden>,
423 }
424
425 #[derive(Clone)]
427 pub enum Ability {
428 Copy(kw::Copy),
429 Drop(kw::Drop),
430 Key(kw::Key),
431 Store(kw::Store),
432 }
433
434 pub struct MacroFun {
437 macro_kw: kw::Macro,
438 fun_kw: kw::Fun,
439 ident: Ident,
440 generics: Option<MacroGenerics>,
441 args: ParenthesisGroup,
442 ret: Option<Cons<Colon, Either<MacroReturn, ParenthesisGroup>>>,
443 body: BraceGroup,
444 }
445
446 struct MacroGenerics {
447 lt_token: Lt,
448 type_args: DelimitedVec<MacroTypeArg, Comma>,
449 gt_token: Gt,
450 }
451
452 struct MacroTypeArg{
454 name: SyntaxIdent,
455 bounds: Option<GenericBounds>,
456 }
457
458 enum MacroReturn {
460 Underscore(Underscore),
461 Concrete(Cons<Option<Ref>, MacroReturnType>),
462 }
463
464 enum MacroReturnType {
471 MacroTypeName(SyntaxIdent),
472 Hybrid(HybridMacroType)
473 }
474
475 struct HybridMacroType {
476 ident: Ident,
477 type_args: Option<Cons<Lt, Many<Either<Type, SyntaxIdent, Box<HybridMacroType>>, Comma>, Gt>>
478 }
479
480 #[derive(Clone)]
485 struct SyntaxIdent {
486 dollar: Dollar,
487 ident: Ident,
488 }
489
490 pub struct MaybeRefType {
494 r#ref: Option<Ref>,
495 r#type: Type,
496 }
497
498 struct Ref {
500 and: And,
501 r#mut: Option<kw::Mut>,
502 }
503
504 #[derive(Clone)]
506 pub struct Type {
507 pub path: ItemPath,
508 pub type_args: Option<TypeArgs>
509 }
510
511 #[derive(Clone)]
513 pub enum ItemPath {
514 Full {
516 named_address: Ident,
517 sep0: PathSep,
518 module: Ident,
519 sep1: PathSep,
520 item: Ident,
521 },
522 Module {
524 module: Ident,
525 sep: PathSep,
526 item: Ident,
527 },
528 Ident(Ident),
530 }
531
532 #[derive(Clone)]
534 pub struct TypeArgs {
535 lt: Lt,
536 args: Many<Box<Type>, Comma>,
537 gt: Gt,
538 }
539}
540
541impl File {
542 pub fn into_modules(self) -> impl Iterator<Item = Module> {
543 match self {
544 Self::ModuleLabel(labeled) => std::iter::once(labeled.into_module()).boxed(),
545 Self::Legacy(modules) => modules.into_iter().boxed(),
546 }
547 }
548}
549
550impl LabeledModule {
551 pub fn into_module(self) -> Module {
552 Module {
553 attrs: self.attrs,
554 keyword: self.keyword,
555 named_address: self.named_address,
556 path_sep: self.path_sep,
557 ident: self.ident,
558 contents: BraceGroupContaining {
559 content: self.contents,
560 },
561 }
562 }
563}
564
565impl Module {
566 pub fn with_implicit_sui_imports(&mut self) -> &mut Self {
570 let implicit_imports: HashMap<_, _> = [
572 "use sui::object;",
573 "use sui::object::ID;",
574 "use sui::object::UID;",
575 "use sui::tx_context;",
576 "use sui::tx_context::TxContext;",
577 "use sui::transfer;",
578 ]
579 .into_iter()
580 .map(|text| {
581 text.to_token_iter()
582 .parse_all::<Import>()
583 .expect("Valid imports")
584 })
585 .map(|import| {
586 let ident = import
587 .imported_idents()
588 .next()
589 .expect("Each import exposes exactly one ident");
590 (ident.clone(), import)
591 })
592 .collect();
593
594 self.add_implicit_imports(implicit_imports)
595 }
596
597 pub fn with_implicit_iota_imports(&mut self) -> &mut Self {
601 let implicit_imports: HashMap<_, _> = [
603 "use iota::object;",
604 "use iota::object::ID;",
605 "use iota::object::UID;",
606 "use iota::tx_context;",
607 "use iota::tx_context::TxContext;",
608 "use iota::transfer;",
609 ]
610 .into_iter()
611 .map(|text| {
612 text.to_token_iter()
613 .parse_all::<Import>()
614 .expect("Valid imports")
615 })
616 .map(|import| {
617 let ident = import
618 .imported_idents()
619 .next()
620 .expect("Each import exposes exactly one ident");
621 (ident.clone(), import)
622 })
623 .collect();
624
625 self.add_implicit_imports(implicit_imports)
626 }
627
628 pub fn fully_qualify_datatype_field_types(&mut self) -> &mut Self {
630 let imports: HashMap<_, _> = self
632 .items()
633 .filter_map(|item| match &item.kind {
634 ItemKind::Import(import) => Some(import),
635 _ => None,
636 })
637 .flat_map(|import| import.flatten())
638 .collect();
639
640 for item in &mut self.contents.content {
642 match &mut item.kind {
643 ItemKind::Enum(e) => {
644 let generics = &e.type_param_idents();
645 e.map_types(|ty| ty.resolve(&imports, generics));
646 }
647 ItemKind::Struct(s) => {
648 let generics = &s.type_param_idents();
649 s.map_types(|ty| ty.resolve(&imports, generics));
650 }
651 _ => (),
652 }
653 }
654
655 self
656 }
657
658 pub fn items(&self) -> impl Iterator<Item = &Item> {
659 self.contents.content.iter()
660 }
661
662 #[cfg(test)]
663 pub fn into_items(self) -> impl Iterator<Item = Item> {
664 self.contents.content.into_iter()
665 }
666
667 fn add_implicit_imports(&mut self, mut implicit_imports: HashMap<Ident, Import>) -> &mut Self {
668 for item in self.items() {
670 let ItemKind::Import(import) = &item.kind else {
671 continue;
672 };
673 for ident in import.imported_idents() {
674 implicit_imports.remove(ident);
675 }
676 }
677
678 for (_, import) in implicit_imports {
680 self.contents.content.push(Item {
681 attrs: vec![],
682 vis: None,
683 kind: ItemKind::Import(import),
684 })
685 }
686 self
687 }
688}
689
690impl Import {
691 pub fn flatten(&self) -> impl Iterator<Item = (Ident, FlatImport)> + '_ {
694 let named_address = self.named_address.clone();
695 match &self.module {
696 ImportModule::One(module_or_items) => module_or_items.flatten(named_address),
698 ImportModule::Many(BraceGroupContaining { content: ms }) => ms
700 .iter()
701 .flat_map(move |Delimited { value, .. }| value.flatten(named_address.clone()))
702 .boxed(),
703 }
704 }
705
706 fn imported_idents(&self) -> impl Iterator<Item = &Ident> {
708 match &self.module {
709 ImportModule::One(module_or_items) => module_or_items.available_idents(),
710 ImportModule::Many(BraceGroupContaining { content: ms }) => ms
711 .iter()
712 .flat_map(|delimited| delimited.value.available_idents())
713 .boxed(),
714 }
715 }
716}
717
718impl ModuleOrItems {
719 fn flatten(&self, named_address: Ident) -> Box<dyn Iterator<Item = (Ident, FlatImport)> + '_> {
721 let module = self.ident.clone();
722
723 let Some(next) = &self.next else {
724 return std::iter::once((
726 module.clone(),
727 FlatImport::Module {
728 named_address,
729 module,
730 },
731 ))
732 .boxed();
733 };
734
735 match next {
736 AliasOrItems::Alias { alias, .. } => std::iter::once((
738 alias.clone(),
739 FlatImport::Module {
740 named_address,
741 module,
742 },
743 ))
744 .boxed(),
745
746 AliasOrItems::Items {
748 item: ImportItem::One(maybe_aliased),
749 ..
750 } => std::iter::once(maybe_aliased.flat_import(named_address, module)).boxed(),
751
752 AliasOrItems::Items {
754 item: ImportItem::Many(BraceGroupContaining { content: items }),
755 ..
756 } => items
757 .iter()
758 .map(move |Delimited { value, .. }| {
759 value.flat_import(named_address.clone(), module.clone())
760 })
761 .boxed(),
762 }
763 }
764
765 fn available_idents(&self) -> Box<dyn Iterator<Item = &Ident> + '_> {
767 let Some(next) = &self.next else {
768 return std::iter::once(&self.ident).boxed();
769 };
770
771 match next {
772 AliasOrItems::Alias { alias, .. } => std::iter::once(alias).boxed(),
773
774 AliasOrItems::Items {
775 item: ImportItem::One(item),
776 ..
777 } => std::iter::once(item.available_ident(&self.ident)).boxed(),
778
779 AliasOrItems::Items {
780 item: ImportItem::Many(BraceGroupContaining { content: items }),
781 ..
782 } => items
783 .iter()
784 .map(|delimited| delimited.value.available_ident(&self.ident))
785 .boxed(),
786 }
787 }
788}
789
790impl MaybeAliased {
791 fn flat_import(&self, named_address: Ident, module: Ident) -> (Ident, FlatImport) {
793 if self.ident == "Self" {
794 (
795 self.alias().unwrap_or(&module).clone(),
796 FlatImport::Module {
797 named_address,
798 module,
799 },
800 )
801 } else {
802 (
803 self.alias().unwrap_or(&self.ident).clone(),
804 FlatImport::Item {
805 named_address,
806 module,
807 r#type: self.ident.clone(),
808 },
809 )
810 }
811 }
812
813 fn available_ident<'a>(&'a self, module: &'a Ident) -> &'a Ident {
814 if self.ident == "Self" {
815 self.alias().unwrap_or(module)
816 } else {
817 self.alias().unwrap_or(&self.ident)
818 }
819 }
820
821 fn alias(&self) -> Option<&Ident> {
823 self.alias.as_ref().map(|cons| &cons.second)
824 }
825}
826
827impl Attribute {
828 pub fn is_doc(&self) -> bool {
830 matches!(
831 &self.contents.content[..],
832 [Delimited {
833 value: Meta::Doc(_),
834 ..
835 }]
836 )
837 }
838
839 pub const fn contents(&self) -> &impl ToTokens {
841 &self.contents.content
842 }
843
844 pub fn metas(&self) -> impl Iterator<Item = &dyn ToTokens> + '_ {
845 self.contents
846 .content
847 .iter()
848 .map(|delimited| &delimited.value as _)
849 }
850
851 pub fn external_attributes(&self) -> impl Iterator<Item = &dyn ToTokens> + '_ {
853 self.contents.content.iter().filter_map(|d| match &d.value {
854 Meta::Other {
855 ident,
856 sub: Some(SubMeta::List(inner)),
857 } if ident == "ext" => Some(&inner.content as _),
858 _ => None,
859 })
860 }
861}
862
863impl ItemKind {
864 pub const fn is_datatype(&self) -> bool {
866 matches!(self, Self::Enum(_) | Self::Struct(_))
867 }
868}
869
870impl Struct {
871 pub fn abilities(&self) -> impl Iterator<Item = &Ability> {
872 use StructKind as K;
873 match &self.kind {
874 K::Braced(braced) => braced
875 .abilities
876 .iter()
877 .flat_map(|a| a.keywords.iter())
878 .map(|d| &d.value)
879 .boxed(),
880 K::Tuple(tuple) => tuple
881 .abilities
882 .iter()
883 .flat_map(|a| a.first.keywords.iter())
884 .map(|d| &d.value)
885 .boxed(),
886 }
887 }
888}
889
890impl BracedStruct {
891 pub fn fields(&self) -> impl Iterator<Item = &NamedField> + Clone + '_ {
892 self.fields.fields()
893 }
894
895 pub fn is_empty(&self) -> bool {
897 self.fields.is_empty()
898 }
899}
900
901impl TupleStruct {
902 pub fn fields(&self) -> impl Iterator<Item = &UnnamedField> + Clone + '_ {
903 self.fields.fields()
904 }
905
906 pub fn is_empty(&self) -> bool {
908 self.fields.is_empty()
909 }
910}
911
912impl Enum {
913 pub fn abilities(&self) -> impl Iterator<Item = &Ability> {
914 self.abilities
915 .iter()
916 .flat_map(|a| a.keywords.iter())
917 .map(|d| &d.value)
918 }
919
920 pub fn variants(&self) -> impl Iterator<Item = &EnumVariant> {
921 self.content
922 .content
923 .iter()
924 .map(|Delimited { value, .. }| value)
925 }
926}
927
928impl NamedFields {
929 pub fn fields(&self) -> impl Iterator<Item = &NamedField> + Clone + '_ {
930 self.0.content.iter().map(|d| &d.value)
931 }
932
933 pub fn is_empty(&self) -> bool {
934 self.0.content.is_empty()
935 }
936}
937
938impl PositionalFields {
939 pub fn new() -> Self {
940 Self(ParenthesisGroupContaining {
941 content: std::iter::empty::<UnnamedField>()
942 .collect::<DelimitedVec<_, _, TrailingDelimiter::Mandatory>>()
943 .into(),
944 })
945 }
946
947 pub fn fields(&self) -> impl Iterator<Item = &UnnamedField> + Clone + '_ {
948 self.0.content.iter().map(|d| &d.value)
949 }
950
951 pub fn is_empty(&self) -> bool {
952 self.0.content.is_empty()
953 }
954}
955
956impl Default for PositionalFields {
957 fn default() -> Self {
958 Self::new()
959 }
960}
961
962impl Type {
963 fn resolve(&mut self, imports: &HashMap<Ident, FlatImport>, generics: &[Ident]) {
965 use ItemPath as P;
966 self.map_types(|ty| ty.resolve(imports, generics));
968
969 let resolved = match &self.path {
973 P::Module {
974 module,
975 item: r#type,
976 ..
977 } => {
978 let Some(FlatImport::Module {
979 named_address,
980 module,
981 }) = imports.get(module)
982 else {
983 return;
984 };
985 P::Full {
986 named_address: named_address.clone(),
987 sep0: PathSep::default(),
988 module: module.clone(),
989 sep1: PathSep::default(),
990 item: r#type.clone(),
991 }
992 }
993 P::Ident(ident) if !generics.contains(ident) => {
994 let Some(FlatImport::Item {
995 named_address,
996 module,
997 r#type,
998 }) = imports.get(ident)
999 else {
1000 return;
1001 };
1002 P::Full {
1003 named_address: named_address.clone(),
1004 sep0: PathSep::default(),
1005 module: module.clone(),
1006 sep1: PathSep::default(),
1007 item: r#type.clone(),
1008 }
1009 }
1010 _ => return,
1012 };
1013 self.path = resolved;
1014 }
1015}
1016
1017impl TypeArgs {
1018 pub fn types(&self) -> impl Iterator<Item = &Type> {
1020 self.args.iter().map(|args| &*args.value)
1021 }
1022}
1023
1024impl Generics {
1025 pub fn generics(&self) -> impl Iterator<Item = &Generic> + '_ {
1026 self.type_args.iter().map(|d| &d.value)
1027 }
1028}
1029
1030impl MaybeRefType {
1031 pub fn is_ref(&self) -> bool {
1033 self.r#ref.as_ref().is_some_and(|r| r.r#mut.is_none())
1034 }
1035
1036 pub const fn type_(&self) -> &Type {
1038 &self.r#type
1039 }
1040}
1041
1042#[cfg_attr(test, derive(derive_more::Display))]
1045pub enum FlatImport {
1046 #[cfg_attr(test, display("{named_address}::{module}"))]
1047 Module { named_address: Ident, module: Ident },
1048 #[cfg_attr(test, display("{named_address}::{module}::{type}"))]
1049 Item {
1050 named_address: Ident,
1051 module: Ident,
1052 r#type: Ident,
1053 },
1054}
1055
1056trait IteratorBoxed<'a>: Iterator + 'a {
1060 fn boxed(self) -> Box<dyn Iterator<Item = Self::Item> + 'a>
1061 where
1062 Self: Sized,
1063 {
1064 Box::new(self)
1065 }
1066}
1067
1068impl<'a, T> IteratorBoxed<'a> for T where T: Iterator + 'a {}
1069
1070trait HasGenerics {
1072 fn generics(&self) -> Option<&Generics>;
1073
1074 fn type_param_idents(&self) -> Vec<Ident> {
1076 self.generics()
1077 .iter()
1078 .flat_map(|generics| generics.generics())
1079 .map(|generic| generic.ident.clone())
1080 .collect()
1081 }
1082}
1083
1084impl HasGenerics for Enum {
1085 fn generics(&self) -> Option<&Generics> {
1086 self.generics.as_ref()
1087 }
1088}
1089
1090impl HasGenerics for Struct {
1091 fn generics(&self) -> Option<&Generics> {
1092 self.generics.as_ref()
1093 }
1094}
1095
1096trait Typed {
1098 fn map_types(&mut self, f: impl FnMut(&mut Type));
1100}
1101
1102impl Typed for Enum {
1103 fn map_types(&mut self, mut f: impl FnMut(&mut Type)) {
1104 mutate_delimited_vec(&mut self.content.content, |variant| {
1105 variant.map_types(&mut f)
1106 });
1107 }
1108}
1109
1110impl Typed for EnumVariant {
1111 fn map_types(&mut self, f: impl FnMut(&mut Type)) {
1112 let Some(fields) = &mut self.fields else {
1113 return;
1114 };
1115 fields.map_types(f);
1116 }
1117}
1118
1119impl Typed for Struct {
1120 fn map_types(&mut self, f: impl FnMut(&mut Type)) {
1121 match &mut self.kind {
1122 StructKind::Braced(braced_struct) => braced_struct.fields.map_types(f),
1123 StructKind::Tuple(tuple_struct) => tuple_struct.fields.map_types(f),
1124 }
1125 }
1126}
1127
1128impl Typed for FieldsKind {
1129 fn map_types(&mut self, f: impl FnMut(&mut Type)) {
1130 match self {
1131 Self::Named(named) => named.map_types(f),
1132 Self::Positional(positional) => positional.map_types(f),
1133 }
1134 }
1135}
1136
1137impl Typed for NamedFields {
1138 fn map_types(&mut self, mut f: impl FnMut(&mut Type)) {
1139 mutate_delimited_vec(&mut self.0.content, |field| f(&mut field.ty));
1140 }
1141}
1142
1143impl Typed for PositionalFields {
1144 fn map_types(&mut self, mut f: impl FnMut(&mut Type)) {
1145 mutate_delimited_vec(&mut self.0.content, |field| f(&mut field.ty));
1146 }
1147}
1148
1149impl Typed for Type {
1150 fn map_types(&mut self, mut f: impl FnMut(&mut Self)) {
1151 if let Some(args) = &mut self.type_args {
1152 mutate_delimited_vec(&mut args.args, |t| f(&mut *t))
1153 }
1154 }
1155}
1156
1157fn mutate_delimited_vec<T, D: Default, const MIN: usize, const MAX: usize>(
1160 dvec: &mut DelimitedVec<T, D, TrailingDelimiter::Optional, MIN, MAX>,
1161 mut f: impl FnMut(&mut T),
1162) {
1163 type ForbiddenDelimited<T, D, const MIN: usize, const MAX: usize> =
1164 DelimitedVec<T, D, TrailingDelimiter::Forbidden, MIN, MAX>;
1165
1166 let temp: ForbiddenDelimited<T, D, MIN, MAX> = std::iter::empty::<T>().collect();
1167 let mut swapped = std::mem::replace(dvec, temp.into());
1168 swapped = swapped
1169 .into_iter()
1170 .map(|mut d| {
1171 f(&mut d.value);
1172 d.value
1173 })
1174 .collect::<ForbiddenDelimited<T, D, MIN, MAX>>()
1175 .into();
1176 *dvec = swapped;
1177}