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}