cyclic_sync/
cyclic_sync.rs

1use std::sync::{Arc, Mutex};
2
3use generic_cursors::mutex::MutexGuardStack;
4
5#[derive(Debug, Clone)]
6pub struct CyclicDataStructure<T> {
7    data: T,
8    next: Option<Arc<Mutex<Self>>>,
9}
10
11impl<T> CyclicDataStructure<T> {
12    fn next(&mut self) -> Option<&Mutex<Self>> {
13        self.next.as_deref()
14    }
15    fn insert_next(&mut self, new_next: Arc<Mutex<Self>>) -> Option<Arc<Mutex<Self>>> {
16        self.next.replace(new_next)
17    }
18    fn take_next(&mut self) -> Option<Arc<Mutex<Self>>> {
19        self.next.take()
20    }
21}
22
23fn main() {
24    let cycle_root = Arc::new(Mutex::new(CyclicDataStructure {
25        data: 0_u32,
26        next: None,
27    }));
28    let mut current = cycle_root.clone();
29    for i in (1..128).rev() {
30        current = Arc::new(Mutex::new(CyclicDataStructure {
31            data: i,
32            next: Some(current),
33        }))
34    }
35    cycle_root.lock().unwrap().next = Some(current);
36
37    // Using a MutRefStack to descend *and then ascend* the data structure.
38    // This cannot be done with regular mutable references.
39    let mut stack = MutexGuardStack::new(&cycle_root).expect("not mutable borrowed yet");
40    println!("Stack currently at item with value: {}", stack.top().data);
41    loop {
42        if let Err(_borrow_error) = stack
43            .descend_with(CyclicDataStructure::next, false)
44            .expect("no node has no next")
45        {
46            println!("Found a cycle!");
47            break;
48        }
49        println!("Descended successfully!");
50        println!("Stack currently at item with value: {}", stack.top().data);
51    }
52    println!("Stack currently at item with value: {}", stack.top().data);
53    loop {
54        if let None = stack.ascend() {
55            println!("Reached the head of the linked list!");
56            break;
57        }
58        println!("Ascended successfully!");
59        println!("Stack currently at item with value: {}", stack.top().data);
60    }
61
62    println!("(Breaking the cycle to prevent miri from complaining about memory leaks)");
63    stack.top_mut().take_next();
64}