1#![cfg_attr(all(doc, not(doctest)), feature(doc_auto_cfg))]
2
3use std::borrow::Cow;
6use std::collections::HashMap;
7
8pub use unsynn;
9use unsynn::*;
10
11#[cfg(test)]
12mod tests;
13
14pub fn sanitize_for_tokenizer(content: &str) -> String {
23 let regex = raw_ident_regex();
24 let mut lines = content.lines().map(|line| {
25 if !line.trim_start().starts_with("//") {
27 regex.replace(line, "$1")
28 } else {
29 Cow::Borrowed(line)
30 }
31 });
32 lines.next().map_or_else(String::new, |line| {
33 let mut sanitized = String::with_capacity(content.len());
34 sanitized.push_str(&line);
35 for line in lines {
36 sanitized.push('\n');
37 sanitized.push_str(&line);
38 }
39 sanitized
40 })
41}
42
43fn raw_ident_regex() -> regex::Regex {
44 regex::Regex::new("`([[:alnum:]_]+)`").expect("Valid regex")
45}
46
47pub mod kw {
48 use unsynn::*;
50
51 unsynn! {
52 pub keyword Struct = "struct";
53 pub keyword Phantom = "phantom";
54 pub keyword Public = "public";
55 pub keyword Has = "has";
56 pub keyword Copy = "copy";
57 pub keyword Drop = "drop";
58 pub keyword Key = "key";
59 pub keyword Store = "store";
60 pub keyword Module = "module";
61 pub keyword Package = "package";
62 pub keyword Friend = "friend";
63 pub keyword Use = "use";
64 pub keyword Fun = "fun";
65 pub keyword As = "as";
66 pub keyword Const = "const";
67 pub keyword Mut = "mut";
68 pub keyword Entry = "entry";
69 pub keyword Native = "native";
70 pub keyword Macro = "macro";
71 pub keyword Vector = "vector";
72 pub keyword Enum = "enum";
73 }
74}
75
76unsynn! {
77 pub enum File {
78 ModuleLabel(LabeledModule),
80 Legacy(Vec<Module>),
82 }
83
84 pub struct LabeledModule {
88 attrs: Vec<Attribute>,
89 keyword: kw::Module,
90 named_address: Ident,
91 path_sep: PathSep,
92 ident: Ident,
93 semicolon: Semicolon,
94 contents: Vec<Item>,
95 }
96
97 pub struct Module {
99 pub attrs: Vec<Attribute>,
100 keyword: kw::Module,
101 pub named_address: Ident,
102 path_sep: PathSep,
103 pub ident: Ident,
104 contents: BraceGroupContaining<Vec<Item>>,
105 }
106
107 pub struct Item {
109 pub attrs: Vec<Attribute>,
110 vis: Option<Visibility>,
111 pub kind: ItemKind,
112 }
113
114 #[derive(Clone)]
118 pub struct Attribute {
119 pound: Pound,
120 contents: BracketGroupContaining<AttributeContent>,
121 }
122
123 #[derive(Clone)]
124 enum AttributeContent {
125 Doc(Cons<DocKw, Assign, LiteralString>),
126 Other(Vec<TokenTree>),
127 }
128
129 keyword DocKw = "doc";
130
131 #[derive(Clone)]
137 struct Visibility {
138 public: kw::Public,
139 modifier: Option<ParenthesisGroupContaining<VisibilityModifier>>,
140 }
141
142 #[derive(Clone)]
148 enum VisibilityModifier {
149 Package(kw::Package),
150 Friend(kw::Friend)
151 }
152
153 #[non_exhaustive]
157 pub enum ItemKind {
158 Struct(Struct),
159 Enum(Enum),
160 Import(Import),
161 UseFun(UseFun),
162 Const(Const),
163 Function(Function),
164 MacroFun(MacroFun),
165 NativeFun(NativeFun)
166 }
167
168 pub struct UseFun {
169 keyword: kw::Use,
170 fun_kw: kw::Fun,
171 path_prefix: Option<Cons<Ident, PathSep, Ident, PathSep>>,
172 fun: Ident,
173 as_kw: kw::As,
174 ty: Ident,
175 dot: Dot,
176 method: Ident,
177 semicolon: Semicolon,
178 }
179
180 pub struct Const {
183 const_kw: kw::Const,
184 ident: Ident,
185 colon: Colon,
186 ty: Type,
187 assign: Assign,
188 expr: ConstVal,
189 semicolon: Semicolon,
190 }
191
192 enum ConstVal {
193 Literal(Literal),
194 Vector(Cons<kw::Vector, BracketGroup>),
195 NamedAddress(Cons<At, Literal>),
196 Expr(Vec<Cons<Except<Semicolon>, TokenTree>>),
198 }
199
200 pub struct Import {
203 keyword: kw::Use,
204 named_address: Ident,
205 path_sep: PathSep,
206 module: ImportModule,
207 semicolon: Semicolon,
208 }
209
210 enum ImportModule {
212 One(ModuleOrItems),
213 Many(BraceGroupContaining<CommaDelimitedVec<ModuleOrItems>>),
214 }
215
216 #[derive(Clone)]
217 struct ModuleOrItems {
218 ident: Ident,
219 next: Option<AliasOrItems>,
220 }
221
222 #[derive(Clone)]
223 enum AliasOrItems {
224 Alias {
225 as_kw: kw::As,
226 alias: Ident,
227 },
228 Items {
229 sep: PathSep,
230 item: ImportItem,
231 }
232 }
233
234 #[derive(Clone)]
235 enum ImportItem {
236 One(MaybeAliased),
237 Many(BraceGroupContaining<CommaDelimitedVec<MaybeAliased>>)
238 }
239
240 #[derive(Clone)]
241 struct MaybeAliased {
242 ident: Ident,
243 alias: Option<Cons<kw::As, Ident>>,
244 }
245
246 #[derive(Clone)]
250 pub struct Struct {
251 keyword: kw::Struct,
252 pub ident: Ident,
253 pub generics: Option<Generics>,
254 pub kind: StructKind,
255 }
256
257 #[derive(Clone)]
259 pub enum StructKind {
260 Braced(BracedStruct),
261 Tuple(TupleStruct),
262 }
263
264 #[derive(Clone)]
266 pub struct BracedStruct {
267 abilities: Option<Abilities>,
268 pub fields: NamedFields,
269 }
270
271 #[derive(Clone)]
274 pub struct TupleStruct {
275 pub fields: PositionalFields,
276 abilities: Option<Cons<Abilities, Semicolon>>
277 }
278
279 #[derive(Clone)]
282 pub struct Enum {
283 keyword: kw::Enum,
284 pub ident: Ident,
285 pub generics: Option<Generics>,
286 pub abilities: Option<Abilities>,
287 content: BraceGroupContaining<CommaDelimitedVec<EnumVariant>>,
288 }
289
290 #[derive(Clone)]
291 pub struct EnumVariant {
292 pub attrs: Vec<Attribute>,
293 pub ident: Ident,
294 pub fields: Option<FieldsKind>
296 }
297
298 #[derive(Clone)]
300 pub enum FieldsKind {
301 Positional(PositionalFields),
302 Named(NamedFields),
303 }
304
305 #[derive(Clone)]
309 pub struct PositionalFields(ParenthesisGroupContaining<DelimitedVec<UnnamedField, Comma>>);
310
311 #[derive(Clone)]
313 pub struct NamedFields(BraceGroupContaining<DelimitedVec<NamedField, Comma>>);
314
315 #[derive(Clone)]
317 pub struct NamedField {
318 pub attrs: Vec<Attribute>,
319 pub ident: Ident,
320 colon: Colon,
321 pub ty: Type,
322 }
323
324 #[derive(Clone)]
326 pub struct UnnamedField {
327 pub attrs: Vec<Attribute>,
328 pub ty: Type,
329 }
330
331 #[derive(Clone)]
338 pub struct Generics {
339 lt_token: Lt,
340 type_args: DelimitedVec<Generic, Comma>,
341 gt_token: Gt,
342 }
343
344 #[derive(Clone)]
352 pub struct Generic {
353 pub phantom: Option<kw::Phantom>,
354 pub ident: Ident,
355 bounds: Option<GenericBounds>
356 }
357
358 #[derive(Clone)]
362 struct GenericBounds {
363 colon: Colon,
364 first_ability: Ability,
365 extra_abilities: Vec<Cons<Plus, Ability>>
366 }
367
368 #[derive(Clone)]
374 struct Abilities {
375 has: kw::Has,
376 keywords: Many<Ability, Comma>,
377 }
378
379 #[derive(Clone)]
381 pub enum Ability {
382 Copy(kw::Copy),
383 Drop(kw::Drop),
384 Key(kw::Key),
385 Store(kw::Store),
386 }
387
388 struct MaybeRefType {
392 r#ref: Option<Ref>,
393 r#type: Type,
394 }
395
396 struct Ref {
398 and: And,
399 r#mut: Option<kw::Mut>,
400 }
401
402 #[derive(Clone)]
404 pub struct Type {
405 pub path: TypePath,
406 pub type_args: Option<TypeArgs>
407 }
408
409 #[derive(Clone)]
411 pub enum TypePath {
412 Full {
414 named_address: Ident,
415 sep0: PathSep,
416 module: Ident,
417 sep1: PathSep,
418 r#type: Ident,
419 },
420 Module {
422 module: Ident,
423 sep: PathSep,
424 r#type: Ident,
425 },
426 Ident(Ident),
428 }
429
430 #[derive(Clone)]
432 pub struct TypeArgs {
433 lt: Lt,
434 args: Many<Box<Type>, Comma>,
435 gt: Gt,
436 }
437
438 pub struct NativeFun {
441 native_kw: kw::Native,
442 fun_kw: kw::Fun,
443 ident: Ident,
444 generics: Option<Generics>,
445 args: ParenthesisGroup,
446 ret: Option<Cons<Colon, Either<MaybeRefType, ParenthesisGroup>>>,
447 semicolon: Semicolon
448 }
449
450 pub struct Function {
451 entry: Option<kw::Entry>,
452 fun_kw: kw::Fun,
453 ident: Ident,
454 generics: Option<Generics>,
455 args: ParenthesisGroup,
456 ret: Option<Cons<Colon, Either<MaybeRefType, ParenthesisGroup>>>,
457 body: BraceGroup,
458 }
459
460 pub struct MacroFun {
463 macro_kw: kw::Macro,
464 fun_kw: kw::Fun,
465 ident: Ident,
466 generics: Option<MacroGenerics>,
467 args: ParenthesisGroup,
468 ret: Option<Cons<Colon, Either<MacroReturn, ParenthesisGroup>>>,
469 body: BraceGroup,
470 }
471
472 struct MacroGenerics {
473 lt_token: Lt,
474 type_args: DelimitedVec<MacroTypeArg, Comma>,
475 gt_token: Gt,
476 }
477
478 struct MacroTypeArg{
480 name: MacroTypeName,
481 bounds: Option<GenericBounds>,
482 }
483
484 enum MacroReturn {
486 Underscore(Underscore),
487 Concrete(Cons<Option<Ref>, MacroReturnType>),
488 }
489
490 enum MacroReturnType {
497 MacroTypeName(MacroTypeName),
498 Hybrid(HybridMacroType)
499 }
500
501 struct HybridMacroType {
502 ident: Ident,
503 type_args: Option<Cons<Lt, Many<Either<Type, MacroTypeName, Box<HybridMacroType>>, Comma>, Gt>>
504 }
505
506 struct MacroTypeName {
508 dollar: Dollar,
509 ident: Ident,
510 }
511}
512
513impl File {
514 pub fn into_modules(self) -> impl Iterator<Item = Module> {
515 match self {
516 Self::ModuleLabel(labeled) => std::iter::once(labeled.into_module()).boxed(),
517 Self::Legacy(modules) => modules.into_iter().boxed(),
518 }
519 }
520}
521
522impl LabeledModule {
523 pub fn into_module(self) -> Module {
524 Module {
525 attrs: self.attrs,
526 keyword: self.keyword,
527 named_address: self.named_address,
528 path_sep: self.path_sep,
529 ident: self.ident,
530 contents: BraceGroupContaining {
531 content: self.contents,
532 },
533 }
534 }
535}
536
537impl Module {
538 pub fn with_implicit_sui_imports(&mut self) -> &mut Self {
542 let implicit_imports: HashMap<_, _> = [
544 "use sui::object;",
545 "use sui::object::ID;",
546 "use sui::object::UID;",
547 "use sui::tx_context;",
548 "use sui::tx_context::TxContext;",
549 "use sui::transfer;",
550 ]
551 .into_iter()
552 .map(|text| {
553 text.to_token_iter()
554 .parse_all::<Import>()
555 .expect("Valid imports")
556 })
557 .map(|import| {
558 let ident = import
559 .imported_idents()
560 .next()
561 .expect("Each import exposes exactly one ident");
562 (ident.clone(), import)
563 })
564 .collect();
565
566 self.add_implicit_imports(implicit_imports)
567 }
568
569 pub fn with_implicit_iota_imports(&mut self) -> &mut Self {
573 let implicit_imports: HashMap<_, _> = [
575 "use iota::object;",
576 "use iota::object::ID;",
577 "use iota::object::UID;",
578 "use iota::tx_context;",
579 "use iota::tx_context::TxContext;",
580 "use iota::transfer;",
581 ]
582 .into_iter()
583 .map(|text| {
584 text.to_token_iter()
585 .parse_all::<Import>()
586 .expect("Valid imports")
587 })
588 .map(|import| {
589 let ident = import
590 .imported_idents()
591 .next()
592 .expect("Each import exposes exactly one ident");
593 (ident.clone(), import)
594 })
595 .collect();
596
597 self.add_implicit_imports(implicit_imports)
598 }
599
600 pub fn fully_qualify_datatype_field_types(&mut self) -> &mut Self {
602 let imports: HashMap<_, _> = self
603 .items()
604 .filter_map(|item| match &item.kind {
605 ItemKind::Import(import) => Some(import),
606 _ => None,
607 })
608 .flat_map(|import| import.flatten())
609 .collect();
610
611 for datatype in self.datatypes_mut() {
612 let generics = datatype.generics();
613 for type_ in datatype.field_types_mut() {
614 type_.resolve(&imports, &generics);
615 }
616 }
617 self
618 }
619
620 pub fn items(&self) -> impl Iterator<Item = &Item> {
621 self.contents.content.iter()
622 }
623
624 #[cfg(test)]
625 pub fn into_items(self) -> impl Iterator<Item = Item> {
626 self.contents.content.into_iter()
627 }
628
629 fn datatypes_mut(&mut self) -> impl Iterator<Item = &mut dyn Datatype> {
630 self.contents.content.iter_mut().filter_map(|item| {
631 Some(match &mut item.kind {
632 ItemKind::Enum(e) => e as _,
633 ItemKind::Struct(s) => s as _,
634 _ => return None,
635 })
636 })
637 }
638
639 fn add_implicit_imports(&mut self, mut implicit_imports: HashMap<Ident, Import>) -> &mut Self {
640 for item in self.items() {
642 let ItemKind::Import(import) = &item.kind else {
643 continue;
644 };
645 for ident in import.imported_idents() {
646 implicit_imports.remove(ident);
647 }
648 }
649
650 for (_, import) in implicit_imports {
652 self.contents.content.push(Item {
653 attrs: vec![],
654 vis: None,
655 kind: ItemKind::Import(import),
656 })
657 }
658 self
659 }
660}
661
662impl Import {
663 fn flatten(&self) -> impl Iterator<Item = (Ident, FlatImport)> + '_ {
666 let named_address = self.named_address.clone();
667 match &self.module {
668 ImportModule::One(module_or_items) => module_or_items.flatten(named_address),
670 ImportModule::Many(BraceGroupContaining {
672 content: DelimitedVec(ms),
673 }) => ms
674 .iter()
675 .flat_map(move |Delimited { value, .. }| value.flatten(named_address.clone()))
676 .boxed(),
677 }
678 }
679
680 fn imported_idents(&self) -> impl Iterator<Item = &Ident> {
682 match &self.module {
683 ImportModule::One(module_or_items) => module_or_items.available_idents(),
684 ImportModule::Many(BraceGroupContaining {
685 content: DelimitedVec(ms),
686 }) => ms
687 .iter()
688 .flat_map(|delimited| delimited.value.available_idents())
689 .boxed(),
690 }
691 }
692}
693
694impl ModuleOrItems {
695 fn flatten(&self, named_address: Ident) -> Box<dyn Iterator<Item = (Ident, FlatImport)> + '_> {
697 let module = self.ident.clone();
698
699 let Some(next) = &self.next else {
700 return std::iter::once((
702 module.clone(),
703 FlatImport::Module {
704 named_address,
705 module,
706 },
707 ))
708 .boxed();
709 };
710
711 match next {
712 AliasOrItems::Alias { alias, .. } => std::iter::once((
714 alias.clone(),
715 FlatImport::Module {
716 named_address,
717 module,
718 },
719 ))
720 .boxed(),
721
722 AliasOrItems::Items {
724 item: ImportItem::One(maybe_aliased),
725 ..
726 } => std::iter::once(maybe_aliased.flat_import(named_address, module)).boxed(),
727
728 AliasOrItems::Items {
730 item:
731 ImportItem::Many(BraceGroupContaining {
732 content: DelimitedVec(items),
733 }),
734 ..
735 } => items
736 .iter()
737 .map(move |Delimited { value, .. }| {
738 value.flat_import(named_address.clone(), module.clone())
739 })
740 .boxed(),
741 }
742 }
743
744 fn available_idents(&self) -> Box<dyn Iterator<Item = &Ident> + '_> {
746 let Some(next) = &self.next else {
747 return std::iter::once(&self.ident).boxed();
748 };
749
750 match next {
751 AliasOrItems::Alias { alias, .. } => std::iter::once(alias).boxed(),
752
753 AliasOrItems::Items {
754 item: ImportItem::One(item),
755 ..
756 } => std::iter::once(item.available_ident(&self.ident)).boxed(),
757
758 AliasOrItems::Items {
759 item:
760 ImportItem::Many(BraceGroupContaining {
761 content: DelimitedVec(items),
762 }),
763 ..
764 } => items
765 .iter()
766 .map(|delimited| delimited.value.available_ident(&self.ident))
767 .boxed(),
768 }
769 }
770}
771
772impl MaybeAliased {
773 fn flat_import(&self, named_address: Ident, module: Ident) -> (Ident, FlatImport) {
775 if self.ident == "Self" {
776 (
777 self.alias().unwrap_or(&module).clone(),
778 FlatImport::Module {
779 named_address,
780 module,
781 },
782 )
783 } else {
784 (
785 self.alias().unwrap_or(&self.ident).clone(),
786 FlatImport::Item {
787 named_address,
788 module,
789 r#type: self.ident.clone(),
790 },
791 )
792 }
793 }
794
795 fn available_ident<'a>(&'a self, module: &'a Ident) -> &'a Ident {
796 if self.ident == "Self" {
797 self.alias().unwrap_or(module)
798 } else {
799 self.alias().unwrap_or(&self.ident)
800 }
801 }
802
803 fn alias(&self) -> Option<&Ident> {
805 self.alias.as_ref().map(|cons| &cons.second)
806 }
807}
808
809impl Attribute {
810 pub const fn is_doc(&self) -> bool {
811 matches!(self.contents.content, AttributeContent::Doc(_))
812 }
813}
814
815impl ItemKind {
816 pub const fn is_datatype(&self) -> bool {
818 matches!(self, Self::Enum(_) | Self::Struct(_))
819 }
820}
821
822impl Struct {
823 pub fn abilities(&self) -> impl Iterator<Item = &Ability> {
824 use StructKind as K;
825 match &self.kind {
826 K::Braced(braced) => braced
827 .abilities
828 .iter()
829 .flat_map(|a| a.keywords.0.iter())
830 .map(|d| &d.value)
831 .boxed(),
832 K::Tuple(tuple) => tuple
833 .abilities
834 .iter()
835 .flat_map(|a| a.first.keywords.0.iter())
836 .map(|d| &d.value)
837 .boxed(),
838 }
839 }
840
841 pub fn field_types_mut(&mut self) -> impl Iterator<Item = &mut Type> {
842 use StructKind as K;
843 match &mut self.kind {
844 K::Tuple(TupleStruct {
845 fields: contents, ..
846 }) => contents.types_mut().boxed(),
847 K::Braced(BracedStruct {
848 fields: contents, ..
849 }) => contents.types_mut().boxed(),
850 }
851 }
852
853 fn fields_group_mut(&mut self) -> &mut dyn FieldsGroup {
854 match &mut self.kind {
855 StructKind::Braced(braced) => &mut braced.fields,
856 StructKind::Tuple(tuple) => &mut tuple.fields,
857 }
858 }
859}
860
861impl BracedStruct {
862 pub fn fields(&self) -> impl Iterator<Item = &NamedField> + Clone + '_ {
863 self.fields.fields()
864 }
865
866 pub const fn is_empty(&self) -> bool {
868 self.fields.is_empty()
869 }
870}
871
872impl TupleStruct {
873 pub fn fields(&self) -> impl Iterator<Item = &UnnamedField> + Clone + '_ {
874 self.fields.fields()
875 }
876
877 pub const fn is_empty(&self) -> bool {
879 self.fields.is_empty()
880 }
881}
882
883impl Enum {
884 pub fn abilities(&self) -> impl Iterator<Item = &Ability> {
885 self.abilities
886 .iter()
887 .flat_map(|a| a.keywords.0.iter())
888 .map(|d| &d.value)
889 }
890
891 pub fn variants(&self) -> impl Iterator<Item = &EnumVariant> {
892 self.content
893 .content
894 .0
895 .iter()
896 .map(|Delimited { value, .. }| value)
897 }
898
899 fn field_groups_mut(&mut self) -> impl Iterator<Item = &mut dyn FieldsGroup> {
900 self.content
901 .content
902 .0
903 .iter_mut()
904 .flat_map(|Delimited { value, .. }| value.fields_mut())
905 }
906}
907
908impl EnumVariant {
909 fn fields_mut(&mut self) -> Option<&mut dyn FieldsGroup> {
910 self.fields.as_mut().map(|x| x as _)
911 }
912}
913
914impl NamedFields {
915 pub fn fields(&self) -> impl Iterator<Item = &NamedField> + Clone + '_ {
916 self.0.content.0.iter().map(|d| &d.value)
917 }
918
919 pub const fn is_empty(&self) -> bool {
920 self.0.content.0.is_empty()
921 }
922}
923
924impl PositionalFields {
925 pub const fn new() -> Self {
926 Self(ParenthesisGroupContaining {
927 content: DelimitedVec(vec![]),
928 })
929 }
930
931 pub fn fields(&self) -> impl Iterator<Item = &UnnamedField> + Clone + '_ {
932 self.0.content.0.iter().map(|d| &d.value)
933 }
934
935 pub const fn is_empty(&self) -> bool {
936 self.0.content.0.is_empty()
937 }
938}
939
940impl Default for PositionalFields {
941 fn default() -> Self {
942 Self::new()
943 }
944}
945
946impl Type {
947 fn resolve(&mut self, imports: &HashMap<Ident, FlatImport>, generics: &[Ident]) {
949 use TypePath as P;
950 for ty in self.type_args_mut() {
952 ty.resolve(imports, generics);
953 }
954
955 let resolved = match &self.path {
959 P::Module { module, r#type, .. } => {
960 let Some(FlatImport::Module {
961 named_address,
962 module,
963 }) = imports.get(module)
964 else {
965 return;
966 };
967 P::Full {
968 named_address: named_address.clone(),
969 sep0: PathSep::default(),
970 module: module.clone(),
971 sep1: PathSep::default(),
972 r#type: r#type.clone(),
973 }
974 }
975 P::Ident(ident) if !generics.contains(ident) => {
976 let Some(FlatImport::Item {
977 named_address,
978 module,
979 r#type,
980 }) = imports.get(ident)
981 else {
982 return;
983 };
984 P::Full {
985 named_address: named_address.clone(),
986 sep0: PathSep::default(),
987 module: module.clone(),
988 sep1: PathSep::default(),
989 r#type: r#type.clone(),
990 }
991 }
992 _ => return,
994 };
995 self.path = resolved;
996 }
997
998 fn type_args_mut(&mut self) -> impl Iterator<Item = &mut Self> {
999 self.type_args
1000 .iter_mut()
1001 .flat_map(|args| args.args.0.iter_mut().map(|d| &mut *d.value))
1002 }
1003}
1004
1005impl TypeArgs {
1006 pub fn types(&self) -> impl Iterator<Item = &Type> {
1008 self.args.0.iter().map(|args| &*args.value)
1009 }
1010}
1011
1012impl Generics {
1013 pub fn generics(&self) -> impl Iterator<Item = &Generic> + '_ {
1014 self.type_args.0.iter().map(|d| &d.value)
1015 }
1016}
1017
1018#[cfg_attr(test, derive(derive_more::Display))]
1021enum FlatImport {
1022 #[cfg_attr(test, display("{named_address}::{module}"))]
1023 Module { named_address: Ident, module: Ident },
1024 #[cfg_attr(test, display("{named_address}::{module}::{type}"))]
1025 Item {
1026 named_address: Ident,
1027 module: Ident,
1028 r#type: Ident,
1029 },
1030}
1031
1032trait IteratorBoxed<'a>: Iterator + 'a {
1036 fn boxed(self) -> Box<dyn Iterator<Item = Self::Item> + 'a>
1037 where
1038 Self: Sized,
1039 {
1040 Box::new(self)
1041 }
1042}
1043
1044impl<'a, T> IteratorBoxed<'a> for T where T: Iterator + 'a {}
1045
1046trait Datatype {
1048 fn generics(&self) -> Vec<Ident>;
1049
1050 fn field_types_mut(&mut self) -> Box<dyn Iterator<Item = &mut Type> + '_>;
1051}
1052
1053impl Datatype for Enum {
1054 fn generics(&self) -> Vec<Ident> {
1055 self.generics
1056 .iter()
1057 .flat_map(|generics| generics.generics())
1058 .map(|generic| generic.ident.clone())
1059 .collect()
1060 }
1061
1062 fn field_types_mut(&mut self) -> Box<dyn Iterator<Item = &mut Type> + '_> {
1063 self.field_groups_mut()
1064 .flat_map(|group| group.types_mut())
1065 .boxed()
1066 }
1067}
1068
1069impl Datatype for Struct {
1070 fn generics(&self) -> Vec<Ident> {
1071 self.generics
1072 .iter()
1073 .flat_map(|generics| generics.generics())
1074 .map(|generic| generic.ident.clone())
1075 .collect()
1076 }
1077
1078 fn field_types_mut(&mut self) -> Box<dyn Iterator<Item = &mut Type> + '_> {
1079 self.fields_group_mut().types_mut()
1080 }
1081}
1082
1083trait FieldsGroup {
1085 fn types_mut(&mut self) -> Box<dyn Iterator<Item = &mut Type> + '_>;
1087}
1088
1089impl FieldsGroup for FieldsKind {
1090 fn types_mut(&mut self) -> Box<dyn Iterator<Item = &mut Type> + '_> {
1091 match self {
1092 Self::Named(named) => named.types_mut(),
1093 Self::Positional(positional) => positional.types_mut(),
1094 }
1095 }
1096}
1097
1098impl FieldsGroup for NamedFields {
1099 fn types_mut(&mut self) -> Box<dyn Iterator<Item = &mut Type> + '_> {
1100 self.0
1101 .content
1102 .0
1103 .iter_mut()
1104 .map(|Delimited { value: field, .. }| &mut field.ty)
1105 .boxed()
1106 }
1107}
1108
1109impl FieldsGroup for PositionalFields {
1110 fn types_mut(&mut self) -> Box<dyn Iterator<Item = &mut Type> + '_> {
1111 self.0
1112 .content
1113 .0
1114 .iter_mut()
1115 .map(|Delimited { value: field, .. }| &mut field.ty)
1116 .boxed()
1117 }
1118}