#![cfg_attr(not(feature = "alloc"), doc = "[`MutCursorVec`]: features#alloc")]
#![cfg_attr(not(feature = "alloc"), doc = "[`MutCursorRootedVec`]: features#alloc")]
#![cfg_attr(feature = "std", doc = "[Vec]: std::vec::Vec")]
#![cfg_attr(feature = "alloc", doc = "[Vec]: alloc::vec::Vec")]
#![doc = include_str!("../README.md")]
#![cfg_attr(docsrs, feature(doc_cfg))]
#![cfg_attr(docsrs, feature(clone_to_uninit))]
#![no_std]
#[cfg(any(test, feature = "alloc"))]
extern crate alloc;
#[cfg(any(test, feature = "std"))]
#[cfg_attr(test, macro_use)]
extern crate std;
#[cfg(doc)]
#[cfg_attr(docsrs, doc(cfg(doc)))]
pub mod features {
#![cfg_attr(not(feature = "alloc"), doc = "Enables the `MutCursorVec` and `MutCursorRootedVec` APIs,")]
#![cfg_attr(not(feature = "alloc"), doc = "as well as the `unique` module.")]
#![cfg_attr(feature = "alloc", doc = "Enables the [`MutCursorVec`] and [`MutCursorRootedVec`] APIs,")]
# module.")]
#![cfg_attr(feature = "alloc", doc = "[`stable_deref_trait`]: stable_deref_trait")]
#![cfg_attr(feature = "alloc", doc = "[`StableDeref`]: stable_deref_trait::StableDeref")]
#![cfg_attr(feature = "alloc", doc = "[`make_unique`]: crate::unique::UniqueExt::make_unique")]
#![cfg_attr(docsrs, doc = "[`CloneToUninit`]: std::clone::CloneToUninit")]
use super::*;
}
use core::ptr::NonNull;
use core::mem::MaybeUninit;
use core::marker::PhantomData;
#[cfg(feature = "alloc")]
mod mut_cursor_vec;
#[cfg(feature = "alloc")]
#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
pub use mut_cursor_vec::*;
#[cfg(feature = "alloc")]
#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
pub mod unique;
#[cfg(feature = "alloc")]
mod rooted_vec;
#[cfg(feature = "alloc")]
#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
pub use rooted_vec::*;
pub struct MutCursor<'root, T: ?Sized + 'root, const N: usize> {
cnt: usize, top: usize,
stack: [MaybeUninit<NonNull<T>>; N],
phantom: PhantomData<&'root mut T>, }
unsafe impl<'a, T, const N: usize> Sync for MutCursor<'a, T, N> where T: Sync, T: ?Sized {}
unsafe impl<'a, T, const N: usize> Send for MutCursor<'a, T, N> where T: Send, T: ?Sized {}
impl<'root, T: ?Sized + 'root, const N: usize> MutCursor<'root, T, N> {
#[inline]
pub fn new(root: &'root mut T) -> Self {
debug_assert!(N > 0);
let mut stack = Self {
cnt: 0,
top: 0,
stack: [MaybeUninit::uninit(); N],
phantom: PhantomData::default(),
};
unsafe{ *stack.stack.get_unchecked_mut(0) = MaybeUninit::new(NonNull::from(root)); }
stack
}
#[inline]
pub fn top(&self) -> &T {
unsafe{ self.stack.get_unchecked(self.top).assume_init().as_ref() }
}
#[inline]
pub fn top_mut(&mut self) -> &mut T {
unsafe{ self.top_mut_internal() }
}
#[inline]
pub fn into_mut(mut self) -> &'root mut T {
unsafe{ self.top_mut_internal() }
}
#[inline]
pub fn try_map_into_mut<U, E, F>(mut self, f: F) -> Result<&'root mut U, (Self, E)>
where for<'r> F: FnOnce(&'r mut T) -> Result<&'r mut U, E>
{
let top_ref = unsafe{ self.top_mut_internal() };
match f(top_ref) {
Ok(r) => Ok(r),
Err(e) => Err((self, e))
}
}
#[inline]
pub fn depth(&self) -> usize {
self.cnt
}
#[inline]
pub const fn capacity(&self) -> usize {
N
}
#[inline]
pub fn advance<F>(&mut self, step_f: F) -> bool
where F: FnOnce(&mut T) -> Option<&mut T>
{
match step_f(unsafe{ self.top_mut_internal() }) {
Some(new_node) => {
unsafe{ self.push(NonNull::from(new_node)); }
true
},
None => false
}
}
#[inline]
pub fn backtrack(&mut self) {
if self.cnt < 1 {
panic!("MutCursor must contain valid reference")
}
if self.top < 1 {
self.top = N-1;
} else {
self.top -= 1;
}
self.cnt -= 1;
}
#[inline]
unsafe fn top_mut_internal(&mut self) -> &'root mut T {
unsafe{ self.stack[self.top].assume_init().as_mut() }
}
#[inline]
unsafe fn push(&mut self, t: NonNull<T>) {
if self.top + 1 < N {
self.top = self.top + 1;
} else {
self.top = 0;
}
*self.stack.get_unchecked_mut(self.top) = MaybeUninit::new(t);
if self.cnt < N-1 {
self.cnt += 1;
}
}
}
impl<'root, T: ?Sized, const N: usize> core::ops::Deref for MutCursor<'root, T, N> {
type Target = T;
fn deref(&self) -> &T {
self.top()
}
}
impl<'root, T: ?Sized, const N: usize> core::ops::DerefMut for MutCursor<'root, T, N> {
fn deref_mut(&mut self) -> &mut T {
self.top_mut()
}
}
#[cfg(test)]
mod test {
use std::*;
use std::{boxed::*, vec::Vec, string::String};
use crate::*;
struct TreeNode {
val: usize,
next: Option<Box<TreeNode>>
}
impl TreeNode {
fn new(count: usize) -> Self {
if count > 0 {
Self {val: count, next: Some(Box::new(Self::new(count-1)))}
} else {
Self {val: 0, next: None}
}
}
fn traverse(&mut self) -> Option<&mut Self> {
self.next.as_mut().map(|boxed| &mut **boxed)
}
}
#[test]
fn basics() {
let mut tree = TreeNode::new(10);
let mut node_stack = MutCursor::<TreeNode, 7>::new(&mut tree);
while node_stack.advance(|node| {
node.traverse()
}) {}
assert_eq!(node_stack.top().val, 0);
assert_eq!(node_stack.depth(), 6);
node_stack.backtrack();
assert_eq!(node_stack.top().val, 1);
assert_eq!(node_stack.depth(), 5);
node_stack.backtrack();
node_stack.backtrack();
node_stack.backtrack();
assert_eq!(node_stack.top().val, 4);
assert_eq!(node_stack.depth(), 2);
while node_stack.advance(|node| {
node.traverse()
}) {}
assert_eq!(node_stack.top().val, 0);
assert_eq!(node_stack.depth(), 6);
node_stack.backtrack();
node_stack.backtrack();
node_stack.backtrack();
node_stack.backtrack();
node_stack.backtrack();
node_stack.backtrack();
assert_eq!(node_stack.top().val, 6);
assert_eq!(node_stack.depth(), 0);
assert_eq!(node_stack.into_mut().val, 6);
}
#[test]
fn try_to_escape_map_closure() {
let mut tree = TreeNode::new(3);
let node_stack = MutCursor::<TreeNode, 1>::new(&mut tree);
let mut _poison: &mut TreeNode;
match node_stack.try_map_into_mut(|node| -> Result<&mut TreeNode, &mut TreeNode> {
Ok(node)
}) {
Ok(_r) => {},
Err(_e) => {}
}
}
#[test]
fn try_to_alias_mut_with_advance() {
let mut x = 1;
let mut c = MutCursor::<_, 1>::new(&mut x);
#[allow(unused_mut)]
let mut _r1: Option<&mut i32> = None;
c.advance(|_r| {
None
});
#[allow(unused_mut)]
let mut _r2: Option<&mut i32> = None;
c.advance(|_r| {
None
});
}
#[test]
fn test_variance() {
let mut dummy = String::new();
let mut dummy_ref = &mut dummy;
#[allow(unused_mut)]
let mut _c = MutCursor::<_, 1>::new(&mut dummy_ref);
{
#[allow(unused_mut)]
let mut _hello = String::from("hello!");
println!("{}", dummy_ref); }
println!("{}", dummy_ref); }
use std::{thread, thread::ScopedJoinHandle};
#[test]
fn multi_thread_test() {
let thread_cnt = 128;
let mut data: Vec<TreeNode> = vec![];
for _ in 0..thread_cnt {
data.push(TreeNode::new(10));
}
let mut data_refs: Vec<&mut TreeNode> = data.iter_mut().collect();
thread::scope(|scope| {
let mut threads: Vec<ScopedJoinHandle<()>> = Vec::with_capacity(thread_cnt);
for _ in 0..thread_cnt {
let tree = data_refs.pop().unwrap();
let mut node_stack = MutCursor::<TreeNode, 7>::new(tree);
let thread = scope.spawn(move || {
while node_stack.advance(|node| {
node.traverse()
}) {}
assert_eq!(node_stack.top().val, 0);
assert_eq!(node_stack.depth(), 6);
node_stack.backtrack();
assert_eq!(node_stack.top().val, 1);
assert_eq!(node_stack.depth(), 5);
node_stack.backtrack();
node_stack.backtrack();
node_stack.backtrack();
assert_eq!(node_stack.top().val, 4);
assert_eq!(node_stack.depth(), 2);
while node_stack.advance(|node| {
node.traverse()
}) {}
assert_eq!(node_stack.top().val, 0);
assert_eq!(node_stack.depth(), 6);
node_stack.backtrack();
node_stack.backtrack();
node_stack.backtrack();
node_stack.backtrack();
node_stack.backtrack();
node_stack.backtrack();
assert_eq!(node_stack.top().val, 6);
assert_eq!(node_stack.depth(), 0);
assert_eq!(node_stack.into_mut().val, 6);
});
threads.push(thread);
};
for thread in threads {
thread.join().unwrap();
}
});
}
}