abi_stable_derive/sabi_trait/
replace_self_path.rs

1//! Contains the `replace_self_path` function,and the `ReplaceWith` enum.
2
3use 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/// What to do with the a path component when it's found.
13#[derive(Debug, Clone)]
14pub(crate) enum ReplaceWith {
15    /// Replaces the identifier of the path component with another.
16    Ident(Ident),
17    /// Removes the path component.
18    Remove,
19    /// Keeps the path component.
20    Keep,
21}
22
23// This is only pub(crate) because it appears as a bound of `replace_self_path`.
24pub(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
55/// Replaces all associated types of `Self` from `value`.
56///
57/// `replace_with` determines what happens to `Self::` when `Some()` is
58/// returned from `is_assoc_type`.
59///
60/// `is_assoc_type` is used to find the associated types to replace
61/// (when the function returns Some(_)),
62/// as well as what to replace them with.
63///
64///
65pub(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
84// This is only pub(crate) because it is used within the VisitMutWith trait.
85pub(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        // println!("\nbefore:{}",(&*segments).into_token_stream() );
108        // println!("segments[1]:{}",segments.iter().nth(1).into_token_stream() );
109
110        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        // println!("is_replaced:{:?}",is_replaced );
133        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        // println!("after:{}",(&*i).into_token_stream() );
153    }
154}