Skip to content

Commit

Permalink
Merge pull request #96 from arthurprs/thinarc-with-arc-mut
Browse files Browse the repository at this point in the history
Add ThinArc::with_arc_mut
  • Loading branch information
Manishearth authored Sep 16, 2024
2 parents 2686349 + 12f3f7b commit c9b3d01
Showing 1 changed file with 50 additions and 0 deletions.
50 changes: 50 additions & 0 deletions src/thin_arc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,26 @@ impl<H, T> ThinArc<H, T> {
f(&transient)
}

/// Temporarily converts |self| into a bonafide Arc and exposes it to the
/// provided callback. The refcount is not modified.
#[inline]
pub fn with_arc_mut<F, U>(&mut self, f: F) -> U
where
F: FnOnce(&mut Arc<HeaderSliceWithLength<H, [T]>>) -> U,
{
// Synthesize transient Arc, which never touches the refcount of the ArcInner.
let mut transient = unsafe {
ManuallyDrop::new(Arc {
p: ptr::NonNull::new_unchecked(thin_to_thick(self.ptr.as_ptr())),
phantom: PhantomData,
})
};

// Expose the transient Arc to the callback, which may clone it if it wants
// and forward the result to the user
f(&mut transient)
}

/// Creates a `ThinArc` for a HeaderSlice using the given header struct and
/// iterator to generate the slice.
pub fn from_header_and_iter<I>(header: H, items: I) -> Self
Expand Down Expand Up @@ -450,6 +470,36 @@ mod tests {
})
}

#[test]
fn with_arc_mut() {
let mut arc: ThinArc<u8, u16> = ThinArc::from_header_and_slice(1u8, &[1, 2, 3]);
arc.with_arc_mut(|arc| Arc::get_mut(arc).unwrap().slice.fill(2));
arc.with_arc_mut(|arc| assert!(Arc::get_unique(arc).is_some()));
arc.with_arc(|arc| assert!(Arc::is_unique(arc)));
// Using clone to that the layout generated in new_uninit_slice is compatible
// with ArcInner.
let arcs = [
arc.clone(),
arc.clone(),
arc.clone(),
arc.clone(),
arc.clone(),
];
arc.with_arc(|arc| assert_eq!(6, Arc::count(&arc)));

// If the layout is not compatible, then the data might be corrupted.
assert_eq!(arc.header.header, 1);
assert_eq!(&arc.slice, [2, 2, 2]);

// Drop the arcs and check the count and the content to
// make sure it isn't corrupted.
drop(arcs);
arc.with_arc_mut(|arc| assert!(Arc::get_unique(arc).is_some()));
arc.with_arc(|arc| assert!(Arc::is_unique(arc)));
assert_eq!(arc.header.header, 1);
assert_eq!(&arc.slice, [2, 2, 2]);
}

#[allow(dead_code)]
const fn is_partial_ord<T: ?Sized + PartialOrd>() {}

Expand Down

0 comments on commit c9b3d01

Please sign in to comment.