1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
//! the houser of uninitialized memory. €$@!0В!℡
//!
//! contains [`Image`], an uninitialized image.
use crate::{CopyWithinUnchecked, span::Span};
use std::{hint::assert_unchecked, mem::MaybeUninit, num::NonZeroU32, ops::Index};
/// A uninitialized image. Be sure to initialize it!
#[derive(Hash)]
pub struct Image<T: Copy, const CHANNELS: usize> {
/// Has capacity w * h * c
buffer: Vec<T>,
width: NonZeroU32,
height: NonZeroU32,
}
impl<I: Span, T: Copy, const C: usize> Index<I> for Image<T, C> {
type Output = [T];
fn index(&self, index: I) -> &Self::Output {
&self.buffer()[index.range::<C>((self.width(), self.height()))]
}
}
impl<T: Copy, const CHANNELS: usize> Image<T, CHANNELS> {
/// Create a new uninit image. This is not init.
pub fn new(width: NonZeroU32, height: NonZeroU32) -> Self {
Self {
buffer: Vec::with_capacity(width.get() as usize * height.get() as usize * CHANNELS),
width,
height,
}
}
/// Write to the image.
///
/// # Safety
/// index must be in bounds.
/// data and indexed range must have same len.
pub unsafe fn write(&mut self, data: &[T], i: impl Span) {
// SAFETY: caller
let dat = unsafe { self.slice(i) };
// SAFETY: caller
unsafe { assert_unchecked(dat.len() == data.len()) };
dat.write_copy_of_slice(data);
}
/// Slice the image.
///
/// # Safety
/// index must be in bounds.
pub unsafe fn slice(&mut self, i: impl Span) -> &mut [MaybeUninit<T>] {
let range = i.range::<CHANNELS>((self.width(), self.height()));
// SAFETY: assured
unsafe { self.buf().get_unchecked_mut(range) }
}
/// Copy a range to a position.
///
/// # Safety
///
/// both parts must be in bounds.
pub unsafe fn copy_within(&mut self, i: impl Span, to: usize) {
let range = i.range::<CHANNELS>((self.width(), self.height()));
// SAFETY: copy!
unsafe { self.buf().copy_within_unchecked(range, to) };
}
/// # Safety
///
/// the output index is not guaranteed to be in bounds
#[inline]
pub fn at(&self, x: u32, y: u32) -> usize {
crate::At::at::<CHANNELS>((self.width(), self.height()), x, y)
}
#[inline]
/// get the height as a [`u32`]
pub const fn height(&self) -> u32 {
self.height.get()
}
#[inline]
/// get the width as a [`u32`]
pub const fn width(&self) -> u32 {
self.width.get()
}
#[inline]
/// create a new image
///
/// # Safety
///
/// does not check that buffer.capacity() == w * h * C
///
/// using this with invalid values may result in future UB
pub const unsafe fn with_buf(buffer: Vec<T>, width: NonZeroU32, height: NonZeroU32) -> Self {
Self {
buffer,
width,
height,
}
}
/// consumes the image, returning the image buffer
pub fn take_buffer(self) -> Vec<T> {
self.buffer
}
/// returns a immutable reference to the backing buffer
pub fn buffer(&self) -> &[T] {
&self.buffer
}
/// returns a mutable reference to the backing buffer
pub fn buf(&mut self) -> &mut [MaybeUninit<T>] {
self.buffer.spare_capacity_mut()
}
/// initializes this image, assuming you have done your job
/// # Safety
/// requires initialization
pub unsafe fn init(&mut self) {
// SAFETY: we have trust for our callers.
unsafe {
self.buffer
.set_len(self.width() as usize * self.height() as usize * CHANNELS)
};
}
/// initializes this image, mapping to a normal [`crate::Image`] type.
///
/// # Safety
/// UB if you have not init the image
pub unsafe fn assume_init(mut self) -> crate::Image<Vec<T>, CHANNELS> {
// SAFETY: its apparently init
unsafe { self.init() };
// SAFETY: image all init, good to go
unsafe { crate::Image::new(self.width, self.height, self.buffer) }
}
}