1#![cfg_attr(nightly, feature(doc_cfg))]
2#![expect(clippy::result_large_err, reason = "Error from the unsynn crate")]
3
4use std::borrow::Cow;
7use std::collections::HashMap;
8
9pub use unsynn;
10use unsynn::*;
11
12mod functions;
13#[cfg(test)]
14mod tests;
15mod vis;
16
17#[cfg(feature = "fun-sig")]
18pub use self::functions::FunctionArg;
19pub use self::functions::{Function, NativeFun};
20pub use self::vis::Visibility;
21
22pub fn sanitize_for_tokenizer(content: &str) -> String {
31 let regex = raw_ident_regex();
32 let mut lines = content.lines().map(|line| {
33 if !line.trim_start().starts_with("//") {
35 regex.replace(line, "$1")
36 } else {
37 Cow::Borrowed(line)
38 }
39 });
40 lines.next().map_or_else(String::new, |line| {
41 let mut sanitized = String::with_capacity(content.len());
42 sanitized.push_str(&line);
43 for line in lines {
44 sanitized.push('\n');
45 sanitized.push_str(&line);
46 }
47 sanitized
48 })
49}
50
51fn raw_ident_regex() -> regex::Regex {
52 regex::Regex::new("`([[:alnum:]_]+)`").expect("Valid regex")
53}
54
55pub mod kw {
56 use unsynn::*;
58
59 unsynn! {
60 pub keyword Struct = "struct";
61 pub keyword Phantom = "phantom";
62 pub keyword Public = "public";
63 pub keyword Has = "has";
64 pub keyword Copy = "copy";
65 pub keyword Drop = "drop";
66 pub keyword Key = "key";
67 pub keyword Store = "store";
68 pub keyword Module = "module";
69 pub keyword Package = "package";
70 pub keyword Friend = "friend";
71 pub keyword Use = "use";
72 pub keyword Fun = "fun";
73 pub keyword As = "as";
74 pub keyword Const = "const";
75 pub keyword Mut = "mut";
76 pub keyword Entry = "entry";
77 pub keyword Native = "native";
78 pub keyword Macro = "macro";
79 pub keyword Vector = "vector";
80 pub keyword Enum = "enum";
81 }
82}
83
84unsynn! {
85 pub enum File {
86 ModuleLabel(LabeledModule),
88 Legacy(Vec<Module>),
90 }
91
92 pub struct LabeledModule {
96 attrs: Vec<Attributes>,
97 keyword: kw::Module,
98 named_address: Ident,
99 path_sep: PathSep,
100 ident: Ident,
101 semicolon: Semicolon,
102 contents: Vec<Item>,
103 }
104
105 pub struct Module {
107 pub attrs: Vec<Attributes>,
108 keyword: kw::Module,
109 pub named_address: Ident,
110 path_sep: PathSep,
111 pub ident: Ident,
112 contents: BraceGroupContaining<Vec<Item>>,
113 }
114
115 pub struct Item {
117 pub attrs: Vec<Attributes>,
118 vis: Option<Vis>,
119 pub kind: ItemKind,
120 }
121
122 #[derive(Clone)]
130 pub struct Attributes {
131 pound: Pound,
132 contents: BracketGroupContaining<DelimitedVec<Attribute, Comma, TrailingDelimiter::Optional>>,
133 }
134
135 #[derive(Clone)]
145 enum Attribute {
146 Doc(Cons<DocKw, Assign, LiteralString>),
148 For(ForKw),
149 Other {
150 ident: Ident,
151 sub: Option<SubAttribute>,
152 }
153 }
154
155 keyword DocKw = "doc";
156 keyword ForKw = "for";
157
158 #[derive(Clone)]
159 enum SubAttribute {
160 Eq(Cons<Assign, AttributeValue>),
161 List(ParenthesisGroupContaining<DelimitedVec<Box<Attribute>, Comma, TrailingDelimiter::Optional>>),
162 }
163
164 #[derive(Clone)]
171 enum AttributeValue {
172 Lit(Literal),
173 NameAccessChain {
177 leading_name_access: Either<SyntaxIdent, Ident>,
180 path: DelimitedVec<PathSep, Ident, TrailingDelimiter::Forbidden>,
183 },
184 }
185
186 #[derive(Clone)]
192 struct Vis {
193 public: kw::Public,
194 modifier: Option<ParenthesisGroupContaining<VisibilityModifier>>,
195 }
196
197 #[derive(Clone)]
203 enum VisibilityModifier {
204 Package(kw::Package),
205 Friend(kw::Friend)
206 }
207
208 #[non_exhaustive]
212 pub enum ItemKind {
213 Struct(Struct),
214 Enum(Enum),
215 Import(Import),
216 UseFun(UseFun),
217 Const(Const),
218 Function(Function),
219 MacroFun(MacroFun),
220 NativeFun(NativeFun)
221 }
222
223 pub struct UseFun {
225 keyword: kw::Use,
226 fun_kw: kw::Fun,
227 fun_path: ItemPath,
228 as_kw: kw::As,
229 ty: Ident,
230 dot: Dot,
231 method: Ident,
232 semicolon: Semicolon,
233 }
234
235 pub struct Const {
238 const_kw: kw::Const,
240 ident: Ident,
242 colon: Colon,
244 ty: Type,
246 assign: Assign,
248 expr: Vec<Cons<Except<Semicolon>, TokenTree>>,
250 semicolon: Semicolon,
252 }
253
254 pub struct Import {
257 keyword: kw::Use,
258 named_address: Ident,
259 path_sep: PathSep,
260 module: ImportModule,
261 semicolon: Semicolon,
262 }
263
264 enum ImportModule {
266 One(ModuleOrItems),
267 Many(BraceGroupContaining<CommaDelimitedVec<ModuleOrItems>>),
268 }
269
270 #[derive(Clone)]
271 struct ModuleOrItems {
272 ident: Ident,
273 next: Option<AliasOrItems>,
274 }
275
276 #[derive(Clone)]
277 enum AliasOrItems {
278 Alias {
279 as_kw: kw::As,
280 alias: Ident,
281 },
282 Items {
283 sep: PathSep,
284 item: ImportItem,
285 }
286 }
287
288 #[derive(Clone)]
289 enum ImportItem {
290 One(MaybeAliased),
291 Many(BraceGroupContaining<CommaDelimitedVec<MaybeAliased>>)
292 }
293
294 #[derive(Clone)]
295 struct MaybeAliased {
296 ident: Ident,
297 alias: Option<Cons<kw::As, Ident>>,
298 }
299
300 #[derive(Clone)]
304 pub struct Struct {
305 keyword: kw::Struct,
306 pub ident: Ident,
307 pub generics: Option<Generics>,
308 pub kind: StructKind,
309 }
310
311 #[derive(Clone)]
313 pub enum StructKind {
314 Braced(BracedStruct),
315 Tuple(TupleStruct),
316 }
317
318 #[derive(Clone)]
320 pub struct BracedStruct {
321 abilities: Option<Abilities>,
322 pub fields: NamedFields,
323 }
324
325 #[derive(Clone)]
328 pub struct TupleStruct {
329 pub fields: PositionalFields,
330 abilities: Option<Cons<Abilities, Semicolon>>
331 }
332
333 #[derive(Clone)]
336 pub struct Enum {
337 keyword: kw::Enum,
338 pub ident: Ident,
339 pub generics: Option<Generics>,
340 abilities: Option<Abilities>,
341 content: BraceGroupContaining<CommaDelimitedVec<EnumVariant>>,
342 }
343
344 #[derive(Clone)]
345 pub struct EnumVariant {
346 pub attrs: Vec<Attributes>,
347 pub ident: Ident,
348 pub fields: Option<FieldsKind>
350 }
351
352 #[derive(Clone)]
354 pub enum FieldsKind {
355 Positional(PositionalFields),
356 Named(NamedFields),
357 }
358
359 #[derive(Clone)]
363 pub struct PositionalFields(ParenthesisGroupContaining<DelimitedVec<UnnamedField, Comma>>);
364
365 #[derive(Clone)]
367 pub struct NamedFields(BraceGroupContaining<DelimitedVec<NamedField, Comma>>);
368
369 #[derive(Clone)]
371 pub struct NamedField {
372 pub attrs: Vec<Attributes>,
373 pub ident: Ident,
374 colon: Colon,
375 pub ty: Type,
376 }
377
378 #[derive(Clone)]
380 pub struct UnnamedField {
381 pub attrs: Vec<Attributes>,
382 pub ty: Type,
383 }
384
385 #[derive(Clone)]
392 pub struct Generics {
393 lt_token: Lt,
394 type_args: DelimitedVec<Generic, Comma>,
395 gt_token: Gt,
396 }
397
398 #[derive(Clone)]
406 pub struct Generic {
407 pub phantom: Option<kw::Phantom>,
408 pub ident: Ident,
409 bounds: Option<GenericBounds>
410 }
411
412 #[derive(Clone)]
416 struct GenericBounds {
417 colon: Colon,
418 abilities: Many<Ability, Plus, TrailingDelimiter::Forbidden>,
419 }
420
421 #[derive(Clone)]
427 struct Abilities {
428 has: kw::Has,
429 keywords: Many<Ability, Comma, TrailingDelimiter::Forbidden>,
430 }
431
432 #[derive(Clone)]
434 pub enum Ability {
435 Copy(kw::Copy),
436 Drop(kw::Drop),
437 Key(kw::Key),
438 Store(kw::Store),
439 }
440
441 pub struct MacroFun {
444 macro_kw: kw::Macro,
445 fun_kw: kw::Fun,
446 ident: Ident,
447 generics: Option<MacroGenerics>,
448 args: ParenthesisGroup,
449 ret: Option<Cons<Colon, Either<MacroReturn, ParenthesisGroup>>>,
450 body: BraceGroup,
451 }
452
453 struct MacroGenerics {
454 lt_token: Lt,
455 type_args: DelimitedVec<MacroTypeArg, Comma>,
456 gt_token: Gt,
457 }
458
459 struct MacroTypeArg{
461 name: SyntaxIdent,
462 bounds: Option<GenericBounds>,
463 }
464
465 enum MacroReturn {
467 Underscore(Underscore),
468 Concrete(Cons<Option<Ref>, MacroReturnType>),
469 }
470
471 enum MacroReturnType {
478 MacroTypeName(SyntaxIdent),
479 Hybrid(HybridMacroType)
480 }
481
482 struct HybridMacroType {
483 ident: Ident,
484 type_args: Option<Cons<Lt, Many<Either<Type, SyntaxIdent, Box<HybridMacroType>>, Comma>, Gt>>
485 }
486
487 #[derive(Clone)]
492 struct SyntaxIdent {
493 dollar: Dollar,
494 ident: Ident,
495 }
496
497 pub struct MaybeRefType {
501 r#ref: Option<Ref>,
502 r#type: Type,
503 }
504
505 struct Ref {
507 and: And,
508 r#mut: Option<kw::Mut>,
509 }
510
511 #[derive(Clone)]
513 pub struct Type {
514 pub path: ItemPath,
515 pub type_args: Option<TypeArgs>
516 }
517
518 #[derive(Clone)]
520 pub enum ItemPath {
521 Full {
523 named_address: Ident,
524 sep0: PathSep,
525 module: Ident,
526 sep1: PathSep,
527 item: Ident,
528 },
529 Module {
531 module: Ident,
532 sep: PathSep,
533 item: Ident,
534 },
535 Ident(Ident),
537 }
538
539 #[derive(Clone)]
541 pub struct TypeArgs {
542 lt: Lt,
543 args: Many<Box<Type>, Comma>,
544 gt: Gt,
545 }
546}
547
548impl File {
549 pub fn into_modules(self) -> impl Iterator<Item = Module> {
550 match self {
551 Self::ModuleLabel(labeled) => std::iter::once(labeled.into_module()).boxed(),
552 Self::Legacy(modules) => modules.into_iter().boxed(),
553 }
554 }
555}
556
557impl LabeledModule {
558 pub fn into_module(self) -> Module {
559 Module {
560 attrs: self.attrs,
561 keyword: self.keyword,
562 named_address: self.named_address,
563 path_sep: self.path_sep,
564 ident: self.ident,
565 contents: BraceGroupContaining {
566 content: self.contents,
567 },
568 }
569 }
570}
571
572impl Module {
573 pub fn with_implicit_sui_imports(&mut self) -> &mut Self {
577 let implicit_imports: HashMap<_, _> = [
579 "use sui::object;",
580 "use sui::object::ID;",
581 "use sui::object::UID;",
582 "use sui::tx_context;",
583 "use sui::tx_context::TxContext;",
584 "use sui::transfer;",
585 ]
586 .into_iter()
587 .map(|text| {
588 text.to_token_iter()
589 .parse_all::<Import>()
590 .expect("Valid imports")
591 })
592 .map(|import| {
593 let ident = import
594 .imported_idents()
595 .next()
596 .expect("Each import exposes exactly one ident");
597 (ident.clone(), import)
598 })
599 .collect();
600
601 self.add_implicit_imports(implicit_imports)
602 }
603
604 pub fn with_implicit_iota_imports(&mut self) -> &mut Self {
608 let implicit_imports: HashMap<_, _> = [
610 "use iota::object;",
611 "use iota::object::ID;",
612 "use iota::object::UID;",
613 "use iota::tx_context;",
614 "use iota::tx_context::TxContext;",
615 "use iota::transfer;",
616 ]
617 .into_iter()
618 .map(|text| {
619 text.to_token_iter()
620 .parse_all::<Import>()
621 .expect("Valid imports")
622 })
623 .map(|import| {
624 let ident = import
625 .imported_idents()
626 .next()
627 .expect("Each import exposes exactly one ident");
628 (ident.clone(), import)
629 })
630 .collect();
631
632 self.add_implicit_imports(implicit_imports)
633 }
634
635 pub fn fully_qualify_datatype_field_types(&mut self) -> &mut Self {
637 let imports: HashMap<_, _> = self
639 .items()
640 .filter_map(|item| match &item.kind {
641 ItemKind::Import(import) => Some(import),
642 _ => None,
643 })
644 .flat_map(|import| import.flatten())
645 .collect();
646
647 for item in &mut self.contents.content {
649 match &mut item.kind {
650 ItemKind::Enum(e) => {
651 let generics = &e.type_param_idents();
652 e.map_types(|ty| ty.resolve(&imports, generics));
653 }
654 ItemKind::Struct(s) => {
655 let generics = &s.type_param_idents();
656 s.map_types(|ty| ty.resolve(&imports, generics));
657 }
658 _ => (),
659 }
660 }
661
662 self
663 }
664
665 pub fn items(&self) -> impl Iterator<Item = &Item> {
666 self.contents.content.iter()
667 }
668
669 #[cfg(test)]
670 pub fn into_items(self) -> impl Iterator<Item = Item> {
671 self.contents.content.into_iter()
672 }
673
674 fn add_implicit_imports(&mut self, mut implicit_imports: HashMap<Ident, Import>) -> &mut Self {
675 for item in self.items() {
677 let ItemKind::Import(import) = &item.kind else {
678 continue;
679 };
680 for ident in import.imported_idents() {
681 implicit_imports.remove(ident);
682 }
683 }
684
685 for (_, import) in implicit_imports {
687 self.contents.content.push(Item {
688 attrs: vec![],
689 vis: None,
690 kind: ItemKind::Import(import),
691 })
692 }
693 self
694 }
695}
696
697impl Import {
698 pub fn flatten(&self) -> impl Iterator<Item = (Ident, FlatImport)> + '_ {
701 let named_address = self.named_address.clone();
702 match &self.module {
703 ImportModule::One(module_or_items) => module_or_items.flatten(named_address),
705 ImportModule::Many(BraceGroupContaining { content: ms }) => ms
707 .iter()
708 .flat_map(move |Delimited { value, .. }| value.flatten(named_address.clone()))
709 .boxed(),
710 }
711 }
712
713 fn imported_idents(&self) -> impl Iterator<Item = &Ident> {
715 match &self.module {
716 ImportModule::One(module_or_items) => module_or_items.available_idents(),
717 ImportModule::Many(BraceGroupContaining { content: ms }) => ms
718 .iter()
719 .flat_map(|delimited| delimited.value.available_idents())
720 .boxed(),
721 }
722 }
723}
724
725impl ModuleOrItems {
726 fn flatten(&self, named_address: Ident) -> Box<dyn Iterator<Item = (Ident, FlatImport)> + '_> {
728 let module = self.ident.clone();
729
730 let Some(next) = &self.next else {
731 return std::iter::once((
733 module.clone(),
734 FlatImport::Module {
735 named_address,
736 module,
737 },
738 ))
739 .boxed();
740 };
741
742 match next {
743 AliasOrItems::Alias { alias, .. } => std::iter::once((
745 alias.clone(),
746 FlatImport::Module {
747 named_address,
748 module,
749 },
750 ))
751 .boxed(),
752
753 AliasOrItems::Items {
755 item: ImportItem::One(maybe_aliased),
756 ..
757 } => std::iter::once(maybe_aliased.flat_import(named_address, module)).boxed(),
758
759 AliasOrItems::Items {
761 item: ImportItem::Many(BraceGroupContaining { content: items }),
762 ..
763 } => items
764 .iter()
765 .map(move |Delimited { value, .. }| {
766 value.flat_import(named_address.clone(), module.clone())
767 })
768 .boxed(),
769 }
770 }
771
772 fn available_idents(&self) -> Box<dyn Iterator<Item = &Ident> + '_> {
774 let Some(next) = &self.next else {
775 return std::iter::once(&self.ident).boxed();
776 };
777
778 match next {
779 AliasOrItems::Alias { alias, .. } => std::iter::once(alias).boxed(),
780
781 AliasOrItems::Items {
782 item: ImportItem::One(item),
783 ..
784 } => std::iter::once(item.available_ident(&self.ident)).boxed(),
785
786 AliasOrItems::Items {
787 item: ImportItem::Many(BraceGroupContaining { content: items }),
788 ..
789 } => items
790 .iter()
791 .map(|delimited| delimited.value.available_ident(&self.ident))
792 .boxed(),
793 }
794 }
795}
796
797impl MaybeAliased {
798 fn flat_import(&self, named_address: Ident, module: Ident) -> (Ident, FlatImport) {
800 if self.ident == "Self" {
801 (
802 self.alias().unwrap_or(&module).clone(),
803 FlatImport::Module {
804 named_address,
805 module,
806 },
807 )
808 } else {
809 (
810 self.alias().unwrap_or(&self.ident).clone(),
811 FlatImport::Item {
812 named_address,
813 module,
814 r#type: self.ident.clone(),
815 },
816 )
817 }
818 }
819
820 fn available_ident<'a>(&'a self, module: &'a Ident) -> &'a Ident {
821 if self.ident == "Self" {
822 self.alias().unwrap_or(module)
823 } else {
824 self.alias().unwrap_or(&self.ident)
825 }
826 }
827
828 fn alias(&self) -> Option<&Ident> {
830 self.alias.as_ref().map(|cons| &cons.second)
831 }
832}
833
834impl Attributes {
835 pub fn is_doc(&self) -> bool {
837 matches!(
838 &self.contents.content[..],
839 [Delimited {
840 value: Attribute::Doc(_),
841 ..
842 }]
843 )
844 }
845
846 pub const fn contents(&self) -> &impl ToTokens {
848 &self.contents.content
849 }
850
851 pub fn erased_attributes(&self) -> impl Iterator<Item = &dyn ToTokens> + '_ {
855 self.contents
856 .content
857 .iter()
858 .map(|delimited| &delimited.value as _)
859 }
860
861 pub fn external_attributes(&self) -> impl Iterator<Item = &dyn ToTokens> + '_ {
863 self.contents.content.iter().filter_map(|d| match &d.value {
864 Attribute::Other {
865 ident,
866 sub: Some(SubAttribute::List(inner)),
867 } if ident == "ext" => Some(&inner.content as _),
868 _ => None,
869 })
870 }
871}
872
873impl ItemKind {
874 pub const fn is_datatype(&self) -> bool {
876 matches!(self, Self::Enum(_) | Self::Struct(_))
877 }
878}
879
880impl Struct {
881 pub fn abilities(&self) -> impl Iterator<Item = &Ability> {
882 use StructKind as K;
883 match &self.kind {
884 K::Braced(braced) => braced
885 .abilities
886 .iter()
887 .flat_map(|a| a.keywords.iter())
888 .map(|d| &d.value)
889 .boxed(),
890 K::Tuple(tuple) => tuple
891 .abilities
892 .iter()
893 .flat_map(|a| a.first.keywords.iter())
894 .map(|d| &d.value)
895 .boxed(),
896 }
897 }
898}
899
900impl BracedStruct {
901 pub fn fields(&self) -> impl Iterator<Item = &NamedField> + Clone + '_ {
902 self.fields.fields()
903 }
904
905 pub fn is_empty(&self) -> bool {
907 self.fields.is_empty()
908 }
909}
910
911impl TupleStruct {
912 pub fn fields(&self) -> impl Iterator<Item = &UnnamedField> + Clone + '_ {
913 self.fields.fields()
914 }
915
916 pub fn is_empty(&self) -> bool {
918 self.fields.is_empty()
919 }
920}
921
922impl Enum {
923 pub fn abilities(&self) -> impl Iterator<Item = &Ability> {
924 self.abilities
925 .iter()
926 .flat_map(|a| a.keywords.iter())
927 .map(|d| &d.value)
928 }
929
930 pub fn variants(&self) -> impl Iterator<Item = &EnumVariant> {
931 self.content
932 .content
933 .iter()
934 .map(|Delimited { value, .. }| value)
935 }
936}
937
938impl NamedFields {
939 pub fn fields(&self) -> impl Iterator<Item = &NamedField> + Clone + '_ {
940 self.0.content.iter().map(|d| &d.value)
941 }
942
943 pub fn is_empty(&self) -> bool {
944 self.0.content.is_empty()
945 }
946}
947
948impl PositionalFields {
949 pub fn new() -> Self {
950 Self(ParenthesisGroupContaining {
951 content: std::iter::empty::<UnnamedField>()
952 .collect::<DelimitedVec<_, _, TrailingDelimiter::Mandatory>>()
953 .into(),
954 })
955 }
956
957 pub fn fields(&self) -> impl Iterator<Item = &UnnamedField> + Clone + '_ {
958 self.0.content.iter().map(|d| &d.value)
959 }
960
961 pub fn is_empty(&self) -> bool {
962 self.0.content.is_empty()
963 }
964}
965
966impl Default for PositionalFields {
967 fn default() -> Self {
968 Self::new()
969 }
970}
971
972impl Type {
973 fn resolve(&mut self, imports: &HashMap<Ident, FlatImport>, generics: &[Ident]) {
975 use ItemPath as P;
976 self.map_types(|ty| ty.resolve(imports, generics));
978
979 let resolved = match &self.path {
983 P::Module {
984 module,
985 item: r#type,
986 ..
987 } => {
988 let Some(FlatImport::Module {
989 named_address,
990 module,
991 }) = imports.get(module)
992 else {
993 return;
994 };
995 P::Full {
996 named_address: named_address.clone(),
997 sep0: PathSep::default(),
998 module: module.clone(),
999 sep1: PathSep::default(),
1000 item: r#type.clone(),
1001 }
1002 }
1003 P::Ident(ident) if !generics.contains(ident) => {
1004 let Some(FlatImport::Item {
1005 named_address,
1006 module,
1007 r#type,
1008 }) = imports.get(ident)
1009 else {
1010 return;
1011 };
1012 P::Full {
1013 named_address: named_address.clone(),
1014 sep0: PathSep::default(),
1015 module: module.clone(),
1016 sep1: PathSep::default(),
1017 item: r#type.clone(),
1018 }
1019 }
1020 _ => return,
1022 };
1023 self.path = resolved;
1024 }
1025}
1026
1027impl TypeArgs {
1028 pub fn types(&self) -> impl Iterator<Item = &Type> {
1030 self.args.iter().map(|args| &*args.value)
1031 }
1032}
1033
1034impl Generics {
1035 pub fn generics(&self) -> impl Iterator<Item = &Generic> + '_ {
1036 self.type_args.iter().map(|d| &d.value)
1037 }
1038}
1039
1040impl MaybeRefType {
1041 pub fn is_ref(&self) -> bool {
1043 self.r#ref.as_ref().is_some_and(|r| r.r#mut.is_none())
1044 }
1045
1046 pub const fn type_(&self) -> &Type {
1048 &self.r#type
1049 }
1050}
1051
1052#[cfg_attr(test, derive(derive_more::Display))]
1055pub enum FlatImport {
1056 #[cfg_attr(test, display("{named_address}::{module}"))]
1057 Module { named_address: Ident, module: Ident },
1058 #[cfg_attr(test, display("{named_address}::{module}::{type}"))]
1059 Item {
1060 named_address: Ident,
1061 module: Ident,
1062 r#type: Ident,
1063 },
1064}
1065
1066trait IteratorBoxed<'a>: Iterator + 'a {
1070 fn boxed(self) -> Box<dyn Iterator<Item = Self::Item> + 'a>
1071 where
1072 Self: Sized,
1073 {
1074 Box::new(self)
1075 }
1076}
1077
1078impl<'a, T> IteratorBoxed<'a> for T where T: Iterator + 'a {}
1079
1080trait HasGenerics {
1082 fn generics(&self) -> Option<&Generics>;
1083
1084 fn type_param_idents(&self) -> Vec<Ident> {
1086 self.generics()
1087 .iter()
1088 .flat_map(|generics| generics.generics())
1089 .map(|generic| generic.ident.clone())
1090 .collect()
1091 }
1092}
1093
1094impl HasGenerics for Enum {
1095 fn generics(&self) -> Option<&Generics> {
1096 self.generics.as_ref()
1097 }
1098}
1099
1100impl HasGenerics for Struct {
1101 fn generics(&self) -> Option<&Generics> {
1102 self.generics.as_ref()
1103 }
1104}
1105
1106trait Typed {
1108 fn map_types(&mut self, f: impl FnMut(&mut Type));
1110}
1111
1112impl Typed for Enum {
1113 fn map_types(&mut self, mut f: impl FnMut(&mut Type)) {
1114 mutate_delimited_vec(&mut self.content.content, |variant| {
1115 variant.map_types(&mut f)
1116 });
1117 }
1118}
1119
1120impl Typed for EnumVariant {
1121 fn map_types(&mut self, f: impl FnMut(&mut Type)) {
1122 let Some(fields) = &mut self.fields else {
1123 return;
1124 };
1125 fields.map_types(f);
1126 }
1127}
1128
1129impl Typed for Struct {
1130 fn map_types(&mut self, f: impl FnMut(&mut Type)) {
1131 match &mut self.kind {
1132 StructKind::Braced(braced_struct) => braced_struct.fields.map_types(f),
1133 StructKind::Tuple(tuple_struct) => tuple_struct.fields.map_types(f),
1134 }
1135 }
1136}
1137
1138impl Typed for FieldsKind {
1139 fn map_types(&mut self, f: impl FnMut(&mut Type)) {
1140 match self {
1141 Self::Named(named) => named.map_types(f),
1142 Self::Positional(positional) => positional.map_types(f),
1143 }
1144 }
1145}
1146
1147impl Typed for NamedFields {
1148 fn map_types(&mut self, mut f: impl FnMut(&mut Type)) {
1149 mutate_delimited_vec(&mut self.0.content, |field| f(&mut field.ty));
1150 }
1151}
1152
1153impl Typed for PositionalFields {
1154 fn map_types(&mut self, mut f: impl FnMut(&mut Type)) {
1155 mutate_delimited_vec(&mut self.0.content, |field| f(&mut field.ty));
1156 }
1157}
1158
1159impl Typed for Type {
1160 fn map_types(&mut self, mut f: impl FnMut(&mut Self)) {
1161 if let Some(args) = &mut self.type_args {
1162 mutate_delimited_vec(&mut args.args, |t| f(&mut *t))
1163 }
1164 }
1165}
1166
1167fn mutate_delimited_vec<T, D: Default, const MIN: usize, const MAX: usize>(
1170 dvec: &mut DelimitedVec<T, D, TrailingDelimiter::Optional, MIN, MAX>,
1171 mut f: impl FnMut(&mut T),
1172) {
1173 type ForbiddenDelimited<T, D, const MIN: usize, const MAX: usize> =
1174 DelimitedVec<T, D, TrailingDelimiter::Forbidden, MIN, MAX>;
1175
1176 let temp: ForbiddenDelimited<T, D, MIN, MAX> = std::iter::empty::<T>().collect();
1177 let mut swapped = std::mem::replace(dvec, temp.into());
1178 swapped = swapped
1179 .into_iter()
1180 .map(|mut d| {
1181 f(&mut d.value);
1182 d.value
1183 })
1184 .collect::<ForbiddenDelimited<T, D, MIN, MAX>>()
1185 .into();
1186 *dvec = swapped;
1187}