use core::ptr::NonNull;
use super::{GhostCell, GhostToken};
pub struct GhostCursor<'a, 'brand, T: ?Sized> {
token: NonNull<GhostToken<'brand>>,
cell: Option<&'a GhostCell<'brand, T>>,
}
impl<'a, 'brand, T: ?Sized> GhostCursor<'a, 'brand, T> {
pub fn new(token: &'a mut GhostToken<'brand>, cell: Option<&'a GhostCell<'brand, T>>) -> Self {
let token = NonNull::from(token);
Self { token, cell }
}
pub fn into_inner(self) -> Option<&'a mut T> {
let token = unsafe { as_mut(self.token) };
self.cell.map(move |cell| cell.borrow_mut(token))
}
pub fn into_parts(self) -> (&'a GhostToken<'brand>, Option<&'a GhostCell<'brand, T>>) {
(unsafe { as_ref(self.token) }, self.cell)
}
pub fn token(&self) -> &GhostToken<'brand> {
unsafe { as_ref(self.token) }
}
pub fn borrow(&self) -> Option<&T> {
let token = unsafe { as_ref(self.token) };
self.cell.map(|cell| cell.borrow(token))
}
pub fn borrow_mut(&mut self) -> Option<&mut T> {
let token = unsafe { as_mut(self.token) };
self.cell.map(move |cell| cell.borrow_mut(token))
}
#[allow(clippy::result_unit_err)]
pub fn move_mut<F>(&mut self, fun: F) -> Result<(), ()>
where
F: FnOnce(&T) -> Option<&GhostCell<'brand, T>>,
{
let token = unsafe { as_ref(self.token) };
let cell = self.cell.ok_or(())?;
let cell = fun(cell.borrow(token)).ok_or(())?;
self.cell = Some(cell);
Ok(())
}
pub fn move_into<U, F>(mut self, fun: F) -> Result<GhostCursor<'a, 'brand, U>, Self>
where
F: FnOnce(&T) -> Option<&GhostCell<'brand, U>>,
{
let result = self.move_into_impl(fun);
result.or(Err(self))
}
fn move_into_impl<U, F>(&mut self, fun: F) -> Result<GhostCursor<'a, 'brand, U>, ()>
where
F: FnOnce(&T) -> Option<&GhostCell<'brand, U>>,
{
let token_mut = unsafe { as_mut(self.token) };
let cell = self.cell.ok_or(())?;
let cell = fun(cell.borrow(token_mut)).ok_or(())?;
Ok(GhostCursor { token: self.token, cell: Some(cell) })
}
}
unsafe fn as_ref<'a, T: ?Sized>(ptr: NonNull<T>) -> &'a T {
&*ptr.as_ptr()
}
unsafe fn as_mut<'a, T: ?Sized>(ptr: NonNull<T>) -> &'a mut T {
&mut *ptr.as_ptr()
}
#[doc(hidden)]
pub mod compile_tests {
pub fn cursor_new_borrows_token_mutably() {}
pub fn cursor_into_inner_leaves_token_borrowed_mutably() {}
pub fn cursor_into_parts_first_part_leaves_token_borrowed_mutably() {}
pub fn cursor_into_parts_second_part_leaves_token_borrowed_mutably() {}
pub fn cursor_move_mut_noescape() {}
}