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