use image::{ImageBuffer, Pixel, Primitive};
pub trait Clamped: PartialOrd + Sized {
fn clamped(self, min: Self, max: Self) -> Self {
let low = if self < min { min } else { self };
if low > max { max } else { low }
}
}
impl<T: PartialOrd> Clamped for T {}
pub(crate) fn remove_at<T>(items: &mut Vec<T>, index: usize) -> Option<T> {
if index >= items.len() {
return None;
}
let mut rest = items.get_mut(index..)?.iter_mut();
if let Some(mut prev) = rest.next() {
for next in rest {
std::mem::swap(prev, next);
prev = next;
}
}
items.pop()
}
pub(crate) fn insert_at<T>(items: &mut Vec<T>, index: usize, item: T) -> Result<(), T> {
if index > items.len() {
return Err(item);
}
items.push(item);
if let Some(tail) = items.get_mut(index..) {
let mut rest = tail.iter_mut().rev();
if let Some(mut prev) = rest.next() {
for next in rest {
std::mem::swap(prev, next);
prev = next;
}
}
}
Ok(())
}
pub(crate) fn chunks<T>(mut rest: &[T], size: usize) -> impl Iterator<Item = &[T]> {
let size = size.max(1);
std::iter::from_fn(move || {
if rest.is_empty() {
return None;
}
let (chunk, tail) = rest.split_at_checked(size.min(rest.len()))?;
rest = tail;
Some(chunk)
})
}
pub(crate) fn chunks_mut<T>(mut rest: &mut [T], size: usize) -> impl Iterator<Item = &mut [T]> {
let size = size.max(1);
std::iter::from_fn(move || {
if rest.is_empty() {
return None;
}
let taken = std::mem::take(&mut rest);
let len = taken.len();
let (chunk, tail) = taken.split_at_mut_checked(size.min(len))?;
rest = tail;
Some(chunk)
})
}
pub(crate) fn copy_into<T: Copy>(dst: &mut [T], src: &[T]) -> bool {
let Some(dst) = dst.get_mut(..src.len()) else {
return false;
};
for (d, s) in dst.iter_mut().zip(src) {
*d = *s;
}
true
}
pub(crate) fn image_from_fn<P: Pixel>(
width: u32,
height: u32,
mut f: impl FnMut(u32, u32) -> P,
) -> Option<ImageBuffer<P, Vec<P::Subpixel>>> {
let len = (width as usize)
.checked_mul(height as usize)?
.checked_mul(usize::from(P::CHANNEL_COUNT))?;
let mut data = Vec::with_capacity(len);
for y in 0..height {
for x in 0..width {
data.extend_from_slice(f(x, y).channels());
}
}
ImageBuffer::from_raw(width, height, data)
}
pub(crate) fn blank_image<P: Pixel>(
width: u32,
height: u32,
) -> Option<ImageBuffer<P, Vec<P::Subpixel>>> {
let len = (width as usize)
.checked_mul(height as usize)?
.checked_mul(usize::from(P::CHANNEL_COUNT))?;
ImageBuffer::from_raw(
width,
height,
vec![<P::Subpixel as Primitive>::DEFAULT_MIN_VALUE; len],
)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn remove_and_insert_keep_order() {
let mut v = vec![1, 2, 3, 4];
assert_eq!(remove_at(&mut v, 1), Some(2));
assert_eq!(v, [1, 3, 4]);
assert_eq!(remove_at(&mut v, 3), None);
assert_eq!(insert_at(&mut v, 0, 9), Ok(()));
assert_eq!(v, [9, 1, 3, 4]);
assert_eq!(insert_at(&mut v, 4, 5), Ok(()));
assert_eq!(v, [9, 1, 3, 4, 5]);
assert_eq!(insert_at(&mut v, 9, 7), Err(7));
}
#[test]
fn chunks_match_std() {
let v: Vec<u8> = (0..10).collect();
let ours: Vec<&[u8]> = chunks(&v, 3).collect();
let std: Vec<&[u8]> = v.chunks(3).collect();
assert_eq!(ours, std);
assert_eq!(chunks(&v, 0).count(), 10);
let mut w = v.clone();
assert_eq!(
chunks_mut(&mut w, 4).map(|c| c.len()).collect::<Vec<_>>(),
[4, 4, 2]
);
}
}