machine_vision_formats/
cow.rs

1//! Copy-on-Write (CoW) image that can either borrow or own its pixel data.
2
3use crate::{
4    image_ref::ImageRef, owned::OImage, ImageBuffer, ImageBufferRef, ImageData, PixelFormat, Stride,
5};
6
7/// A Copy-on-Write (CoW) image that can either borrow or own its pixel data.
8///
9/// `CowImage` provides a flexible way to work with image data that may be either
10/// borrowed from an existing source or owned by the container. This is particularly
11/// useful in scenarios where you want to avoid unnecessary copying when possible,
12/// but still provide owned data when needed.
13///
14/// The enum has two variants:
15/// - `Borrowed`: Contains an [`ImageRef`] that borrows data from elsewhere
16/// - `Owned`: Contains an [`OImage`] that owns its pixel data
17///
18/// Both variants implement the same image traits, allowing them to be used
19/// interchangeably in most contexts.
20///
21/// # Type Parameters
22/// * `F` - The pixel format type that implements [`PixelFormat`]
23///
24/// # Examples
25/// ```rust
26/// # use machine_vision_formats::{cow::CowImage, owned::OImage, image_ref::ImageRef, pixel_format::Mono8};
27/// // Create from borrowed data
28/// let data = [128u8; 100];
29/// let borrowed_ref = ImageRef::<Mono8>::new(10, 10, 10, &data).unwrap();
30/// let cow_borrowed = CowImage::from(borrowed_ref);
31///
32/// // Create from owned data
33/// let owned_image = OImage::<Mono8>::new(10, 10, 10, vec![64u8; 100]).unwrap();
34/// let cow_owned = CowImage::from(owned_image);
35/// ```
36pub enum CowImage<'a, F: PixelFormat> {
37    /// Borrowed image data with a lifetime tied to the source
38    Borrowed(ImageRef<'a, F>),
39    /// Owned image data that manages its own memory
40    Owned(OImage<F>),
41}
42
43impl<'a, F: PixelFormat> From<ImageRef<'a, F>> for CowImage<'a, F> {
44    /// Creates a [`CowImage::Borrowed`] from an [`ImageRef`].
45    ///
46    /// # Examples
47    /// ```rust
48    /// # use machine_vision_formats::{cow::CowImage, image_ref::ImageRef, pixel_format::RGB8};
49    /// let data = [0u8; 300]; // 10x10 RGB image
50    /// let image_ref = ImageRef::<RGB8>::new(10, 10, 30, &data).unwrap();
51    /// let cow_image = CowImage::from(image_ref);
52    /// ```
53    fn from(frame: ImageRef<'a, F>) -> CowImage<'a, F> {
54        CowImage::Borrowed(frame)
55    }
56}
57
58impl<'a, F: PixelFormat> From<OImage<F>> for CowImage<'a, F> {
59    /// Creates a [`CowImage::Owned`] from an [`OImage`].
60    ///
61    /// # Examples
62    /// ```rust
63    /// # use machine_vision_formats::{cow::CowImage, owned::OImage, pixel_format::Mono8};
64    /// let owned_image = OImage::<Mono8>::new(20, 15, 20, vec![128u8; 300]).unwrap();
65    /// let cow_image = CowImage::from(owned_image);
66    /// ```
67    fn from(frame: OImage<F>) -> CowImage<'a, F> {
68        CowImage::Owned(frame)
69    }
70}
71
72impl<F: PixelFormat> Stride for CowImage<'_, F> {
73    /// Returns the stride (bytes per row) of the image.
74    ///
75    /// # Examples
76    /// ```rust
77    /// # use machine_vision_formats::{cow::CowImage, owned::OImage, pixel_format::Mono8, Stride};
78    /// let owned_image = OImage::<Mono8>::new(10, 10, 12, vec![0u8; 120]).unwrap();
79    /// let cow_image = CowImage::from(owned_image);
80    /// assert_eq!(cow_image.stride(), 12);
81    /// ```
82    fn stride(&self) -> usize {
83        match self {
84            CowImage::Borrowed(im) => im.stride(),
85            CowImage::Owned(im) => im.stride(),
86        }
87    }
88}
89
90impl<F: PixelFormat> ImageData<F> for CowImage<'_, F> {
91    /// Returns the width of the image in pixels.
92    ///
93    /// # Examples
94    /// ```rust
95    /// # use machine_vision_formats::{cow::CowImage, owned::OImage, pixel_format::RGB8, ImageData};
96    /// let owned_image = OImage::<RGB8>::new(25, 20, 75, vec![0u8; 1500]).unwrap();
97    /// let cow_image = CowImage::from(owned_image);
98    /// assert_eq!(cow_image.width(), 25);
99    /// ```
100    fn width(&self) -> u32 {
101        match self {
102            CowImage::Borrowed(im) => im.width(),
103            CowImage::Owned(im) => im.width(),
104        }
105    }
106
107    /// Returns the height of the image in pixels.
108    ///
109    /// # Examples
110    /// ```rust
111    /// # use machine_vision_formats::{cow::CowImage, image_ref::ImageRef, pixel_format::Mono8, ImageData};
112    /// let data = [0u8; 200];
113    /// let image_ref = ImageRef::<Mono8>::new(10, 20, 10, &data).unwrap();
114    /// let cow_image = CowImage::from(image_ref);
115    /// assert_eq!(cow_image.height(), 20);
116    /// ```
117    fn height(&self) -> u32 {
118        match self {
119            CowImage::Borrowed(im) => im.height(),
120            CowImage::Owned(im) => im.height(),
121        }
122    }
123
124    /// Returns a reference to the image buffer.
125    ///
126    /// This provides access to the pixel data regardless of whether the image
127    /// is borrowed or owned.
128    ///
129    /// # Examples
130    /// ```rust
131    /// # use machine_vision_formats::{cow::CowImage, owned::OImage, pixel_format::Mono8, ImageData};
132    /// let owned_image = OImage::<Mono8>::new(5, 5, 5, vec![42u8; 25]).unwrap();
133    /// let cow_image = CowImage::from(owned_image);
134    /// let buffer_ref = cow_image.buffer_ref();
135    /// ```
136    fn buffer_ref(&self) -> ImageBufferRef<'_, F> {
137        let image_data = match self {
138            CowImage::Borrowed(im) => im.image_data(),
139            CowImage::Owned(im) => im.image_data(),
140        };
141        ImageBufferRef::new(image_data)
142    }
143
144    /// Consumes the image and returns the pixel data as an owned buffer.
145    ///
146    /// For borrowed images, this copies the data into a new vector.
147    /// For owned images, this moves the existing data without copying.
148    ///
149    /// # Examples
150    /// ```rust
151    /// # use machine_vision_formats::{cow::CowImage, owned::OImage, pixel_format::Mono8, ImageData};
152    /// let owned_image = OImage::<Mono8>::new(4, 4, 4, vec![255u8; 16]).unwrap();
153    /// let cow_image = CowImage::from(owned_image);
154    /// let buffer = cow_image.buffer();
155    /// ```
156    fn buffer(self) -> ImageBuffer<F> {
157        match self {
158            CowImage::Borrowed(im) => ImageBuffer::new(im.image_data().to_vec()),
159            CowImage::Owned(im) => ImageBuffer::new(im.into()),
160        }
161    }
162}