Skip to content
This repository was archived by the owner on Apr 2, 2026. It is now read-only.

Commit 30a48ca

Browse files
committed
recursive-leak: do what was suggested by @zesterer
1 parent b8fc4eb commit 30a48ca

1 file changed

Lines changed: 61 additions & 13 deletions

File tree

src/recursive.rs

Lines changed: 61 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,21 @@
1010
1111
use super::*;
1212

13+
mod private {
14+
pub trait RecursiveState {}
15+
}
16+
17+
use private::RecursiveState;
18+
19+
/// A State which represents when a [`Recursive`](Recursive) has been declared, but not defined
20+
pub struct Declared;
21+
22+
/// A State which represents when a [`Recursive`](Recursive) has been both defined and declared
23+
pub struct Defined;
24+
25+
impl RecursiveState for Declared {}
26+
impl RecursiveState for Defined {}
27+
1328
#[cfg(not(feature = "sync"))]
1429
struct OnceCell<T>(core::cell::Cell<Option<T>>);
1530
#[cfg(not(feature = "sync"))]
@@ -80,11 +95,15 @@ pub struct Indirect<'a, 'b, I: Input<'a>, O, Extra: ParserExtra<'a, I>> {
8095
/// [definition](Recursive::define).
8196
///
8297
/// Prefer to use [`recursive()`], which exists as a convenient wrapper around both operations, if possible.
83-
pub struct Recursive<P: ?Sized> {
98+
pub struct Recursive<P: ?Sized, S: RecursiveState> {
8499
inner: RecursiveInner<P>,
100+
#[allow(dead_code)]
101+
state: EmptyPhantom<S>,
85102
}
86103

87-
impl<'a, 'b, I: Input<'a>, O, E: ParserExtra<'a, I>> Recursive<Indirect<'a, 'b, I, O, E>> {
104+
impl<'a, 'b, I: Input<'a>, O, E: ParserExtra<'a, I>>
105+
Recursive<Indirect<'a, 'b, I, O, E>, Declared>
106+
{
88107
/// Declare the existence of a recursive parser, allowing it to be used to construct parser combinators before
89108
/// being fulled defined.
90109
///
@@ -111,11 +130,11 @@ impl<'a, 'b, I: Input<'a>, O, E: ParserExtra<'a, I>> Recursive<Indirect<'a, 'b,
111130
///
112131
/// // Define the parser in terms of itself.
113132
/// // In this case, the parser parses a right-recursive list of '+' into a singly linked list
114-
/// chain.define(just::<_, _, extra::Err<Simple<char>>>('+')
133+
/// let chain = Recursive::define(just::<_, _, extra::Err<Simple<char>>>('+')
115134
/// .then(chain.clone())
116135
/// .map(|(c, chain)| Chain::Link(c, Box::new(chain)))
117136
/// .or_not()
118-
/// .map(|chain| chain.unwrap_or(Chain::End)));
137+
/// .map(|chain| chain.unwrap_or(Chain::End)), chain);
119138
///
120139
/// assert_eq!(chain.parse("").into_result(), Ok(Chain::End));
121140
/// assert_eq!(
@@ -128,24 +147,36 @@ impl<'a, 'b, I: Input<'a>, O, E: ParserExtra<'a, I>> Recursive<Indirect<'a, 'b,
128147
inner: RecursiveInner::Owned(RefC::new(Indirect {
129148
inner: OnceCell::new(),
130149
})),
150+
state: EmptyPhantom::new(),
131151
}
132152
}
133153

134154
/// Defines the parser after declaring it, allowing it to be used for parsing.
135155
// INFO: Clone bound not actually needed, but good to be safe for future compat
136156
#[track_caller]
137-
pub fn define<P: Parser<'a, I, O, E> + Clone + MaybeSync + 'a + 'b>(&mut self, parser: P) {
157+
pub fn define<P: Parser<'a, I, O, E> + Clone + MaybeSync + 'a + 'b>(
158+
parser: P,
159+
declaration: Self,
160+
) -> Recursive<Indirect<'a, 'b, I, O, E>, Defined> {
138161
let location = *Location::caller();
139-
self.parser()
162+
declaration
163+
.parser()
140164
.inner
141165
.set(Box::new(parser))
142166
.unwrap_or_else(|_| {
143-
panic!("recursive parsers can only be defined once, trying to redefine it at {location}")
167+
panic!(
168+
"recursive parsers can only be defined once, trying to redefine it at {location}"
169+
)
144170
});
171+
172+
Recursive {
173+
state: EmptyPhantom::new(),
174+
inner: declaration.inner,
175+
}
145176
}
146177
}
147178

