Skip to content

Commit db8aec9

Browse files
authored
feat: make visitor early-stoppable (#5)
Signed-off-by: tison <wander4096@gmail.com>
1 parent 7bd3090 commit db8aec9

File tree

5 files changed

+257
-84
lines changed

5 files changed

+257
-84
lines changed

visitor-derive/src/lib.rs

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -230,15 +230,15 @@ fn impl_traversable(input: DeriveInput, mutable: bool) -> Result<TokenStream> {
230230
None
231231
} else {
232232
Some(quote! {
233-
::visitor::#visitor::#enter_method(visitor, self);
233+
::visitor::#visitor::#enter_method(visitor, self)?;
234234
})
235235
};
236236

237237
let leave_self = if skip_visit_self {
238238
None
239239
} else {
240240
Some(quote! {
241-
::visitor::#visitor::#leave_method(visitor, self);
241+
::visitor::#visitor::#leave_method(visitor, self)?;
242242
})
243243
};
244244

@@ -275,10 +275,14 @@ fn impl_traversable(input: DeriveInput, mutable: bool) -> Result<TokenStream> {
275275

276276
Ok(quote! {
277277
impl #impl_generics ::visitor::#impl_trait for #name #ty_generics #where_clause {
278-
fn #method<V: ::visitor::#visitor>(& #mut_modifier self, visitor: &mut V) {
278+
fn #method<V: ::visitor::#visitor>(
279+
& #mut_modifier self,
280+
visitor: &mut V
281+
) -> ::core::ops::ControlFlow<V::Break> {
279282
#enter_self
280283
#traverse_fields
281284
#leave_self
285+
::core::ops::ControlFlow::Continue(())
282286
}
283287
}
284288
})
@@ -410,6 +414,6 @@ fn traverse_field(value: &TokenStream, field: Field, mutable: bool) -> Result<To
410414
)?;
411415

412416
Ok(quote! {
413-
#traverse_fn(#value, visitor);
417+
#traverse_fn(#value, visitor)?;
414418
})
415419
}

visitor/src/function/mod.rs

Lines changed: 107 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -16,62 +16,150 @@
1616
1717
use core::any::Any;
1818
use core::marker::PhantomData;
19+
use core::ops::ControlFlow;
1920

2021
use crate::Visitor;
2122
use crate::VisitorMut;
2223

