temp_stack/
lib.rs

1//! [`TempStack`] is a linked list data structure based on the [`temp_inst`] crate. The intended use
2//! case is that list items are allocated on the call stack; then the list also represents a "stack"
3//! with "frames". Via [`temp_inst`], each frame can contain references to data that is available at
4//! the point where it is constructed, without having to add lifetime parameters.
5//!
6//! # Example
7//!
8//! The following lambda expression parser uses [`TempStack`] as a context that specifies which
9//! variables are in scope, in order to determine the
10//! [de Bruijn index](https://en.wikipedia.org/wiki/De_Bruijn_index) corresponding to a given
11//! variable name.
12//!
13//! ```
14//! # use temp_inst::TempRef;
15//! # use crate::temp_stack::TempStack;
16//! #
17//! #[derive(Clone, PartialEq, Debug)]
18//! enum Expr {
19//!     Var(usize), // A de Bruijn index that specifies which binder the variable references.
20//!     App(Box<Expr>, Box<Expr>),
21//!     Lambda(String, Box<Expr>),
22//! }
23//!
24//! // The context containing the variables that are in scope at any given point during
25//! // parsing. Note how `Ctx` does not require any lifetime parameters, even though it
26//! // references strings with arbitrary lifetimes.
27//! type Ctx = TempStack<(), TempRef<str>>;
28//!
29//! fn parse(s: &str) -> Result<Expr, String> {
30//!     let root_ctx = Ctx::new_root(());
31//!     let (expr, s) = parse_expr(s, &root_ctx)?;
32//!     if !s.is_empty() {
33//!         return Err(format!("unexpected character at `{s}`"));
34//!     }
35//!     Ok(expr)
36//! }
37//!
38//! fn parse_expr<'a>(s: &'a str, ctx: &Ctx) -> Result<(Expr, &'a str), String> {
39//!     let (expr, mut s) = parse_single_expr(s, ctx)?;
40//!     let Some(mut expr) = expr else {
41//!         return Err(format!("expected expression at `{s}`"));
42//!     };
43//!     loop {
44//!         let (arg, r) = parse_single_expr(s, ctx)?;
45//!         s = r;
46//!         let Some(arg) = arg else {
47//!             break;
48//!         };
49//!         expr = Expr::App(Box::new(expr), Box::new(arg));
50//!     }
51//!     Ok((expr, s))
52//! }
53//!
54//! fn parse_single_expr<'a>(s: &'a str, ctx: &Ctx) -> Result<(Option<Expr>, &'a str), String> {
55//!     let s = s.trim_ascii_start();
56//!     if let Some(s) = s.strip_prefix('λ') {
57//!         let s = s.trim_ascii_start();
58//!         let name_len = s
59//!             .find(|ch: char| !ch.is_ascii_alphanumeric())
60//!             .unwrap_or(s.len());
61//!         if name_len == 0 {
62//!             return Err(format!("expected parameter name at `{s}`"));
63//!         }
64//!         let (name, s) = s.split_at(name_len);
65//!         let s = s.trim_ascii_start();
66//!         let Some(s) = s.strip_prefix('.') else {
67//!             return Err(format!("expected `.` at `{s}`"));
68//!         };
69//!         // Create a new context with `name` added.
70//!         let body_ctx = ctx.new_frame(name);
71//!         let (body, s) = parse_expr(s, &body_ctx)?;
72//!         Ok((Some(Expr::Lambda(name.into(), Box::new(body))), s))
73//!     } else if let Some(s) = s.strip_prefix('(') {
74//!         let (body, s) = parse_expr(s, ctx)?;
75//!         let Some(s) = s.strip_prefix(')') else {
76//!             return Err(format!("expected `)` at `{s}`"));
77//!         };
78//!         Ok((Some(body), s))
79//!     } else {
80//!         let name_len = s
81//!             .find(|ch: char| !ch.is_ascii_alphanumeric())
82//!             .unwrap_or(s.len());
83//!         if name_len == 0 {
84//!             Ok((None, s))
85//!         } else {
86//!             let (name, r) = s.split_at(name_len);
87//!             // Determine the De Bruijn index of the nearest `name` in context.
88//!             let Some(idx) = ctx.iter().position(|v| v == name) else {
89//!                 return Err(format!("variable `{name}` not found at `{s}`"));
90//!             };
91//!             Ok((Some(Expr::Var(idx)), r))
92//!         }
93//!     }
94//! }
95//!
96//! assert_eq!(
97//!     parse("λx.x"),
98//!     Ok(Expr::Lambda("x".into(), Box::new(Expr::Var(0))))
99//! );
100//!
101//! assert_eq!(
102//!     parse("λx. x x"),
103//!     Ok(Expr::Lambda(
104//!         "x".into(),
105//!         Box::new(Expr::App(Box::new(Expr::Var(0)), Box::new(Expr::Var(0))))
106//!     ))
107//! );
108//!
109//! assert_eq!(
110//!     parse("λx.λy. y (x y x)"),
111//!     Ok(Expr::Lambda(
112//!         "x".into(),
113//!         Box::new(Expr::Lambda(
114//!             "y".into(),
115//!             Box::new(Expr::App(
116//!                 Box::new(Expr::Var(0)),
117//!                 Box::new(Expr::App(
118//!                     Box::new(Expr::App(Box::new(Expr::Var(1)), Box::new(Expr::Var(0)))),
119//!                     Box::new(Expr::Var(1)),
120//!                 ))
121//!             ))
122//!         ))
123//!     ))
124//! );
125//!
126//! assert_eq!(
127//!     parse("λx.λy. (λz.z) (x z x)"),
128//!     Err("variable `z` not found at `z x)`".into())
129//! );
130//! ```
131
132#![no_std]
133
134use core::{fmt::Debug, iter::FusedIterator, mem::take, pin::Pin};
135
136use either::Either;
137use temp_inst::{TempInst, TempInstPin, TempRefPin, TempRepr, TempReprMut};
138
139/// A linked list consisting of a single item of type `Root` and arbitrarily many items of type
140/// `Frame`. Both types must implement [`temp_inst::TempRepr`], which declares them as "temporary
141/// representations" of possibly lifetime-dependent types such as references.
142///
143/// A [`TempStack`] can be constructed and referenced in a mutable or shared fashion, and in the
144/// mutable case the usual exclusivity rules apply. However, adding an item never alters the list
145/// it was added to; it merely creates a new list that borrows the original one (exclusively or
146/// shared).
147///
148/// # Remarks
149///
150/// Although the root and frames can consist of arbitrary data via [`temp_inst::SelfRepr`], usually
151/// the size of both should be kept small, using references via [`temp_inst::TempRef`] or
152/// [`temp_inst::TempRefMut`] instead, for two reasons.
153/// * Both root and frame data are stored in the same `enum`, so a large root also enlarges each
154///   frame.
155/// * The iterators return copies/clones of the frame data. Therefore, if frames are large,
156///   iteration should be implemented manually.
157#[derive(TempRepr, TempReprMut)]
158pub enum TempStack<Root: TempRepr, Frame: TempRepr> {
159    Root {
160        data: Root,
161    },
162    Frame {
163        data: Frame,
164        parent: TempRefPin<TempStack<Root, Frame>>,
165    },
166}
167
168impl<Root: TempRepr, Frame: TempRepr> TempStack<Root, Frame> {
169    /// Creates a new stack and returns a [`TempInst`] object that only hands out shared references.
170    pub fn new_root(data: Root::Shared<'_>) -> TempStackFrame<'_, Root, Frame> {
171        TempInst::new(Either::Left(data))
172    }
173
174    /// Creates a new stack that extends `self` with the given frame, and returns a [`TempInst`]
175    /// object that only hands out shared references.
176    pub fn new_frame<'a>(&'a self, data: Frame::Shared<'a>) -> TempStackFrame<'a, Root, Frame> {
177        TempInst::new(Either::Right((data, self)))
178    }
179
180    /// Returns an iterator that traverses the stack starting at the current frame and ending at the
181    /// root.
182    ///
183    /// The iterator returns the data of each frame, and also provides [`TempStackIter::into_root`]
184    /// to access the root data.
185    pub fn iter(&self) -> TempStackIter<'_, Root, Frame> {
186        TempStackIter::new(self)
187    }
188}
189
190impl<Root: TempReprMut, Frame: TempReprMut> TempStack<Root, Frame> {
191    /// Creates a new stack and returns a [`TempInstPin`] object that can hand out pinned mutable
192    /// references.
193    ///
194    /// Note that this requires the resulting object to be pinned, e.g. using [`core::pin::pin!`].
195    pub fn new_root_mut(data: Root::Mutable<'_>) -> TempStackFrameMut<'_, Root, Frame> {
196        TempInstPin::new(Either::Left(data))
197    }
198
199    /// Creates a new stack that extends `self` with the given frame, and returns a [`TempInstPin`]
200    /// object that can hand out pinned mutable references.
201    ///
202    /// Note that this requires the resulting object to be pinned, e.g. using [`core::pin::pin!`].
203    pub fn new_frame_mut<'a>(
204        self: Pin<&'a mut Self>,
205        data: Frame::Mutable<'a>,
206    ) -> TempStackFrameMut<'a, Root, Frame> {
207        TempInstPin::new(Either::Right((data, self)))
208    }
209
210    /// Returns an iterator that traverses the stack starting at the current frame and ending at the
211    /// root, returning mutable frames.
212    ///
213    /// The iterator returns the data of each frame, and also provides
214    /// [`TempStackIterMut::into_root`] to access the root data.
215    pub fn iter_mut(self: Pin<&mut Self>) -> TempStackIterMut<'_, Root, Frame> {
216        TempStackIterMut::new(self)
217    }
218}
219
220impl<Root: TempRepr + Debug, Frame: TempRepr + Debug> Debug for TempStack<Root, Frame> {
221    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
222        f.write_str("[")?;
223        self.fmt_contents(f)?;
224        f.write_str("]")?;
225        Ok(())
226    }
227}
228
229impl<Root: TempRepr + Debug, Frame: TempRepr + Debug> TempStack<Root, Frame> {
230    fn fmt_contents(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
231        match self {
232            TempStack::Root { data } => data.fmt(f),
233            TempStack::Frame { data, parent } => {
234                parent.fmt_contents(f)?;
235                let separator = if matches!(**parent, TempStack::Root { .. }) {
236                    "; "
237                } else {
238                    ", "
239                };
240                f.write_str(separator)?;
241                data.fmt(f)
242            }
243        }
244    }
245}
246
247pub type TempStackRef<'a, Root, Frame> = &'a TempStack<Root, Frame>;
248pub type TempStackRefMut<'a, Root, Frame> = Pin<&'a mut TempStack<Root, Frame>>;
249
250pub type TempStackFrame<'a, Root, Frame> = TempInst<'a, TempStack<Root, Frame>>;
251pub type TempStackFrameMut<'a, Root, Frame> = TempInstPin<'a, TempStack<Root, Frame>>;
252
253/// An iterator over frames of a shared `TempStack`.
254pub struct TempStackIter<'a, Root: TempRepr, Frame: TempRepr>(TempStackRef<'a, Root, Frame>);
255
256impl<'a, Root: TempRepr, Frame: TempRepr> TempStackIter<'a, Root, Frame> {
257    fn new(start: TempStackRef<'a, Root, Frame>) -> Self {
258        TempStackIter(start)
259    }
260
261    /// Consumes the iterator and returns the root data of the stack.
262    /// This method is cheap if the iterator has already reached the end, but needs to traverse the
263    /// rest of the stack if it has not.
264    pub fn into_root(mut self) -> Root::Shared<'a> {
265        loop {
266            match self.0 {
267                TempStack::Root { data } => {
268                    return data.get();
269                }
270                TempStack::Frame { parent, .. } => {
271                    self.0 = parent.get();
272                }
273            }
274        }
275    }
276}
277
278impl<'a, Root: TempRepr, Frame: TempRepr> Copy for TempStackIter<'a, Root, Frame> {}
279
280impl<'a, Root: TempRepr, Frame: TempRepr> Clone for TempStackIter<'a, Root, Frame> {
281    fn clone(&self) -> Self {
282        *self
283    }
284}
285
286impl<'a, Root: TempRepr, Frame: TempRepr> Iterator for TempStackIter<'a, Root, Frame> {
287    type Item = Frame::Shared<'a>;
288
289    fn next(&mut self) -> Option<Self::Item> {
290        match self.0 {
291            TempStack::Root { .. } => None,
292            TempStack::Frame { data, parent } => {
293                self.0 = parent.get();
294                Some(data.get())
295            }
296        }
297    }
298}
299
300impl<'a, Root: TempRepr, Frame: TempRepr> FusedIterator for TempStackIter<'a, Root, Frame> {}
301
302/// An iterator over frames of a mutable `TempStack`.
303pub struct TempStackIterMut<'a, Root: TempReprMut, Frame: TempReprMut>(
304    // Note that this should never be `None`, but we temporarily need to extract the value in the
305    // `next` method.
306    Option<TempStackRefMut<'a, Root, Frame>>,
307);
308
309impl<'a, Root: TempReprMut, Frame: TempReprMut> TempStackIterMut<'a, Root, Frame> {
310    fn new(start: TempStackRefMut<'a, Root, Frame>) -> Self {
311        TempStackIterMut(Some(start))
312    }
313
314    /// Consumes the iterator and returns the root data of the stack.
315    /// This method is cheap if the iterator has already reached the end, but needs to traverse the
316    /// rest of the stack if it has not.
317    pub fn into_root(self) -> Root::Mutable<'a> {
318        let mut temp = self.0.unwrap();
319        // SAFETY: This only implements a pinning projection.
320        unsafe {
321            loop {
322                match temp.get_unchecked_mut() {
323                    TempStack::Root { data } => {
324                        return Pin::new_unchecked(data).get_mut_pinned();
325                    }
326                    TempStack::Frame { parent, .. } => {
327                        temp = Pin::new_unchecked(parent).get_mut_pinned();
328                    }
329                }
330            }
331        }
332    }
333}
334
335impl<'a, Root: TempReprMut, Frame: TempReprMut> Iterator for TempStackIterMut<'a, Root, Frame> {
336    type Item = Frame::Mutable<'a>;
337
338    fn next(&mut self) -> Option<Self::Item> {
339        let temp = take(&mut self.0).unwrap();
340        // SAFETY: This only implements a pinning projection.
341        unsafe {
342            let temp = temp.get_unchecked_mut();
343            match temp {
344                TempStack::Root { .. } => {
345                    self.0 = Some(Pin::new_unchecked(temp));
346                    None
347                }
348                TempStack::Frame { data, parent } => {
349                    self.0 = Some(Pin::new_unchecked(parent).get_mut_pinned());
350                    Some(Pin::new_unchecked(data).get_mut_pinned())
351                }
352            }
353        }
354    }
355}
356
357impl<'a, Root: TempReprMut, Frame: TempReprMut> FusedIterator
358    for TempStackIterMut<'a, Root, Frame>
359{
360}
361
362#[cfg(test)]
363mod tests {
364    use core::pin::pin;
365
366    use temp_inst::{TempRef, TempRefMut};
367
368    use super::*;
369
370    #[test]
371    fn empty_stack() {
372        let root = 42;
373        let stack = TempStack::<TempRef<i32>, ()>::new_root(&root);
374
375        let mut iter = stack.iter();
376        assert!(iter.next().is_none());
377        let root_ref = iter.into_root();
378        assert_eq!(*root_ref, 42);
379    }
380
381    #[test]
382    fn empty_stack_mut() {
383        let mut root = 42;
384        let stack = pin!(TempStack::<TempRefMut<i32>, ()>::new_root_mut(&mut root));
385
386        let mut iter = stack.deref_pin().iter_mut();
387        assert!(iter.next().is_none());
388        let root_ref = iter.into_root();
389        assert_eq!(*root_ref, 42);
390        *root_ref += 1;
391        assert_eq!(root, 43);
392    }
393
394    #[test]
395    fn stack_with_frames() {
396        let root = 42;
397        let stack = TempStack::<TempRef<i32>, TempRef<i32>>::new_root(&root);
398        let stack = stack.new_frame(&1);
399        let stack = stack.new_frame(&2);
400        let stack = stack.new_frame(&3);
401
402        let mut iter = stack.iter();
403        assert_eq!(iter.next(), Some(&3));
404        assert_eq!(iter.next(), Some(&2));
405        assert_eq!(iter.next(), Some(&1));
406        assert!(iter.next().is_none());
407        let root_ref = iter.into_root();
408        assert_eq!(*root_ref, 42);
409
410        let iter = stack.iter();
411        let root_ref = iter.into_root();
412        assert_eq!(*root_ref, 42);
413    }
414
415    #[test]
416    fn stack_with_frames_mut() {
417        let mut root = 42;
418        let stack = pin!(TempStack::<TempRefMut<i32>, TempRefMut<i32>>::new_root_mut(
419            &mut root
420        ));
421        let mut frame1 = 1;
422        let stack = pin!(stack.deref_pin().new_frame_mut(&mut frame1));
423        let mut frame2 = 2;
424        let stack = pin!(stack.deref_pin().new_frame_mut(&mut frame2));
425        let mut frame3 = 3;
426        let mut stack = pin!(stack.deref_pin().new_frame_mut(&mut frame3));
427
428        let mut iter = stack.as_mut().deref_pin().iter_mut();
429        let frame3_ref = iter.next().unwrap();
430        assert_eq!(frame3_ref, &mut 3);
431        *frame3_ref += 1;
432        assert_eq!(iter.next(), Some(&mut 2));
433        let frame1_ref = iter.next().unwrap();
434        assert_eq!(frame1_ref, &mut 1);
435        *frame1_ref -= 1;
436        assert!(iter.next().is_none());
437        let root_ref = iter.into_root();
438        assert_eq!(*root_ref, 42);
439        *root_ref += 1;
440
441        let iter = stack.deref_pin().iter_mut();
442        let root_ref = iter.into_root();
443        assert_eq!(*root_ref, 43);
444
445        assert_eq!(root, 43);
446        assert_eq!(frame1, 0);
447        assert_eq!(frame2, 2);
448        assert_eq!(frame3, 4);
449    }
450
451    #[test]
452    fn stack_with_branching() {
453        let root = 42;
454        let stack = TempStack::<TempRef<i32>, TempRef<i32>>::new_root(&root);
455        let stack = stack.new_frame(&1);
456        let stack = stack.new_frame(&2);
457        let stack2 = stack.new_frame(&11);
458        let stack = stack.new_frame(&3);
459        let stack2 = stack2.new_frame(&12);
460        let stack2 = stack2.new_frame(&13);
461
462        let mut iter = stack.iter();
463        assert_eq!(iter.next(), Some(&3));
464        assert_eq!(iter.next(), Some(&2));
465        assert_eq!(iter.next(), Some(&1));
466        assert!(iter.next().is_none());
467
468        let mut iter2 = stack2.iter();
469        assert_eq!(iter2.next(), Some(&13));
470        assert_eq!(iter2.next(), Some(&12));
471        assert_eq!(iter2.next(), Some(&11));
472        assert_eq!(iter2.next(), Some(&2));
473        assert_eq!(iter2.next(), Some(&1));
474        assert!(iter2.next().is_none());
475    }
476
477    #[test]
478    fn stack_with_branching_mut() {
479        let mut root = 42;
480        let stack = pin!(TempStack::<TempRefMut<i32>, TempRefMut<i32>>::new_root_mut(
481            &mut root
482        ));
483        let mut frame1 = 1;
484        let stack = pin!(stack.deref_pin().new_frame_mut(&mut frame1));
485        let mut frame2 = 2;
486        let mut stack = pin!(stack.deref_pin().new_frame_mut(&mut frame2));
487        let mut frame3 = 3;
488        let stack2 = pin!(stack.as_mut().deref_pin().new_frame_mut(&mut frame3));
489
490        let mut iter = stack2.deref_pin().iter_mut();
491        let frame3_ref = iter.next().unwrap();
492        assert_eq!(frame3_ref, &mut 3);
493        *frame3_ref += 1;
494        assert_eq!(iter.next(), Some(&mut 2));
495        let frame1_ref = iter.next().unwrap();
496        assert_eq!(frame1_ref, &mut 1);
497        *frame1_ref -= 1;
498        assert!(iter.next().is_none());
499        let root_ref = iter.into_root();
500        assert_eq!(*root_ref, 42);
501        *root_ref += 1;
502
503        let mut iter = stack.deref_pin().iter_mut();
504        assert_eq!(iter.next(), Some(&mut 2));
505        assert_eq!(iter.next(), Some(&mut 0));
506        assert!(iter.next().is_none());
507        let root_ref = iter.into_root();
508        assert_eq!(*root_ref, 43);
509
510        assert_eq!(root, 43);
511        assert_eq!(frame1, 0);
512        assert_eq!(frame2, 2);
513        assert_eq!(frame3, 4);
514    }
515}