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<Attributes>,
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<Attributes>,
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<Attributes>,
117 vis: Option<Vis>,
118 pub kind: ItemKind,
119 }
120
121 #[derive(Clone)]
129 pub struct Attributes {
130 pound: Pound,
131 contents: BracketGroupContaining<DelimitedVec<Attribute, Comma, TrailingDelimiter::Optional>>,
132 }
133
134 #[derive(Clone)]
144 enum Attribute {
145 Doc(Cons<DocKw, Assign, LiteralString>),
147 For(ForKw),
148 Other {
149 ident: Ident,
150 sub: Option<SubAttribute>,
151 }
152 }
153
154 keyword DocKw = "doc";
155 keyword ForKw = "for";
156
157 #[derive(Clone)]
158 enum SubAttribute {
159 Eq(Cons<Assign, AttributeValue>),
160 List(ParenthesisGroupContaining<DelimitedVec<Box<Attribute>, Comma, TrailingDelimiter::Optional>>),
161 }
162
163 #[derive(Clone)]
170 enum AttributeValue {
171 Lit(Literal),
172 NameAccessChain {
176 leading_name_access: Either<SyntaxIdent, Ident>,
179 path: DelimitedVec<PathSep, Ident, TrailingDelimiter::Forbidden>,
182 },
183 }
184
185 #[derive(Clone)]
191 struct Vis {
192 public: kw::Public,
193 modifier: Option<ParenthesisGroupContaining<VisibilityModifier>>,
194 }
195
196 #[derive(Clone)]
202 enum VisibilityModifier {
203 Package(kw::Package),
204 Friend(kw::Friend)
205 }
206
207 #[non_exhaustive]
211 pub enum ItemKind {
212 Struct(Struct),
213 Enum(Enum),
214 Import(Import),
215 UseFun(UseFun),
216 Const(Const),
217 Function(Function),
218 MacroFun(MacroFun),
219 NativeFun(NativeFun)
220 }
221
222 pub struct UseFun {
224 keyword: kw::Use,
225 fun_kw: kw::Fun,
226 fun_path: ItemPath,
227 as_kw: kw::As,
228 ty: Ident,
229 dot: Dot,
230 method: Ident,
231 semicolon: Semicolon,
232 }
233
234 pub struct Const {
237 const_kw: kw::Const,
239 ident: Ident,
241 colon: Colon,
243 ty: Type,
245 assign: Assign,
247 expr: Vec<Cons<Except<Semicolon>, TokenTree>>,
249 semicolon: Semicolon,
251 }
252
253 pub struct Import {
256 keyword: kw::Use,
257 named_address: Ident,
258 path_sep: PathSep,
259 module: ImportModule,
260 semicolon: Semicolon,
261 }
262
263 enum ImportModule {
265 One(ModuleOrItems),
266 Many(BraceGroupContaining<CommaDelimitedVec<ModuleOrItems>>),
267 }
268
269 #[derive(Clone)]
270 struct ModuleOrItems {
271 ident: Ident,
272 next: Option<AliasOrItems>,
273 }
274
275 #[derive(Clone)]
276 enum AliasOrItems {
277 Alias {
278 as_kw: kw::As,
279 alias: Ident,
280 },
281 Items {
282 sep: PathSep,
283 item: ImportItem,
284 }
285 }
286
287 #[derive(Clone)]
288 enum ImportItem {
289 One(MaybeAliased),
290 Many(BraceGroupContaining<CommaDelimitedVec<MaybeAliased>>)
291 }
292
293 #[derive(Clone)]
294 struct MaybeAliased {
295 ident: Ident,
296 alias: Option<Cons<kw::As, Ident>>,
297 }
298
299 #[derive(Clone)]
303 pub struct Struct {
304 keyword: kw::Struct,
305 pub ident: Ident,
306 pub generics: Option<Generics>,
307 pub kind: StructKind,
308 }
309
310 #[derive(Clone)]
312 pub enum StructKind {
313 Braced(BracedStruct),
314 Tuple(TupleStruct),
315 }
316
317 #[derive(Clone)]
319 pub struct BracedStruct {
320 abilities: Option<Abilities>,
321 pub fields: NamedFields,
322 }
323
324 #[derive(Clone)]
327 pub struct TupleStruct {
328 pub fields: PositionalFields,
329 abilities: Option<Cons<Abilities, Semicolon>>
330 }
331
332 #[derive(Clone)]
335 pub struct Enum {
336 keyword: kw::Enum,
337 pub ident: Ident,
338 pub generics: Option<Generics>,
339 abilities: Option<Abilities>,
340 content: BraceGroupContaining<CommaDelimitedVec<EnumVariant>>,
341 }
342
343 #[derive(Clone)]
344 pub struct EnumVariant {
345 pub attrs: Vec<Attributes>,
346 pub ident: Ident,
347 pub fields: Option<FieldsKind>
349 }
350
351 #[derive(Clone)]
353 pub enum FieldsKind {
354 Positional(PositionalFields),
355 Named(NamedFields),
356 }
357
358 #[derive(Clone)]
362 pub struct PositionalFields(ParenthesisGroupContaining<DelimitedVec<UnnamedField, Comma>>);
363
364 #[derive(Clone)]
366 pub struct NamedFields(BraceGroupContaining<DelimitedVec<NamedField, Comma>>);
367
368 #[derive(Clone)]
370 pub struct NamedField {
371 pub attrs: Vec<Attributes>,
372 pub ident: Ident,
373 colon: Colon,
374 pub ty: Type,
375 }
376
377 #[derive(Clone)]
379 pub struct UnnamedField {
380 pub attrs: Vec<Attributes>,
381 pub ty: Type,
382 }
383
384 #[derive(Clone)]
391 pub struct Generics {
392 lt_token: Lt,
393 type_args: DelimitedVec<Generic, Comma>,
394 gt_token: Gt,
395 }
396
397 #[derive(Clone)]
405 pub struct Generic {
406 pub phantom: Option<kw::Phantom>,
407 pub ident: Ident,
408 bounds: Option<GenericBounds>
409 }
410
411 #[derive(Clone)]
415 struct GenericBounds {
416 colon: Colon,
417 abilities: Many<Ability, Plus, TrailingDelimiter::Forbidden>,
418 }
419
420 #[derive(Clone)]
426 struct Abilities {
427 has: kw::Has,
428 keywords: Many<Ability, Comma, TrailingDelimiter::Forbidden>,
429 }
430
431 #[derive(Clone)]
433 pub enum Ability {
434 Copy(kw::Copy),
435 Drop(kw::Drop),
436 Key(kw::Key),
437 Store(kw::Store),
438 }
439
440 pub struct MacroFun {
443 macro_kw: kw::Macro,
444 fun_kw: kw::Fun,
445 ident: Ident,
446 generics: Option<MacroGenerics>,
447 args: ParenthesisGroup,
448 ret: Option<Cons<Colon, Either<MacroReturn, ParenthesisGroup>>>,
449 body: BraceGroup,
450 }
451
452 struct MacroGenerics {
453 lt_token: Lt,
454 type_args: DelimitedVec<MacroTypeArg, Comma>,
455 gt_token: Gt,
456 }
457
458 struct MacroTypeArg{
460 name: SyntaxIdent,
461 bounds: Option<GenericBounds>,
462 }
463
464 enum MacroReturn {
466 Underscore(Underscore),
467 Concrete(Cons<Option<Ref>, MacroReturnType>),
468 }
469
470 enum MacroReturnType {
477 MacroTypeName(SyntaxIdent),
478 Hybrid(HybridMacroType)
479 }
480
481 struct HybridMacroType {
482 ident: Ident,
483 type_args: Option<Cons<Lt, Many<Either<Type, SyntaxIdent, Box<HybridMacroType>>, Comma>, Gt>>
484 }
485
486 #[derive(Clone)]
491 struct SyntaxIdent {
492 dollar: Dollar,
493 ident: Ident,
494 }
495
496 pub struct MaybeRefType {
500 r#ref: Option<Ref>,
501 r#type: Type,
502 }
503
504 struct Ref {
506 and: And,
507 r#mut: Option<kw::Mut>,
508 }
509
510 #[derive(Clone)]
512 pub struct Type {
513 pub path: ItemPath,
514 pub type_args: Option<TypeArgs>
515 }
516
517 #[derive(Clone)]
519 pub enum ItemPath {
520 Full {
522 named_address: Ident,
523 sep0: PathSep,
524 module: Ident,
525 sep1: PathSep,
526 item: Ident,
527 },
528 Module {
530 module: Ident,
531 sep: PathSep,
532 item: Ident,
533 },
534 Ident(Ident),
536 }
537
538 #[derive(Clone)]
540 pub struct TypeArgs {
541 lt: Lt,
542 args: Many<Box<Type>, Comma>,
543 gt: Gt,
544 }
545}
546
547impl File {
548 pub fn into_modules(self) -> impl Iterator<Item = Module> {
549 match self {
550 Self::ModuleLabel(labeled) => std::iter::once(labeled.into_module()).boxed(),
551 Self::Legacy(modules) => modules.into_iter().boxed(),
552 }
553 }
554}
555
556impl LabeledModule {
557 pub fn into_module(self) -> Module {
558 Module {
559 attrs: self.attrs,
560 keyword: self.keyword,
561 named_address: self.named_address,
562 path_sep: self.path_sep,
563 ident: self.ident,
564 contents: BraceGroupContaining {
565 content: self.contents,
566 },
567 }
568 }
569}
570
571impl Module {
572 pub fn with_implicit_sui_imports(&mut self) -> &mut Self {
576 let implicit_imports: HashMap<_, _> = [
578 "use sui::object;",
579 "use sui::object::ID;",
580 "use sui::object::UID;",
581 "use sui::tx_context;",
582 "use sui::tx_context::TxContext;",
583 "use sui::transfer;",
584 ]
585 .into_iter()
586 .map(|text| {
587 text.to_token_iter()
588 .parse_all::<Import>()
589 .expect("Valid imports")
590 })
591 .map(|import| {
592 let ident = import
593 .imported_idents()
594 .next()
595 .expect("Each import exposes exactly one ident");
596 (ident.clone(), import)
597 })
598 .collect();
599
600 self.add_implicit_imports(implicit_imports)
601 }
602
603 pub fn with_implicit_iota_imports(&mut self) -> &mut Self {
607 let implicit_imports: HashMap<_, _> = [
609 "use iota::object;",
610 "use iota::object::ID;",
611 "use iota::object::UID;",
612 "use iota::tx_context;",
613 "use iota::tx_context::TxContext;",
614 "use iota::transfer;",
615 ]
616 .into_iter()
617 .map(|text| {
618 text.to_token_iter()
619 .parse_all::<Import>()
620 .expect("Valid imports")
621 })
622 .map(|import| {
623 let ident = import
624 .imported_idents()
625 .next()
626 .expect("Each import exposes exactly one ident");
627 (ident.clone(), import)
628 })
629 .collect();
630
631 self.add_implicit_imports(implicit_imports)
632 }
633
634 pub fn fully_qualify_datatype_field_types(&mut self) -> &mut Self {
636 let imports: HashMap<_, _> = self
638 .items()
639 .filter_map(|item| match &item.kind {
640 ItemKind::Import(import) => Some(import),
641 _ => None,
642 })
643 .flat_map(|import| import.flatten())
644 .collect();
645
646 for item in &mut self.contents.content {
648 match &mut item.kind {
649 ItemKind::Enum(e) => {
650 let generics = &e.type_param_idents();
651 e.map_types(|ty| ty.resolve(&imports, generics));
652 }
653 ItemKind::Struct(s) => {
654 let generics = &s.type_param_idents();
655 s.map_types(|ty| ty.resolve(&imports, generics));
656 }
657 _ => (),
658 }
659 }
660
661 self
662 }
663
664 pub fn items(&self) -> impl Iterator<Item = &Item> {
665 self.contents.content.iter()
666 }
667
668 #[cfg(test)]
669 pub fn into_items(self) -> impl Iterator<Item = Item> {
670 self.contents.content.into_iter()
671 }
672
673 fn add_implicit_imports(&mut self, mut implicit_imports: HashMap<Ident, Import>) -> &mut Self {
674 for item in self.items() {
676 let ItemKind::Import(import) = &item.kind else {
677 continue;
678 };
679 for ident in import.imported_idents() {
680 implicit_imports.remove(ident);
681 }
682 }
683
684 for (_, import) in implicit_imports {
686 self.contents.content.push(Item {
687 attrs: vec![],
688 vis: None,
689 kind: ItemKind::Import(import),
690 })
691 }
692 self
693 }
694}
695
696impl Import {
697 pub fn flatten(&self) -> impl Iterator<Item = (Ident, FlatImport)> + '_ {
700 let named_address = self.named_address.clone();
701 match &self.module {
702 ImportModule::One(module_or_items) => module_or_items.flatten(named_address),
704 ImportModule::Many(BraceGroupContaining { content: ms }) => ms
706 .iter()
707 .flat_map(move |Delimited { value, .. }| value.flatten(named_address.clone()))
708 .boxed(),
709 }
710 }
711
712 fn imported_idents(&self) -> impl Iterator<Item = &Ident> {
714 match &self.module {
715 ImportModule::One(module_or_items) => module_or_items.available_idents(),
716 ImportModule::Many(BraceGroupContaining { content: ms }) => ms
717 .iter()
718 .flat_map(|delimited| delimited.value.available_idents())
719 .boxed(),
720 }
721 }
722}
723
724impl ModuleOrItems {
725 fn flatten(&self, named_address: Ident) -> Box<dyn Iterator<Item = (Ident, FlatImport)> + '_> {
727 let module = self.ident.clone();
728
729 let Some(next) = &self.next else {
730 return std::iter::once((
732 module.clone(),
733 FlatImport::Module {
734 named_address,
735 module,
736 },
737 ))
738 .boxed();
739 };
740
741 match next {
742 AliasOrItems::Alias { alias, .. } => std::iter::once((
744 alias.clone(),
745 FlatImport::Module {
746 named_address,
747 module,
748 },
749 ))
750 .boxed(),
751
752 AliasOrItems::Items {
754 item: ImportItem::One(maybe_aliased),
755 ..
756 } => std::iter::once(maybe_aliased.flat_import(named_address, module)).boxed(),
757
758 AliasOrItems::Items {
760 item: ImportItem::Many(BraceGroupContaining { content: items }),
761 ..
762 } => items
763 .iter()
764 .map(move |Delimited { value, .. }| {
765 value.flat_import(named_address.clone(), module.clone())
766 })
767 .boxed(),
768 }
769 }
770
771 fn available_idents(&self) -> Box<dyn Iterator<Item = &Ident> + '_> {
773 let Some(next) = &self.next else {
774 return std::iter::once(&self.ident).boxed();
775 };
776
777 match next {
778 AliasOrItems::Alias { alias, .. } => std::iter::once(alias).boxed(),
779
780 AliasOrItems::Items {
781 item: ImportItem::One(item),
782 ..
783 } => std::iter::once(item.available_ident(&self.ident)).boxed(),
784
785 AliasOrItems::Items {
786 item: ImportItem::Many(BraceGroupContaining { content: items }),
787 ..
788 } => items
789 .iter()
790 .map(|delimited| delimited.value.available_ident(&self.ident))
791 .boxed(),
792 }
793 }
794}
795
796impl MaybeAliased {
797 fn flat_import(&self, named_address: Ident, module: Ident) -> (Ident, FlatImport) {
799 if self.ident == "Self" {
800 (
801 self.alias().unwrap_or(&module).clone(),
802 FlatImport::Module {
803 named_address,
804 module,
805 },
806 )
807 } else {
808 (
809 self.alias().unwrap_or(&self.ident).clone(),
810 FlatImport::Item {
811 named_address,
812 module,
813 r#type: self.ident.clone(),
814 },
815 )
816 }
817 }
818
819 fn available_ident<'a>(&'a self, module: &'a Ident) -> &'a Ident {
820 if self.ident == "Self" {
821 self.alias().unwrap_or(module)
822 } else {
823 self.alias().unwrap_or(&self.ident)
824 }
825 }
826
827 fn alias(&self) -> Option<&Ident> {
829 self.alias.as_ref().map(|cons| &cons.second)
830 }
831}
832
833impl Attributes {
834 pub fn is_doc(&self) -> bool {
836 matches!(
837 &self.contents.content[..],
838 [Delimited {
839 value: Attribute::Doc(_),
840 ..
841 }]
842 )
843 }
844
845 pub const fn contents(&self) -> &impl ToTokens {
847 &self.contents.content
848 }
849
850 pub fn erased_attributes(&self) -> impl Iterator<Item = &dyn ToTokens> + '_ {
854 self.contents
855 .content
856 .iter()
857 .map(|delimited| &delimited.value as _)
858 }
859
860 pub fn external_attributes(&self) -> impl Iterator<Item = &dyn ToTokens> + '_ {
862 self.contents.content.iter().filter_map(|d| match &d.value {
863 Attribute::Other {
864 ident,
865 sub: Some(SubAttribute::List(inner)),
866 } if ident == "ext" => Some(&inner.content as _),
867 _ => None,
868 })
869 }
870}
871
872impl ItemKind {
873 pub const fn is_datatype(&self) -> bool {
875 matches!(self, Self::Enum(_) | Self::Struct(_))
876 }
877}
878
879impl Struct {
880 pub fn abilities(&self) -> impl Iterator<Item = &Ability> {
881 use StructKind as K;
882 match &self.kind {
883 K::Braced(braced) => braced
884 .abilities
885 .iter()
886 .flat_map(|a| a.keywords.iter())
887 .map(|d| &d.value)
888 .boxed(),
889 K::Tuple(tuple) => tuple
890 .abilities
891 .iter()
892 .flat_map(|a| a.first.keywords.iter())
893 .map(|d| &d.value)
894 .boxed(),
895 }
896 }
897}
898
899impl BracedStruct {
900 pub fn fields(&self) -> impl Iterator<Item = &NamedField> + Clone + '_ {
901 self.fields.fields()
902 }
903
904 pub fn is_empty(&self) -> bool {
906 self.fields.is_empty()
907 }
908}
909
910impl TupleStruct {
911 pub fn fields(&self) -> impl Iterator<Item = &UnnamedField> + Clone + '_ {
912 self.fields.fields()
913 }
914
915 pub fn is_empty(&self) -> bool {
917 self.fields.is_empty()
918 }
919}
920
921impl Enum {
922 pub fn abilities(&self) -> impl Iterator<Item = &Ability> {
923 self.abilities
924 .iter()
925 .flat_map(|a| a.keywords.iter())
926 .map(|d| &d.value)
927 }
928
929 pub fn variants(&self) -> impl Iterator<Item = &EnumVariant> {
930 self.content
931 .content
932 .iter()
933 .map(|Delimited { value, .. }| value)
934 }
935}
936
937impl NamedFields {
938 pub fn fields(&self) -> impl Iterator<Item = &NamedField> + Clone + '_ {
939 self.0.content.iter().map(|d| &d.value)
940 }
941
942 pub fn is_empty(&self) -> bool {
943 self.0.content.is_empty()
944 }
945}
946
947impl PositionalFields {
948 pub fn new() -> Self {
949 Self(ParenthesisGroupContaining {
950 content: std::iter::empty::<UnnamedField>()
951 .collect::<DelimitedVec<_, _, TrailingDelimiter::Mandatory>>()
952 .into(),
953 })
954 }
955
956 pub fn fields(&self) -> impl Iterator<Item = &UnnamedField> + Clone + '_ {
957 self.0.content.iter().map(|d| &d.value)
958 }
959
960 pub fn is_empty(&self) -> bool {
961 self.0.content.is_empty()
962 }
963}
964
965impl Default for PositionalFields {
966 fn default() -> Self {
967 Self::new()
968 }
969}
970
971impl Type {
972 fn resolve(&mut self, imports: &HashMap<Ident, FlatImport>, generics: &[Ident]) {
974 use ItemPath as P;
975 self.map_types(|ty| ty.resolve(imports, generics));
977
978 let resolved = match &self.path {
982 P::Module {
983 module,
984 item: r#type,
985 ..
986 } => {
987 let Some(FlatImport::Module {
988 named_address,
989 module,
990 }) = imports.get(module)
991 else {
992 return;
993 };
994 P::Full {
995 named_address: named_address.clone(),
996 sep0: PathSep::default(),
997 module: module.clone(),
998 sep1: PathSep::default(),
999 item: r#type.clone(),
1000 }
1001 }
1002 P::Ident(ident) if !generics.contains(ident) => {
1003 let Some(FlatImport::Item {
1004 named_address,
1005 module,
1006 r#type,
1007 }) = imports.get(ident)
1008 else {
1009 return;
1010 };
1011 P::Full {
1012 named_address: named_address.clone(),
1013 sep0: PathSep::default(),
1014 module: module.clone(),
1015 sep1: PathSep::default(),
1016 item: r#type.clone(),
1017 }
1018 }
1019 _ => return,
1021 };
1022 self.path = resolved;
1023 }
1024}
1025
1026impl TypeArgs {
1027 pub fn types(&self) -> impl Iterator<Item = &Type> {
1029 self.args.iter().map(|args| &*args.value)
1030 }
1031}
1032
1033impl Generics {
1034 pub fn generics(&self) -> impl Iterator<Item = &Generic> + '_ {
1035 self.type_args.iter().map(|d| &d.value)
1036 }
1037}
1038
1039impl MaybeRefType {
1040 pub fn is_ref(&self) -> bool {
1042 self.r#ref.as_ref().is_some_and(|r| r.r#mut.is_none())
1043 }
1044
1045 pub const fn type_(&self) -> &Type {
1047 &self.r#type
1048 }
1049}
1050
1051#[cfg_attr(test, derive(derive_more::Display))]
1054pub enum FlatImport {
1055 #[cfg_attr(test, display("{named_address}::{module}"))]
1056 Module { named_address: Ident, module: Ident },
1057 #[cfg_attr(test, display("{named_address}::{module}::{type}"))]
1058 Item {
1059 named_address: Ident,
1060 module: Ident,
1061 r#type: Ident,
1062 },
1063}
1064
1065trait IteratorBoxed<'a>: Iterator + 'a {
1069 fn boxed(self) -> Box<dyn Iterator<Item = Self::Item> + 'a>
1070 where
1071 Self: Sized,
1072 {
1073 Box::new(self)
1074 }
1075}
1076
1077impl<'a, T> IteratorBoxed<'a> for T where T: Iterator + 'a {}
1078
1079trait HasGenerics {
1081 fn generics(&self) -> Option<&Generics>;
1082
1083 fn type_param_idents(&self) -> Vec<Ident> {
1085 self.generics()
1086 .iter()
1087 .flat_map(|generics| generics.generics())
1088 .map(|generic| generic.ident.clone())
1089 .collect()
1090 }
1091}
1092
1093impl HasGenerics for Enum {
1094 fn generics(&self) -> Option<&Generics> {
1095 self.generics.as_ref()
1096 }
1097}
1098
1099impl HasGenerics for Struct {
1100 fn generics(&self) -> Option<&Generics> {
1101 self.generics.as_ref()
1102 }
1103}
1104
1105trait Typed {
1107 fn map_types(&mut self, f: impl FnMut(&mut Type));
1109}
1110
1111impl Typed for Enum {
1112 fn map_types(&mut self, mut f: impl FnMut(&mut Type)) {
1113 mutate_delimited_vec(&mut self.content.content, |variant| {
1114 variant.map_types(&mut f)
1115 });
1116 }
1117}
1118
1119impl Typed for EnumVariant {
1120 fn map_types(&mut self, f: impl FnMut(&mut Type)) {
1121 let Some(fields) = &mut self.fields else {
1122 return;
1123 };
1124 fields.map_types(f);
1125 }
1126}
1127
1128impl Typed for Struct {
1129 fn map_types(&mut self, f: impl FnMut(&mut Type)) {
1130 match &mut self.kind {
1131 StructKind::Braced(braced_struct) => braced_struct.fields.map_types(f),
1132 StructKind::Tuple(tuple_struct) => tuple_struct.fields.map_types(f),
1133 }
1134 }
1135}
1136
1137impl Typed for FieldsKind {
1138 fn map_types(&mut self, f: impl FnMut(&mut Type)) {
1139 match self {
1140 Self::Named(named) => named.map_types(f),
1141 Self::Positional(positional) => positional.map_types(f),
1142 }
1143 }
1144}
1145
1146impl Typed for NamedFields {
1147 fn map_types(&mut self, mut f: impl FnMut(&mut Type)) {
1148 mutate_delimited_vec(&mut self.0.content, |field| f(&mut field.ty));
1149 }
1150}
1151
1152impl Typed for PositionalFields {
1153 fn map_types(&mut self, mut f: impl FnMut(&mut Type)) {
1154 mutate_delimited_vec(&mut self.0.content, |field| f(&mut field.ty));
1155 }
1156}
1157
1158impl Typed for Type {
1159 fn map_types(&mut self, mut f: impl FnMut(&mut Self)) {
1160 if let Some(args) = &mut self.type_args {
1161 mutate_delimited_vec(&mut args.args, |t| f(&mut *t))
1162 }
1163 }
1164}
1165
1166fn mutate_delimited_vec<T, D: Default, const MIN: usize, const MAX: usize>(
1169 dvec: &mut DelimitedVec<T, D, TrailingDelimiter::Optional, MIN, MAX>,
1170 mut f: impl FnMut(&mut T),
1171) {
1172 type ForbiddenDelimited<T, D, const MIN: usize, const MAX: usize> =
1173 DelimitedVec<T, D, TrailingDelimiter::Forbidden, MIN, MAX>;
1174
1175 let temp: ForbiddenDelimited<T, D, MIN, MAX> = std::iter::empty::<T>().collect();
1176 let mut swapped = std::mem::replace(dvec, temp.into());
1177 swapped = swapped
1178 .into_iter()
1179 .map(|mut d| {
1180 f(&mut d.value);
1181 d.value
1182 })
1183 .collect::<ForbiddenDelimited<T, D, MIN, MAX>>()
1184 .into();
1185 *dvec = swapped;
1186}