use crate::emu::ffi::ll_mode;
use std::assert_matches;
#[derive(Debug)]
#[derive_const(Clone)]
pub struct Mode {
channel_count: u8,
width: u16,
height: u16,
frame_count: u32,
}
impl Mode {
pub const MIN_CHANNEL_COUNT: u32 = 1;
pub const MAX_CHANNEL_COUNT: u32 = 2_u32.pow(u8::BITS - 1);
pub const MIN_WIDTH: u32 = 1;
pub const MAX_WIDTH: u32 = 2_u32.pow(u16::BITS - 1);
pub const MIN_FRAME_COUNT: u32 = 0;
pub const MAX_FRAME_COUNT: u32 = 2_u32.pow(u32::BITS - 1);
#[must_use]
pub fn from_ffi(mode: &ll_mode) -> Self {
assert_matches!(
mode.channel_count,
1..=Self::MAX_CHANNEL_COUNT,
"channel count must be non-zero and at most `{}`",
Self::MAX_CHANNEL_COUNT,
);
assert_matches!(
mode.width,
1..=Self::MAX_WIDTH,
"frame width must be non-zero and at most `{}`",
Self::MAX_WIDTH,
);
assert_matches!(
mode.height,
1..=Self::MAX_WIDTH,
"frame height must be non-zero and at most `{}`",
Self::MAX_WIDTH,
);
assert_matches!(
mode.frame_count,
1..=Self::MAX_FRAME_COUNT,
"frame count must be non-zero and at most `{}`",
Self::MAX_FRAME_COUNT,
);
let render_size = u128::from(mode.channel_count)
.wrapping_mul(mode.channel_count.into())
.wrapping_mul(mode.width.into())
.wrapping_mul(mode.height.into())
.wrapping_mul(mode.frame_count.into());
assert_matches!(
isize::try_from(render_size),
Ok(_),
"render size `{render_size}` may not be greater than `{}`",
isize::MAX,
);
Self {
channel_count: mode.channel_count as u8,
width: mode.width as u16,
height: mode.height as u16,
frame_count: mode.frame_count,
}
}
#[inline]
#[must_use]
pub const fn sample_count(&self) -> usize {
let channel_count = usize::from(self.channel_count);
let width = usize::from(self.width);
let height = usize::from(self.height);
let frame_count = self.frame_count as usize;
let result = channel_count
.wrapping_mul(width)
.wrapping_mul(height)
.wrapping_mul(frame_count);
debug_assert!(isize::try_from(result).is_ok());
result
}
#[inline]
#[must_use]
pub const fn channel_count(&self) -> u32 {
self.channel_count.into()
}
#[inline]
#[must_use]
pub const fn width(&self) -> u32 {
self.width.into()
}
#[inline]
#[must_use]
pub const fn height(&self) -> u32 {
self.height.into()
}
#[inline(always)]
#[must_use]
pub const fn frame_count(&self) -> u32 {
self.frame_count
}
#[inline]
#[must_use]
pub const fn frame_stride(&self) -> u64 {
u64::from(self.channel_count())
.wrapping_mul(self.width().into())
.wrapping_mul(self.height().into())
}
}
const impl Default for Mode {
#[inline(always)]
fn default() -> Self {
Self {
channel_count: 1,
width: 1,
height: 1,
frame_count: 0,
}
}
}