1#![cfg_attr(all(doc, not(doctest)), 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<AttributeContent>,
126 }
127
128 #[derive(Clone)]
129 enum AttributeContent {
130 Doc(Cons<DocKw, Assign, LiteralString>),
131 Other(Vec<TokenTree>),
132 }
133
134 keyword DocKw = "doc";
135
136 #[derive(Clone)]
142 struct Vis {
143 public: kw::Public,
144 modifier: Option<ParenthesisGroupContaining<VisibilityModifier>>,
145 }
146
147 #[derive(Clone)]
153 enum VisibilityModifier {
154 Package(kw::Package),
155 Friend(kw::Friend)
156 }
157
158 #[non_exhaustive]
162 pub enum ItemKind {
163 Struct(Struct),
164 Enum(Enum),
165 Import(Import),
166 UseFun(UseFun),
167 Const(Const),
168 Function(Function),
169 MacroFun(MacroFun),
170 NativeFun(NativeFun)
171 }
172
173 pub struct UseFun {
175 keyword: kw::Use,
176 fun_kw: kw::Fun,
177 path_prefix: Option<Cons<Ident, PathSep, Ident, PathSep>>,
178 fun: Ident,
179 as_kw: kw::As,
180 ty: Ident,
181 dot: Dot,
182 method: Ident,
183 semicolon: Semicolon,
184 }
185
186 pub struct Const {
189 const_kw: kw::Const,
190 ident: Ident,
191 colon: Colon,
192 ty: Type,
193 assign: Assign,
194 expr: ConstVal,
195 semicolon: Semicolon,
196 }
197
198 enum ConstVal {
199 Literal(Literal),
200 Vector(Cons<kw::Vector, BracketGroup>),
201 NamedAddress(Cons<At, Literal>),
202 Expr(Vec<Cons<Except<Semicolon>, TokenTree>>),
204 }
205
206 pub struct Import {
209 keyword: kw::Use,
210 named_address: Ident,
211 path_sep: PathSep,
212 module: ImportModule,
213 semicolon: Semicolon,
214 }
215
216 enum ImportModule {
218 One(ModuleOrItems),
219 Many(BraceGroupContaining<CommaDelimitedVec<ModuleOrItems>>),
220 }
221
222 #[derive(Clone)]
223 struct ModuleOrItems {
224 ident: Ident,
225 next: Option<AliasOrItems>,
226 }
227
228 #[derive(Clone)]
229 enum AliasOrItems {
230 Alias {
231 as_kw: kw::As,
232 alias: Ident,
233 },
234 Items {
235 sep: PathSep,
236 item: ImportItem,
237 }
238 }
239
240 #[derive(Clone)]
241 enum ImportItem {
242 One(MaybeAliased),
243 Many(BraceGroupContaining<CommaDelimitedVec<MaybeAliased>>)
244 }
245
246 #[derive(Clone)]
247 struct MaybeAliased {
248 ident: Ident,
249 alias: Option<Cons<kw::As, Ident>>,
250 }
251
252 #[derive(Clone)]
256 pub struct Struct {
257 keyword: kw::Struct,
258 pub ident: Ident,
259 pub generics: Option<Generics>,
260 pub kind: StructKind,
261 }
262
263 #[derive(Clone)]
265 pub enum StructKind {
266 Braced(BracedStruct),
267 Tuple(TupleStruct),
268 }
269
270 #[derive(Clone)]
272 pub struct BracedStruct {
273 abilities: Option<Abilities>,
274 pub fields: NamedFields,
275 }
276
277 #[derive(Clone)]
280 pub struct TupleStruct {
281 pub fields: PositionalFields,
282 abilities: Option<Cons<Abilities, Semicolon>>
283 }
284
285 #[derive(Clone)]
288 pub struct Enum {
289 keyword: kw::Enum,
290 pub ident: Ident,
291 pub generics: Option<Generics>,
292 abilities: Option<Abilities>,
293 content: BraceGroupContaining<CommaDelimitedVec<EnumVariant>>,
294 }
295
296 #[derive(Clone)]
297 pub struct EnumVariant {
298 pub attrs: Vec<Attribute>,
299 pub ident: Ident,
300 pub fields: Option<FieldsKind>
302 }
303
304 #[derive(Clone)]
306 pub enum FieldsKind {
307 Positional(PositionalFields),
308 Named(NamedFields),
309 }
310
311 #[derive(Clone)]
315 pub struct PositionalFields(ParenthesisGroupContaining<DelimitedVec<UnnamedField, Comma>>);
316
317 #[derive(Clone)]
319 pub struct NamedFields(BraceGroupContaining<DelimitedVec<NamedField, Comma>>);
320
321 #[derive(Clone)]
323 pub struct NamedField {
324 pub attrs: Vec<Attribute>,
325 pub ident: Ident,
326 colon: Colon,
327 pub ty: Type,
328 }
329
330 #[derive(Clone)]
332 pub struct UnnamedField {
333 pub attrs: Vec<Attribute>,
334 pub ty: Type,
335 }
336
337 #[derive(Clone)]
344 pub struct Generics {
345 lt_token: Lt,
346 type_args: DelimitedVec<Generic, Comma>,
347 gt_token: Gt,
348 }
349
350 #[derive(Clone)]
358 pub struct Generic {
359 pub phantom: Option<kw::Phantom>,
360 pub ident: Ident,
361 bounds: Option<GenericBounds>
362 }
363
364 #[derive(Clone)]
368 struct GenericBounds {
369 colon: Colon,
370 first_ability: Ability,
371 extra_abilities: Vec<Cons<Plus, Ability>>
372 }
373
374 #[derive(Clone)]
380 struct Abilities {
381 has: kw::Has,
382 keywords: Many<Ability, Comma>,
383 }
384
385 #[derive(Clone)]
387 pub enum Ability {
388 Copy(kw::Copy),
389 Drop(kw::Drop),
390 Key(kw::Key),
391 Store(kw::Store),
392 }
393
394 pub struct NativeFun {
397 native_kw: kw::Native,
398 fun_kw: kw::Fun,
399 ident: Ident,
400 generics: Option<Generics>,
401 args: ParenthesisGroup,
402 ret: Option<Cons<Colon, Either<MaybeRefType, ParenthesisGroup>>>,
403 semicolon: Semicolon
404 }
405
406 pub struct MacroFun {
409 macro_kw: kw::Macro,
410 fun_kw: kw::Fun,
411 ident: Ident,
412 generics: Option<MacroGenerics>,
413 args: ParenthesisGroup,
414 ret: Option<Cons<Colon, Either<MacroReturn, ParenthesisGroup>>>,
415 body: BraceGroup,
416 }
417
418 struct MacroGenerics {
419 lt_token: Lt,
420 type_args: DelimitedVec<MacroTypeArg, Comma>,
421 gt_token: Gt,
422 }
423
424 struct MacroTypeArg{
426 name: MacroTypeName,
427 bounds: Option<GenericBounds>,
428 }
429
430 enum MacroReturn {
432 Underscore(Underscore),
433 Concrete(Cons<Option<Ref>, MacroReturnType>),
434 }
435
436 enum MacroReturnType {
443 MacroTypeName(MacroTypeName),
444 Hybrid(HybridMacroType)
445 }
446
447 struct HybridMacroType {
448 ident: Ident,
449 type_args: Option<Cons<Lt, Many<Either<Type, MacroTypeName, Box<HybridMacroType>>, Comma>, Gt>>
450 }
451
452 struct MacroTypeName {
454 dollar: Dollar,
455 ident: Ident,
456 }
457
458 struct MaybeRefType {
462 r#ref: Option<Ref>,
463 r#type: Type,
464 }
465
466 struct Ref {
468 and: And,
469 r#mut: Option<kw::Mut>,
470 }
471
472 #[derive(Clone)]
474 pub struct Type {
475 pub path: TypePath,
476 pub type_args: Option<TypeArgs>
477 }
478
479 #[derive(Clone)]
481 pub enum TypePath {
482 Full {
484 named_address: Ident,
485 sep0: PathSep,
486 module: Ident,
487 sep1: PathSep,
488 r#type: Ident,
489 },
490 Module {
492 module: Ident,
493 sep: PathSep,
494 r#type: Ident,
495 },
496 Ident(Ident),
498 }
499
500 #[derive(Clone)]
502 pub struct TypeArgs {
503 lt: Lt,
504 args: Many<Box<Type>, Comma>,
505 gt: Gt,
506 }
507}
508
509impl File {
510 pub fn into_modules(self) -> impl Iterator<Item = Module> {
511 match self {
512 Self::ModuleLabel(labeled) => std::iter::once(labeled.into_module()).boxed(),
513 Self::Legacy(modules) => modules.into_iter().boxed(),
514 }
515 }
516}
517
518impl LabeledModule {
519 pub fn into_module(self) -> Module {
520 Module {
521 attrs: self.attrs,
522 keyword: self.keyword,
523 named_address: self.named_address,
524 path_sep: self.path_sep,
525 ident: self.ident,
526 contents: BraceGroupContaining {
527 content: self.contents,
528 },
529 }
530 }
531}
532
533impl Module {
534 pub fn with_implicit_sui_imports(&mut self) -> &mut Self {
538 let implicit_imports: HashMap<_, _> = [
540 "use sui::object;",
541 "use sui::object::ID;",
542 "use sui::object::UID;",
543 "use sui::tx_context;",
544 "use sui::tx_context::TxContext;",
545 "use sui::transfer;",
546 ]
547 .into_iter()
548 .map(|text| {
549 text.to_token_iter()
550 .parse_all::<Import>()
551 .expect("Valid imports")
552 })
553 .map(|import| {
554 let ident = import
555 .imported_idents()
556 .next()
557 .expect("Each import exposes exactly one ident");
558 (ident.clone(), import)
559 })
560 .collect();
561
562 self.add_implicit_imports(implicit_imports)
563 }
564
565 pub fn with_implicit_iota_imports(&mut self) -> &mut Self {
569 let implicit_imports: HashMap<_, _> = [
571 "use iota::object;",
572 "use iota::object::ID;",
573 "use iota::object::UID;",
574 "use iota::tx_context;",
575 "use iota::tx_context::TxContext;",
576 "use iota::transfer;",
577 ]
578 .into_iter()
579 .map(|text| {
580 text.to_token_iter()
581 .parse_all::<Import>()
582 .expect("Valid imports")
583 })
584 .map(|import| {
585 let ident = import
586 .imported_idents()
587 .next()
588 .expect("Each import exposes exactly one ident");
589 (ident.clone(), import)
590 })
591 .collect();
592
593 self.add_implicit_imports(implicit_imports)
594 }
595
596 pub fn fully_qualify_datatype_field_types(&mut self) -> &mut Self {
598 let imports: HashMap<_, _> = self
600 .items()
601 .filter_map(|item| match &item.kind {
602 ItemKind::Import(import) => Some(import),
603 _ => None,
604 })
605 .flat_map(|import| import.flatten())
606 .collect();
607
608 for item in &mut self.contents.content {
610 match &mut item.kind {
611 ItemKind::Enum(e) => {
612 let generics = &e.generics();
613 e.map_types(|ty| ty.resolve(&imports, generics));
614 }
615 ItemKind::Struct(s) => {
616 let generics = &s.generics();
617 s.map_types(|ty| ty.resolve(&imports, generics));
618 }
619 _ => (),
620 }
621 }
622
623 self
624 }
625
626 pub fn items(&self) -> impl Iterator<Item = &Item> {
627 self.contents.content.iter()
628 }
629
630 #[cfg(test)]
631 pub fn into_items(self) -> impl Iterator<Item = Item> {
632 self.contents.content.into_iter()
633 }
634
635 fn add_implicit_imports(&mut self, mut implicit_imports: HashMap<Ident, Import>) -> &mut Self {
636 for item in self.items() {
638 let ItemKind::Import(import) = &item.kind else {
639 continue;
640 };
641 for ident in import.imported_idents() {
642 implicit_imports.remove(ident);
643 }
644 }
645
646 for (_, import) in implicit_imports {
648 self.contents.content.push(Item {
649 attrs: vec![],
650 vis: None,
651 kind: ItemKind::Import(import),
652 })
653 }
654 self
655 }
656}
657
658impl Import {
659 fn flatten(&self) -> impl Iterator<Item = (Ident, FlatImport)> + '_ {
662 let named_address = self.named_address.clone();
663 match &self.module {
664 ImportModule::One(module_or_items) => module_or_items.flatten(named_address),
666 ImportModule::Many(BraceGroupContaining { content: ms }) => ms
668 .iter()
669 .flat_map(move |Delimited { value, .. }| value.flatten(named_address.clone()))
670 .boxed(),
671 }
672 }
673
674 fn imported_idents(&self) -> impl Iterator<Item = &Ident> {
676 match &self.module {
677 ImportModule::One(module_or_items) => module_or_items.available_idents(),
678 ImportModule::Many(BraceGroupContaining { content: ms }) => ms
679 .iter()
680 .flat_map(|delimited| delimited.value.available_idents())
681 .boxed(),
682 }
683 }
684}
685
686impl ModuleOrItems {
687 fn flatten(&self, named_address: Ident) -> Box<dyn Iterator<Item = (Ident, FlatImport)> + '_> {
689 let module = self.ident.clone();
690
691 let Some(next) = &self.next else {
692 return std::iter::once((
694 module.clone(),
695 FlatImport::Module {
696 named_address,
697 module,
698 },
699 ))
700 .boxed();
701 };
702
703 match next {
704 AliasOrItems::Alias { alias, .. } => std::iter::once((
706 alias.clone(),
707 FlatImport::Module {
708 named_address,
709 module,
710 },
711 ))
712 .boxed(),
713
714 AliasOrItems::Items {
716 item: ImportItem::One(maybe_aliased),
717 ..
718 } => std::iter::once(maybe_aliased.flat_import(named_address, module)).boxed(),
719
720 AliasOrItems::Items {
722 item: ImportItem::Many(BraceGroupContaining { content: items }),
723 ..
724 } => items
725 .iter()
726 .map(move |Delimited { value, .. }| {
727 value.flat_import(named_address.clone(), module.clone())
728 })
729 .boxed(),
730 }
731 }
732
733 fn available_idents(&self) -> Box<dyn Iterator<Item = &Ident> + '_> {
735 let Some(next) = &self.next else {
736 return std::iter::once(&self.ident).boxed();
737 };
738
739 match next {
740 AliasOrItems::Alias { alias, .. } => std::iter::once(alias).boxed(),
741
742 AliasOrItems::Items {
743 item: ImportItem::One(item),
744 ..
745 } => std::iter::once(item.available_ident(&self.ident)).boxed(),
746
747 AliasOrItems::Items {
748 item: ImportItem::Many(BraceGroupContaining { content: items }),
749 ..
750 } => items
751 .iter()
752 .map(|delimited| delimited.value.available_ident(&self.ident))
753 .boxed(),
754 }
755 }
756}
757
758impl MaybeAliased {
759 fn flat_import(&self, named_address: Ident, module: Ident) -> (Ident, FlatImport) {
761 if self.ident == "Self" {
762 (
763 self.alias().unwrap_or(&module).clone(),
764 FlatImport::Module {
765 named_address,
766 module,
767 },
768 )
769 } else {
770 (
771 self.alias().unwrap_or(&self.ident).clone(),
772 FlatImport::Item {
773 named_address,
774 module,
775 r#type: self.ident.clone(),
776 },
777 )
778 }
779 }
780
781 fn available_ident<'a>(&'a self, module: &'a Ident) -> &'a Ident {
782 if self.ident == "Self" {
783 self.alias().unwrap_or(module)
784 } else {
785 self.alias().unwrap_or(&self.ident)
786 }
787 }
788
789 fn alias(&self) -> Option<&Ident> {
791 self.alias.as_ref().map(|cons| &cons.second)
792 }
793}
794
795impl Attribute {
796 pub const fn is_doc(&self) -> bool {
798 matches!(self.contents.content, AttributeContent::Doc(_))
799 }
800
801 pub const fn contents(&self) -> &impl ToTokens {
803 &self.contents.content
804 }
805}
806
807impl ItemKind {
808 pub const fn is_datatype(&self) -> bool {
810 matches!(self, Self::Enum(_) | Self::Struct(_))
811 }
812}
813
814impl Struct {
815 pub fn abilities(&self) -> impl Iterator<Item = &Ability> {
816 use StructKind as K;
817 match &self.kind {
818 K::Braced(braced) => braced
819 .abilities
820 .iter()
821 .flat_map(|a| a.keywords.iter())
822 .map(|d| &d.value)
823 .boxed(),
824 K::Tuple(tuple) => tuple
825 .abilities
826 .iter()
827 .flat_map(|a| a.first.keywords.iter())
828 .map(|d| &d.value)
829 .boxed(),
830 }
831 }
832}
833
834impl BracedStruct {
835 pub fn fields(&self) -> impl Iterator<Item = &NamedField> + Clone + '_ {
836 self.fields.fields()
837 }
838
839 pub fn is_empty(&self) -> bool {
841 self.fields.is_empty()
842 }
843}
844
845impl TupleStruct {
846 pub fn fields(&self) -> impl Iterator<Item = &UnnamedField> + Clone + '_ {
847 self.fields.fields()
848 }
849
850 pub fn is_empty(&self) -> bool {
852 self.fields.is_empty()
853 }
854}
855
856impl Enum {
857 pub fn abilities(&self) -> impl Iterator<Item = &Ability> {
858 self.abilities
859 .iter()
860 .flat_map(|a| a.keywords.iter())
861 .map(|d| &d.value)
862 }
863
864 pub fn variants(&self) -> impl Iterator<Item = &EnumVariant> {
865 self.content
866 .content
867 .iter()
868 .map(|Delimited { value, .. }| value)
869 }
870}
871
872impl NamedFields {
873 pub fn fields(&self) -> impl Iterator<Item = &NamedField> + Clone + '_ {
874 self.0.content.iter().map(|d| &d.value)
875 }
876
877 pub fn is_empty(&self) -> bool {
878 self.0.content.is_empty()
879 }
880}
881
882impl PositionalFields {
883 pub fn new() -> Self {
884 Self(ParenthesisGroupContaining {
885 content: std::iter::empty::<UnnamedField>()
886 .collect::<DelimitedVec<_, _, TrailingDelimiter::Mandatory>>()
887 .into(),
888 })
889 }
890
891 pub fn fields(&self) -> impl Iterator<Item = &UnnamedField> + Clone + '_ {
892 self.0.content.iter().map(|d| &d.value)
893 }
894
895 pub fn is_empty(&self) -> bool {
896 self.0.content.is_empty()
897 }
898}
899
900impl Default for PositionalFields {
901 fn default() -> Self {
902 Self::new()
903 }
904}
905
906impl Type {
907 fn resolve(&mut self, imports: &HashMap<Ident, FlatImport>, generics: &[Ident]) {
909 use TypePath as P;
910 self.map_types(|ty| ty.resolve(imports, generics));
912
913 let resolved = match &self.path {
917 P::Module { module, r#type, .. } => {
918 let Some(FlatImport::Module {
919 named_address,
920 module,
921 }) = imports.get(module)
922 else {
923 return;
924 };
925 P::Full {
926 named_address: named_address.clone(),
927 sep0: PathSep::default(),
928 module: module.clone(),
929 sep1: PathSep::default(),
930 r#type: r#type.clone(),
931 }
932 }
933 P::Ident(ident) if !generics.contains(ident) => {
934 let Some(FlatImport::Item {
935 named_address,
936 module,
937 r#type,
938 }) = imports.get(ident)
939 else {
940 return;
941 };
942 P::Full {
943 named_address: named_address.clone(),
944 sep0: PathSep::default(),
945 module: module.clone(),
946 sep1: PathSep::default(),
947 r#type: r#type.clone(),
948 }
949 }
950 _ => return,
952 };
953 self.path = resolved;
954 }
955}
956
957impl TypeArgs {
958 pub fn types(&self) -> impl Iterator<Item = &Type> {
960 self.args.iter().map(|args| &*args.value)
961 }
962}
963
964impl Generics {
965 pub fn generics(&self) -> impl Iterator<Item = &Generic> + '_ {
966 self.type_args.iter().map(|d| &d.value)
967 }
968}
969
970#[cfg_attr(test, derive(derive_more::Display))]
973enum FlatImport {
974 #[cfg_attr(test, display("{named_address}::{module}"))]
975 Module { named_address: Ident, module: Ident },
976 #[cfg_attr(test, display("{named_address}::{module}::{type}"))]
977 Item {
978 named_address: Ident,
979 module: Ident,
980 r#type: Ident,
981 },
982}
983
984trait IteratorBoxed<'a>: Iterator + 'a {
988 fn boxed(self) -> Box<dyn Iterator<Item = Self::Item> + 'a>
989 where
990 Self: Sized,
991 {
992 Box::new(self)
993 }
994}
995
996impl<'a, T> IteratorBoxed<'a> for T where T: Iterator + 'a {}
997
998trait Datatype {
1000 fn generics(&self) -> Vec<Ident>;
1001}
1002
1003impl Datatype for Enum {
1004 fn generics(&self) -> Vec<Ident> {
1005 self.generics
1006 .iter()
1007 .flat_map(|generics| generics.generics())
1008 .map(|generic| generic.ident.clone())
1009 .collect()
1010 }
1011}
1012
1013impl Datatype for Struct {
1014 fn generics(&self) -> Vec<Ident> {
1015 self.generics
1016 .iter()
1017 .flat_map(|generics| generics.generics())
1018 .map(|generic| generic.ident.clone())
1019 .collect()
1020 }
1021}
1022
1023trait Typed {
1025 fn map_types(&mut self, f: impl FnMut(&mut Type));
1027}
1028
1029impl Typed for Enum {
1030 fn map_types(&mut self, mut f: impl FnMut(&mut Type)) {
1031 mutate_delimited_vec(&mut self.content.content, |variant| {
1032 variant.map_types(&mut f)
1033 });
1034 }
1035}
1036
1037impl Typed for EnumVariant {
1038 fn map_types(&mut self, f: impl FnMut(&mut Type)) {
1039 let Some(fields) = &mut self.fields else {
1040 return;
1041 };
1042 fields.map_types(f);
1043 }
1044}
1045
1046impl Typed for Struct {
1047 fn map_types(&mut self, f: impl FnMut(&mut Type)) {
1048 match &mut self.kind {
1049 StructKind::Braced(braced_struct) => braced_struct.fields.map_types(f),
1050 StructKind::Tuple(tuple_struct) => tuple_struct.fields.map_types(f),
1051 }
1052 }
1053}
1054
1055impl Typed for FieldsKind {
1056 fn map_types(&mut self, f: impl FnMut(&mut Type)) {
1057 match self {
1058 Self::Named(named) => named.map_types(f),
1059 Self::Positional(positional) => positional.map_types(f),
1060 }
1061 }
1062}
1063
1064impl Typed for NamedFields {
1065 fn map_types(&mut self, mut f: impl FnMut(&mut Type)) {
1066 mutate_delimited_vec(&mut self.0.content, |field| f(&mut field.ty));
1067 }
1068}
1069
1070impl Typed for PositionalFields {
1071 fn map_types(&mut self, mut f: impl FnMut(&mut Type)) {
1072 mutate_delimited_vec(&mut self.0.content, |field| f(&mut field.ty));
1073 }
1074}
1075
1076impl Typed for Type {
1077 fn map_types(&mut self, mut f: impl FnMut(&mut Self)) {
1078 if let Some(args) = &mut self.type_args {
1079 mutate_delimited_vec(&mut args.args, |t| f(&mut *t))
1080 }
1081 }
1082}
1083
1084fn mutate_delimited_vec<T, D: Default, const MIN: usize, const MAX: usize>(
1087 dvec: &mut DelimitedVec<T, D, TrailingDelimiter::Optional, MIN, MAX>,
1088 mut f: impl FnMut(&mut T),
1089) {
1090 type ForbiddenDelimited<T, D, const MIN: usize, const MAX: usize> =
1091 DelimitedVec<T, D, TrailingDelimiter::Forbidden, MIN, MAX>;
1092
1093 let temp: ForbiddenDelimited<T, D, MIN, MAX> = std::iter::empty::<T>().collect();
1094 let mut swapped = std::mem::replace(dvec, temp.into());
1095 swapped = swapped
1096 .into_iter()
1097 .map(|mut d| {
1098 f(&mut d.value);
1099 d.value
1100 })
1101 .collect::<ForbiddenDelimited<T, D, MIN, MAX>>()
1102 .into();
1103 *dvec = swapped;
1104}