abi_stable_derive/sabi_trait/
replace_self_path.rs
1use as_derive_utils::spanned_err;
4
5use syn::visit_mut::VisitMut;
6use syn::{Ident, TraitItemType, TypePath};
7
8use std::mem;
9
10use crate::utils::{LinearResult, SynResultExt};
11
12#[derive(Debug, Clone)]
14pub(crate) enum ReplaceWith {
15 Ident(Ident),
17 Remove,
19 Keep,
21}
22
23pub(crate) trait VisitMutWith {
25 fn visit_mut_with<F>(&mut self, other: &mut SelfReplacer<F>)
26 where
27 F: FnMut(&Ident) -> Option<ReplaceWith>;
28}
29
30macro_rules! impl_visit_mut_with {
31 (
32 $( ($self_:ty,$method:path) ),*
33 $(,)*
34 ) => (
35 $(
36 impl VisitMutWith for $self_{
37 #[inline]
38 fn visit_mut_with<F>(&mut self,other:&mut SelfReplacer<F>)
39 where
40 F: FnMut(&Ident) -> Option<ReplaceWith>,
41 {
42 $method(other,self);
43 }
44 }
45 )*
46 )
47}
48
49impl_visit_mut_with! {
50 (syn::WherePredicate,VisitMut::visit_where_predicate_mut),
51 (TraitItemType,VisitMut::visit_trait_item_type_mut),
52 (syn::Type,VisitMut::visit_type_mut),
53}
54
55pub(crate) fn replace_self_path<V, F>(
66 value: &mut V,
67 replace_with: ReplaceWith,
68 is_assoc_type: F,
69) -> Result<(), syn::Error>
70where
71 V: VisitMutWith,
72 F: FnMut(&Ident) -> Option<ReplaceWith>,
73{
74 let mut replacer = SelfReplacer {
75 is_assoc_type,
76 buffer: Vec::with_capacity(2),
77 replace_with,
78 errors: LinearResult::ok(()),
79 };
80 value.visit_mut_with(&mut replacer);
81 replacer.errors.into()
82}
83
84pub(crate) struct SelfReplacer<F> {
86 is_assoc_type: F,
87 buffer: Vec<ReplaceWith>,
88 replace_with: ReplaceWith,
89 errors: LinearResult<()>,
90}
91
92impl<F> VisitMut for SelfReplacer<F>
93where
94 F: FnMut(&Ident) -> Option<ReplaceWith>,
95{
96 fn visit_type_path_mut(&mut self, i: &mut TypePath) {
97 if let Some(qself) = i.qself.as_mut() {
98 self.visit_type_mut(&mut qself.ty);
99 }
100
101 let segments = &mut i.path.segments;
102
103 for segment in &mut *segments {
104 self.visit_path_arguments_mut(&mut segment.arguments);
105 }
106
107 let is_self = segments[0].ident == "Self";
111
112 match (segments.len(), is_self) {
113 (0, true) | (1, true) => {
114 self.errors.push_err(spanned_err!(
115 segments,
116 "Self can't be used in a parameter,return type,or associated type.",
117 ));
118 return;
119 }
120 (2, true) => {}
121 (_, true) => {
122 self.errors.push_err(spanned_err!(
123 segments,
124 "Paths with 3 or more components are currently unsupported",
125 ));
126 return;
127 }
128 (_, false) => return,
129 }
130
131 let is_replaced = (self.is_assoc_type)(&segments[1].ident);
132 if let Some(replace_assoc_with) = is_replaced {
134 let mut prev_segments = mem::take(segments).into_iter();
135
136 self.buffer.clear();
137 self.buffer.push(self.replace_with.clone());
138 self.buffer.push(replace_assoc_with);
139 for replace_with in self.buffer.drain(..) {
140 let prev_segment = prev_segments.next();
141 match replace_with {
142 ReplaceWith::Ident(ident) => {
143 segments.push(ident.into());
144 }
145 ReplaceWith::Remove => {}
146 ReplaceWith::Keep => {
147 segments.extend(prev_segment);
148 }
149 }
150 }
151 }
152 }
154}