2324
/// Type returned by `make_visitor` factories.
24-
pub struct FnVisitor<T, F1, F2> {
25+
pub struct FnVisitor<T, B, F1, F2> {
2526
enter: F1,
2627
leave: F2,
27-
m: PhantomData<T>,
28+
marker_type: PhantomData<T>,
29+
marker_break: PhantomData<B>,
2830
}
2931

30-
impl<T: Any, F1: FnMut(&T), F2: FnMut(&T)> Visitor for FnVisitor<T, F1, F2> {
31-
fn enter(&mut self, this: &dyn Any) {
32+
impl<T, B, F1, F2> Visitor for FnVisitor<T, B, F1, F2>
33+
where
34+
T: Any,
35+
F1: FnMut(&T) -> ControlFlow<B>,
36+
F2: FnMut(&T) -> ControlFlow<B>,
37+
{
38+
type Break = B;
39+
40+
fn enter(&mut self, this: &dyn Any) -> ControlFlow<Self::Break> {
3241
if let Some(item) = this.downcast_ref::<T>() {
33-
(self.enter)(item);
42+
(self.enter)(item)?;
3443
}
44+
ControlFlow::Continue(())
3545
}
3646

37-
fn leave(&mut self, this: &dyn Any) {
47+
fn leave(&mut self, this: &dyn Any) -> ControlFlow<Self::Break> {
3848
if let Some(item) = this.downcast_ref::<T>() {
39-
(self.leave)(item);
49+
(self.leave)(item)?;
4050
}
51+
ControlFlow::Continue(())
4152
}
4253
}
4354

44-
impl<T: Any, F1: FnMut(&mut T), F2: FnMut(&mut T)> VisitorMut for FnVisitor<T, F1, F2> {
45-
fn enter_mut(&mut self, this: &mut dyn Any) {
55+
impl<T, B, F1, F2> VisitorMut for FnVisitor<T, B, F1, F2>
56+
where
57+
T: Any,
58+
F1: FnMut(&mut T) -> ControlFlow<B>,
59+
F2: FnMut(&mut T) -> ControlFlow<B>,
60+
{
61+
type Break = B;
62+
63+
fn enter_mut(&mut self, this: &mut dyn Any) -> ControlFlow<Self::Break> {
4664
if let Some(item) = this.downcast_mut::<T>() {
47-
(self.enter)(item);
65+
(self.enter)(item)?;
4866
}
67+
ControlFlow::Continue(())
4968
}
5069

51-
fn leave_mut(&mut self, this: &mut dyn Any) {
70+
fn leave_mut(&mut self, this: &mut dyn Any) -> ControlFlow<Self::Break> {
5271
if let Some(item) = this.downcast_mut::<T>() {
53-
(self.leave)(item);
72+
(self.leave)(item)?;
5473
}
74+
ControlFlow::Continue(())
5575
}
5676
}
5777

78+
type DefaultVisitFn<T, B> = fn(&T) -> ControlFlow<B>;
79+
type DefaultVisitFnMut<T, B> = fn(&mut T) -> ControlFlow<B>;
80+
5881
/// Create a visitor that only visits items of a specific type from a function or a closure.
59-
pub fn make_visitor<T, F1: FnMut(&T), F2: FnMut(&T)>(enter: F1, leave: F2) -> FnVisitor<T, F1, F2> {
82+
pub fn make_visitor<T, B, F1, F2>(enter: F1, leave: F2) -> FnVisitor<T, B, F1, F2>
83+
where
84+
T: Any,
85+
F1: FnMut(&T) -> ControlFlow<B>,
86+
F2: FnMut(&T) -> ControlFlow<B>,
87+
{
6088
FnVisitor {
6189
enter,
6290
leave,
63-
m: PhantomData,
91+
marker_type: PhantomData,
92+
marker_break: PhantomData,
93+
}
94+
}
95+
96+
/// Similar to [`make_visitor`], but the closure will only be called on entering.
97+
pub fn make_visitor_enter<T, B, F>(enter: F) -> FnVisitor<T, B, F, DefaultVisitFn<T, B>>
98+
where
99+
T: Any,
100+
F: FnMut(&T) -> ControlFlow<B>,
101+
{
102+
FnVisitor {
103+
enter,
104+
leave: |_| ControlFlow::Continue(()),
105+
marker_type: PhantomData,
106+
marker_break: PhantomData,
107+
}
108+
}
109+
110+
/// Similar to [`make_visitor`], but the closure will only be called on leaving.
111+
pub fn make_visitor_leave<T, B, F>(leave: F) -> FnVisitor<T, B, DefaultVisitFn<T, B>, F>
112+
where
113+
T: Any,
114+
F: FnMut(&T) -> ControlFlow<B>,
115+
{
116+
FnVisitor {
117+
enter: |_| ControlFlow::Continue(()),
118+
leave,
119+
marker_type: PhantomData,
120+
marker_break: PhantomData,
64121
}
65122
}
66123

67124
/// Create a visitor that only visits mutable items of a specific type from a function or a closure.
68-
pub fn make_visitor_mut<T, F1: FnMut(&mut T), F2: FnMut(&mut T)>(
69-
enter: F1,
70-
leave: F2,
71-
) -> FnVisitor<T, F1, F2> {
125+
pub fn make_visitor_mut<T, B, F1, F2>(enter: F1, leave: F2) -> FnVisitor<T, B, F1, F2>
126+
where
127+
T: Any,
128+
F1: FnMut(&mut T) -> ControlFlow<B>,
129+
F2: FnMut(&mut T) -> ControlFlow<B>,
130+
{
131+
FnVisitor {
132+
enter,
133+
leave,
134+
marker_type: PhantomData,
135+
marker_break: PhantomData,
136+
}
137+
}
138+
139+
/// Similar to [`make_visitor_mut`], but the closure will only be called on entering.
140+
pub fn make_visitor_enter_mut<T, B, F>(enter: F) -> FnVisitor<T, B, F, DefaultVisitFnMut<T, B>>
141+
where
142+
T: Any,
143+
F: FnMut(&mut T) -> ControlFlow<B>,
144+
{
72145
FnVisitor {
73146
enter,
147+
leave: |_| ControlFlow::Continue(()),
148+
marker_type: PhantomData,
149+
marker_break: PhantomData,
150+
}
151+
}
152+
153+
/// Similar to [`make_visitor_mut`], but the closure will only be called on leaving.
154+
pub fn make_visitor_leave_mut<T, B, F>(leave: F) -> FnVisitor<T, B, DefaultVisitFnMut<T, B>, F>
155+
where
156+
T: Any,
157+
F: FnMut(&mut T) -> ControlFlow<B>,
158+
{
159+
FnVisitor {
160+
enter: |_| ControlFlow::Continue(()),
74161
leave,
75-
m: PhantomData,
162+
marker_type: PhantomData,
163+
marker_break: PhantomData,
76164
}
77165
}

0 commit comments

Comments
 (0)