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;
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 NativeFun {
437 native_kw: kw::Native,
438 fun_kw: kw::Fun,
439 ident: Ident,
440 generics: Option<Generics>,
441 args: ParenthesisGroup,
442 ret: Option<Cons<Colon, Either<MaybeRefType, ParenthesisGroup>>>,
443 semicolon: Semicolon
444 }
445
446 pub struct MacroFun {
449 macro_kw: kw::Macro,
450 fun_kw: kw::Fun,
451 ident: Ident,
452 generics: Option<MacroGenerics>,
453 args: ParenthesisGroup,
454 ret: Option<Cons<Colon, Either<MacroReturn, ParenthesisGroup>>>,
455 body: BraceGroup,
456 }
457
458 struct MacroGenerics {
459 lt_token: Lt,
460 type_args: DelimitedVec<MacroTypeArg, Comma>,
461 gt_token: Gt,
462 }
463
464 struct MacroTypeArg{
466 name: SyntaxIdent,
467 bounds: Option<GenericBounds>,
468 }
469
470 enum MacroReturn {
472 Underscore(Underscore),
473 Concrete(Cons<Option<Ref>, MacroReturnType>),
474 }
475
476 enum MacroReturnType {
483 MacroTypeName(SyntaxIdent),
484 Hybrid(HybridMacroType)
485 }
486
487 struct HybridMacroType {
488 ident: Ident,
489 type_args: Option<Cons<Lt, Many<Either<Type, SyntaxIdent, Box<HybridMacroType>>, Comma>, Gt>>
490 }
491
492 #[derive(Clone)]
497 struct SyntaxIdent {
498 dollar: Dollar,
499 ident: Ident,
500 }
501
502 struct MaybeRefType {
506 r#ref: Option<Ref>,
507 r#type: Type,
508 }
509
510 struct Ref {
512 and: And,
513 r#mut: Option<kw::Mut>,
514 }
515
516 #[derive(Clone)]
518 pub struct Type {
519 pub path: ItemPath,
520 pub type_args: Option<TypeArgs>
521 }
522
523 #[derive(Clone)]
525 pub enum ItemPath {
526 Full {
528 named_address: Ident,
529 sep0: PathSep,
530 module: Ident,
531 sep1: PathSep,
532 item: Ident,
533 },
534 Module {
536 module: Ident,
537 sep: PathSep,
538 item: Ident,
539 },
540 Ident(Ident),
542 }
543
544 #[derive(Clone)]
546 pub struct TypeArgs {
547 lt: Lt,
548 args: Many<Box<Type>, Comma>,
549 gt: Gt,
550 }
551}
552
553impl File {
554 pub fn into_modules(self) -> impl Iterator<Item = Module> {
555 match self {
556 Self::ModuleLabel(labeled) => std::iter::once(labeled.into_module()).boxed(),
557 Self::Legacy(modules) => modules.into_iter().boxed(),
558 }
559 }
560}
561
562impl LabeledModule {
563 pub fn into_module(self) -> Module {
564 Module {
565 attrs: self.attrs,
566 keyword: self.keyword,
567 named_address: self.named_address,
568 path_sep: self.path_sep,
569 ident: self.ident,
570 contents: BraceGroupContaining {
571 content: self.contents,
572 },
573 }
574 }
575}
576
577impl Module {
578 pub fn with_implicit_sui_imports(&mut self) -> &mut Self {
582 let implicit_imports: HashMap<_, _> = [
584 "use sui::object;",
585 "use sui::object::ID;",
586 "use sui::object::UID;",
587 "use sui::tx_context;",
588 "use sui::tx_context::TxContext;",
589 "use sui::transfer;",
590 ]
591 .into_iter()
592 .map(|text| {
593 text.to_token_iter()
594 .parse_all::<Import>()
595 .expect("Valid imports")
596 })
597 .map(|import| {
598 let ident = import
599 .imported_idents()
600 .next()
601 .expect("Each import exposes exactly one ident");
602 (ident.clone(), import)
603 })
604 .collect();
605
606 self.add_implicit_imports(implicit_imports)
607 }
608
609 pub fn with_implicit_iota_imports(&mut self) -> &mut Self {
613 let implicit_imports: HashMap<_, _> = [
615 "use iota::object;",
616 "use iota::object::ID;",
617 "use iota::object::UID;",
618 "use iota::tx_context;",
619 "use iota::tx_context::TxContext;",
620 "use iota::transfer;",
621 ]
622 .into_iter()
623 .map(|text| {
624 text.to_token_iter()
625 .parse_all::<Import>()
626 .expect("Valid imports")
627 })
628 .map(|import| {
629 let ident = import
630 .imported_idents()
631 .next()
632 .expect("Each import exposes exactly one ident");
633 (ident.clone(), import)
634 })
635 .collect();
636
637 self.add_implicit_imports(implicit_imports)
638 }
639
640 pub fn fully_qualify_datatype_field_types(&mut self) -> &mut Self {
642 let imports: HashMap<_, _> = self
644 .items()
645 .filter_map(|item| match &item.kind {
646 ItemKind::Import(import) => Some(import),
647 _ => None,
648 })
649 .flat_map(|import| import.flatten())
650 .collect();
651
652 for item in &mut self.contents.content {
654 match &mut item.kind {
655 ItemKind::Enum(e) => {
656 let generics = &e.generics();
657 e.map_types(|ty| ty.resolve(&imports, generics));
658 }
659 ItemKind::Struct(s) => {
660 let generics = &s.generics();
661 s.map_types(|ty| ty.resolve(&imports, generics));
662 }
663 _ => (),
664 }
665 }
666
667 self
668 }
669
670 pub fn items(&self) -> impl Iterator<Item = &Item> {
671 self.contents.content.iter()
672 }
673
674 #[cfg(test)]
675 pub fn into_items(self) -> impl Iterator<Item = Item> {
676 self.contents.content.into_iter()
677 }
678
679 fn add_implicit_imports(&mut self, mut implicit_imports: HashMap<Ident, Import>) -> &mut Self {
680 for item in self.items() {
682 let ItemKind::Import(import) = &item.kind else {
683 continue;
684 };
685 for ident in import.imported_idents() {
686 implicit_imports.remove(ident);
687 }
688 }
689
690 for (_, import) in implicit_imports {
692 self.contents.content.push(Item {
693 attrs: vec![],
694 vis: None,
695 kind: ItemKind::Import(import),
696 })
697 }
698 self
699 }
700}
701
702impl Import {
703 pub fn flatten(&self) -> impl Iterator<Item = (Ident, FlatImport)> + '_ {
706 let named_address = self.named_address.clone();
707 match &self.module {
708 ImportModule::One(module_or_items) => module_or_items.flatten(named_address),
710 ImportModule::Many(BraceGroupContaining { content: ms }) => ms
712 .iter()
713 .flat_map(move |Delimited { value, .. }| value.flatten(named_address.clone()))
714 .boxed(),
715 }
716 }
717
718 fn imported_idents(&self) -> impl Iterator<Item = &Ident> {
720 match &self.module {
721 ImportModule::One(module_or_items) => module_or_items.available_idents(),
722 ImportModule::Many(BraceGroupContaining { content: ms }) => ms
723 .iter()
724 .flat_map(|delimited| delimited.value.available_idents())
725 .boxed(),
726 }
727 }
728}
729
730impl ModuleOrItems {
731 fn flatten(&self, named_address: Ident) -> Box<dyn Iterator<Item = (Ident, FlatImport)> + '_> {
733 let module = self.ident.clone();
734
735 let Some(next) = &self.next else {
736 return std::iter::once((
738 module.clone(),
739 FlatImport::Module {
740 named_address,
741 module,
742 },
743 ))
744 .boxed();
745 };
746
747 match next {
748 AliasOrItems::Alias { alias, .. } => std::iter::once((
750 alias.clone(),
751 FlatImport::Module {
752 named_address,
753 module,
754 },
755 ))
756 .boxed(),
757
758 AliasOrItems::Items {
760 item: ImportItem::One(maybe_aliased),
761 ..
762 } => std::iter::once(maybe_aliased.flat_import(named_address, module)).boxed(),
763
764 AliasOrItems::Items {
766 item: ImportItem::Many(BraceGroupContaining { content: items }),
767 ..
768 } => items
769 .iter()
770 .map(move |Delimited { value, .. }| {
771 value.flat_import(named_address.clone(), module.clone())
772 })
773 .boxed(),
774 }
775 }
776
777 fn available_idents(&self) -> Box<dyn Iterator<Item = &Ident> + '_> {
779 let Some(next) = &self.next else {
780 return std::iter::once(&self.ident).boxed();
781 };
782
783 match next {
784 AliasOrItems::Alias { alias, .. } => std::iter::once(alias).boxed(),
785
786 AliasOrItems::Items {
787 item: ImportItem::One(item),
788 ..
789 } => std::iter::once(item.available_ident(&self.ident)).boxed(),
790
791 AliasOrItems::Items {
792 item: ImportItem::Many(BraceGroupContaining { content: items }),
793 ..
794 } => items
795 .iter()
796 .map(|delimited| delimited.value.available_ident(&self.ident))
797 .boxed(),
798 }
799 }
800}
801
802impl MaybeAliased {
803 fn flat_import(&self, named_address: Ident, module: Ident) -> (Ident, FlatImport) {
805 if self.ident == "Self" {
806 (
807 self.alias().unwrap_or(&module).clone(),
808 FlatImport::Module {
809 named_address,
810 module,
811 },
812 )
813 } else {
814 (
815 self.alias().unwrap_or(&self.ident).clone(),
816 FlatImport::Item {
817 named_address,
818 module,
819 r#type: self.ident.clone(),
820 },
821 )
822 }
823 }
824
825 fn available_ident<'a>(&'a self, module: &'a Ident) -> &'a Ident {
826 if self.ident == "Self" {
827 self.alias().unwrap_or(module)
828 } else {
829 self.alias().unwrap_or(&self.ident)
830 }
831 }
832
833 fn alias(&self) -> Option<&Ident> {
835 self.alias.as_ref().map(|cons| &cons.second)
836 }
837}
838
839impl Attribute {
840 pub fn is_doc(&self) -> bool {
842 matches!(
843 &self.contents.content[..],
844 [Delimited {
845 value: Meta::Doc(_),
846 ..
847 }]
848 )
849 }
850
851 pub const fn contents(&self) -> &impl ToTokens {
853 &self.contents.content
854 }
855
856 pub fn metas(&self) -> impl Iterator<Item = &dyn ToTokens> + '_ {
857 self.contents
858 .content
859 .iter()
860 .map(|delimited| &delimited.value as _)
861 }
862
863 pub fn external_attributes(&self) -> impl Iterator<Item = &dyn ToTokens> + '_ {
865 self.contents.content.iter().filter_map(|d| match &d.value {
866 Meta::Other {
867 ident,
868 sub: Some(SubMeta::List(inner)),
869 } if ident == "ext" => Some(&inner.content as _),
870 _ => None,
871 })
872 }
873}
874
875impl ItemKind {
876 pub const fn is_datatype(&self) -> bool {
878 matches!(self, Self::Enum(_) | Self::Struct(_))
879 }
880}
881
882impl Struct {
883 pub fn abilities(&self) -> impl Iterator<Item = &Ability> {
884 use StructKind as K;
885 match &self.kind {
886 K::Braced(braced) => braced
887 .abilities
888 .iter()
889 .flat_map(|a| a.keywords.iter())
890 .map(|d| &d.value)
891 .boxed(),
892 K::Tuple(tuple) => tuple
893 .abilities
894 .iter()
895 .flat_map(|a| a.first.keywords.iter())
896 .map(|d| &d.value)
897 .boxed(),
898 }
899 }
900}
901
902impl BracedStruct {
903 pub fn fields(&self) -> impl Iterator<Item = &NamedField> + Clone + '_ {
904 self.fields.fields()
905 }
906
907 pub fn is_empty(&self) -> bool {
909 self.fields.is_empty()
910 }
911}
912
913impl TupleStruct {
914 pub fn fields(&self) -> impl Iterator<Item = &UnnamedField> + Clone + '_ {
915 self.fields.fields()
916 }
917
918 pub fn is_empty(&self) -> bool {
920 self.fields.is_empty()
921 }
922}
923
924impl Enum {
925 pub fn abilities(&self) -> impl Iterator<Item = &Ability> {
926 self.abilities
927 .iter()
928 .flat_map(|a| a.keywords.iter())
929 .map(|d| &d.value)
930 }
931
932 pub fn variants(&self) -> impl Iterator<Item = &EnumVariant> {
933 self.content
934 .content
935 .iter()
936 .map(|Delimited { value, .. }| value)
937 }
938}
939
940impl NamedFields {
941 pub fn fields(&self) -> impl Iterator<Item = &NamedField> + Clone + '_ {
942 self.0.content.iter().map(|d| &d.value)
943 }
944
945 pub fn is_empty(&self) -> bool {
946 self.0.content.is_empty()
947 }
948}
949
950impl PositionalFields {
951 pub fn new() -> Self {
952 Self(ParenthesisGroupContaining {
953 content: std::iter::empty::<UnnamedField>()
954 .collect::<DelimitedVec<_, _, TrailingDelimiter::Mandatory>>()
955 .into(),
956 })
957 }
958
959 pub fn fields(&self) -> impl Iterator<Item = &UnnamedField> + Clone + '_ {
960 self.0.content.iter().map(|d| &d.value)
961 }
962
963 pub fn is_empty(&self) -> bool {
964 self.0.content.is_empty()
965 }
966}
967
968impl Default for PositionalFields {
969 fn default() -> Self {
970 Self::new()
971 }
972}
973
974impl Type {
975 fn resolve(&mut self, imports: &HashMap<Ident, FlatImport>, generics: &[Ident]) {
977 use ItemPath as P;
978 self.map_types(|ty| ty.resolve(imports, generics));
980
981 let resolved = match &self.path {
985 P::Module {
986 module,
987 item: r#type,
988 ..
989 } => {
990 let Some(FlatImport::Module {
991 named_address,
992 module,
993 }) = imports.get(module)
994 else {
995 return;
996 };
997 P::Full {
998 named_address: named_address.clone(),
999 sep0: PathSep::default(),
1000 module: module.clone(),
1001 sep1: PathSep::default(),
1002 item: r#type.clone(),
1003 }
1004 }
1005 P::Ident(ident) if !generics.contains(ident) => {
1006 let Some(FlatImport::Item {
1007 named_address,
1008 module,
1009 r#type,
1010 }) = imports.get(ident)
1011 else {
1012 return;
1013 };
1014 P::Full {
1015 named_address: named_address.clone(),
1016 sep0: PathSep::default(),
1017 module: module.clone(),
1018 sep1: PathSep::default(),
1019 item: r#type.clone(),
1020 }
1021 }
1022 _ => return,
1024 };
1025 self.path = resolved;
1026 }
1027}
1028
1029impl TypeArgs {
1030 pub fn types(&self) -> impl Iterator<Item = &Type> {
1032 self.args.iter().map(|args| &*args.value)
1033 }
1034}
1035
1036impl Generics {
1037 pub fn generics(&self) -> impl Iterator<Item = &Generic> + '_ {
1038 self.type_args.iter().map(|d| &d.value)
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 Datatype {
1072 fn generics(&self) -> Vec<Ident>;
1073}
1074
1075impl Datatype for Enum {
1076 fn generics(&self) -> Vec<Ident> {
1077 self.generics
1078 .iter()
1079 .flat_map(|generics| generics.generics())
1080 .map(|generic| generic.ident.clone())
1081 .collect()
1082 }
1083}
1084
1085impl Datatype for Struct {
1086 fn generics(&self) -> Vec<Ident> {
1087 self.generics
1088 .iter()
1089 .flat_map(|generics| generics.generics())
1090 .map(|generic| generic.ident.clone())
1091 .collect()
1092 }
1093}
1094
1095trait Typed {
1097 fn map_types(&mut self, f: impl FnMut(&mut Type));
1099}
1100
1101impl Typed for Enum {
1102 fn map_types(&mut self, mut f: impl FnMut(&mut Type)) {
1103 mutate_delimited_vec(&mut self.content.content, |variant| {
1104 variant.map_types(&mut f)
1105 });
1106 }
1107}
1108
1109impl Typed for EnumVariant {
1110 fn map_types(&mut self, f: impl FnMut(&mut Type)) {
1111 let Some(fields) = &mut self.fields else {
1112 return;
1113 };
1114 fields.map_types(f);
1115 }
1116}
1117
1118impl Typed for Struct {
1119 fn map_types(&mut self, f: impl FnMut(&mut Type)) {
1120 match &mut self.kind {
1121 StructKind::Braced(braced_struct) => braced_struct.fields.map_types(f),
1122 StructKind::Tuple(tuple_struct) => tuple_struct.fields.map_types(f),
1123 }
1124 }
1125}
1126
1127impl Typed for FieldsKind {
1128 fn map_types(&mut self, f: impl FnMut(&mut Type)) {
1129 match self {
1130 Self::Named(named) => named.map_types(f),
1131 Self::Positional(positional) => positional.map_types(f),
1132 }
1133 }
1134}
1135
1136impl Typed for NamedFields {
1137 fn map_types(&mut self, mut f: impl FnMut(&mut Type)) {
1138 mutate_delimited_vec(&mut self.0.content, |field| f(&mut field.ty));
1139 }
1140}
1141
1142impl Typed for PositionalFields {
1143 fn map_types(&mut self, mut f: impl FnMut(&mut Type)) {
1144 mutate_delimited_vec(&mut self.0.content, |field| f(&mut field.ty));
1145 }
1146}
1147
1148impl Typed for Type {
1149 fn map_types(&mut self, mut f: impl FnMut(&mut Self)) {
1150 if let Some(args) = &mut self.type_args {
1151 mutate_delimited_vec(&mut args.args, |t| f(&mut *t))
1152 }
1153 }
1154}
1155
1156fn mutate_delimited_vec<T, D: Default, const MIN: usize, const MAX: usize>(
1159 dvec: &mut DelimitedVec<T, D, TrailingDelimiter::Optional, MIN, MAX>,
1160 mut f: impl FnMut(&mut T),
1161) {
1162 type ForbiddenDelimited<T, D, const MIN: usize, const MAX: usize> =
1163 DelimitedVec<T, D, TrailingDelimiter::Forbidden, MIN, MAX>;
1164
1165 let temp: ForbiddenDelimited<T, D, MIN, MAX> = std::iter::empty::<T>().collect();
1166 let mut swapped = std::mem::replace(dvec, temp.into());
1167 swapped = swapped
1168 .into_iter()
1169 .map(|mut d| {
1170 f(&mut d.value);
1171 d.value
1172 })
1173 .collect::<ForbiddenDelimited<T, D, MIN, MAX>>()
1174 .into();
1175 *dvec = swapped;
1176}