syntree/builder/checkpoint.rs
1use core::cell::Cell;
2
3use alloc::rc::Rc;
4
5/// The identifier of a node as returned by functions such as
6/// [`Builder::checkpoint`].
7///
8/// This can be used as a checkpoint in [`Builder::close_at`], and a checkpoint
9/// can be fetched up front from [`Builder::checkpoint`].
10///
11/// # Checkpoints and cloned builders
12///
13/// A checkpoint belongs to the builder that handed it out, and closing it
14/// updates it in place. A cloned [`Builder`] hands out its own checkpoints, so
15/// one taken from the clone can be used on it without affecting the original.
16/// A checkpoint taken *before* cloning still belongs to the original: closing
17/// it on the clone updates it for the original too, so get a fresh checkpoint
18/// from the clone instead.
19///
20/// ```
21/// let mut a = syntree::Builder::new();
22/// let c = a.checkpoint()?;
23///
24/// let mut b = a.clone();
25/// let c2 = b.checkpoint()?;
26/// b.token("lit", 1)?;
27/// b.close_at(&c2, "speculative")?;
28///
29/// a.token("lit", 1)?;
30/// a.close_at(&c, "root")?;
31///
32/// assert_eq!(a.build()?, syntree::tree! { "root" => { ("lit", 1) } });
33/// # Ok::<_, Box<dyn core::error::Error>>(())
34/// ```
35///
36/// [`Builder`]: crate::Builder
37/// [`Builder::close_at`]: crate::Builder::close_at
38/// [`Builder::checkpoint`]: crate::Builder::checkpoint
39#[derive(Debug, Clone)]
40#[repr(transparent)]
41pub struct Checkpoint<P>(Rc<Cell<Inner<P>>>)
42where
43 P: Copy;
44
45impl<P> Checkpoint<P>
46where
47 P: Copy,
48{
49 pub(crate) fn new(node: P, parent: Option<P>) -> Self {
50 Self(Rc::new(Cell::new(Inner { node, parent })))
51 }
52
53 /// A new checkpoint with the same state which does not share updates with
54 /// this one.
55 pub(crate) fn deep_clone(&self) -> Self {
56 Self(Rc::new(Cell::new(self.0.get())))
57 }
58
59 pub(crate) fn set(&self, node: P, parent: Option<P>) {
60 self.0.set(Inner { node, parent });
61 }
62
63 pub(crate) fn node(&self) -> P {
64 self.0.get().node
65 }
66
67 pub(crate) fn parent(&self) -> Option<P> {
68 self.0.get().parent
69 }
70
71 pub(crate) fn get(&self) -> (P, Option<P>) {
72 let Inner { node, parent } = self.0.get();
73 (node, parent)
74 }
75}
76
77/// The shared state of a checkpoint.
78#[derive(Debug, Clone, Copy)]
79struct Inner<P> {
80 // The node being wrapped by the checkpoint.
81 node: P,
82 // The parent node of the context being checkpointed.
83 parent: Option<P>,
84}