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_addres: 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_addres: 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: MaybeAliased,
219 items: Option<Cons<PathSep, ImportItem>>,
220 }
221
222 #[derive(Clone)]
223 enum ImportItem {
224 One(MaybeAliased),
225 Many(BraceGroupContaining<CommaDelimitedVec<MaybeAliased>>)
226 }
227
228 #[derive(Clone)]
229 struct MaybeAliased {
230 ident: Ident,
231 alias: Option<Cons<kw::As, Ident>>,
232 }
233
234 #[derive(Clone)]
238 pub struct Struct {
239 keyword: kw::Struct,
240 pub ident: Ident,
241 pub generics: Option<Generics>,
242 pub kind: StructKind,
243 }
244
245 #[derive(Clone)]
247 pub enum StructKind {
248 Braced(BracedStruct),
249 Tuple(TupleStruct),
250 }
251
252 #[derive(Clone)]
254 pub struct BracedStruct {
255 abilities: Option<Abilities>,
256 pub fields: NamedFields,
257 }
258
259 #[derive(Clone)]
262 pub struct TupleStruct {
263 pub fields: PositionalFields,
264 abilities: Option<Cons<Abilities, Semicolon>>
265 }
266
267 #[derive(Clone)]
270 pub struct Enum {
271 keyword: kw::Enum,
272 pub ident: Ident,
273 pub generics: Option<Generics>,
274 pub abilities: Option<Abilities>,
275 content: BraceGroupContaining<CommaDelimitedVec<EnumVariant>>,
276 }
277
278 #[derive(Clone)]
279 pub struct EnumVariant {
280 pub attrs: Vec<Attribute>,
281 pub ident: Ident,
282 pub fields: Option<FieldsKind>
284 }
285
286 #[derive(Clone)]
288 pub enum FieldsKind {
289 Positional(PositionalFields),
290 Named(NamedFields),
291 }
292
293 #[derive(Clone)]
297 pub struct PositionalFields(ParenthesisGroupContaining<DelimitedVec<UnnamedField, Comma>>);
298
299 #[derive(Clone)]
301 pub struct NamedFields(BraceGroupContaining<DelimitedVec<NamedField, Comma>>);
302
303 #[derive(Clone)]
305 pub struct NamedField {
306 pub attrs: Vec<Attribute>,
307 pub ident: Ident,
308 colon: Colon,
309 pub ty: Type,
310 }
311
312 #[derive(Clone)]
314 pub struct UnnamedField {
315 pub attrs: Vec<Attribute>,
316 pub ty: Type,
317 }
318
319 #[derive(Clone)]
326 pub struct Generics {
327 lt_token: Lt,
328 type_args: DelimitedVec<Generic, Comma>,
329 gt_token: Gt,
330 }
331
332 #[derive(Clone)]
340 pub struct Generic {
341 pub phantom: Option<kw::Phantom>,
342 pub ident: Ident,
343 bounds: Option<GenericBounds>
344 }
345
346 #[derive(Clone)]
350 struct GenericBounds {
351 colon: Colon,
352 first_ability: Ability,
353 extra_abilities: Vec<Cons<Plus, Ability>>
354 }
355
356 #[derive(Clone)]
362 struct Abilities {
363 has: kw::Has,
364 keywords: Many<Ability, Comma>,
365 }
366
367 #[derive(Clone)]
369 pub enum Ability {
370 Copy(kw::Copy),
371 Drop(kw::Drop),
372 Key(kw::Key),
373 Store(kw::Store),
374 }
375
376 struct MaybeRefType {
380 r#ref: Option<Ref>,
381 r#type: Type,
382 }
383
384 struct Ref {
386 and: And,
387 r#mut: Option<kw::Mut>,
388 }
389
390 #[derive(Clone)]
392 pub struct Type {
393 pub path: TypePath,
394 pub type_args: Option<TypeArgs>
395 }
396
397 #[derive(Clone)]
399 pub enum TypePath {
400 Full {
402 named_address: Ident,
403 sep0: PathSep,
404 module: Ident,
405 sep1: PathSep,
406 r#type: Ident,
407 },
408 Module {
410 module: Ident,
411 sep: PathSep,
412 r#type: Ident,
413 },
414 Ident(Ident),
416 }
417
418 #[derive(Clone)]
420 pub struct TypeArgs {
421 lt: Lt,
422 args: Many<Box<Type>, Comma>,
423 gt: Gt,
424 }
425
426 pub struct NativeFun {
429 native_kw: kw::Native,
430 fun_kw: kw::Fun,
431 ident: Ident,
432 generics: Option<Generics>,
433 args: ParenthesisGroup,
434 ret: Option<Cons<Colon, Either<MaybeRefType, ParenthesisGroup>>>,
435 semicolon: Semicolon
436 }
437
438 pub struct Function {
439 entry: Option<kw::Entry>,
440 fun_kw: kw::Fun,
441 ident: Ident,
442 generics: Option<Generics>,
443 args: ParenthesisGroup,
444 ret: Option<Cons<Colon, Either<MaybeRefType, ParenthesisGroup>>>,
445 body: BraceGroup,
446 }
447
448 pub struct MacroFun {
451 macro_kw: kw::Macro,
452 fun_kw: kw::Fun,
453 ident: Ident,
454 generics: Option<MacroGenerics>,
455 args: ParenthesisGroup,
456 ret: Option<Cons<Colon, Either<MacroReturn, ParenthesisGroup>>>,
457 body: BraceGroup,
458 }
459
460 struct MacroGenerics {
461 lt_token: Lt,
462 type_args: DelimitedVec<MacroTypeArg, Comma>,
463 gt_token: Gt,
464 }
465
466 struct MacroTypeArg{
468 name: MacroTypeName,
469 bounds: Option<GenericBounds>,
470 }
471
472 enum MacroReturn {
474 Underscore(Underscore),
475 Concrete(Cons<Option<Ref>, MacroReturnType>),
476 }
477
478 enum MacroReturnType {
485 MacroTypeName(MacroTypeName),
486 Hybrid(HybridMacroType)
487 }
488
489 struct HybridMacroType {
490 ident: Ident,
491 type_args: Option<Cons<Lt, Many<Either<Type, MacroTypeName, Box<HybridMacroType>>, Comma>, Gt>>
492 }
493
494 struct MacroTypeName {
496 dollar: Dollar,
497 ident: Ident,
498 }
499}
500
501impl File {
502 pub fn into_modules(self) -> impl Iterator<Item = Module> {
503 match self {
504 Self::ModuleLabel(labeled) => std::iter::once(labeled.into_module()).boxed(),
505 Self::Legacy(modules) => modules.into_iter().boxed(),
506 }
507 }
508}
509
510impl LabeledModule {
511 pub fn into_module(self) -> Module {
512 Module {
513 attrs: self.attrs,
514 keyword: self.keyword,
515 named_addres: self.named_addres,
516 path_sep: self.path_sep,
517 ident: self.ident,
518 contents: BraceGroupContaining {
519 content: self.contents,
520 },
521 }
522 }
523}
524
525impl Module {
526 pub fn with_implicit_sui_imports(&mut self) -> &mut Self {
530 let implicit_imports: HashMap<_, _> = [
532 "use sui::object;",
533 "use sui::object::ID;",
534 "use sui::object::UID;",
535 "use sui::tx_context;",
536 "use sui::tx_context::TxContext;",
537 "use sui::transfer;",
538 ]
539 .into_iter()
540 .map(|text| {
541 text.to_token_iter()
542 .parse_all::<Import>()
543 .expect("Valid imports")
544 })
545 .map(|import| {
546 let ident = import
547 .imported_idents()
548 .next()
549 .expect("Each import exposes exactly one ident");
550 (ident.clone(), import)
551 })
552 .collect();
553
554 self.add_implicit_imports(implicit_imports)
555 }
556
557 pub fn with_implicit_iota_imports(&mut self) -> &mut Self {
561 let implicit_imports: HashMap<_, _> = [
563 "use iota::object;",
564 "use iota::object::ID;",
565 "use iota::object::UID;",
566 "use iota::tx_context;",
567 "use iota::tx_context::TxContext;",
568 "use iota::transfer;",
569 ]
570 .into_iter()
571 .map(|text| {
572 text.to_token_iter()
573 .parse_all::<Import>()
574 .expect("Valid imports")
575 })
576 .map(|import| {
577 let ident = import
578 .imported_idents()
579 .next()
580 .expect("Each import exposes exactly one ident");
581 (ident.clone(), import)
582 })
583 .collect();
584
585 self.add_implicit_imports(implicit_imports)
586 }
587
588 pub fn fully_qualify_datatype_field_types(&mut self) -> &mut Self {
590 let imports: HashMap<_, _> = self
591 .items()
592 .filter_map(|item| match &item.kind {
593 ItemKind::Import(import) => Some(import),
594 _ => None,
595 })
596 .flat_map(|import| import.flatten())
597 .collect();
598
599 for datatype in self.datatypes_mut() {
600 let generics = datatype.generics();
601 for type_ in datatype.field_types_mut() {
602 type_.resolve(&imports, &generics);
603 }
604 }
605 self
606 }
607
608 pub fn items(&self) -> impl Iterator<Item = &Item> {
609 self.contents.content.iter()
610 }
611
612 fn datatypes_mut(&mut self) -> impl Iterator<Item = &mut dyn Datatype> {
613 self.contents.content.iter_mut().filter_map(|item| {
614 Some(match &mut item.kind {
615 ItemKind::Enum(e) => e as _,
616 ItemKind::Struct(s) => s as _,
617 _ => return None,
618 })
619 })
620 }
621
622 fn add_implicit_imports(&mut self, mut implicit_imports: HashMap<Ident, Import>) -> &mut Self {
623 for item in self.items() {
625 let ItemKind::Import(import) = &item.kind else {
626 continue;
627 };
628 for ident in import.imported_idents() {
629 implicit_imports.remove(ident);
630 }
631 }
632
633 for (_, import) in implicit_imports {
635 self.contents.content.push(Item {
636 attrs: vec![],
637 vis: None,
638 kind: ItemKind::Import(import),
639 })
640 }
641 self
642 }
643}
644
645impl Import {
646 fn flatten(&self) -> impl Iterator<Item = (Ident, FlatImport)> + use<> {
647 let named_address = self.named_address.clone();
648 match &self.module {
649 ImportModule::One(module_or_items) => module_or_items.flatten(named_address),
651 ImportModule::Many(BraceGroupContaining {
653 content: DelimitedVec(ms),
654 }) => ms
655 .clone()
656 .into_iter()
657 .flat_map(move |Delimited { value, .. }| value.flatten(named_address.clone()))
658 .boxed(),
659 }
660 }
661
662 fn imported_idents(&self) -> impl Iterator<Item = &Ident> {
664 match &self.module {
665 ImportModule::One(module_or_items) => module_or_items.available_idents(),
666 ImportModule::Many(BraceGroupContaining {
667 content: DelimitedVec(ms),
668 }) => ms
669 .iter()
670 .flat_map(|delimited| delimited.value.available_idents())
671 .boxed(),
672 }
673 }
674}
675
676impl ModuleOrItems {
677 fn flatten(&self, named_address: Ident) -> Box<dyn Iterator<Item = (Ident, FlatImport)>> {
678 let Self { ident, items } = self;
679 let module = ident.clone();
680 let Some(Cons { second: items, .. }) = items else {
681 return std::iter::once((
683 module.available_as().clone(),
684 FlatImport::Module {
685 named_address,
686 module: module.ident,
687 },
688 ))
689 .boxed();
690 };
691 match items {
692 ImportItem::One(maybe_aliased) => std::iter::once((
694 maybe_aliased.available_as().clone(),
695 FlatImport::Item {
696 named_address,
697 module: module.ident,
699 r#type: maybe_aliased.ident.clone(),
700 },
701 ))
702 .boxed(),
703 ImportItem::Many(BraceGroupContaining {
705 content: DelimitedVec(items),
706 }) => {
707 let delimiteds = items.clone();
708 delimiteds
709 .into_iter()
710 .map(move |Delimited { value, .. }| {
711 (
712 value.available_as().clone(),
713 FlatImport::Item {
714 named_address: named_address.clone(),
715 module: module.ident.clone(),
717 r#type: value.ident,
718 },
719 )
720 })
721 .boxed()
722 }
723 }
724 }
725
726 fn available_idents(&self) -> Box<dyn Iterator<Item = &Ident> + '_> {
727 let Some(Cons { second: items, .. }) = &self.items else {
728 return std::iter::once(self.ident.available_as()).boxed();
729 };
730 match items {
731 ImportItem::One(item) => std::iter::once(item.available_as()).boxed(),
732 ImportItem::Many(BraceGroupContaining {
733 content: DelimitedVec(items),
734 }) => items
735 .iter()
736 .map(|delimited| delimited.value.available_as())
737 .boxed(),
738 }
739 }
740}
741
742impl MaybeAliased {
743 const fn available_as(&self) -> &Ident {
745 if let Some(Cons { second: alias, .. }) = &self.alias {
746 alias
747 } else {
748 &self.ident
749 }
750 }
751}
752
753impl Attribute {
754 pub const fn is_doc(&self) -> bool {
755 matches!(self.contents.content, AttributeContent::Doc(_))
756 }
757}
758
759impl ItemKind {
760 pub const fn is_datatype(&self) -> bool {
762 matches!(self, Self::Enum(_) | Self::Struct(_))
763 }
764}
765
766impl Struct {
767 pub fn abilities(&self) -> impl Iterator<Item = &Ability> {
768 use StructKind as K;
769 match &self.kind {
770 K::Braced(braced) => braced
771 .abilities
772 .iter()
773 .flat_map(|a| a.keywords.0.iter())
774 .map(|d| &d.value)
775 .boxed(),
776 K::Tuple(tuple) => tuple
777 .abilities
778 .iter()
779 .flat_map(|a| a.first.keywords.0.iter())
780 .map(|d| &d.value)
781 .boxed(),
782 }
783 }
784
785 pub fn field_types_mut(&mut self) -> impl Iterator<Item = &mut Type> {
786 use StructKind as K;
787 match &mut self.kind {
788 K::Tuple(TupleStruct {
789 fields: contents, ..
790 }) => contents.types_mut().boxed(),
791 K::Braced(BracedStruct {
792 fields: contents, ..
793 }) => contents.types_mut().boxed(),
794 }
795 }
796
797 fn fields_group_mut(&mut self) -> &mut dyn FieldsGroup {
798 match &mut self.kind {
799 StructKind::Braced(braced) => &mut braced.fields,
800 StructKind::Tuple(tuple) => &mut tuple.fields,
801 }
802 }
803}
804
805impl BracedStruct {
806 pub fn fields(&self) -> impl Iterator<Item = &NamedField> + Clone + '_ {
807 self.fields.fields()
808 }
809
810 pub const fn is_empty(&self) -> bool {
812 self.fields.is_empty()
813 }
814}
815
816impl TupleStruct {
817 pub fn fields(&self) -> impl Iterator<Item = &UnnamedField> + Clone + '_ {
818 self.fields.fields()
819 }
820
821 pub const fn is_empty(&self) -> bool {
823 self.fields.is_empty()
824 }
825}
826
827impl Enum {
828 pub fn abilities(&self) -> impl Iterator<Item = &Ability> {
829 self.abilities
830 .iter()
831 .flat_map(|a| a.keywords.0.iter())
832 .map(|d| &d.value)
833 }
834
835 pub fn variants(&self) -> impl Iterator<Item = &EnumVariant> {
836 self.content
837 .content
838 .0
839 .iter()
840 .map(|Delimited { value, .. }| value)
841 }
842
843 fn field_groups_mut(&mut self) -> impl Iterator<Item = &mut dyn FieldsGroup> {
844 self.content
845 .content
846 .0
847 .iter_mut()
848 .flat_map(|Delimited { value, .. }| value.fields_mut())
849 }
850}
851
852impl EnumVariant {
853 fn fields_mut(&mut self) -> Option<&mut dyn FieldsGroup> {
854 self.fields.as_mut().map(|x| x as _)
855 }
856}
857
858impl NamedFields {
859 pub fn fields(&self) -> impl Iterator<Item = &NamedField> + Clone + '_ {
860 self.0.content.0.iter().map(|d| &d.value)
861 }
862
863 pub const fn is_empty(&self) -> bool {
864 self.0.content.0.is_empty()
865 }
866}
867
868impl PositionalFields {
869 pub const fn new() -> Self {
870 Self(ParenthesisGroupContaining {
871 content: DelimitedVec(vec![]),
872 })
873 }
874
875 pub fn fields(&self) -> impl Iterator<Item = &UnnamedField> + Clone + '_ {
876 self.0.content.0.iter().map(|d| &d.value)
877 }
878
879 pub const fn is_empty(&self) -> bool {
880 self.0.content.0.is_empty()
881 }
882}
883
884impl Default for PositionalFields {
885 fn default() -> Self {
886 Self::new()
887 }
888}
889
890impl Type {
891 fn resolve(&mut self, imports: &HashMap<Ident, FlatImport>, generics: &[Ident]) {
893 use TypePath as P;
894 for ty in self.type_args_mut() {
896 ty.resolve(imports, generics);
897 }
898
899 let resolved = match &self.path {
903 P::Module { module, r#type, .. } => {
904 let Some(FlatImport::Module {
905 named_address,
906 module,
907 }) = imports.get(module)
908 else {
909 return;
910 };
911 P::Full {
912 named_address: named_address.clone(),
913 sep0: PathSep::default(),
914 module: module.clone(),
915 sep1: PathSep::default(),
916 r#type: r#type.clone(),
917 }
918 }
919 P::Ident(ident) if !generics.contains(ident) => {
920 let Some(FlatImport::Item {
921 named_address,
922 module,
923 r#type,
924 }) = imports.get(ident)
925 else {
926 return;
927 };
928 P::Full {
929 named_address: named_address.clone(),
930 sep0: PathSep::default(),
931 module: module.clone(),
932 sep1: PathSep::default(),
933 r#type: r#type.clone(),
934 }
935 }
936 _ => return,
938 };
939 self.path = resolved;
940 }
941
942 fn type_args_mut(&mut self) -> impl Iterator<Item = &mut Self> {
943 self.type_args
944 .iter_mut()
945 .flat_map(|args| args.args.0.iter_mut().map(|d| &mut *d.value))
946 }
947}
948
949impl TypeArgs {
950 pub fn types(&self) -> impl Iterator<Item = &Type> {
952 self.args.0.iter().map(|args| &*args.value)
953 }
954}
955
956impl Generics {
957 pub fn generics(&self) -> impl Iterator<Item = &Generic> + '_ {
958 self.type_args.0.iter().map(|d| &d.value)
959 }
960}
961
962enum FlatImport {
965 Module {
966 named_address: Ident,
967 module: Ident,
968 },
969 Item {
970 named_address: Ident,
971 module: Ident,
972 r#type: Ident,
973 },
974}
975
976trait IteratorBoxed<'a>: Iterator + 'a {
980 fn boxed(self) -> Box<dyn Iterator<Item = Self::Item> + 'a>
981 where
982 Self: Sized,
983 {
984 Box::new(self)
985 }
986}
987
988impl<'a, T> IteratorBoxed<'a> for T where T: Iterator + 'a {}
989
990trait Datatype {
992 fn generics(&self) -> Vec<Ident>;
993
994 fn field_types_mut(&mut self) -> Box<dyn Iterator<Item = &mut Type> + '_>;
995}
996
997impl Datatype for Enum {
998 fn generics(&self) -> Vec<Ident> {
999 self.generics
1000 .iter()
1001 .flat_map(|generics| generics.generics())
1002 .map(|generic| generic.ident.clone())
1003 .collect()
1004 }
1005
1006 fn field_types_mut(&mut self) -> Box<dyn Iterator<Item = &mut Type> + '_> {
1007 self.field_groups_mut()
1008 .flat_map(|group| group.types_mut())
1009 .boxed()
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 fn field_types_mut(&mut self) -> Box<dyn Iterator<Item = &mut Type> + '_> {
1023 self.fields_group_mut().types_mut()
1024 }
1025}
1026
1027trait FieldsGroup {
1029 fn types_mut(&mut self) -> Box<dyn Iterator<Item = &mut Type> + '_>;
1031}
1032
1033impl FieldsGroup for FieldsKind {
1034 fn types_mut(&mut self) -> Box<dyn Iterator<Item = &mut Type> + '_> {
1035 match self {
1036 Self::Named(named) => named.types_mut(),
1037 Self::Positional(positional) => positional.types_mut(),
1038 }
1039 }
1040}
1041
1042impl FieldsGroup for NamedFields {
1043 fn types_mut(&mut self) -> Box<dyn Iterator<Item = &mut Type> + '_> {
1044 self.0
1045 .content
1046 .0
1047 .iter_mut()
1048 .map(|Delimited { value: field, .. }| &mut field.ty)
1049 .boxed()
1050 }
1051}
1052
1053impl FieldsGroup for PositionalFields {
1054 fn types_mut(&mut self) -> Box<dyn Iterator<Item = &mut Type> + '_> {
1055 self.0
1056 .content
1057 .0
1058 .iter_mut()
1059 .map(|Delimited { value: field, .. }| &mut field.ty)
1060 .boxed()
1061 }
1062}