use super::{GeometryOverflow, InsufficientPlane, InsufficientStride, ZeroDimension};
use derive_more::{IsVariant, TryUnwrap, Unwrap};
use thiserror::Error;
#[derive(Debug, Clone, Copy)]
pub struct GbrpFrame<'a> {
g: &'a [u8],
b: &'a [u8],
r: &'a [u8],
width: u32,
height: u32,
g_stride: u32,
b_stride: u32,
r_stride: u32,
}
impl<'a> GbrpFrame<'a> {
#[cfg_attr(not(tarpaulin), inline(always))]
#[allow(clippy::too_many_arguments)]
pub const fn try_new(
g: &'a [u8],
b: &'a [u8],
r: &'a [u8],
width: u32,
height: u32,
g_stride: u32,
b_stride: u32,
r_stride: u32,
) -> Result<Self, GbrpFrameError> {
if width == 0 || height == 0 {
return Err(GbrpFrameError::ZeroDimension(ZeroDimension::new(
width, height,
)));
}
if g_stride < width {
return Err(GbrpFrameError::InsufficientGStride(
InsufficientStride::new(g_stride, width),
));
}
if b_stride < width {
return Err(GbrpFrameError::InsufficientBStride(
InsufficientStride::new(b_stride, width),
));
}
if r_stride < width {
return Err(GbrpFrameError::InsufficientRStride(
InsufficientStride::new(r_stride, width),
));
}
let g_min = match (g_stride as usize).checked_mul(height as usize) {
Some(v) => v,
None => {
return Err(GbrpFrameError::GeometryOverflow(GeometryOverflow::new(
g_stride, height,
)));
}
};
if g.len() < g_min {
return Err(GbrpFrameError::InsufficientGPlane(InsufficientPlane::new(
g_min,
g.len(),
)));
}
let b_min = match (b_stride as usize).checked_mul(height as usize) {
Some(v) => v,
None => {
return Err(GbrpFrameError::GeometryOverflow(GeometryOverflow::new(
b_stride, height,
)));
}
};
if b.len() < b_min {
return Err(GbrpFrameError::InsufficientBPlane(InsufficientPlane::new(
b_min,
b.len(),
)));
}
let r_min = match (r_stride as usize).checked_mul(height as usize) {
Some(v) => v,
None => {
return Err(GbrpFrameError::GeometryOverflow(GeometryOverflow::new(
r_stride, height,
)));
}
};
if r.len() < r_min {
return Err(GbrpFrameError::InsufficientRPlane(InsufficientPlane::new(
r_min,
r.len(),
)));
}
Ok(Self {
g,
b,
r,
width,
height,
g_stride,
b_stride,
r_stride,
})
}
#[cfg_attr(not(tarpaulin), inline(always))]
#[allow(clippy::too_many_arguments)]
pub const fn new(
g: &'a [u8],
b: &'a [u8],
r: &'a [u8],
width: u32,
height: u32,
g_stride: u32,
b_stride: u32,
r_stride: u32,
) -> Self {
match Self::try_new(g, b, r, width, height, g_stride, b_stride, r_stride) {
Ok(frame) => frame,
Err(_) => panic!("invalid GbrpFrame dimensions or plane lengths"),
}
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn g(&self) -> &'a [u8] {
self.g
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn b(&self) -> &'a [u8] {
self.b
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn r(&self) -> &'a [u8] {
self.r
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn width(&self) -> u32 {
self.width
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn height(&self) -> u32 {
self.height
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn g_stride(&self) -> u32 {
self.g_stride
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn b_stride(&self) -> u32 {
self.b_stride
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn r_stride(&self) -> u32 {
self.r_stride
}
#[allow(dead_code)] #[cfg_attr(not(tarpaulin), inline(always))]
pub(crate) const fn y(&self) -> &'a [u8] {
self.g
}
#[allow(dead_code)] #[cfg_attr(not(tarpaulin), inline(always))]
pub(crate) const fn u(&self) -> &'a [u8] {
self.b
}
#[allow(dead_code)] #[cfg_attr(not(tarpaulin), inline(always))]
pub(crate) const fn v(&self) -> &'a [u8] {
self.r
}
#[allow(dead_code)] #[cfg_attr(not(tarpaulin), inline(always))]
pub(crate) const fn y_stride(&self) -> u32 {
self.g_stride
}
#[allow(dead_code)] #[cfg_attr(not(tarpaulin), inline(always))]
pub(crate) const fn u_stride(&self) -> u32 {
self.b_stride
}
#[allow(dead_code)] #[cfg_attr(not(tarpaulin), inline(always))]
pub(crate) const fn v_stride(&self) -> u32 {
self.r_stride
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, IsVariant, TryUnwrap, Unwrap, Error)]
#[non_exhaustive]
#[unwrap(ref, ref_mut)]
#[try_unwrap(ref, ref_mut)]
pub enum GbrpFrameError {
#[error(transparent)]
ZeroDimension(ZeroDimension),
#[error(transparent)]
InsufficientGStride(InsufficientStride),
#[error(transparent)]
InsufficientBStride(InsufficientStride),
#[error(transparent)]
InsufficientRStride(InsufficientStride),
#[error(transparent)]
InsufficientGPlane(InsufficientPlane),
#[error(transparent)]
InsufficientBPlane(InsufficientPlane),
#[error(transparent)]
InsufficientRPlane(InsufficientPlane),
#[error(transparent)]
GeometryOverflow(GeometryOverflow),
}
#[derive(Debug, Clone, Copy)]
pub struct GbrapFrame<'a> {
g: &'a [u8],
b: &'a [u8],
r: &'a [u8],
a: &'a [u8],
width: u32,
height: u32,
g_stride: u32,
b_stride: u32,
r_stride: u32,
a_stride: u32,
}
impl<'a> GbrapFrame<'a> {
#[cfg_attr(not(tarpaulin), inline(always))]
#[allow(clippy::too_many_arguments)]
pub const fn try_new(
g: &'a [u8],
b: &'a [u8],
r: &'a [u8],
a: &'a [u8],
width: u32,
height: u32,
g_stride: u32,
b_stride: u32,
r_stride: u32,
a_stride: u32,
) -> Result<Self, GbrapFrameError> {
if width == 0 || height == 0 {
return Err(GbrapFrameError::ZeroDimension(ZeroDimension::new(
width, height,
)));
}
if g_stride < width {
return Err(GbrapFrameError::InsufficientGStride(
InsufficientStride::new(g_stride, width),
));
}
if b_stride < width {
return Err(GbrapFrameError::InsufficientBStride(
InsufficientStride::new(b_stride, width),
));
}
if r_stride < width {
return Err(GbrapFrameError::InsufficientRStride(
InsufficientStride::new(r_stride, width),
));
}
if a_stride < width {
return Err(GbrapFrameError::InsufficientAStride(
InsufficientStride::new(a_stride, width),
));
}
let g_min = match (g_stride as usize).checked_mul(height as usize) {
Some(v) => v,
None => {
return Err(GbrapFrameError::GeometryOverflow(GeometryOverflow::new(
g_stride, height,
)));
}
};
if g.len() < g_min {
return Err(GbrapFrameError::InsufficientGPlane(InsufficientPlane::new(
g_min,
g.len(),
)));
}
let b_min = match (b_stride as usize).checked_mul(height as usize) {
Some(v) => v,
None => {
return Err(GbrapFrameError::GeometryOverflow(GeometryOverflow::new(
b_stride, height,
)));
}
};
if b.len() < b_min {
return Err(GbrapFrameError::InsufficientBPlane(InsufficientPlane::new(
b_min,
b.len(),
)));
}
let r_min = match (r_stride as usize).checked_mul(height as usize) {
Some(v) => v,
None => {
return Err(GbrapFrameError::GeometryOverflow(GeometryOverflow::new(
r_stride, height,
)));
}
};
if r.len() < r_min {
return Err(GbrapFrameError::InsufficientRPlane(InsufficientPlane::new(
r_min,
r.len(),
)));
}
let a_min = match (a_stride as usize).checked_mul(height as usize) {
Some(v) => v,
None => {
return Err(GbrapFrameError::GeometryOverflow(GeometryOverflow::new(
a_stride, height,
)));
}
};
if a.len() < a_min {
return Err(GbrapFrameError::InsufficientAPlane(InsufficientPlane::new(
a_min,
a.len(),
)));
}
Ok(Self {
g,
b,
r,
a,
width,
height,
g_stride,
b_stride,
r_stride,
a_stride,
})
}
#[cfg_attr(not(tarpaulin), inline(always))]
#[allow(clippy::too_many_arguments)]
pub const fn new(
g: &'a [u8],
b: &'a [u8],
r: &'a [u8],
a: &'a [u8],
width: u32,
height: u32,
g_stride: u32,
b_stride: u32,
r_stride: u32,
a_stride: u32,
) -> Self {
match Self::try_new(
g, b, r, a, width, height, g_stride, b_stride, r_stride, a_stride,
) {
Ok(frame) => frame,
Err(_) => panic!("invalid GbrapFrame dimensions or plane lengths"),
}
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn g(&self) -> &'a [u8] {
self.g
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn b(&self) -> &'a [u8] {
self.b
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn r(&self) -> &'a [u8] {
self.r
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn a(&self) -> &'a [u8] {
self.a
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn width(&self) -> u32 {
self.width
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn height(&self) -> u32 {
self.height
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn g_stride(&self) -> u32 {
self.g_stride
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn b_stride(&self) -> u32 {
self.b_stride
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn r_stride(&self) -> u32 {
self.r_stride
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn a_stride(&self) -> u32 {
self.a_stride
}
#[allow(dead_code)] #[cfg_attr(not(tarpaulin), inline(always))]
pub(crate) const fn y(&self) -> &'a [u8] {
self.g
}
#[allow(dead_code)] #[cfg_attr(not(tarpaulin), inline(always))]
pub(crate) const fn u(&self) -> &'a [u8] {
self.b
}
#[allow(dead_code)] #[cfg_attr(not(tarpaulin), inline(always))]
pub(crate) const fn v(&self) -> &'a [u8] {
self.r
}
#[allow(dead_code)] #[cfg_attr(not(tarpaulin), inline(always))]
pub(crate) const fn y_stride(&self) -> u32 {
self.g_stride
}
#[allow(dead_code)] #[cfg_attr(not(tarpaulin), inline(always))]
pub(crate) const fn u_stride(&self) -> u32 {
self.b_stride
}
#[allow(dead_code)] #[cfg_attr(not(tarpaulin), inline(always))]
pub(crate) const fn v_stride(&self) -> u32 {
self.r_stride
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, IsVariant, TryUnwrap, Unwrap, Error)]
#[non_exhaustive]
#[unwrap(ref, ref_mut)]
#[try_unwrap(ref, ref_mut)]
pub enum GbrapFrameError {
#[error(transparent)]
ZeroDimension(ZeroDimension),
#[error(transparent)]
InsufficientGStride(InsufficientStride),
#[error(transparent)]
InsufficientBStride(InsufficientStride),
#[error(transparent)]
InsufficientRStride(InsufficientStride),
#[error(transparent)]
InsufficientAStride(InsufficientStride),
#[error(transparent)]
InsufficientGPlane(InsufficientPlane),
#[error(transparent)]
InsufficientBPlane(InsufficientPlane),
#[error(transparent)]
InsufficientRPlane(InsufficientPlane),
#[error(transparent)]
InsufficientAPlane(InsufficientPlane),
#[error(transparent)]
GeometryOverflow(GeometryOverflow),
}