use image::RgbImage;
use std::sync::Arc;
pub trait ArcCow<T> {
fn make_mut(arc: &mut Arc<T>) -> &mut T
where
T: Clone;
fn unwrap_or_clone(arc: Arc<T>) -> T
where
T: Clone;
}
impl ArcCow<RgbImage> for RgbImage {
fn make_mut(arc: &mut Arc<RgbImage>) -> &mut RgbImage {
Arc::make_mut(arc)
}
fn unwrap_or_clone(arc: Arc<RgbImage>) -> RgbImage {
Arc::try_unwrap(arc).unwrap_or_else(|arc| (*arc).clone())
}
}
pub fn clone_if_shared(image: Arc<RgbImage>) -> Arc<RgbImage> {
match Arc::try_unwrap(image) {
Ok(owned) => Arc::new(owned),
Err(arc) => Arc::new((*arc).clone()),
}
}
pub fn modify_cow<F>(mut image: Arc<RgbImage>, f: F) -> Arc<RgbImage>
where
F: FnOnce(&mut RgbImage),
{
f(Arc::make_mut(&mut image));
image
}
#[cfg(test)]
mod tests {
use super::*;
use image::Rgb;
#[test]
fn test_clone_if_shared_unique() {
let image = Arc::new(RgbImage::new(10, 10));
let result = clone_if_shared(image);
assert_eq!(Arc::strong_count(&result), 1);
}
#[test]
fn test_clone_if_shared_multiple_refs() {
let image = Arc::new(RgbImage::new(10, 10));
let clone1 = Arc::clone(&image);
let _clone2 = Arc::clone(&image);
let result = clone_if_shared(clone1);
assert_eq!(Arc::strong_count(&result), 1);
assert_eq!(Arc::strong_count(&image), 2); }
#[test]
fn test_modify_cow_unique() {
let image = Arc::new(RgbImage::new(10, 10));
let ptr_before = Arc::as_ptr(&image);
let modified = modify_cow(image, |img| {
for pixel in img.pixels_mut() {
*pixel = Rgb([255, 0, 0]);
}
});
let ptr_after = Arc::as_ptr(&modified);
assert_eq!(ptr_before, ptr_after);
assert_eq!(modified.get_pixel(0, 0), &Rgb([255, 0, 0]));
}
#[test]
fn test_modify_cow_shared() {
let image = Arc::new(RgbImage::new(10, 10));
let clone = Arc::clone(&image);
let ptr_original = Arc::as_ptr(&image);
let modified = modify_cow(clone, |img| {
for pixel in img.pixels_mut() {
*pixel = Rgb([255, 0, 0]);
}
});
let ptr_modified = Arc::as_ptr(&modified);
assert_ne!(ptr_original, ptr_modified);
assert_eq!(image.get_pixel(0, 0), &Rgb([0, 0, 0]));
assert_eq!(modified.get_pixel(0, 0), &Rgb([255, 0, 0]));
}
#[test]
fn test_unwrap_or_clone_unique() {
let image = Arc::new(RgbImage::new(10, 10));
let owned = RgbImage::unwrap_or_clone(image);
assert_eq!(owned.dimensions(), (10, 10));
}
#[test]
fn test_unwrap_or_clone_shared() {
let image = Arc::new(RgbImage::new(10, 10));
let _clone = Arc::clone(&image);
let owned = RgbImage::unwrap_or_clone(image);
assert_eq!(owned.dimensions(), (10, 10));
}
#[test]
fn test_make_mut() {
let mut image = Arc::new(RgbImage::new(10, 10));
let img_mut = RgbImage::make_mut(&mut image);
img_mut.put_pixel(0, 0, Rgb([255, 0, 0]));
assert_eq!(image.get_pixel(0, 0), &Rgb([255, 0, 0]));
}
}