1use std::sync::Arc;
6
7#[derive(Debug, Clone, PartialEq, Eq)]
9#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
10pub struct PureFile {
11 pub attrs: Vec<PureAttribute>,
13 pub items: Vec<PureItem>,
15}
16
17unsafe impl Send for PureFile {}
19unsafe impl Sync for PureFile {}
20
21impl PureFile {
22 pub fn new() -> Self {
24 Self {
25 attrs: Vec::new(),
26 items: Vec::new(),
27 }
28 }
29
30 pub fn functions(&self) -> Vec<&PureFn> {
32 self.items
33 .iter()
34 .filter_map(|item| {
35 if let PureItem::Fn(f) = item {
36 Some(f)
37 } else {
38 None
39 }
40 })
41 .collect()
42 }
43
44 pub fn structs(&self) -> Vec<&PureStruct> {
46 self.items
47 .iter()
48 .filter_map(|item| {
49 if let PureItem::Struct(s) = item {
50 Some(s)
51 } else {
52 None
53 }
54 })
55 .collect()
56 }
57
58 pub fn uses(&self) -> Vec<&PureUse> {
60 self.items
61 .iter()
62 .filter_map(|item| {
63 if let PureItem::Use(u) = item {
64 Some(u)
65 } else {
66 None
67 }
68 })
69 .collect()
70 }
71
72 pub fn find_fn(&self, name: &str) -> Option<&PureFn> {
74 self.functions().into_iter().find(|f| f.name == name)
75 }
76
77 pub fn traits(&self) -> Vec<&PureTrait> {
79 self.items
80 .iter()
81 .filter_map(|item| {
82 if let PureItem::Trait(t) = item {
83 Some(t)
84 } else {
85 None
86 }
87 })
88 .collect()
89 }
90
91 pub fn impls(&self) -> Vec<&PureImpl> {
93 self.items
94 .iter()
95 .filter_map(|item| {
96 if let PureItem::Impl(i) = item {
97 Some(i)
98 } else {
99 None
100 }
101 })
102 .collect()
103 }
104
105 pub fn into_arc(self) -> Arc<Self> {
107 Arc::new(self)
108 }
109}
110
111impl Default for PureFile {
112 fn default() -> Self {
113 Self::new()
114 }
115}
116
117#[derive(Debug, Clone, PartialEq, Eq)]
125#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
126pub enum PureItem {
127 Use(PureUse),
129 Fn(PureFn),
131 Struct(PureStruct),
133 Enum(PureEnum),
135 Impl(PureImpl),
137 Const(PureConst),
139 Static(PureStatic),
141 Type(PureTypeAlias),
143 Mod(PureMod),
145 Trait(PureTrait),
147 Macro(PureMacro),
149 Other(String),
151}
152
153#[derive(Debug, Clone, PartialEq, Eq)]
160#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
161pub enum PureAttrMeta {
162 Path,
164 List(String),
166 NameValue(String),
168}
169
170#[derive(Debug, Clone, PartialEq, Eq)]
172#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
173pub struct PureAttribute {
174 pub path: String,
176 pub meta: PureAttrMeta,
178 pub is_inner: bool,
180}
181
182#[derive(Debug, Clone, PartialEq, Eq)]
184#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
185pub struct PureUse {
186 pub vis: PureVis,
188 pub tree: PureUseTree,
190}
191
192#[derive(Debug, Clone, PartialEq, Eq)]
194#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
195pub enum PureUseTree {
196 Path {
198 path: String,
200 tree: Box<PureUseTree>,
202 },
203 Name(String),
205 Rename {
207 name: String,
209 rename: String,
211 },
212 Glob,
214 Group(Vec<PureUseTree>),
216}
217
218#[derive(Debug, Clone, PartialEq, Eq, Default)]
220#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
221pub enum PureVis {
222 #[default]
224 Private,
225 Public,
227 Crate,
229 Super,
231 In(String),
233}
234
235#[derive(Debug, Clone, PartialEq, Eq)]
237#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
238pub struct PureFn {
239 pub attrs: Vec<PureAttribute>,
241 pub vis: PureVis,
243 pub is_async: bool,
245 #[cfg_attr(feature = "serde", serde(default))]
248 pub is_async_inferred: bool,
249 pub is_const: bool,
251 pub is_unsafe: bool,
253 #[cfg_attr(feature = "serde", serde(default))]
255 pub abi: Option<String>,
256 pub name: String,
258 pub generics: PureGenerics,
260 pub params: Vec<PureParam>,
262 pub ret: Option<PureType>,
264 pub body: PureBlock,
266}
267
268impl PureFn {
269 pub fn is_effectively_async(&self) -> bool {
275 self.is_async || self.is_async_inferred
276 }
277}
278
279#[derive(Debug, Clone, PartialEq, Eq)]
281#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
282pub enum PureParam {
283 SelfValue {
285 is_ref: bool,
287 is_mut: bool,
289 },
290 Typed {
292 name: String,
294 ty: PureType,
296 },
297}
298
299#[derive(Debug, Clone, PartialEq, Eq)]
310#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
311pub struct PureClosureParam {
312 pub pattern: PurePattern,
314 pub ty: Option<PureType>,
316}
317
318impl PureClosureParam {
319 pub fn untyped(pattern: PurePattern) -> Self {
321 Self { pattern, ty: None }
322 }
323
324 pub fn typed(pattern: PurePattern, ty: PureType) -> Self {
326 Self {
327 pattern,
328 ty: Some(ty),
329 }
330 }
331}
332
333#[derive(Debug, Clone, PartialEq, Eq, Default)]
335#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
336pub struct PureBlock {
337 pub stmts: Vec<PureStmt>,
339}
340
341impl PureBlock {
342 #[inline]
344 pub fn get_stmt(&self, index: usize) -> Option<&PureStmt> {
345 self.stmts.get(index)
346 }
347
348 #[inline]
350 pub fn get_stmt_mut(&mut self, index: usize) -> Option<&mut PureStmt> {
351 self.stmts.get_mut(index)
352 }
353
354 #[inline]
356 pub fn len(&self) -> usize {
357 self.stmts.len()
358 }
359
360 #[inline]
362 pub fn is_empty(&self) -> bool {
363 self.stmts.is_empty()
364 }
365}
366
367#[derive(Debug, Clone, PartialEq, Eq)]
369#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
370pub enum PureStmt {
371 Local {
373 pattern: PurePattern,
375 ty: Option<PureType>,
377 init: Option<PureExpr>,
379 },
380 Semi(PureExpr),
382 Expr(PureExpr),
384 Item(Box<PureItem>),
386}
387
388impl PureStmt {
389 pub fn get_expr(&self) -> Option<&PureExpr> {
394 match self {
395 PureStmt::Local { init, .. } => init.as_ref(),
396 PureStmt::Semi(e) | PureStmt::Expr(e) => Some(e),
397 PureStmt::Item(_) => None,
398 }
399 }
400
401 pub fn get_expr_mut(&mut self) -> Option<&mut PureExpr> {
403 match self {
404 PureStmt::Local { init, .. } => init.as_mut(),
405 PureStmt::Semi(e) | PureStmt::Expr(e) => Some(e),
406 PureStmt::Item(_) => None,
407 }
408 }
409
410 pub fn has_expr(&self) -> bool {
412 match self {
413 PureStmt::Local { init, .. } => init.is_some(),
414 PureStmt::Semi(_) | PureStmt::Expr(_) => true,
415 PureStmt::Item(_) => false,
416 }
417 }
418}
419
420#[derive(Debug, Clone, PartialEq, Eq)]
422#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
423pub enum PurePattern {
424 Ident {
426 name: String,
428 is_mut: bool,
430 },
431 Wild,
433 Tuple(Vec<PurePattern>),
435 Struct {
437 path: String,
439 fields: Vec<(String, PurePattern)>,
441 rest: bool,
443 },
444 Ref {
446 is_mut: bool,
448 pattern: Box<PurePattern>,
450 },
451 Lit(String),
453 Or(Vec<PurePattern>),
455 Path(String),
457 Range {
459 start: Option<String>,
461 end: Option<String>,
463 inclusive: bool,
465 },
466 Slice(Vec<PurePattern>),
468 Rest,
470 Other(String),
472}
473
474#[derive(Debug, Clone, PartialEq, Eq)]
476#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
477pub enum PureExpr {
478 Lit(String),
480 Path(String),
482 Binary {
484 op: String,
486 left: Box<PureExpr>,
488 right: Box<PureExpr>,
490 },
491 Unary {
493 op: String,
495 expr: Box<PureExpr>,
497 },
498 Call {
500 func: Box<PureExpr>,
502 args: Vec<PureExpr>,
504 },
505 MethodCall {
507 receiver: Box<PureExpr>,
509 method: String,
511 turbofish: Option<String>,
513 args: Vec<PureExpr>,
515 },
516 Field {
518 expr: Box<PureExpr>,
520 field: String,
522 },
523 Index {
525 expr: Box<PureExpr>,
527 index: Box<PureExpr>,
529 },
530 Block {
532 label: Option<String>,
534 block: PureBlock,
536 },
537 If {
539 cond: Box<PureExpr>,
541 then_branch: PureBlock,
543 else_branch: Option<Box<PureExpr>>,
545 },
546 Match {
548 expr: Box<PureExpr>,
550 arms: Vec<PureMatchArm>,
552 },
553 Loop {
555 label: Option<String>,
557 body: PureBlock,
559 },
560 While {
562 label: Option<String>,
564 cond: Box<PureExpr>,
566 body: PureBlock,
568 },
569 For {
571 label: Option<String>,
573 pat: PurePattern,
575 expr: Box<PureExpr>,
577 body: PureBlock,
579 },
580 Return(Option<Box<PureExpr>>),
582 Break {
584 label: Option<String>,
586 expr: Option<Box<PureExpr>>,
588 },
589 Continue {
591 label: Option<String>,
593 },
594 Closure {
596 is_async: bool,
598 is_move: bool,
600 params: Vec<PureClosureParam>,
602 ret: Option<PureType>,
604 body: Box<PureExpr>,
606 },
607 Struct {
609 path: String,
611 fields: Vec<(String, PureExpr)>,
613 },
614 Tuple(Vec<PureExpr>),
616 Array(Vec<PureExpr>),
618 Ref {
620 is_mut: bool,
622 expr: Box<PureExpr>,
624 },
625 Macro {
627 name: String,
629 delimiter: MacroDelimiter,
631 tokens: String,
633 },
634 Await(Box<PureExpr>),
636 Try(Box<PureExpr>),
638 Range {
640 start: Option<Box<PureExpr>>,
642 end: Option<Box<PureExpr>>,
644 inclusive: bool,
646 },
647 Cast {
649 expr: Box<PureExpr>,
651 ty: PureType,
653 },
654 Let {
656 pattern: PurePattern,
658 expr: Box<PureExpr>,
660 },
661 Async {
663 is_move: bool,
665 body: PureBlock,
667 },
668 Unsafe(PureBlock),
670 Repeat {
672 expr: Box<PureExpr>,
674 len: Box<PureExpr>,
676 },
677 Other(String),
679}
680
681impl PureExpr {
682 pub fn method_call(receiver: Box<PureExpr>, method: String, args: Vec<PureExpr>) -> Self {
684 PureExpr::MethodCall {
685 receiver,
686 method,
687 turbofish: None,
688 args,
689 }
690 }
691
692 pub fn closure(params: Vec<PureClosureParam>, body: Box<PureExpr>) -> Self {
694 PureExpr::Closure {
695 is_async: false,
696 is_move: false,
697 params,
698 ret: None,
699 body,
700 }
701 }
702
703 pub fn get_child(&self, index: usize) -> Option<&PureExpr> {
723 match self {
724 PureExpr::Unary { expr, .. }
726 | PureExpr::Field { expr, .. }
727 | PureExpr::Ref { expr, .. }
728 | PureExpr::Await(expr)
729 | PureExpr::Try(expr)
730 | PureExpr::Cast { expr, .. }
731 | PureExpr::Let { expr, .. } => {
732 if index == 0 {
733 Some(expr)
734 } else {
735 None
736 }
737 }
738
739 PureExpr::Binary { left, right, .. } => match index {
741 0 => Some(left),
742 1 => Some(right),
743 _ => None,
744 },
745 PureExpr::Index { expr, index: idx } => match index {
746 0 => Some(expr),
747 1 => Some(idx),
748 _ => None,
749 },
750 PureExpr::Repeat { expr, len } => match index {
751 0 => Some(expr),
752 1 => Some(len),
753 _ => None,
754 },
755
756 PureExpr::Call { func, args } => {
758 if index == 0 {
759 Some(func)
760 } else {
761 args.get(index - 1)
762 }
763 }
764 PureExpr::MethodCall { receiver, args, .. } => {
765 if index == 0 {
766 Some(receiver)
767 } else {
768 args.get(index - 1)
769 }
770 }
771
772 PureExpr::Range { start, end, .. } => match index {
774 0 => start.as_deref(),
775 1 => end.as_deref(),
776 _ => None,
777 },
778 PureExpr::If {
779 cond, else_branch, ..
780 } => match index {
781 0 => Some(cond),
782 1 => else_branch.as_deref(),
783 _ => None,
784 },
785 PureExpr::Return(opt) => {
786 if index == 0 {
787 opt.as_deref()
788 } else {
789 None
790 }
791 }
792 PureExpr::Break { expr: opt, .. } => {
793 if index == 0 {
794 opt.as_deref()
795 } else {
796 None
797 }
798 }
799
800 PureExpr::While { cond, .. } => {
802 if index == 0 {
803 Some(cond)
804 } else {
805 None
806 }
807 }
808 PureExpr::For { expr, .. } => {
809 if index == 0 {
810 Some(expr)
811 } else {
812 None
813 }
814 }
815 PureExpr::Match { expr, .. } => {
816 if index == 0 {
817 Some(expr)
818 } else {
819 None
820 }
821 }
822
823 PureExpr::Closure { body, .. } => {
825 if index == 0 {
826 Some(body)
827 } else {
828 None
829 }
830 }
831
832 PureExpr::Tuple(exprs) | PureExpr::Array(exprs) => exprs.get(index),
834 PureExpr::Struct { fields, .. } => fields.get(index).map(|(_, e)| e),
835
836 PureExpr::Lit(_)
838 | PureExpr::Path(_)
839 | PureExpr::Block { .. }
840 | PureExpr::Loop { .. }
841 | PureExpr::Async { .. }
842 | PureExpr::Unsafe(_)
843 | PureExpr::Continue { .. }
844 | PureExpr::Macro { .. }
845 | PureExpr::Other(_) => None,
846 }
847 }
848
849 pub fn get_child_mut(&mut self, index: usize) -> Option<&mut PureExpr> {
851 match self {
852 PureExpr::Unary { expr, .. }
853 | PureExpr::Field { expr, .. }
854 | PureExpr::Ref { expr, .. }
855 | PureExpr::Await(expr)
856 | PureExpr::Try(expr)
857 | PureExpr::Cast { expr, .. }
858 | PureExpr::Let { expr, .. } => {
859 if index == 0 {
860 Some(expr)
861 } else {
862 None
863 }
864 }
865
866 PureExpr::Binary { left, right, .. } => match index {
867 0 => Some(left),
868 1 => Some(right),
869 _ => None,
870 },
871 PureExpr::Index { expr, index: idx } => match index {
872 0 => Some(expr),
873 1 => Some(idx),
874 _ => None,
875 },
876 PureExpr::Repeat { expr, len } => match index {
877 0 => Some(expr),
878 1 => Some(len),
879 _ => None,
880 },
881
882 PureExpr::Call { func, args } => {
883 if index == 0 {
884 Some(func)
885 } else {
886 args.get_mut(index - 1)
887 }
888 }
889 PureExpr::MethodCall { receiver, args, .. } => {
890 if index == 0 {
891 Some(receiver)
892 } else {
893 args.get_mut(index - 1)
894 }
895 }
896
897 PureExpr::Range { start, end, .. } => match index {
898 0 => start.as_deref_mut(),
899 1 => end.as_deref_mut(),
900 _ => None,
901 },
902 PureExpr::If {
903 cond, else_branch, ..
904 } => match index {
905 0 => Some(cond.as_mut()),
906 1 => else_branch.as_deref_mut(),
907 _ => None,
908 },
909 PureExpr::Return(opt) => {
910 if index == 0 {
911 opt.as_deref_mut()
912 } else {
913 None
914 }
915 }
916 PureExpr::Break { expr: opt, .. } => {
917 if index == 0 {
918 opt.as_deref_mut()
919 } else {
920 None
921 }
922 }
923
924 PureExpr::While { cond, .. } => {
925 if index == 0 {
926 Some(cond)
927 } else {
928 None
929 }
930 }
931 PureExpr::For { expr, .. } => {
932 if index == 0 {
933 Some(expr)
934 } else {
935 None
936 }
937 }
938 PureExpr::Match { expr, .. } => {
939 if index == 0 {
940 Some(expr)
941 } else {
942 None
943 }
944 }
945
946 PureExpr::Closure { body, .. } => {
947 if index == 0 {
948 Some(body)
949 } else {
950 None
951 }
952 }
953
954 PureExpr::Tuple(exprs) | PureExpr::Array(exprs) => exprs.get_mut(index),
955 PureExpr::Struct { fields, .. } => fields.get_mut(index).map(|(_, e)| e),
956
957 PureExpr::Lit(_)
958 | PureExpr::Path(_)
959 | PureExpr::Block { .. }
960 | PureExpr::Loop { .. }
961 | PureExpr::Async { .. }
962 | PureExpr::Unsafe(_)
963 | PureExpr::Continue { .. }
964 | PureExpr::Macro { .. }
965 | PureExpr::Other(_) => None,
966 }
967 }
968
969 pub fn get_block(&self) -> Option<&PureBlock> {
971 match self {
972 PureExpr::Block { block: b, .. }
973 | PureExpr::Loop { body: b, .. }
974 | PureExpr::Unsafe(b) => Some(b),
975 PureExpr::Async { body, .. } => Some(body),
976 PureExpr::If { then_branch, .. } => Some(then_branch),
977 PureExpr::While { body, .. } | PureExpr::For { body, .. } => Some(body),
978 _ => None,
979 }
980 }
981
982 pub fn get_block_mut(&mut self) -> Option<&mut PureBlock> {
984 match self {
985 PureExpr::Block { block: b, .. }
986 | PureExpr::Loop { body: b, .. }
987 | PureExpr::Unsafe(b) => Some(b),
988 PureExpr::Async { body, .. } => Some(body),
989 PureExpr::If { then_branch, .. } => Some(then_branch),
990 PureExpr::While { body, .. } | PureExpr::For { body, .. } => Some(body),
991 _ => None,
992 }
993 }
994
995 pub fn child_count(&self) -> usize {
997 match self {
998 PureExpr::Lit(_)
999 | PureExpr::Path(_)
1000 | PureExpr::Continue { .. }
1001 | PureExpr::Macro { .. }
1002 | PureExpr::Other(_)
1003 | PureExpr::Block { .. }
1004 | PureExpr::Loop { .. }
1005 | PureExpr::Async { .. }
1006 | PureExpr::Unsafe(_) => 0,
1007
1008 PureExpr::Unary { .. }
1009 | PureExpr::Field { .. }
1010 | PureExpr::Ref { .. }
1011 | PureExpr::Await(_)
1012 | PureExpr::Try(_)
1013 | PureExpr::Cast { .. }
1014 | PureExpr::Let { .. }
1015 | PureExpr::Closure { .. }
1016 | PureExpr::While { .. }
1017 | PureExpr::For { .. }
1018 | PureExpr::Match { .. } => 1,
1019
1020 PureExpr::Binary { .. } | PureExpr::Index { .. } | PureExpr::Repeat { .. } => 2,
1021
1022 PureExpr::Range { start, end, .. } => start.is_some() as usize + end.is_some() as usize,
1023 PureExpr::If { else_branch, .. } => 1 + else_branch.is_some() as usize,
1024 PureExpr::Return(opt) => opt.is_some() as usize,
1025 PureExpr::Break { expr: opt, .. } => opt.is_some() as usize,
1026
1027 PureExpr::Call { args, .. } => 1 + args.len(),
1028 PureExpr::MethodCall { args, .. } => 1 + args.len(),
1029 PureExpr::Tuple(v) | PureExpr::Array(v) => v.len(),
1030 PureExpr::Struct { fields, .. } => fields.len(),
1031 }
1032 }
1033
1034 pub fn navigate(&self, path: &[usize]) -> Option<&PureExpr> {
1043 let mut current = self;
1044 for &idx in path {
1045 current = current.get_child(idx)?;
1046 }
1047 Some(current)
1048 }
1049
1050 pub fn navigate_mut(&mut self, path: &[usize]) -> Option<&mut PureExpr> {
1052 let mut current = self;
1053 for &idx in path {
1054 current = current.get_child_mut(idx)?;
1055 }
1056 Some(current)
1057 }
1058}
1059
1060#[derive(Debug, Clone, PartialEq, Eq)]
1062#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1063pub struct PureMatchArm {
1064 pub pattern: PurePattern,
1066 pub guard: Option<PureExpr>,
1068 pub body: PureExpr,
1070}
1071
1072#[derive(Debug, Clone, PartialEq, Eq)]
1074#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1075pub enum PureType {
1076 Path(String),
1078 Ref {
1080 lifetime: Option<String>,
1082 is_mut: bool,
1084 ty: Box<PureType>,
1086 },
1087 Tuple(Vec<PureType>),
1089 Array {
1091 ty: Box<PureType>,
1093 len: String,
1095 },
1096 Slice(Box<PureType>),
1098 Fn {
1100 params: Vec<PureType>,
1102 ret: Option<Box<PureType>>,
1104 },
1105 ImplTrait(Vec<String>),
1107 TraitObject(Vec<String>),
1109 Infer,
1111 Never,
1113 Other(String),
1115}
1116
1117#[derive(Debug, Clone, PartialEq, Eq, Default)]
1119#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1120pub struct PureGenerics {
1121 pub params: Vec<PureGenericParam>,
1123 pub where_clause: Vec<String>,
1125}
1126
1127#[derive(Debug, Clone, PartialEq, Eq)]
1129#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1130pub enum PureGenericParam {
1131 Type {
1133 name: String,
1135 bounds: Vec<String>,
1137 },
1138 Lifetime {
1140 name: String,
1142 bounds: Vec<String>,
1144 },
1145 Const {
1147 name: String,
1149 ty: String,
1151 },
1152}
1153
1154#[derive(Debug, Clone, PartialEq, Eq)]
1156#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1157pub struct PureStruct {
1158 pub attrs: Vec<PureAttribute>,
1160 pub vis: PureVis,
1162 pub name: String,
1164 pub generics: PureGenerics,
1166 pub fields: PureFields,
1168}
1169
1170#[derive(Debug, Clone, PartialEq, Eq)]
1172#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1173pub enum PureFields {
1174 Named(Vec<PureField>),
1176 Tuple(Vec<PureType>),
1178 Unit,
1180}
1181
1182#[derive(Debug, Clone, PartialEq, Eq)]
1184#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1185pub struct PureField {
1186 pub attrs: Vec<PureAttribute>,
1188 pub vis: PureVis,
1190 pub name: String,
1192 pub ty: PureType,
1194}
1195
1196#[derive(Debug, Clone, PartialEq, Eq)]
1198#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1199pub struct PureEnum {
1200 pub attrs: Vec<PureAttribute>,
1202 pub vis: PureVis,
1204 pub name: String,
1206 pub generics: PureGenerics,
1208 pub variants: Vec<PureVariant>,
1210}
1211
1212#[derive(Debug, Clone, PartialEq, Eq)]
1214#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1215pub struct PureVariant {
1216 pub attrs: Vec<PureAttribute>,
1218 pub name: String,
1220 pub fields: PureFields,
1222 pub discriminant: Option<String>,
1224}
1225
1226#[derive(Debug, Clone, PartialEq, Eq)]
1228#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1229pub struct PureImpl {
1230 pub attrs: Vec<PureAttribute>,
1232 pub generics: PureGenerics,
1234 pub is_unsafe: bool,
1236 pub trait_: Option<String>,
1238 pub self_ty: String,
1240 pub items: Vec<PureImplItem>,
1242}
1243
1244#[derive(Debug, Clone, PartialEq, Eq)]
1246#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1247pub enum PureImplItem {
1248 Fn(PureFn),
1250 Const(PureConst),
1252 Type(PureTypeAlias),
1254 Other(String),
1256}
1257
1258#[derive(Debug, Clone, PartialEq, Eq)]
1260#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1261pub struct PureConst {
1262 pub attrs: Vec<PureAttribute>,
1264 pub vis: PureVis,
1266 pub name: String,
1268 pub ty: PureType,
1270 pub value: Option<PureExpr>,
1272}
1273
1274#[derive(Debug, Clone, PartialEq, Eq)]
1276#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1277pub struct PureStatic {
1278 pub attrs: Vec<PureAttribute>,
1280 pub vis: PureVis,
1282 pub is_mut: bool,
1284 pub name: String,
1286 pub ty: PureType,
1288 pub value: PureExpr,
1290}
1291
1292#[derive(Debug, Clone, PartialEq, Eq)]
1294#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1295pub struct PureTypeAlias {
1296 pub attrs: Vec<PureAttribute>,
1298 pub vis: PureVis,
1300 pub name: String,
1302 pub generics: PureGenerics,
1304 pub ty: PureType,
1306}
1307
1308#[derive(Debug, Clone, PartialEq, Eq)]
1314#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1315pub struct PureMod {
1316 pub attrs: Vec<PureAttribute>,
1319 pub vis: PureVis,
1321 pub name: String,
1323 pub items: Vec<PureItem>,
1325}
1326
1327#[derive(Debug, Clone, PartialEq, Eq)]
1329#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1330pub struct PureTrait {
1331 pub attrs: Vec<PureAttribute>,
1333 pub vis: PureVis,
1335 pub is_unsafe: bool,
1337 pub is_auto: bool,
1339 pub name: String,
1341 pub generics: PureGenerics,
1343 pub supertraits: Vec<String>,
1345 pub items: Vec<PureTraitItem>,
1347}
1348
1349#[derive(Debug, Clone, PartialEq, Eq)]
1351#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1352pub enum PureTraitItem {
1353 Fn(PureFn),
1355 Const(PureConst),
1357 Type {
1359 name: String,
1361 bounds: Vec<String>,
1363 default: Option<PureType>,
1365 },
1366 Other(String),
1368}
1369
1370#[derive(Debug, Clone, PartialEq, Eq)]
1372#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1373pub struct PureMacro {
1374 pub path: String,
1376 pub delimiter: MacroDelimiter,
1378 pub tokens: String,
1380}
1381
1382#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1384#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1385pub enum MacroDelimiter {
1386 Paren,
1388 Brace,
1390 Bracket,
1392}
1393
1394#[cfg(test)]
1395mod tests {
1396 use super::*;
1397
1398 #[test]
1399 fn test_pure_file_send_sync() {
1400 fn assert_send_sync<T: Send + Sync>() {}
1401 assert_send_sync::<PureFile>();
1402 }
1403
1404 #[test]
1405 #[cfg(feature = "serde")]
1406 fn test_serde_json_roundtrip() {
1407 let file = PureFile::from_source(
1408 r#"
1409 use std::io;
1410
1411 fn hello(name: &str) -> String {
1412 format!("Hello, {}!", name)
1413 }
1414
1415 struct Point {
1416 x: i32,
1417 y: i32,
1418 }
1419 "#,
1420 )
1421 .unwrap();
1422
1423 let json = serde_json::to_string_pretty(&file).unwrap();
1425 assert!(json.contains("hello"));
1426 assert!(json.contains("Point"));
1427
1428 let restored: PureFile = serde_json::from_str(&json).unwrap();
1430 assert_eq!(file, restored);
1431 }
1432
1433 #[test]
1434 #[cfg(feature = "serde")]
1435 fn test_serde_compact() {
1436 let file = PureFile::from_source("fn main() {}").unwrap();
1437
1438 let json = serde_json::to_string(&file).unwrap();
1440
1441 assert!(json.len() < 500);
1443
1444 let restored: PureFile = serde_json::from_str(&json).unwrap();
1446 assert_eq!(file, restored);
1447 }
1448
1449 #[test]
1450 #[cfg(feature = "serde")]
1451 fn test_serde_complex_ast() {
1452 let file = PureFile::from_source(
1453 r#"
1454 pub struct Config<T: Clone> {
1455 pub name: String,
1456 pub value: T,
1457 }
1458
1459 impl<T: Clone> Config<T> {
1460 pub fn new(name: String, value: T) -> Self {
1461 Self { name, value }
1462 }
1463 }
1464
1465 pub trait Configurable {
1466 fn config(&self) -> &str;
1467 }
1468 "#,
1469 )
1470 .unwrap();
1471
1472 let json = serde_json::to_string(&file).unwrap();
1473 let restored: PureFile = serde_json::from_str(&json).unwrap();
1474 assert_eq!(file, restored);
1475
1476 assert_eq!(restored.structs().len(), 1);
1478 assert_eq!(restored.structs()[0].name, "Config");
1479 }
1480
1481 #[test]
1484 fn test_pure_block_navigation() {
1485 let block = PureBlock {
1486 stmts: vec![
1487 PureStmt::Semi(PureExpr::Lit("1".into())),
1488 PureStmt::Semi(PureExpr::Lit("2".into())),
1489 PureStmt::Expr(PureExpr::Lit("3".into())),
1490 ],
1491 };
1492
1493 assert_eq!(block.len(), 3);
1494 assert!(!block.is_empty());
1495
1496 let stmt0 = block.get_stmt(0).unwrap();
1497 assert!(matches!(stmt0, PureStmt::Semi(PureExpr::Lit(s)) if s == "1"));
1498
1499 let stmt2 = block.get_stmt(2).unwrap();
1500 assert!(matches!(stmt2, PureStmt::Expr(PureExpr::Lit(s)) if s == "3"));
1501
1502 assert!(block.get_stmt(3).is_none());
1503 }
1504
1505 #[test]
1506 fn test_pure_stmt_get_expr() {
1507 let semi = PureStmt::Semi(PureExpr::Lit("x".into()));
1508 assert!(semi.has_expr());
1509 assert!(matches!(semi.get_expr(), Some(PureExpr::Lit(_))));
1510
1511 let local_with_init = PureStmt::Local {
1512 pattern: PurePattern::Ident {
1513 name: "x".into(),
1514 is_mut: false,
1515 },
1516 ty: None,
1517 init: Some(PureExpr::Lit("42".into())),
1518 };
1519 assert!(local_with_init.has_expr());
1520 assert!(matches!(local_with_init.get_expr(), Some(PureExpr::Lit(_))));
1521
1522 let local_no_init = PureStmt::Local {
1523 pattern: PurePattern::Ident {
1524 name: "x".into(),
1525 is_mut: false,
1526 },
1527 ty: None,
1528 init: None,
1529 };
1530 assert!(!local_no_init.has_expr());
1531 assert!(local_no_init.get_expr().is_none());
1532 }
1533
1534 #[test]
1535 fn test_pure_expr_get_child_binary() {
1536 let expr = PureExpr::Binary {
1538 op: "+".into(),
1539 left: Box::new(PureExpr::Path("a".into())),
1540 right: Box::new(PureExpr::Path("b".into())),
1541 };
1542
1543 assert_eq!(expr.child_count(), 2);
1544
1545 let left = expr.get_child(0).unwrap();
1546 assert!(matches!(left, PureExpr::Path(s) if s == "a"));
1547
1548 let right = expr.get_child(1).unwrap();
1549 assert!(matches!(right, PureExpr::Path(s) if s == "b"));
1550
1551 assert!(expr.get_child(2).is_none());
1552 }
1553
1554 #[test]
1555 fn test_pure_expr_get_child_method_call() {
1556 let expr = PureExpr::MethodCall {
1558 receiver: Box::new(PureExpr::Path("x".into())),
1559 method: "foo".into(),
1560 turbofish: None,
1561 args: vec![PureExpr::Path("a".into()), PureExpr::Path("b".into())],
1562 };
1563
1564 assert_eq!(expr.child_count(), 3); let receiver = expr.get_child(0).unwrap();
1567 assert!(matches!(receiver, PureExpr::Path(s) if s == "x"));
1568
1569 let arg0 = expr.get_child(1).unwrap();
1570 assert!(matches!(arg0, PureExpr::Path(s) if s == "a"));
1571
1572 let arg1 = expr.get_child(2).unwrap();
1573 assert!(matches!(arg1, PureExpr::Path(s) if s == "b"));
1574
1575 assert!(expr.get_child(3).is_none());
1576 }
1577
1578 #[test]
1579 fn test_pure_expr_navigate() {
1580 let expr = PureExpr::MethodCall {
1582 receiver: Box::new(PureExpr::Path("x".into())),
1583 method: "foo".into(),
1584 turbofish: None,
1585 args: vec![
1586 PureExpr::Binary {
1587 op: "+".into(),
1588 left: Box::new(PureExpr::Path("a".into())),
1589 right: Box::new(PureExpr::Path("b".into())),
1590 },
1591 PureExpr::Path("c".into()),
1592 ],
1593 };
1594
1595 let r = expr.navigate(&[0]).unwrap();
1597 assert!(matches!(r, PureExpr::Path(s) if s == "x"));
1598
1599 let arg0 = expr.navigate(&[1]).unwrap();
1601 assert!(matches!(arg0, PureExpr::Binary { .. }));
1602
1603 let a = expr.navigate(&[1, 0]).unwrap();
1605 assert!(matches!(a, PureExpr::Path(s) if s == "a"));
1606
1607 let b = expr.navigate(&[1, 1]).unwrap();
1609 assert!(matches!(b, PureExpr::Path(s) if s == "b"));
1610
1611 assert!(expr.navigate(&[1, 2]).is_none());
1613 assert!(expr.navigate(&[5]).is_none());
1614 }
1615
1616 #[test]
1617 fn test_pure_expr_get_block() {
1618 let block_expr = PureExpr::Block {
1619 label: None,
1620 block: PureBlock {
1621 stmts: vec![PureStmt::Expr(PureExpr::Lit("1".into()))],
1622 },
1623 };
1624 assert!(block_expr.get_block().is_some());
1625 assert_eq!(block_expr.get_block().unwrap().len(), 1);
1626
1627 let lit = PureExpr::Lit("x".into());
1628 assert!(lit.get_block().is_none());
1629 }
1630}