Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add make_mut functions for Rc and Arc #21

Merged
merged 1 commit into from
Jul 15, 2022
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 40 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,8 @@ pub trait DynClone: Sealed {
}

use alloc::boxed::Box;
use alloc::rc::Rc;
use alloc::sync::Arc;

pub fn clone<T>(t: &T) -> T
where
Expand All @@ -141,6 +143,44 @@ where
unsafe { Box::from_raw(fat_ptr as *mut T) }
}

pub fn arc_make_mut<T>(arc: &mut Arc<T>) -> &mut T
where
T: ?Sized + DynClone,
{
// Atomic. Find out whether the Arc in the argument is the single holder of
// a reference count (strong or weak) on the target object. If yes, it is
// guaranteed to remain that way throughout the rest of this function
// because no other threads could bump the reference count through any other
// Arc (because no others exist) or through this Arc (because the current
// thread holds an exclusive borrow of it).
let is_unique = Arc::get_mut(arc).is_some();
if !is_unique {
// Non-atomic.
let clone = Arc::from(clone_box(&**arc));
// Atomic. Check the reference counts again to find out whether the old
// object needs to be dropped. Probably not, but it can happen if all
// the other holders of a reference count went away during the time that
// the clone operation took.
*arc = clone;
}
// Non-atomic. TODO: replace with Arc::get_mut_unchecked when stable.
let ptr = Arc::as_ptr(arc) as *mut T;
unsafe { &mut *ptr }
}

pub fn rc_make_mut<T>(rc: &mut Rc<T>) -> &mut T
where
T: ?Sized + DynClone,
{
let is_unique = Rc::get_mut(rc).is_some();
if !is_unique {
let clone = Rc::from(clone_box(&**rc));
*rc = clone;
}
let ptr = Rc::as_ptr(rc) as *mut T;
unsafe { &mut *ptr }
}

impl<T> DynClone for T
where
T: Clone,
Expand Down