Skip to content

Commit

Permalink
Remove anyhow, implement concrete error types (#17)
Browse files Browse the repository at this point in the history
  • Loading branch information
FreezyLemon authored Mar 31, 2023
1 parent 244b05a commit 153dcb8
Show file tree
Hide file tree
Showing 12 changed files with 177 additions and 112 deletions.
3 changes: 1 addition & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,12 @@ default = ["fastmath"]
fastmath = []

[dependencies]
anyhow = "1.0.65"
av-data = "0.4.1"
debug_unreachable = { package = "new_debug_unreachable", version = "1.0.4" }
log = "0.4.17"
nalgebra = "0.32.2"
num-traits = "0.2.15"
paste = "1.0.9"
thiserror = "1.0.40"
v_frame = "0.3.0"

[dev-dependencies]
Expand Down
49 changes: 49 additions & 0 deletions src/errors.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
use thiserror::Error;

/// Error type for when converting data from one color space to another fails.
///
/// Note that some conversions are infallible. These conversions will be
/// implemented in the [`From<T>`] trait. Check the type's documentation
/// to see which conversions are implemented.
#[derive(Debug, Error, Clone, Copy, PartialEq, Eq)]
pub enum ConversionError {
#[error("Cannot convert between YUV and RGB using these matrix coefficients.")]
UnsupportedMatrixCoefficients,
#[error("No matrix coefficients were specified.")]
UnspecifiedMatrixCoefficients,
#[error("Cannot convert between YUV and RGB using these primaries.")]
UnsupportedColorPrimaries,
#[error("No primaries were specified.")]
UnspecifiedColorPrimaries,
#[error("Cannot convert between YUV and RGB using this transfer function.")]
UnsupportedTransferCharacteristic,
#[error("No transfer function was specified.")]
UnspecifiedTransferCharacteristic,
}

/// Error type for when creating one of the colorspace structs fails.
///
/// Note that the [`Yuv`] struct uses a separate Error type, [`YuvError`].
///
/// # Example
/// ```
/// use yuvxyb::{CreationError, LinearRgb};
///
/// // 10 pixels is not enough for the resolution 1920x1080
/// let float_data = vec![[0f32; 3]; 10];
/// let result = LinearRgb::new(float_data, 1920, 1080);
///
/// assert!(result.is_err());
/// assert_eq!(result.unwrap_err(), CreationError::ResolutionMismatch);
/// ```
///
/// [`Yuv`]: crate::yuv::Yuv
/// [`YuvError`]: crate::yuv::YuvError
#[derive(Debug, Error, Clone, Copy, PartialEq, Eq)]
pub enum CreationError {
/// There is a mismatch between the supplied data and the supplied resolution.
///
/// Generally, data.len() should be equal to width * height.
#[error("Data length does not match the specified dimensions.")]
ResolutionMismatch,
}
8 changes: 3 additions & 5 deletions src/hsl.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
use anyhow::{bail, Result};

use crate::LinearRgb;
use crate::{CreationError, LinearRgb};

/// HSL Color Space: Hue, Saturation, Lightness.
///
Expand All @@ -26,9 +24,9 @@ pub struct Hsl {
impl Hsl {
/// # Errors
/// - If data length does not match `width * height`
pub fn new(data: Vec<[f32; 3]>, width: usize, height: usize) -> Result<Self> {
pub fn new(data: Vec<[f32; 3]>, width: usize, height: usize) -> Result<Self, CreationError> {
if data.len() != width * height {
bail!("Data length does not match specified dimensions");
return Err(CreationError::ResolutionMismatch);
}

Ok(Self {
Expand Down
4 changes: 3 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,17 +35,19 @@ mod math;
mod rgb_xyb;
mod yuv_rgb;

mod errors;
mod hsl;
mod linear_rgb;
mod rgb;
mod xyb;
mod yuv;

pub use crate::errors::{ConversionError, CreationError};
pub use crate::hsl::Hsl;
pub use crate::linear_rgb::LinearRgb;
pub use crate::rgb::Rgb;
pub use crate::xyb::Xyb;
pub use crate::yuv::{Yuv, YuvConfig};
pub use crate::yuv::{Yuv, YuvConfig, YuvError};
pub use av_data::pixel::{ColorPrimaries, MatrixCoefficients, TransferCharacteristic};
pub use num_traits::{FromPrimitive, ToPrimitive};
pub use v_frame::{
Expand Down
19 changes: 9 additions & 10 deletions src/linear_rgb.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
use anyhow::{bail, Result};
use av_data::pixel::ColorPrimaries;
use v_frame::prelude::Pixel;

use crate::{
rgb_xyb::xyb_to_linear_rgb,
yuv_rgb::{transform_primaries, TransferFunction},
Hsl, Rgb, Xyb, Yuv,
ConversionError, CreationError, Hsl, Rgb, Xyb, Yuv,
};

#[derive(Debug, Clone)]
Expand All @@ -18,9 +17,9 @@ pub struct LinearRgb {
impl LinearRgb {
/// # Errors
/// - If data length does not match `width * height`
pub fn new(data: Vec<[f32; 3]>, width: usize, height: usize) -> Result<Self> {
pub fn new(data: Vec<[f32; 3]>, width: usize, height: usize) -> Result<Self, CreationError> {
if data.len() != width * height {
bail!("Data length does not match specified dimensions");
return Err(CreationError::ResolutionMismatch);
}

Ok(Self {
Expand Down Expand Up @@ -63,26 +62,26 @@ impl LinearRgb {
}

impl<T: Pixel> TryFrom<Yuv<T>> for LinearRgb {
type Error = anyhow::Error;
type Error = ConversionError;

fn try_from(yuv: Yuv<T>) -> Result<Self> {
fn try_from(yuv: Yuv<T>) -> Result<Self, Self::Error> {
Self::try_from(&yuv)
}
}

impl<T: Pixel> TryFrom<&Yuv<T>> for LinearRgb {
type Error = anyhow::Error;
type Error = ConversionError;

fn try_from(yuv: &Yuv<T>) -> Result<Self> {
fn try_from(yuv: &Yuv<T>) -> Result<Self, Self::Error> {
let rgb = Rgb::try_from(yuv)?;
Self::try_from(rgb)
}
}

impl TryFrom<Rgb> for LinearRgb {
type Error = anyhow::Error;
type Error = ConversionError;

fn try_from(rgb: Rgb) -> Result<Self> {
fn try_from(rgb: Rgb) -> Result<Self, Self::Error> {
let width = rgb.width();
let height = rgb.height();
let transfer = rgb.transfer();
Expand Down
3 changes: 1 addition & 2 deletions src/math.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use core::f32;
use core::f32::consts::LOG2_E;

/// Computes the cube root of x.
///
///
/// The argument must be normal (not NaN, +/-INF or subnormal).
/// This is required for optimization purposes.
pub fn cbrtf(x: f32) -> f32 {
Expand Down Expand Up @@ -67,7 +67,6 @@ fn cbrtf_fast(x: f32) -> f32 {
t as f32
}


// The following implementation of powf is based on José Fonseca's
// polynomial-based implementation, ported to Rust as scalar code
// so that the compiler can auto-vectorize and otherwise optimize.
Expand Down
25 changes: 13 additions & 12 deletions src/rgb.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
use anyhow::{bail, Result};
use av_data::pixel::{ColorPrimaries, TransferCharacteristic};
use v_frame::prelude::Pixel;

use crate::{
yuv_rgb::{transform_primaries, yuv_to_rgb, TransferFunction},
LinearRgb, Xyb, Yuv,
ConversionError, CreationError, LinearRgb, Xyb, Yuv,
};

#[derive(Debug, Clone)]
Expand All @@ -25,9 +24,9 @@ impl Rgb {
height: usize,
mut transfer: TransferCharacteristic,
mut primaries: ColorPrimaries,
) -> Result<Self> {
) -> Result<Self, CreationError> {
if data.len() != width * height {
bail!("Data length does not match specified dimensions");
return Err(CreationError::ResolutionMismatch);
}

if transfer == TransferCharacteristic::Unspecified {
Expand Down Expand Up @@ -97,17 +96,17 @@ impl Rgb {
}

impl<T: Pixel> TryFrom<Yuv<T>> for Rgb {
type Error = anyhow::Error;
type Error = ConversionError;

fn try_from(yuv: Yuv<T>) -> Result<Self> {
fn try_from(yuv: Yuv<T>) -> Result<Self, Self::Error> {
Self::try_from(&yuv)
}
}

impl<T: Pixel> TryFrom<&Yuv<T>> for Rgb {
type Error = anyhow::Error;
type Error = ConversionError;

fn try_from(yuv: &Yuv<T>) -> Result<Self> {
fn try_from(yuv: &Yuv<T>) -> Result<Self, Self::Error> {
let data = yuv_to_rgb(yuv)?;

Ok(Self {
Expand All @@ -122,18 +121,20 @@ impl<T: Pixel> TryFrom<&Yuv<T>> for Rgb {

// From XYB
impl TryFrom<(Xyb, TransferCharacteristic, ColorPrimaries)> for Rgb {
type Error = anyhow::Error;
type Error = ConversionError;

fn try_from(other: (Xyb, TransferCharacteristic, ColorPrimaries)) -> Result<Self> {
fn try_from(other: (Xyb, TransferCharacteristic, ColorPrimaries)) -> Result<Self, Self::Error> {
let lrgb = LinearRgb::from(other.0);
Self::try_from((lrgb, other.1, other.2))
}
}

impl TryFrom<(LinearRgb, TransferCharacteristic, ColorPrimaries)> for Rgb {
type Error = anyhow::Error;
type Error = ConversionError;

fn try_from(other: (LinearRgb, TransferCharacteristic, ColorPrimaries)) -> Result<Self> {
fn try_from(
other: (LinearRgb, TransferCharacteristic, ColorPrimaries),
) -> Result<Self, Self::Error> {
let lrgb = other.0;
let (mut transfer, mut primaries) = (other.1, other.2);

Expand Down
19 changes: 9 additions & 10 deletions src/xyb.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
use anyhow::{bail, Result};
use v_frame::prelude::Pixel;

use crate::{rgb_xyb::linear_rgb_to_xyb, LinearRgb, Rgb, Yuv};
use crate::{rgb_xyb::linear_rgb_to_xyb, ConversionError, CreationError, LinearRgb, Rgb, Yuv};

#[derive(Debug, Clone)]
pub struct Xyb {
Expand All @@ -13,9 +12,9 @@ pub struct Xyb {
impl Xyb {
/// # Errors
/// - If data length does not match `width * height`
pub fn new(data: Vec<[f32; 3]>, width: usize, height: usize) -> Result<Self> {
pub fn new(data: Vec<[f32; 3]>, width: usize, height: usize) -> Result<Self, CreationError> {
if data.len() != width * height {
bail!("Data length does not match specified dimensions");
return Err(CreationError::ResolutionMismatch);
}

Ok(Self {
Expand Down Expand Up @@ -58,26 +57,26 @@ impl Xyb {
}

impl<T: Pixel> TryFrom<Yuv<T>> for Xyb {
type Error = anyhow::Error;
type Error = ConversionError;

fn try_from(yuv: Yuv<T>) -> Result<Self> {
fn try_from(yuv: Yuv<T>) -> Result<Self, Self::Error> {
Self::try_from(&yuv)
}
}

impl<T: Pixel> TryFrom<&Yuv<T>> for Xyb {
type Error = anyhow::Error;
type Error = ConversionError;

fn try_from(yuv: &Yuv<T>) -> Result<Self> {
fn try_from(yuv: &Yuv<T>) -> Result<Self, Self::Error> {
let rgb = Rgb::try_from(yuv)?;
Self::try_from(rgb)
}
}

impl TryFrom<Rgb> for Xyb {
type Error = anyhow::Error;
type Error = ConversionError;

fn try_from(rgb: Rgb) -> Result<Self> {
fn try_from(rgb: Rgb) -> Result<Self, Self::Error> {
let lrgb = LinearRgb::try_from(rgb)?;
Ok(Self::from(lrgb))
}
Expand Down
Loading

0 comments on commit 153dcb8

Please sign in to comment.