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 {
812 matches!(self.contents.content, AttributeContent::Doc(_))
813 }
814
815 pub const fn contents(&self) -> &impl ToTokens {
817 &self.contents.content
818 }
819}
820
821impl ItemKind {
822 pub const fn is_datatype(&self) -> bool {
824 matches!(self, Self::Enum(_) | Self::Struct(_))
825 }
826}
827
828impl Struct {
829 pub fn abilities(&self) -> impl Iterator<Item = &Ability> {
830 use StructKind as K;
831 match &self.kind {
832 K::Braced(braced) => braced
833 .abilities
834 .iter()
835 .flat_map(|a| a.keywords.0.iter())
836 .map(|d| &d.value)
837 .boxed(),
838 K::Tuple(tuple) => tuple
839 .abilities
840 .iter()
841 .flat_map(|a| a.first.keywords.0.iter())
842 .map(|d| &d.value)
843 .boxed(),
844 }
845 }
846
847 pub fn field_types_mut(&mut self) -> impl Iterator<Item = &mut Type> {
848 use StructKind as K;
849 match &mut self.kind {
850 K::Tuple(TupleStruct {
851 fields: contents, ..
852 }) => contents.types_mut().boxed(),
853 K::Braced(BracedStruct {
854 fields: contents, ..
855 }) => contents.types_mut().boxed(),
856 }
857 }
858
859 fn fields_group_mut(&mut self) -> &mut dyn FieldsGroup {
860 match &mut self.kind {
861 StructKind::Braced(braced) => &mut braced.fields,
862 StructKind::Tuple(tuple) => &mut tuple.fields,
863 }
864 }
865}
866
867impl BracedStruct {
868 pub fn fields(&self) -> impl Iterator<Item = &NamedField> + Clone + '_ {
869 self.fields.fields()
870 }
871
872 pub const fn is_empty(&self) -> bool {
874 self.fields.is_empty()
875 }
876}
877
878impl TupleStruct {
879 pub fn fields(&self) -> impl Iterator<Item = &UnnamedField> + Clone + '_ {
880 self.fields.fields()
881 }
882
883 pub const fn is_empty(&self) -> bool {
885 self.fields.is_empty()
886 }
887}
888
889impl Enum {
890 pub fn abilities(&self) -> impl Iterator<Item = &Ability> {
891 self.abilities
892 .iter()
893 .flat_map(|a| a.keywords.0.iter())
894 .map(|d| &d.value)
895 }
896
897 pub fn variants(&self) -> impl Iterator<Item = &EnumVariant> {
898 self.content
899 .content
900 .0
901 .iter()
902 .map(|Delimited { value, .. }| value)
903 }
904
905 fn field_groups_mut(&mut self) -> impl Iterator<Item = &mut dyn FieldsGroup> {
906 self.content
907 .content
908 .0
909 .iter_mut()
910 .flat_map(|Delimited { value, .. }| value.fields_mut())
911 }
912}
913
914impl EnumVariant {
915 fn fields_mut(&mut self) -> Option<&mut dyn FieldsGroup> {
916 self.fields.as_mut().map(|x| x as _)
917 }
918}
919
920impl NamedFields {
921 pub fn fields(&self) -> impl Iterator<Item = &NamedField> + Clone + '_ {
922 self.0.content.0.iter().map(|d| &d.value)
923 }
924
925 pub const fn is_empty(&self) -> bool {
926 self.0.content.0.is_empty()
927 }
928}
929
930impl PositionalFields {
931 pub const fn new() -> Self {
932 Self(ParenthesisGroupContaining {
933 content: DelimitedVec(vec![]),
934 })
935 }
936
937 pub fn fields(&self) -> impl Iterator<Item = &UnnamedField> + Clone + '_ {
938 self.0.content.0.iter().map(|d| &d.value)
939 }
940
941 pub const fn is_empty(&self) -> bool {
942 self.0.content.0.is_empty()
943 }
944}
945
946impl Default for PositionalFields {
947 fn default() -> Self {
948 Self::new()
949 }
950}
951
952impl Type {
953 fn resolve(&mut self, imports: &HashMap<Ident, FlatImport>, generics: &[Ident]) {
955 use TypePath as P;
956 for ty in self.type_args_mut() {
958 ty.resolve(imports, generics);
959 }
960
961 let resolved = match &self.path {
965 P::Module { module, r#type, .. } => {
966 let Some(FlatImport::Module {
967 named_address,
968 module,
969 }) = imports.get(module)
970 else {
971 return;
972 };
973 P::Full {
974 named_address: named_address.clone(),
975 sep0: PathSep::default(),
976 module: module.clone(),
977 sep1: PathSep::default(),
978 r#type: r#type.clone(),
979 }
980 }
981 P::Ident(ident) if !generics.contains(ident) => {
982 let Some(FlatImport::Item {
983 named_address,
984 module,
985 r#type,
986 }) = imports.get(ident)
987 else {
988 return;
989 };
990 P::Full {
991 named_address: named_address.clone(),
992 sep0: PathSep::default(),
993 module: module.clone(),
994 sep1: PathSep::default(),
995 r#type: r#type.clone(),
996 }
997 }
998 _ => return,
1000 };
1001 self.path = resolved;
1002 }
1003
1004 fn type_args_mut(&mut self) -> impl Iterator<Item = &mut Self> {
1005 self.type_args
1006 .iter_mut()
1007 .flat_map(|args| args.args.0.iter_mut().map(|d| &mut *d.value))
1008 }
1009}
1010
1011impl TypeArgs {
1012 pub fn types(&self) -> impl Iterator<Item = &Type> {
1014 self.args.0.iter().map(|args| &*args.value)
1015 }
1016}
1017
1018impl Generics {
1019 pub fn generics(&self) -> impl Iterator<Item = &Generic> + '_ {
1020 self.type_args.0.iter().map(|d| &d.value)
1021 }
1022}
1023
1024#[cfg_attr(test, derive(derive_more::Display))]
1027enum FlatImport {
1028 #[cfg_attr(test, display("{named_address}::{module}"))]
1029 Module { named_address: Ident, module: Ident },
1030 #[cfg_attr(test, display("{named_address}::{module}::{type}"))]
1031 Item {
1032 named_address: Ident,
1033 module: Ident,
1034 r#type: Ident,
1035 },
1036}
1037
1038trait IteratorBoxed<'a>: Iterator + 'a {
1042 fn boxed(self) -> Box<dyn Iterator<Item = Self::Item> + 'a>
1043 where
1044 Self: Sized,
1045 {
1046 Box::new(self)
1047 }
1048}
1049
1050impl<'a, T> IteratorBoxed<'a> for T where T: Iterator + 'a {}
1051
1052trait Datatype {
1054 fn generics(&self) -> Vec<Ident>;
1055
1056 fn field_types_mut(&mut self) -> Box<dyn Iterator<Item = &mut Type> + '_>;
1057}
1058
1059impl Datatype for Enum {
1060 fn generics(&self) -> Vec<Ident> {
1061 self.generics
1062 .iter()
1063 .flat_map(|generics| generics.generics())
1064 .map(|generic| generic.ident.clone())
1065 .collect()
1066 }
1067
1068 fn field_types_mut(&mut self) -> Box<dyn Iterator<Item = &mut Type> + '_> {
1069 self.field_groups_mut()
1070 .flat_map(|group| group.types_mut())
1071 .boxed()
1072 }
1073}
1074
1075impl Datatype for Struct {
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 fn field_types_mut(&mut self) -> Box<dyn Iterator<Item = &mut Type> + '_> {
1085 self.fields_group_mut().types_mut()
1086 }
1087}
1088
1089trait FieldsGroup {
1091 fn types_mut(&mut self) -> Box<dyn Iterator<Item = &mut Type> + '_>;
1093}
1094
1095impl FieldsGroup for FieldsKind {
1096 fn types_mut(&mut self) -> Box<dyn Iterator<Item = &mut Type> + '_> {
1097 match self {
1098 Self::Named(named) => named.types_mut(),
1099 Self::Positional(positional) => positional.types_mut(),
1100 }
1101 }
1102}
1103
1104impl FieldsGroup for NamedFields {
1105 fn types_mut(&mut self) -> Box<dyn Iterator<Item = &mut Type> + '_> {
1106 self.0
1107 .content
1108 .0
1109 .iter_mut()
1110 .map(|Delimited { value: field, .. }| &mut field.ty)
1111 .boxed()
1112 }
1113}
1114
1115impl FieldsGroup for PositionalFields {
1116 fn types_mut(&mut self) -> Box<dyn Iterator<Item = &mut Type> + '_> {
1117 self.0
1118 .content
1119 .0
1120 .iter_mut()
1121 .map(|Delimited { value: field, .. }| &mut field.ty)
1122 .boxed()
1123 }
1124}