diff --git a/Cargo.lock b/Cargo.lock index 04e7d4f..77173a9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17,6 +17,12 @@ version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" +[[package]] +name = "anyhow" +version = "1.0.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" + [[package]] name = "atty" version = "0.2.14" @@ -160,6 +166,7 @@ dependencies = [ name = "crab-rt" version = "0.1.0" dependencies = [ + "anyhow", "core_affinity", "core_maths", "criterion", diff --git a/Cargo.toml b/Cargo.toml index bffdeaf..644aed5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -26,7 +26,7 @@ required-features = ["uefi"] [features] default = ["std"] -std = ["dep:image", "rand/default", "dep:core_affinity"] +std = ["dep:image", "rand/default", "dep:core_affinity", "dep:anyhow"] uefi = ["dep:uefi", "dep:core_maths", "dep:log"] [dependencies] @@ -36,6 +36,7 @@ core_affinity = { version = "0.8.1", optional = true } uefi = { version = "0.28.0", features = ["alloc", "global_allocator", "logger", "panic_handler"], optional = true } core_maths = { version = "0.1.0", optional = true } log = { version = "0.4.21", optional = true } +anyhow = { version = "1.0.86", optional = true } [dev-dependencies] criterion = "0.4" diff --git a/examples/rt_nextweek.rs b/examples/rt_nextweek.rs index aa730db..d8e9bbc 100644 --- a/examples/rt_nextweek.rs +++ b/examples/rt_nextweek.rs @@ -242,7 +242,9 @@ fn earth() -> Scene { .add_sphere(Sphere::new( Point3::new(0., 0., 0.), 2., - Arc::new(Lambertian::new(Image::load("resources/earthmap.jpg"))), + Arc::new(Lambertian::new( + Image::load("resources/earthmap.jpg").unwrap(), + )), )) .build() } diff --git a/src/aabb.rs b/src/aabb.rs index 261fe43..81c9514 100644 --- a/src/aabb.rs +++ b/src/aabb.rs @@ -15,7 +15,7 @@ pub struct Aabb { impl Aabb { /// Constructs an AABB from two opposite points. /// - /// # Panic + /// # Panics /// Panics in `debug` mode if `min.x > max.x || min.y > max.y || min.z > max.z`. /// /// # Examples diff --git a/src/bin/uefi.rs b/src/bin/uefi.rs index 13d5276..3459305 100644 --- a/src/bin/uefi.rs +++ b/src/bin/uefi.rs @@ -25,7 +25,7 @@ use uefi::table::boot::{EventType, Tpl}; /// Return the `num_views` [`PartialRowViewMut`] of the given slice. /// -/// # Panic +/// # Panics /// Panics if given slice's length is not a multiple of width. fn partial_row_views_mut<'a, T>( slice: &'a mut [T], diff --git a/src/camera.rs b/src/camera.rs index 882c15a..9882d09 100644 --- a/src/camera.rs +++ b/src/camera.rs @@ -24,7 +24,7 @@ pub struct Camera { impl Camera { /// Constructs a new `Camera` with the given lookfrom and lookat points and the vfov and aspect ratio. /// - /// # Panic + /// # Panics /// Panics if `lookfrom == lookat`. /// Panics if `aspect_ratio <= 0.`. /// @@ -71,7 +71,7 @@ impl Camera { /// Consumes the `Camera` and returns self after setting the vup. /// - /// # Panic + /// # Panics /// Panics if `vup == Vec3::new(0., 0., 0.)`. /// /// # Example @@ -107,7 +107,7 @@ impl Camera { /// Consumes the `Camera` and returns self after setting the aperture. /// - /// # Panic + /// # Panics /// Panics if `aperture < 0.`. /// /// # Example @@ -129,7 +129,7 @@ impl Camera { /// Consumes the `Camera` and returns self after setting the focus distance. /// - /// # Panic + /// # Panics /// Panics if `focus_dist == 0.`. /// /// # Example diff --git a/src/core/ray.rs b/src/core/ray.rs index 5074f59..6d6d390 100644 --- a/src/core/ray.rs +++ b/src/core/ray.rs @@ -14,7 +14,7 @@ pub struct Ray { impl Ray { /// Constructs a new `Ray` from the given origin, direction and time. /// - /// # Panic + /// # Panics /// Panics in `debug` mode if `direction == Vec3::new(0., 0., 0.)`. /// /// # Examples diff --git a/src/core/vec.rs b/src/core/vec.rs index 63bcb2a..c482c06 100644 --- a/src/core/vec.rs +++ b/src/core/vec.rs @@ -1,5 +1,5 @@ use core::{ - convert, iter, + iter, ops::{self, Add, Sub}, }; @@ -370,7 +370,7 @@ macro_rules! forward_ref_binop { }; } -impl ops::Add for Vec3 { +impl ops::Add for Vec3 { type Output = Self; #[inline(always)] @@ -381,7 +381,7 @@ impl ops::Add for Vec3 { forward_ref_binop! { impl Add, add for Vec3, Vec3 } -impl ops::AddAssign for Vec3 { +impl ops::AddAssign for Vec3 { #[inline] fn add_assign(&mut self, rhs: Self) { self.x += rhs.x; @@ -408,7 +408,7 @@ impl ops::Neg for &Vec3 { } } -impl ops::Sub for Vec3 { +impl ops::Sub for Vec3 { type Output = Self; #[inline(always)] @@ -420,7 +420,7 @@ impl ops::Sub for Vec3 { forward_ref_binop! { impl Sub, sub for Vec3, Vec3 } -impl ops::SubAssign for Vec3 { +impl ops::SubAssign for Vec3 { #[inline] fn sub_assign(&mut self, rhs: Self) { self.x -= rhs.x; @@ -429,7 +429,7 @@ impl ops::SubAssign for Vec3 { } } -impl ops::Mul for Vec3 { +impl ops::Mul for Vec3 { type Output = Self; #[inline(always)] @@ -508,7 +508,7 @@ impl ops::DivAssign for Vec3 { } } -impl ops::Div for Vec3 { +impl ops::Div for Vec3 { type Output = Self; #[inline(always)] @@ -534,55 +534,63 @@ impl ops::IndexMut for Vec3 { } #[cfg(feature = "std")] -impl convert::Into> for Vec3 { +impl From for Rgb { #[inline(always)] - fn into(self) -> Rgb { - Rgb([ - (255. * self.x.clamp(0., 1.)) as u8, - (255. * self.y.clamp(0., 1.)) as u8, - (255. * self.z.clamp(0., 1.)) as u8, + fn from(vec: Vec3) -> Self { + #[allow(clippy::cast_possible_truncation)] + #[allow(clippy::cast_sign_loss)] + Self([ + (255. * vec.x.clamp(0., 1.)) as u8, + (255. * vec.y.clamp(0., 1.)) as u8, + (255. * vec.z.clamp(0., 1.)) as u8, ]) } } #[cfg(feature = "std")] -impl convert::Into> for &Vec3 { +impl From<&Vec3> for Rgb { #[inline(always)] - fn into(self) -> Rgb { - Rgb([ - (255. * self.x.clamp(0., 1.)) as u8, - (255. * self.y.clamp(0., 1.)) as u8, - (255. * self.z.clamp(0., 1.)) as u8, + fn from(vec: &Vec3) -> Self { + #[allow(clippy::cast_possible_truncation)] + #[allow(clippy::cast_sign_loss)] + Self([ + (255. * vec.x.clamp(0., 1.)) as u8, + (255. * vec.y.clamp(0., 1.)) as u8, + (255. * vec.z.clamp(0., 1.)) as u8, ]) } } #[cfg(feature = "uefi")] -impl convert::Into for Vec3 { +impl From for BltPixel { #[inline(always)] - fn into(self) -> BltPixel { - BltPixel::new( - (255. * self.x.clamp(0., 1.)) as u8, - (255. * self.y.clamp(0., 1.)) as u8, - (255. * self.z.clamp(0., 1.)) as u8, + fn from(vec: Vec3) -> Self { + #[allow(clippy::cast_possible_truncation)] + #[allow(clippy::cast_sign_loss)] + Self::new( + (255. * vec.x.clamp(0., 1.)) as u8, + (255. * vec.y.clamp(0., 1.)) as u8, + (255. * vec.z.clamp(0., 1.)) as u8, ) } } #[cfg(feature = "uefi")] -impl convert::Into for &Vec3 { +impl From<&Vec3> for BltPixel { #[inline(always)] - fn into(self) -> BltPixel { - BltPixel::new( - (255. * self.x.clamp(0., 1.)) as u8, - (255. * self.y.clamp(0., 1.)) as u8, - (255. * self.z.clamp(0., 1.)) as u8, + fn from(vec: &Vec3) -> Self { + #[allow(clippy::cast_possible_truncation)] + #[allow(clippy::cast_sign_loss)] + Self::new( + (255. * vec.x.clamp(0., 1.)) as u8, + (255. * vec.y.clamp(0., 1.)) as u8, + (255. * vec.z.clamp(0., 1.)) as u8, ) } } // Needed if using rayon -impl iter::Sum for Vec3 { +impl iter::Sum for Vec3 { #[inline(always)] fn sum>(iter: I) -> Self { iter.fold(Self::zero(), Add::add) @@ -596,10 +604,10 @@ mod tests { use quickcheck::{Arbitrary, Gen, TestResult}; impl Arbitrary for Vec3 { - fn arbitrary(g: &mut Gen) -> Vec3 { + fn arbitrary(g: &mut Gen) -> Self { let nan_to_default = |f: f32| if f.is_nan() { f32::default() } else { f }; - Vec3::new( + Self::new( nan_to_default(f32::arbitrary(g)), nan_to_default(f32::arbitrary(g)), nan_to_default(f32::arbitrary(g)), diff --git a/src/lib.rs b/src/lib.rs index 2ed7f5d..423bf98 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -8,6 +8,7 @@ clippy::nursery, clippy::cargo )] +#![allow(clippy::inline_always)] extern crate alloc; #[cfg(feature = "std")] diff --git a/src/materials/dielectric.rs b/src/materials/dielectric.rs index b819b1f..bc3e792 100644 --- a/src/materials/dielectric.rs +++ b/src/materials/dielectric.rs @@ -22,7 +22,7 @@ pub struct Dielectric { impl Dielectric { /// Constructs a new `Dielectric` material with the given refractive index. /// - /// # Panic + /// # Panics /// Panics if `refractive_index < 1.`. /// /// # Examples diff --git a/src/objects/constant_medium.rs b/src/objects/constant_medium.rs index efe20d8..64fe08c 100644 --- a/src/objects/constant_medium.rs +++ b/src/objects/constant_medium.rs @@ -19,9 +19,9 @@ pub struct ConstantMedium { } impl ConstantMedium { - /// Constructs a new ConstantMedium with the given boundary, density and phase function. + /// Constructs a new [`ConstantMedium`] with the given boundary, density and phase function. /// - /// # Panic + /// # Panics /// Panics if `density == 0.`. #[inline] #[must_use] diff --git a/src/objects/rotate.rs b/src/objects/rotate.rs index a447334..9f02bc3 100644 --- a/src/objects/rotate.rs +++ b/src/objects/rotate.rs @@ -95,6 +95,6 @@ impl Hitable for RotateY { #[must_use] fn bounding_box(&self, _time_interval: (f32, f32)) -> Option { - self.hasbox.then(|| self.bbox) + self.hasbox.then_some(self.bbox) } } diff --git a/src/objects/sphere.rs b/src/objects/sphere.rs index d010eb1..e22d04c 100644 --- a/src/objects/sphere.rs +++ b/src/objects/sphere.rs @@ -24,7 +24,7 @@ pub struct Sphere { impl Sphere { /// Constructs a sphere from the given center, radius and material. /// - /// # Panic + /// # Panics /// Panics if `radius <= 0.`. /// /// # Examples diff --git a/src/textures/image.rs b/src/textures/image.rs index f5209cf..5fda90c 100644 --- a/src/textures/image.rs +++ b/src/textures/image.rs @@ -2,6 +2,9 @@ use super::Texture; use crate::vec::{Point3, Vec3}; use alloc::vec::Vec; +#[cfg(feature = "std")] +use anyhow::Result; + // For now the image only support RGB #[derive(Debug)] pub struct Image { @@ -12,6 +15,8 @@ pub struct Image { } impl Image { + /// # Panics + /// Panics if the data length is not equal to `width * height * 3`. #[inline] #[must_use] pub fn new(width: usize, height: usize, data: Vec) -> Self { @@ -25,14 +30,16 @@ impl Image { } #[cfg(feature = "std")] - #[must_use] - pub fn load(filename: &str) -> Self { - // TODO: Handle error - let image_buffer = image::open(filename).unwrap().into_rgb8(); + pub fn load(filename: &str) -> Result { + let image_buffer = image::open(filename)?.into_rgb8(); let width = image_buffer.width(); let height = image_buffer.height(); - Self::new(width as usize, height as usize, image_buffer.into_raw()) + Ok(Self::new( + width as usize, + height as usize, + image_buffer.into_raw(), + )) } } @@ -55,9 +62,9 @@ impl Texture for Image { let color_scale = 1. / 255.; let pixel = i * 3 + j * 3 * self.width; Vec3::new( - color_scale * self.data[pixel] as f32, - color_scale * self.data[pixel + 1] as f32, - color_scale * self.data[pixel + 2] as f32, + color_scale * f32::from(self.data[pixel]), + color_scale * f32::from(self.data[pixel + 1]), + color_scale * f32::from(self.data[pixel + 2]), ) } } diff --git a/src/utils.rs b/src/utils.rs index e71fa11..54ddb1e 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -12,6 +12,7 @@ use std::thread_local; #[cfg(not(feature = "std"))] use core_maths::*; +#[derive(Debug)] pub struct SmallThreadRng { rng: Rc>, } @@ -87,6 +88,7 @@ pub fn rng() -> impl Rng { SmallRng::from_seed([0; 32]) } +#[must_use] pub fn random_unit_vector() -> Vec3 { random_in_unit_sphere().unit() } @@ -161,11 +163,12 @@ pub fn refract(uv: &Vec3, n: &Vec3, etai_over_etat: f32) -> Vec3 { } /// Computes the specular reflection coefficient by approximating the Fresnel equations. -/// https://en.wikipedia.org/wiki/Schlick%27s_approximation -/// R(theta) = R_0 + (1 - R_0)(1 - cos(theta))^5 +/// +/// [Schlick's approximation](https://en.wikipedia.org/wiki/Schlick%27s_approximation) +/// `R(theta) = R_0 + (1 - R_0)(1 - cos(theta))^5` /// where -/// R_0 = \frac{n_1 - n_2}{n_1 + n_2}^2 -/// Schlick-approximation is used to efficiently calculate vacuum-medium type of interactions. +/// `R_0 = \frac{n_1 - n_2}{n_1 + n_2}^2` +/// is used to efficiently calculate vacuum-medium type of interactions. #[inline] #[must_use] pub fn schlick(cosine: f32, refraction_index: f32) -> f32 {