image_merger/cell.rs
1use super::core::Image;
2use image::Pixel;
3use std::{
4 cell::UnsafeCell,
5 marker::{Send, Sync},
6 ops::Deref,
7};
8
9/// A struct that allows multible mutable references to an underlying image's data buffer. This is an
10/// unsafe struct and should only be used when no two items are trying to change the same place in the underlying
11/// image's data buffer. This struct is used to allow multible threads to write to the same image at the same time.
12pub struct ImageCell<P: Pixel, U: image::GenericImage<Pixel = P>> {
13 underlying: UnsafeCell<Image<P, U>>,
14}
15
16/// Represents a handout of an image cell. This struct is used to write to the image cell's underlying
17/// image's data buffer without a mutable reference to the underlying image.
18pub struct Handout<'a, P: Pixel, U: image::GenericImage<Pixel = P>> {
19 ic: &'a ImageCell<P, U>,
20 x: u32,
21 y: u32,
22}
23
24impl<P: Pixel, U: image::GenericImage<Pixel = P>> ImageCell<P, U> {
25 pub fn new(image: Image<P, U>) -> Self {
26 Self {
27 underlying: UnsafeCell::new(image),
28 }
29 }
30
31 /// Returns the underlying image.
32 pub fn into_inner(self) -> Image<P, U> {
33 self.underlying.into_inner()
34 }
35
36 #[allow(clippy::mut_from_ref)]
37 pub(crate) fn get_image_mut(&self) -> &mut Image<P, U> {
38 unsafe { &mut *self.underlying.get() }
39 }
40
41 /// Requests a handout at the given coordinates of the undelrying image. Can be be used to write
42 /// to an underlying image buffer across threads without a mutable reference to the underlying image.
43 /// # Safety
44 /// This function is unsafe because it does not implement any thread safety via locks or anything else. It is up to the caller to ensure that
45 /// no two threads are trying to write to the same place in the underlying image's data buffer.
46 ///
47 /// # Arguments
48 /// * `x` - The x coordinate of the pixel to request a handout for.
49 /// * `y` - The y coordinate of the pixel to request a handout for.
50 /// # Returns
51 /// A handout that can be used to write to the underlying image's data buffer.
52 /// # Example
53 /// ```
54 /// use image_merger::{Rgb, raw::ImageCell, Image};
55 /// use image::ImageBuffer;
56 ///
57 /// let buf: ImageBuffer<Rgb<u8>, Vec<u8>> = ImageBuffer::new(100, 100);
58 /// let cell = ImageCell::new(Image::from(buf));
59 /// let mut handout = unsafe { cell.request_handout(0, 0) };
60 /// handout.put_pixel(Rgb([255, 255, 255]));
61 /// ```
62 pub unsafe fn request_handout(&self, x: u32, y: u32) -> Handout<P, U> {
63 Handout { ic: self, x, y }
64 }
65}
66
67impl<P: Pixel, U: image::GenericImage<Pixel = P>> Deref for ImageCell<P, U> {
68 type Target = Image<P, U>;
69
70 fn deref(&self) -> &Self::Target {
71 unsafe { &*self.underlying.get() }
72 }
73}
74
75unsafe impl<P: Pixel, U: image::GenericImage<Pixel = P>> Sync for ImageCell<P, U> {}
76unsafe impl<P: Pixel, U: image::GenericImage<Pixel = P>> Send for ImageCell<P, U> {}
77
78impl<'a, P: Pixel, U: image::GenericImage<Pixel = P>> Handout<'a, P, U> {
79 /// Puts a pixel at the handout's coordinates.
80 /// # Arguments
81 /// * `pixel` - The pixel to place.
82 pub fn put_pixel(&mut self, pixel: P) {
83 let image = self.ic.get_image_mut();
84 image.put_pixel(self.x, self.y, pixel);
85 }
86
87 /// Same as `put_pixel` but does not check bounds.
88 /// # Safety
89 /// This function is unsafe because it does not check bounds wen placing the pixel.
90 /// # Arguments
91 /// * `pixel` - The pixel to place.
92 pub unsafe fn unsafe_put_pixel(&mut self, pixel: P) {
93 let image = self.ic.get_image_mut();
94 image.unsafe_put_pixel(self.x, self.y, pixel);
95 }
96}