148-
impl<P: ?Sized> Recursive<P> {
179+
impl<P: ?Sized, S: RecursiveState> Recursive<P, S> {
149180
#[inline]
150181
fn parser(&self) -> RefC<P> {
151182
match &self.inner {
@@ -157,9 +188,22 @@ impl<P: ?Sized> Recursive<P> {
157188
}
158189
}
159190

160-
impl<P: ?Sized> Clone for Recursive<P> {
191+
impl<P: ?Sized> Clone for Recursive<P, Declared> {
192+
fn clone(&self) -> Self {
193+
Self {
194+
state: EmptyPhantom::new(),
195+
inner: match &self.inner {
196+
RecursiveInner::Owned(x) => RecursiveInner::Unowned(RefC::downgrade(x)),
197+
RecursiveInner::Unowned(x) => RecursiveInner::Unowned(x.clone()),
198+
},
199+
}
200+
}
201+
}
202+
203+
impl<P: ?Sized> Clone for Recursive<P, Defined> {
161204
fn clone(&self) -> Self {
162205
Self {
206+
state: EmptyPhantom::new(),
163207
inner: match &self.inner {
164208
RecursiveInner::Owned(x) => RecursiveInner::Owned(x.clone()),
165209
RecursiveInner::Unowned(x) => RecursiveInner::Unowned(x.clone()),
@@ -179,10 +223,11 @@ pub(crate) fn recurse<R, F: FnOnce() -> R>(f: F) -> R {
179223
f()
180224
}
181225

182-
impl<'a, 'b, I, O, E> ParserSealed<'a, I, O, E> for Recursive<Indirect<'a, 'b, I, O, E>>
226+
impl<'a, 'b, I, O, E, S> ParserSealed<'a, I, O, E> for Recursive<Indirect<'a, 'b, I, O, E>, S>
183227
where
184228
I: Input<'a>,
185229
E: ParserExtra<'a, I>,
230+
S: RecursiveState,
186231
{
187232
#[inline]
188233
fn go<M: Mode>(&self, inp: &mut InputRef<'a, '_, I, E>) -> PResult<M, O> {
@@ -201,10 +246,11 @@ where
201246
go_extra!(O);
202247
}
203248

204-
impl<'a, 'b, I, O, E> ParserSealed<'a, I, O, E> for Recursive<Direct<'a, 'b, I, O, E>>
249+
impl<'a, 'b, I, O, E, S> ParserSealed<'a, I, O, E> for Recursive<Direct<'a, 'b, I, O, E>, S>
205250
where
206251
I: Input<'a>,
207252
E: ParserExtra<'a, I>,
253+
S: RecursiveState,
208254
{
209255
#[inline]
210256
fn go<M: Mode>(&self, inp: &mut InputRef<'a, '_, I, E>) -> PResult<M, O> {
@@ -264,23 +310,25 @@ where
264310
/// ])));
265311
/// ```
266312
// INFO: Clone bound not actually needed, but good to be safe for future compat
267-
pub fn recursive<'a, 'b, I, O, E, A, F>(f: F) -> Recursive<Direct<'a, 'b, I, O, E>>
313+
pub fn recursive<'a, 'b, I, O, E, A, F>(f: F) -> Recursive<Direct<'a, 'b, I, O, E>, Defined>
268314
where
269315
I: Input<'a>,
270316
E: ParserExtra<'a, I>,
271317
A: Parser<'a, I, O, E> + Clone + MaybeSync + 'b,
272-
F: FnOnce(Recursive<Direct<'a, 'b, I, O, E>>) -> A,
318+
F: FnOnce(Recursive<Direct<'a, 'b, I, O, E>, Declared>) -> A,
273319
{
274320
let rc = RefC::new_cyclic(|rc| {
275321
let rc: RefW<DynParser<'a, 'b, I, O, E>> = rc.clone() as _;
276322
let parser = Recursive {
277323
inner: RecursiveInner::Unowned(rc.clone()),
324+
state: EmptyPhantom::<Declared>::new(),
278325
};
279326

280327
f(parser)
281328
});
282329

283330
Recursive {
284331
inner: RecursiveInner::Owned(rc),
332+
state: EmptyPhantom::new(),
285333
}
286334
}

0 commit comments

Comments
 (0)