diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f2fa6a694..fc73f0650 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -24,6 +24,7 @@ jobs: - uses: dtolnay/rust-toolchain@1.60.0 with: components: clippy + - uses: taiki-e/install-action@cargo-hack - name: Minimal check run: cargo clippy -v -p palette --no-default-features --features std - name: find-crate check @@ -33,9 +34,7 @@ jobs: - name: Test all features run: cargo test -v -p palette --all-features - name: Test each feature - shell: bash - working-directory: palette - run: bash ../scripts/test_features.sh + run: cargo hack test --tests --feature-powerset --ignore-private --skip default,find-crate --optional-deps libm --depth 2 integration_tests: name: integration tests strategy: @@ -63,8 +62,13 @@ jobs: with: toolchain: ${{ matrix.toolchain }} components: clippy + - uses: taiki-e/install-action@cargo-hack - name: Check all features run: cargo clippy -v -p palette --all-features + - name: Check each feature with libm + run: cargo hack clippy --each-feature --ignore-private --features libm --skip default,find-crate --ignore-unknown-features + - name: Check each feature with std + run: cargo hack clippy --each-feature --ignore-private --features std --skip default,find-crate --optional-deps libm --ignore-unknown-features no_std: name: "Test #[no_std]" runs-on: ubuntu-latest diff --git a/benchmarks/Cargo.toml b/benchmarks/Cargo.toml index d71a209d3..cc0b78b4f 100644 --- a/benchmarks/Cargo.toml +++ b/benchmarks/Cargo.toml @@ -7,6 +7,7 @@ description = "Benchmark crate for palette." repository = "https://github.com/Ogeon/palette" license = "MIT OR Apache-2.0" edition = "2018" +publish = false [[bench]] path = "benches/cie.rs" diff --git a/integration_tests/Cargo.toml b/integration_tests/Cargo.toml index e49aed389..ab1875217 100644 --- a/integration_tests/Cargo.toml +++ b/integration_tests/Cargo.toml @@ -7,6 +7,7 @@ description = "Integration test crate for palette." repository = "https://github.com/Ogeon/palette" license = "MIT OR Apache-2.0" edition = "2018" +publish = false [[example]] name = "issue_283" diff --git a/no_std_test/Cargo.toml b/no_std_test/Cargo.toml index 27bc17b07..9a89d4dd6 100644 --- a/no_std_test/Cargo.toml +++ b/no_std_test/Cargo.toml @@ -7,6 +7,7 @@ description = "Test crate for #[no_std]." repository = "https://github.com/Ogeon/palette" license = "MIT OR Apache-2.0" edition = "2018" +publish = false [[bin]] name = "no_std_test" diff --git a/palette/Cargo.toml b/palette/Cargo.toml index 61e70097b..dec69e3d8 100644 --- a/palette/Cargo.toml +++ b/palette/Cargo.toml @@ -33,9 +33,9 @@ named_from_str = ["named", "phf"] named = [] random = ["rand"] serializing = ["serde", "std"] -#ignore in feature test find-crate = ["palette_derive/find-crate"] -std = ["approx?/std"] +std = ["alloc", "approx?/std"] +alloc = [] [lib] bench = false diff --git a/palette/README.md b/palette/README.md index b64088942..b7cf25289 100644 --- a/palette/README.md +++ b/palette/README.md @@ -41,7 +41,8 @@ These features are enabled by default: * `"named"` - Enables color constants, located in the `named` module. * `"named_from_str"` - Enables `named::from_str`, which maps name strings to colors. -* `"std"` - Enables use of the standard library. +* `"std"` - Enables use of the standard library. Also enables `"alloc"`. +* `"alloc"` - Enables implementations for allocating types, such as `Vec` or `Box`. * `"approx"` - Enables approximate comparison using [`approx`]. These features are disabled by default: @@ -55,7 +56,7 @@ These features are disabled by default: ### Using palette in an embedded environment -Palette supports `#![no_std]` environments by disabling the `"std"` feature. It uses [`libm`] to provide the floating-point operations that are typically in `std`. However, serializing with `serde` is not available without the standard library. +Palette supports `#![no_std]` environments by disabling the `"std"` feature. It uses [`libm`], via the `"libm"` feature, to provide the floating-point operations that are typically in `std`, and the `"alloc"` feature to provide features that use allocating types. However, serializing with `serde` is not available without the standard library. ## Examples diff --git a/palette/src/alpha/alpha.rs b/palette/src/alpha/alpha.rs index b1f8266e2..e1e92351c 100644 --- a/palette/src/alpha/alpha.rs +++ b/palette/src/alpha/alpha.rs @@ -1240,8 +1240,8 @@ mod test { #[test] fn check_min_max_components() { - assert_relative_eq!(Rgba::::min_alpha(), 0.0); - assert_relative_eq!(Rgba::::max_alpha(), 1.0); + assert_eq!(Rgba::::min_alpha(), 0.0); + assert_eq!(Rgba::::max_alpha(), 1.0); } #[cfg(feature = "serializing")] diff --git a/palette/src/blend/test.rs b/palette/src/blend/test.rs index f1ef1d825..b6d16764f 100644 --- a/palette/src/blend/test.rs +++ b/palette/src/blend/test.rs @@ -1,3 +1,5 @@ +#![cfg(feature = "approx")] + use crate::{ blend::{Blend, BlendWith, Compose}, LinSrgb, LinSrgba, diff --git a/palette/src/cast/array.rs b/palette/src/cast/array.rs index a0f2dc191..e55b6ac20 100644 --- a/palette/src/cast/array.rs +++ b/palette/src/cast/array.rs @@ -1,5 +1,8 @@ use core::mem::{transmute_copy, ManuallyDrop}; +#[cfg(feature = "alloc")] +use alloc::{boxed::Box, vec::Vec}; + pub use palette_derive::ArrayCast; use crate::ArrayExt; @@ -958,7 +961,7 @@ where /// let color2 = Box::new(Srgb::new(23u8, 198, 76)); /// let array2 = >::from(color2); /// ``` -#[cfg(feature = "std")] +#[cfg(feature = "alloc")] #[inline] pub fn into_array_box(value: Box) -> Box where @@ -1000,7 +1003,7 @@ where /// let array2 = Box::new([23, 198, 76]); /// let color2 = >>::from(array2); /// ``` -#[cfg(feature = "std")] +#[cfg(feature = "alloc")] #[inline] pub fn from_array_box(value: Box) -> Box where @@ -1030,7 +1033,7 @@ where /// vec![[64, 139, 10], [93, 18, 214]].into_boxed_slice() /// ) /// ``` -#[cfg(feature = "std")] +#[cfg(feature = "alloc")] #[inline] pub fn into_array_slice_box(values: Box<[T]>) -> Box<[T::Array]> where @@ -1053,7 +1056,7 @@ where /// vec![64, 139, 10, 93, 18, 214].into_boxed_slice() /// ) /// ``` -#[cfg(feature = "std")] +#[cfg(feature = "alloc")] #[inline] pub fn into_component_slice_box(values: Box<[T]>) -> Box<[::Item]> where @@ -1076,7 +1079,7 @@ where /// vec![Srgb::new(64u8, 139, 10), Srgb::new(93, 18, 214)].into_boxed_slice() /// ) /// ``` -#[cfg(feature = "std")] +#[cfg(feature = "alloc")] #[inline] pub fn from_array_slice_box(values: Box<[T::Array]>) -> Box<[T]> where @@ -1116,7 +1119,7 @@ where /// let components = vec![64, 139, 10, 93, 18, 214, 0, 123].into_boxed_slice(); /// cast::from_component_slice_box::>(components); /// ``` -#[cfg(feature = "std")] +#[cfg(feature = "alloc")] #[inline] pub fn from_component_slice_box(values: Box<[::Item]>) -> Box<[T]> where @@ -1162,7 +1165,7 @@ where /// unreachable!(); /// } /// ``` -#[cfg(feature = "std")] +#[cfg(feature = "alloc")] #[inline] pub fn try_from_component_slice_box( values: Box<[::Item]>, @@ -1191,7 +1194,7 @@ where /// vec![[64, 139, 10], [93, 18, 214]] /// ) /// ``` -#[cfg(feature = "std")] +#[cfg(feature = "alloc")] #[inline] pub fn into_array_vec(values: Vec) -> Vec where @@ -1223,7 +1226,7 @@ where /// vec![64, 139, 10, 93, 18, 214] /// ) /// ``` -#[cfg(feature = "std")] +#[cfg(feature = "alloc")] #[inline] pub fn into_component_vec(values: Vec) -> Vec<::Item> where @@ -1257,7 +1260,7 @@ where /// vec![Srgb::new(64u8, 139, 10), Srgb::new(93, 18, 214)] /// ) /// ``` -#[cfg(feature = "std")] +#[cfg(feature = "alloc")] #[inline] pub fn from_array_vec(values: Vec) -> Vec where @@ -1316,7 +1319,7 @@ where /// components.reserve_exact(2); // Not a multiple of 3 /// cast::from_component_vec::>(components); /// ``` -#[cfg(feature = "std")] +#[cfg(feature = "alloc")] #[inline] pub fn from_component_vec(values: Vec<::Item>) -> Vec where @@ -1376,7 +1379,7 @@ where /// unreachable!(); /// } /// ``` -#[cfg(feature = "std")] +#[cfg(feature = "alloc")] #[inline] pub fn try_from_component_vec( values: Vec<::Item>, @@ -1419,7 +1422,7 @@ where /// Map values of color A to values of color B without creating a new `Vec`. /// /// This uses the guarantees of [`ArrayCast`] to reuse the allocation. -#[cfg(feature = "std")] +#[cfg(feature = "alloc")] #[inline] pub fn map_vec_in_place(values: Vec, mut map: F) -> Vec where @@ -1453,7 +1456,7 @@ where /// Map values of color A to values of color B without creating a new `Box<[B]>`. /// /// This uses the guarantees of [`ArrayCast`] to reuse the allocation. -#[cfg(feature = "std")] +#[cfg(feature = "alloc")] #[inline] pub fn map_slice_box_in_place(values: Box<[A]>, mut map: F) -> Box<[B]> where @@ -1499,20 +1502,20 @@ impl std::error::Error for SliceCastError {} /// The error type returned when casting a boxed slice of components fails. #[derive(Clone, PartialEq, Eq)] -#[cfg(feature = "std")] +#[cfg(feature = "alloc")] pub struct BoxedSliceCastError { /// The original values. pub values: Box<[T]>, } -#[cfg(feature = "std")] +#[cfg(feature = "alloc")] impl core::fmt::Debug for BoxedSliceCastError { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { f.debug_struct("BoxedSliceCastError").finish() } } -#[cfg(feature = "std")] +#[cfg(feature = "alloc")] impl core::fmt::Display for BoxedSliceCastError { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { f.write_str("could not convert boxed component slice to colors") @@ -1524,7 +1527,7 @@ impl std::error::Error for BoxedSliceCastError {} /// The error type returned when casting a `Vec` of components fails. #[derive(Clone, PartialEq, Eq)] -#[cfg(feature = "std")] +#[cfg(feature = "alloc")] pub struct VecCastError { /// The type of error that occurred. pub kind: VecCastErrorKind, @@ -1533,7 +1536,7 @@ pub struct VecCastError { pub values: Vec, } -#[cfg(feature = "std")] +#[cfg(feature = "alloc")] impl core::fmt::Debug for VecCastError { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { f.debug_struct("VecCastError") @@ -1542,7 +1545,7 @@ impl core::fmt::Debug for VecCastError { } } -#[cfg(feature = "std")] +#[cfg(feature = "alloc")] impl core::fmt::Display for VecCastError { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { f.write_str("could not convert component vector to colors") @@ -1554,7 +1557,7 @@ impl std::error::Error for VecCastError {} /// The type of error that is returned when casting a `Vec` of components. #[derive(Debug, Clone, Copy, PartialEq, Eq)] -#[cfg(feature = "std")] +#[cfg(feature = "alloc")] pub enum VecCastErrorKind { /// The type of error returned when the length of a `Vec` didn't match the /// requirements. @@ -1567,9 +1570,10 @@ pub enum VecCastErrorKind { #[cfg(test)] mod test { + #[cfg(feature = "alloc")] use crate::{LinSrgb, Srgb}; - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] #[test] fn array_vec_len_cap() { let mut original = vec![ @@ -1596,11 +1600,12 @@ mod test { assert_eq!(colors.capacity(), 8); } + #[cfg(feature = "alloc")] #[test] fn map_vec_in_place() { fn do_things(rgb: Srgb) -> LinSrgb { let mut linear = rgb.into_linear(); - std::mem::swap(&mut linear.red, &mut linear.blue); + core::mem::swap(&mut linear.red, &mut linear.blue); linear } @@ -1615,11 +1620,12 @@ mod test { ) } + #[cfg(feature = "alloc")] #[test] fn map_slice_box_in_place() { fn do_things(rgb: Srgb) -> LinSrgb { let mut linear = rgb.into_linear(); - std::mem::swap(&mut linear.red, &mut linear.blue); + core::mem::swap(&mut linear.red, &mut linear.blue); linear } diff --git a/palette/src/cast/as_arrays_traits.rs b/palette/src/cast/as_arrays_traits.rs index 15445f243..6f02cd855 100644 --- a/palette/src/cast/as_arrays_traits.rs +++ b/palette/src/cast/as_arrays_traits.rs @@ -78,8 +78,8 @@ macro_rules! impl_as_arrays { impl_as_arrays!([C], [C; M] where (const M: usize)); -#[cfg(feature = "std")] -impl_as_arrays!(Box<[C]>, Vec); +#[cfg(feature = "alloc")] +impl_as_arrays!(alloc::boxed::Box<[C]>, alloc::vec::Vec); /// Trait for casting a reference to collection of arrays into a reference to /// collection of colors without copying. @@ -167,8 +167,8 @@ macro_rules! impl_arrays_as { impl_arrays_as!([[T; N]], [[T; N]; M] where (const M: usize)); -#[cfg(feature = "std")] -impl_arrays_as!(Box<[[T; N]]>, Vec<[T; N]>); +#[cfg(feature = "alloc")] +impl_arrays_as!(alloc::boxed::Box<[[T; N]]>, alloc::vec::Vec<[T; N]>); #[cfg(test)] mod test { diff --git a/palette/src/cast/as_components_traits.rs b/palette/src/cast/as_components_traits.rs index 656018cee..8165d1835 100644 --- a/palette/src/cast/as_components_traits.rs +++ b/palette/src/cast/as_components_traits.rs @@ -82,8 +82,8 @@ macro_rules! impl_as_components { impl_as_components!([C], [C; M] where (const M: usize)); -#[cfg(feature = "std")] -impl_as_components!(Box<[C]>, Vec); +#[cfg(feature = "alloc")] +impl_as_components!(alloc::boxed::Box<[C]>, alloc::vec::Vec); /// Trait for trying to cast a reference to collection of color components into /// a reference to collection of colors without copying. @@ -221,8 +221,8 @@ macro_rules! impl_try_components_as { impl_try_components_as!([T], [T; M] where (const M: usize)); -#[cfg(feature = "std")] -impl_try_components_as!(Box<[T]>, Vec); +#[cfg(feature = "alloc")] +impl_try_components_as!(alloc::boxed::Box<[T]>, alloc::vec::Vec); /// Trait for casting a reference to collection of color components into a /// reference to collection of colors without copying. diff --git a/palette/src/cast/as_uints_traits.rs b/palette/src/cast/as_uints_traits.rs index 5c0f4a464..3471cab4b 100644 --- a/palette/src/cast/as_uints_traits.rs +++ b/palette/src/cast/as_uints_traits.rs @@ -94,8 +94,8 @@ macro_rules! impl_as_uints { impl_as_uints!([C], [C; N] where (const N: usize)); -#[cfg(feature = "std")] -impl_as_uints!(Box<[C]>, Vec); +#[cfg(feature = "alloc")] +impl_as_uints!(alloc::boxed::Box<[C]>, alloc::vec::Vec); /// Trait for casting a reference to a collection of unsigned integers into a /// reference to a collection of colors without copying. @@ -219,8 +219,8 @@ macro_rules! impl_uints_as { impl_uints_as!([C::Uint], [C::Uint; N] where (const N: usize)); -#[cfg(feature = "std")] -impl_uints_as!(Box<[C::Uint]>, Vec); +#[cfg(feature = "alloc")] +impl_uints_as!(alloc::boxed::Box<[C::Uint]>, alloc::vec::Vec); #[cfg(test)] mod test { diff --git a/palette/src/cast/from_into_arrays_traits.rs b/palette/src/cast/from_into_arrays_traits.rs index f9c66079f..afadec1c4 100644 --- a/palette/src/cast/from_into_arrays_traits.rs +++ b/palette/src/cast/from_into_arrays_traits.rs @@ -3,7 +3,7 @@ use super::{ into_array_slice_mut, ArrayCast, }; -#[cfg(feature = "std")] +#[cfg(feature = "alloc")] use super::{from_array_slice_box, from_array_vec, into_array_slice_box, into_array_vec}; /// Trait for casting a collection of colors from a collection of arrays without @@ -104,27 +104,27 @@ macro_rules! impl_from_arrays_slice { impl_from_arrays_slice!([[T; N]], [[T; N]; M] where (const M: usize)); -#[cfg(feature = "std")] -impl_from_arrays_slice!(Box<[[T; N]]>, Vec<[T; N]>); +#[cfg(feature = "alloc")] +impl_from_arrays_slice!(alloc::boxed::Box<[[T; N]]>, alloc::vec::Vec<[T; N]>); -#[cfg(feature = "std")] -impl FromArrays> for Box<[C]> +#[cfg(feature = "alloc")] +impl FromArrays> for alloc::boxed::Box<[C]> where C: ArrayCast, { #[inline] - fn from_arrays(arrays: Box<[[T; N]]>) -> Self { + fn from_arrays(arrays: alloc::boxed::Box<[[T; N]]>) -> Self { from_array_slice_box(arrays) } } -#[cfg(feature = "std")] -impl FromArrays> for Vec +#[cfg(feature = "alloc")] +impl FromArrays> for alloc::vec::Vec where C: ArrayCast, { #[inline] - fn from_arrays(arrays: Vec<[T; N]>) -> Self { + fn from_arrays(arrays: alloc::vec::Vec<[T; N]>) -> Self { from_array_vec(arrays) } } @@ -205,27 +205,27 @@ macro_rules! impl_into_arrays_slice { impl_into_arrays_slice!([C], [C; M] where (const M: usize)); -#[cfg(feature = "std")] -impl_into_arrays_slice!(Box<[C]>, Vec); +#[cfg(feature = "alloc")] +impl_into_arrays_slice!(alloc::boxed::Box<[C]>, alloc::vec::Vec); -#[cfg(feature = "std")] -impl IntoArrays> for Box<[C]> +#[cfg(feature = "alloc")] +impl IntoArrays> for alloc::boxed::Box<[C]> where C: ArrayCast, { #[inline] - fn into_arrays(self) -> Box<[[T; N]]> { + fn into_arrays(self) -> alloc::boxed::Box<[[T; N]]> { into_array_slice_box(self) } } -#[cfg(feature = "std")] -impl IntoArrays> for Vec +#[cfg(feature = "alloc")] +impl IntoArrays> for alloc::vec::Vec where C: ArrayCast, { #[inline] - fn into_arrays(self) -> Vec<[T; N]> { + fn into_arrays(self) -> alloc::vec::Vec<[T; N]> { into_array_vec(self) } } @@ -346,93 +346,125 @@ mod test { fn from_arrays() { let slice: &[[u8; 3]] = &[[1, 2, 3], [4, 5, 6]]; let slice_mut: &mut [[u8; 3]] = &mut [[1, 2, 3], [4, 5, 6]]; - let mut slice_box: Box<[[u8; 3]]> = vec![[1, 2, 3], [4, 5, 6]].into_boxed_slice(); - let mut vec: Vec<[u8; 3]> = vec![[1, 2, 3], [4, 5, 6]]; let mut array: [[u8; 3]; 2] = [[1, 2, 3], [4, 5, 6]]; let _ = <&[Srgb]>::from_arrays(slice); - let _ = <&[Srgb]>::from_arrays(&slice_box); - let _ = <&[Srgb]>::from_arrays(&vec); let _ = <&[Srgb]>::from_arrays(&array); let _ = <&mut [Srgb]>::from_arrays(slice_mut); + let _ = <&mut [Srgb]>::from_arrays(&mut array); + + let _ = <[Srgb; 2]>::from_arrays(array); + } + + #[cfg(feature = "alloc")] + #[test] + fn from_arrays_alloc() { + let mut slice_box: Box<[[u8; 3]]> = vec![[1, 2, 3], [4, 5, 6]].into_boxed_slice(); + let mut vec: Vec<[u8; 3]> = vec![[1, 2, 3], [4, 5, 6]]; + + let _ = <&[Srgb]>::from_arrays(&slice_box); + let _ = <&[Srgb]>::from_arrays(&vec); + let _ = <&mut [Srgb]>::from_arrays(&mut slice_box); let _ = <&mut [Srgb]>::from_arrays(&mut vec); - let _ = <&mut [Srgb]>::from_arrays(&mut array); let _ = Box::<[Srgb]>::from_arrays(slice_box); let _ = Vec::>::from_arrays(vec); - let _ = <[Srgb; 2]>::from_arrays(array); } #[test] fn arrays_into() { let slice: &[[u8; 3]] = &[[1, 2, 3], [4, 5, 6]]; let slice_mut: &mut [[u8; 3]] = &mut [[1, 2, 3], [4, 5, 6]]; - let mut slice_box: Box<[[u8; 3]]> = vec![[1, 2, 3], [4, 5, 6]].into_boxed_slice(); - let mut vec: Vec<[u8; 3]> = vec![[1, 2, 3], [4, 5, 6]]; let mut array: [[u8; 3]; 2] = [[1, 2, 3], [4, 5, 6]]; let _: &[Srgb] = slice.arrays_into(); - let _: &[Srgb] = (&slice_box).arrays_into(); - let _: &[Srgb] = (&vec).arrays_into(); let _: &[Srgb] = (&array).arrays_into(); let _: &mut [Srgb] = slice_mut.arrays_into(); + let _: &mut [Srgb] = (&mut array).arrays_into(); + + let _: [Srgb; 2] = array.arrays_into(); + } + + #[cfg(feature = "alloc")] + #[test] + fn arrays_into_alloc() { + let mut slice_box: Box<[[u8; 3]]> = vec![[1, 2, 3], [4, 5, 6]].into_boxed_slice(); + let mut vec: Vec<[u8; 3]> = vec![[1, 2, 3], [4, 5, 6]]; + + let _: &[Srgb] = (&slice_box).arrays_into(); + let _: &[Srgb] = (&vec).arrays_into(); + let _: &mut [Srgb] = (&mut slice_box).arrays_into(); let _: &mut [Srgb] = (&mut vec).arrays_into(); - let _: &mut [Srgb] = (&mut array).arrays_into(); let _: Box<[Srgb]> = slice_box.arrays_into(); let _: Vec> = vec.arrays_into(); - let _: [Srgb; 2] = array.arrays_into(); } #[test] fn into_arrays() { let slice: &[Srgb] = &[Srgb::new(1, 2, 3), Srgb::new(4, 5, 6)]; let slice_mut: &mut [Srgb] = &mut [Srgb::new(1, 2, 3), Srgb::new(4, 5, 6)]; + let mut array: [Srgb; 2] = [Srgb::new(1, 2, 3), Srgb::new(4, 5, 6)]; + + let _: &[[u8; 3]] = slice.into_arrays(); + let _: &[[u8; 3]] = (&array).into_arrays(); + + let _: &mut [[u8; 3]] = slice_mut.into_arrays(); + let _: &mut [[u8; 3]] = (&mut array).into_arrays(); + + let _: [[u8; 3]; 2] = array.into_arrays(); + } + + #[cfg(feature = "alloc")] + #[test] + fn into_arrays_alloc() { let mut slice_box: Box<[Srgb]> = vec![Srgb::new(1, 2, 3), Srgb::new(4, 5, 6)].into_boxed_slice(); let mut vec: Vec> = vec![Srgb::new(1, 2, 3), Srgb::new(4, 5, 6)]; - let mut array: [Srgb; 2] = [Srgb::new(1, 2, 3), Srgb::new(4, 5, 6)]; - let _: &[[u8; 3]] = slice.into_arrays(); let _: &[[u8; 3]] = (&slice_box).into_arrays(); let _: &[[u8; 3]] = (&vec).into_arrays(); - let _: &[[u8; 3]] = (&array).into_arrays(); - let _: &mut [[u8; 3]] = slice_mut.into_arrays(); let _: &mut [[u8; 3]] = (&mut slice_box).into_arrays(); let _: &mut [[u8; 3]] = (&mut vec).into_arrays(); - let _: &mut [[u8; 3]] = (&mut array).into_arrays(); let _: Box<[[u8; 3]]> = slice_box.into_arrays(); let _: Vec<[u8; 3]> = vec.into_arrays(); - let _: [[u8; 3]; 2] = array.into_arrays(); } #[test] fn arrays_from() { let slice: &[Srgb] = &[Srgb::new(1, 2, 3), Srgb::new(4, 5, 6)]; let slice_mut: &mut [Srgb] = &mut [Srgb::new(1, 2, 3), Srgb::new(4, 5, 6)]; + let mut array: [Srgb; 2] = [Srgb::new(1, 2, 3), Srgb::new(4, 5, 6)]; + + let _ = <&[[u8; 3]]>::arrays_from(slice); + let _ = <&[[u8; 3]]>::arrays_from(&array); + + let _ = <&mut [[u8; 3]]>::arrays_from(slice_mut); + let _ = <&mut [[u8; 3]]>::arrays_from(&mut array); + + let _ = <[[u8; 3]; 2]>::arrays_from(array); + } + + #[cfg(feature = "alloc")] + #[test] + fn arrays_from_alloc() { let mut slice_box: Box<[Srgb]> = vec![Srgb::new(1, 2, 3), Srgb::new(4, 5, 6)].into_boxed_slice(); let mut vec: Vec> = vec![Srgb::new(1, 2, 3), Srgb::new(4, 5, 6)]; - let mut array: [Srgb; 2] = [Srgb::new(1, 2, 3), Srgb::new(4, 5, 6)]; - let _ = <&[[u8; 3]]>::arrays_from(slice); let _ = <&[[u8; 3]]>::arrays_from(&slice_box); let _ = <&[[u8; 3]]>::arrays_from(&vec); - let _ = <&[[u8; 3]]>::arrays_from(&array); - let _ = <&mut [[u8; 3]]>::arrays_from(slice_mut); let _ = <&mut [[u8; 3]]>::arrays_from(&mut slice_box); let _ = <&mut [[u8; 3]]>::arrays_from(&mut vec); - let _ = <&mut [[u8; 3]]>::arrays_from(&mut array); let _ = Box::<[[u8; 3]]>::arrays_from(slice_box); let _ = Vec::<[u8; 3]>::arrays_from(vec); - let _ = <[[u8; 3]; 2]>::arrays_from(array); } } diff --git a/palette/src/cast/from_into_components_traits.rs b/palette/src/cast/from_into_components_traits.rs index 817c04f9b..616f9d4d2 100644 --- a/palette/src/cast/from_into_components_traits.rs +++ b/palette/src/cast/from_into_components_traits.rs @@ -7,7 +7,7 @@ use super::{ try_from_component_slice, try_from_component_slice_mut, ArrayCast, SliceCastError, }; -#[cfg(feature = "std")] +#[cfg(feature = "alloc")] use super::{ into_component_slice_box, into_component_vec, try_from_component_slice_box, try_from_component_vec, BoxedSliceCastError, VecCastError, @@ -144,11 +144,11 @@ macro_rules! impl_try_from_components_slice { impl_try_from_components_slice!([T], [T; N] where (const N: usize)); -#[cfg(feature = "std")] -impl_try_from_components_slice!(Box<[T]>, Vec); +#[cfg(feature = "alloc")] +impl_try_from_components_slice!(alloc::boxed::Box<[T]>, alloc::vec::Vec); -#[cfg(feature = "std")] -impl TryFromComponents> for Box<[C]> +#[cfg(feature = "alloc")] +impl TryFromComponents> for alloc::boxed::Box<[C]> where C: ArrayCast, C::Array: ArrayExt, @@ -156,13 +156,13 @@ where type Error = BoxedSliceCastError; #[inline] - fn try_from_components(components: Box<[T]>) -> Result { + fn try_from_components(components: alloc::boxed::Box<[T]>) -> Result { try_from_component_slice_box(components) } } -#[cfg(feature = "std")] -impl TryFromComponents> for Vec +#[cfg(feature = "alloc")] +impl TryFromComponents> for alloc::vec::Vec where C: ArrayCast, C::Array: ArrayExt, @@ -170,7 +170,7 @@ where type Error = VecCastError; #[inline] - fn try_from_components(components: Vec) -> Result { + fn try_from_components(components: alloc::vec::Vec) -> Result { try_from_component_vec(components) } } @@ -346,29 +346,29 @@ macro_rules! impl_into_components_slice { impl_into_components_slice!([C], [C; N] where (const N: usize)); -#[cfg(feature = "std")] -impl_into_components_slice!(Box<[C]>, Vec); +#[cfg(feature = "alloc")] +impl_into_components_slice!(alloc::boxed::Box<[C]>, alloc::vec::Vec); -#[cfg(feature = "std")] -impl IntoComponents> for Box<[C]> +#[cfg(feature = "alloc")] +impl IntoComponents> for alloc::boxed::Box<[C]> where C: ArrayCast, C::Array: ArrayExt, { #[inline] - fn into_components(self) -> Box<[T]> { + fn into_components(self) -> alloc::boxed::Box<[T]> { into_component_slice_box(self) } } -#[cfg(feature = "std")] -impl IntoComponents> for Vec +#[cfg(feature = "alloc")] +impl IntoComponents> for alloc::vec::Vec where C: ArrayCast, C::Array: ArrayExt, { #[inline] - fn into_components(self) -> Vec { + fn into_components(self) -> alloc::vec::Vec { into_component_vec(self) } } @@ -606,139 +606,187 @@ mod test { fn try_from_components() { let slice: &[u8] = &[1, 2, 3, 4, 5, 6]; let slice_mut: &mut [u8] = &mut [1, 2, 3, 4, 5, 6]; - let mut slice_box: Box<[u8]> = vec![1, 2, 3, 4, 5, 6].into_boxed_slice(); - let mut vec: Vec = vec![1, 2, 3, 4, 5, 6]; let mut array: [u8; 6] = [1, 2, 3, 4, 5, 6]; let _ = <&[Srgb]>::try_from_components(slice).unwrap(); - let _ = <&[Srgb]>::try_from_components(&slice_box).unwrap(); - let _ = <&[Srgb]>::try_from_components(&vec).unwrap(); let _ = <&[Srgb]>::try_from_components(&array).unwrap(); let _ = <&mut [Srgb]>::try_from_components(slice_mut).unwrap(); + let _ = <&mut [Srgb]>::try_from_components(&mut array).unwrap(); + + let _ = <[Srgb; 2]>::try_from_components(array).unwrap(); + } + + #[cfg(feature = "alloc")] + #[test] + fn try_from_components_alloc() { + let mut slice_box: Box<[u8]> = vec![1, 2, 3, 4, 5, 6].into_boxed_slice(); + let mut vec: Vec = vec![1, 2, 3, 4, 5, 6]; + + let _ = <&[Srgb]>::try_from_components(&slice_box).unwrap(); + let _ = <&[Srgb]>::try_from_components(&vec).unwrap(); + let _ = <&mut [Srgb]>::try_from_components(&mut slice_box).unwrap(); let _ = <&mut [Srgb]>::try_from_components(&mut vec).unwrap(); - let _ = <&mut [Srgb]>::try_from_components(&mut array).unwrap(); let _ = Box::<[Srgb]>::try_from_components(slice_box).unwrap(); let _ = Vec::>::try_from_components(vec).unwrap(); - let _ = <[Srgb; 2]>::try_from_components(array).unwrap(); } #[test] fn try_components_into() { let slice: &[u8] = &[1, 2, 3, 4, 5, 6]; let slice_mut: &mut [u8] = &mut [1, 2, 3, 4, 5, 6]; - let mut slice_box: Box<[u8]> = vec![1, 2, 3, 4, 5, 6].into_boxed_slice(); - let mut vec: Vec = vec![1, 2, 3, 4, 5, 6]; let mut array: [u8; 6] = [1, 2, 3, 4, 5, 6]; let _: &[Srgb] = slice.try_components_into().unwrap(); - let _: &[Srgb] = (&slice_box).try_components_into().unwrap(); - let _: &[Srgb] = (&vec).try_components_into().unwrap(); let _: &[Srgb] = (&array).try_components_into().unwrap(); let _: &mut [Srgb] = slice_mut.try_components_into().unwrap(); + let _: &mut [Srgb] = (&mut array).try_components_into().unwrap(); + + let _: [Srgb; 2] = array.try_components_into().unwrap(); + } + + #[cfg(feature = "alloc")] + #[test] + fn try_components_into_alloc() { + let mut slice_box: Box<[u8]> = vec![1, 2, 3, 4, 5, 6].into_boxed_slice(); + let mut vec: Vec = vec![1, 2, 3, 4, 5, 6]; + + let _: &[Srgb] = (&slice_box).try_components_into().unwrap(); + let _: &[Srgb] = (&vec).try_components_into().unwrap(); + let _: &mut [Srgb] = (&mut slice_box).try_components_into().unwrap(); let _: &mut [Srgb] = (&mut vec).try_components_into().unwrap(); - let _: &mut [Srgb] = (&mut array).try_components_into().unwrap(); let _: Box<[Srgb]> = slice_box.try_components_into().unwrap(); let _: Vec> = vec.try_components_into().unwrap(); - let _: [Srgb; 2] = array.try_components_into().unwrap(); } #[test] fn from_components() { let slice: &[u8] = &[1, 2, 3, 4, 5, 6]; let slice_mut: &mut [u8] = &mut [1, 2, 3, 4, 5, 6]; - let mut slice_box: Box<[u8]> = vec![1, 2, 3, 4, 5, 6].into_boxed_slice(); - let mut vec: Vec = vec![1, 2, 3, 4, 5, 6]; let mut array: [u8; 6] = [1, 2, 3, 4, 5, 6]; let _ = <&[Srgb]>::from_components(slice); - let _ = <&[Srgb]>::from_components(&slice_box); - let _ = <&[Srgb]>::from_components(&vec); let _ = <&[Srgb]>::from_components(&array); let _ = <&mut [Srgb]>::from_components(slice_mut); + let _ = <&mut [Srgb]>::from_components(&mut array); + + let _ = <[Srgb; 2]>::from_components(array); + } + + #[cfg(feature = "alloc")] + #[test] + fn from_components_alloc() { + let mut slice_box: Box<[u8]> = vec![1, 2, 3, 4, 5, 6].into_boxed_slice(); + let mut vec: Vec = vec![1, 2, 3, 4, 5, 6]; + + let _ = <&[Srgb]>::from_components(&slice_box); + let _ = <&[Srgb]>::from_components(&vec); + let _ = <&mut [Srgb]>::from_components(&mut slice_box); let _ = <&mut [Srgb]>::from_components(&mut vec); - let _ = <&mut [Srgb]>::from_components(&mut array); let _ = Box::<[Srgb]>::from_components(slice_box); let _ = Vec::>::from_components(vec); - let _ = <[Srgb; 2]>::from_components(array); } #[test] fn components_into() { let slice: &[u8] = &[1, 2, 3, 4, 5, 6]; let slice_mut: &mut [u8] = &mut [1, 2, 3, 4, 5, 6]; - let mut slice_box: Box<[u8]> = vec![1, 2, 3, 4, 5, 6].into_boxed_slice(); - let mut vec: Vec = vec![1, 2, 3, 4, 5, 6]; let mut array: [u8; 6] = [1, 2, 3, 4, 5, 6]; let _: &[Srgb] = slice.components_into(); - let _: &[Srgb] = (&slice_box).components_into(); - let _: &[Srgb] = (&vec).components_into(); let _: &[Srgb] = (&array).components_into(); let _: &mut [Srgb] = slice_mut.components_into(); + let _: &mut [Srgb] = (&mut array).components_into(); + + let _: [Srgb; 2] = array.components_into(); + } + + #[cfg(feature = "alloc")] + #[test] + fn components_into_alloc() { + let mut slice_box: Box<[u8]> = vec![1, 2, 3, 4, 5, 6].into_boxed_slice(); + let mut vec: Vec = vec![1, 2, 3, 4, 5, 6]; + + let _: &[Srgb] = (&slice_box).components_into(); + let _: &[Srgb] = (&vec).components_into(); + let _: &mut [Srgb] = (&mut slice_box).components_into(); let _: &mut [Srgb] = (&mut vec).components_into(); - let _: &mut [Srgb] = (&mut array).components_into(); let _: Box<[Srgb]> = slice_box.components_into(); let _: Vec> = vec.components_into(); - let _: [Srgb; 2] = array.components_into(); } #[test] fn into_components() { let slice: &[Srgb] = &[Srgb::new(1, 2, 3), Srgb::new(4, 5, 6)]; let slice_mut: &mut [Srgb] = &mut [Srgb::new(1, 2, 3), Srgb::new(4, 5, 6)]; + let mut array: [Srgb; 2] = [Srgb::new(1, 2, 3), Srgb::new(4, 5, 6)]; + + let _: &[u8] = slice.into_components(); + let _: &[u8] = (&array).into_components(); + + let _: &mut [u8] = slice_mut.into_components(); + let _: &mut [u8] = (&mut array).into_components(); + + let _: [u8; 6] = array.into_components(); + } + + #[cfg(feature = "alloc")] + #[test] + fn into_components_alloc() { let mut slice_box: Box<[Srgb]> = vec![Srgb::new(1, 2, 3), Srgb::new(4, 5, 6)].into_boxed_slice(); let mut vec: Vec> = vec![Srgb::new(1, 2, 3), Srgb::new(4, 5, 6)]; - let mut array: [Srgb; 2] = [Srgb::new(1, 2, 3), Srgb::new(4, 5, 6)]; - let _: &[u8] = slice.into_components(); let _: &[u8] = (&slice_box).into_components(); let _: &[u8] = (&vec).into_components(); - let _: &[u8] = (&array).into_components(); - let _: &mut [u8] = slice_mut.into_components(); let _: &mut [u8] = (&mut slice_box).into_components(); let _: &mut [u8] = (&mut vec).into_components(); - let _: &mut [u8] = (&mut array).into_components(); let _: Box<[u8]> = slice_box.into_components(); let _: Vec = vec.into_components(); - let _: [u8; 6] = array.into_components(); } #[test] fn components_from() { let slice: &[Srgb] = &[Srgb::new(1, 2, 3), Srgb::new(4, 5, 6)]; let slice_mut: &mut [Srgb] = &mut [Srgb::new(1, 2, 3), Srgb::new(4, 5, 6)]; + let mut array: [Srgb; 2] = [Srgb::new(1, 2, 3), Srgb::new(4, 5, 6)]; + + let _ = <&[u8]>::components_from(slice); + let _ = <&[u8]>::components_from(&array); + + let _ = <&mut [u8]>::components_from(slice_mut); + let _ = <&mut [u8]>::components_from(&mut array); + + let _ = <[u8; 6]>::components_from(array); + } + + #[cfg(feature = "alloc")] + #[test] + fn components_from_alloc() { let mut slice_box: Box<[Srgb]> = vec![Srgb::new(1, 2, 3), Srgb::new(4, 5, 6)].into_boxed_slice(); let mut vec: Vec> = vec![Srgb::new(1, 2, 3), Srgb::new(4, 5, 6)]; - let mut array: [Srgb; 2] = [Srgb::new(1, 2, 3), Srgb::new(4, 5, 6)]; - let _ = <&[u8]>::components_from(slice); let _ = <&[u8]>::components_from(&slice_box); let _ = <&[u8]>::components_from(&vec); - let _ = <&[u8]>::components_from(&array); - let _ = <&mut [u8]>::components_from(slice_mut); let _ = <&mut [u8]>::components_from(&mut slice_box); let _ = <&mut [u8]>::components_from(&mut vec); - let _ = <&mut [u8]>::components_from(&mut array); let _ = Box::<[u8]>::components_from(slice_box); let _ = Vec::::components_from(vec); - let _ = <[u8; 6]>::components_from(array); } } diff --git a/palette/src/cast/from_into_uints_traits.rs b/palette/src/cast/from_into_uints_traits.rs index c2556e06e..5316b3017 100644 --- a/palette/src/cast/from_into_uints_traits.rs +++ b/palette/src/cast/from_into_uints_traits.rs @@ -3,7 +3,7 @@ use super::{ into_uint_slice_mut, UintCast, }; -#[cfg(feature = "std")] +#[cfg(feature = "alloc")] use super::{from_uint_slice_box, from_uint_vec, into_uint_slice_box, into_uint_vec}; /// Trait for casting a collection of colors from a collection of unsigned @@ -122,27 +122,27 @@ macro_rules! impl_from_uints_slice { impl_from_uints_slice!([C::Uint], [C::Uint; N] where (const N: usize)); -#[cfg(feature = "std")] -impl_from_uints_slice!(Box<[C::Uint]>, Vec); +#[cfg(feature = "alloc")] +impl_from_uints_slice!(alloc::boxed::Box<[C::Uint]>, alloc::vec::Vec); -#[cfg(feature = "std")] -impl FromUints> for Box<[C]> +#[cfg(feature = "alloc")] +impl FromUints> for alloc::boxed::Box<[C]> where C: UintCast, { #[inline] - fn from_uints(uints: Box<[C::Uint]>) -> Self { + fn from_uints(uints: alloc::boxed::Box<[C::Uint]>) -> Self { from_uint_slice_box(uints) } } -#[cfg(feature = "std")] -impl FromUints> for Vec +#[cfg(feature = "alloc")] +impl FromUints> for alloc::vec::Vec where C: UintCast, { #[inline] - fn from_uints(uints: Vec) -> Self { + fn from_uints(uints: alloc::vec::Vec) -> Self { from_uint_vec(uints) } } @@ -241,27 +241,27 @@ macro_rules! impl_into_uints_slice { impl_into_uints_slice!([C], [C; M] where (const M: usize)); -#[cfg(feature = "std")] -impl_into_uints_slice!(Box<[C]>, Vec); +#[cfg(feature = "alloc")] +impl_into_uints_slice!(alloc::boxed::Box<[C]>, alloc::vec::Vec); -#[cfg(feature = "std")] -impl IntoUints> for Box<[C]> +#[cfg(feature = "alloc")] +impl IntoUints> for alloc::boxed::Box<[C]> where C: UintCast, { #[inline] - fn into_uints(self) -> Box<[C::Uint]> { + fn into_uints(self) -> alloc::boxed::Box<[C::Uint]> { into_uint_slice_box(self) } } -#[cfg(feature = "std")] -impl IntoUints> for Vec +#[cfg(feature = "alloc")] +impl IntoUints> for alloc::vec::Vec where C: UintCast, { #[inline] - fn into_uints(self) -> Vec { + fn into_uints(self) -> alloc::vec::Vec { into_uint_vec(self) } } @@ -418,46 +418,62 @@ mod test { fn from_uints() { let slice: &[u32] = &[0x01020304, 0x05060708]; let slice_mut: &mut [u32] = &mut [0x01020304, 0x05060708]; - let mut slice_box: Box<[u32]> = vec![0x01020304, 0x05060708].into_boxed_slice(); - let mut vec: Vec = vec![0x01020304, 0x05060708]; let mut array: [u32; 2] = [0x01020304, 0x05060708]; let _ = <&[PackedRgba]>::from_uints(slice); - let _ = <&[PackedRgba]>::from_uints(&slice_box); - let _ = <&[PackedRgba]>::from_uints(&vec); let _ = <&[PackedRgba]>::from_uints(&array); let _ = <&mut [PackedRgba]>::from_uints(slice_mut); + let _ = <&mut [PackedRgba]>::from_uints(&mut array); + + let _ = <[PackedRgba; 2]>::from_uints(array); + } + + #[cfg(feature = "alloc")] + #[test] + fn from_uints_alloc() { + let mut slice_box: Box<[u32]> = vec![0x01020304, 0x05060708].into_boxed_slice(); + let mut vec: Vec = vec![0x01020304, 0x05060708]; + + let _ = <&[PackedRgba]>::from_uints(&slice_box); + let _ = <&[PackedRgba]>::from_uints(&vec); + let _ = <&mut [PackedRgba]>::from_uints(&mut slice_box); let _ = <&mut [PackedRgba]>::from_uints(&mut vec); - let _ = <&mut [PackedRgba]>::from_uints(&mut array); let _ = Box::<[PackedRgba]>::from_uints(slice_box); let _ = Vec::::from_uints(vec); - let _ = <[PackedRgba; 2]>::from_uints(array); } #[test] fn uints_into() { let slice: &[u32] = &[0x01020304, 0x05060708]; let slice_mut: &mut [u32] = &mut [0x01020304, 0x05060708]; - let mut slice_box: Box<[u32]> = vec![0x01020304, 0x05060708].into_boxed_slice(); - let mut vec: Vec = vec![0x01020304, 0x05060708]; let mut array: [u32; 2] = [0x01020304, 0x05060708]; let _: &[PackedRgba] = slice.uints_into(); - let _: &[PackedRgba] = (&slice_box).uints_into(); - let _: &[PackedRgba] = (&vec).uints_into(); let _: &[PackedRgba] = (&array).uints_into(); let _: &mut [PackedRgba] = slice_mut.uints_into(); + let _: &mut [PackedRgba] = (&mut array).uints_into(); + + let _: [PackedRgba; 2] = array.uints_into(); + } + + #[cfg(feature = "alloc")] + #[test] + fn uints_into_alloc() { + let mut slice_box: Box<[u32]> = vec![0x01020304, 0x05060708].into_boxed_slice(); + let mut vec: Vec = vec![0x01020304, 0x05060708]; + + let _: &[PackedRgba] = (&slice_box).uints_into(); + let _: &[PackedRgba] = (&vec).uints_into(); + let _: &mut [PackedRgba] = (&mut slice_box).uints_into(); let _: &mut [PackedRgba] = (&mut vec).uints_into(); - let _: &mut [PackedRgba] = (&mut array).uints_into(); let _: Box<[PackedRgba]> = slice_box.uints_into(); let _: Vec = vec.uints_into(); - let _: [PackedRgba; 2] = array.uints_into(); } #[test] @@ -465,26 +481,34 @@ mod test { let slice: &[PackedRgba] = &[Srgba::new(1, 2, 3, 4).into(), Srgba::new(5, 6, 7, 8).into()]; let slice_mut: &mut [PackedRgba] = &mut [Srgba::new(1, 2, 3, 4).into(), Srgba::new(5, 6, 7, 8).into()]; + let mut array: [PackedRgba; 2] = + [Srgba::new(1, 2, 3, 4).into(), Srgba::new(5, 6, 7, 8).into()]; + + let _: &[u32] = slice.into_uints(); + let _: &[u32] = (&array).into_uints(); + + let _: &mut [u32] = slice_mut.into_uints(); + let _: &mut [u32] = (&mut array).into_uints(); + + let _: [u32; 2] = array.into_uints(); + } + + #[cfg(feature = "alloc")] + #[test] + fn into_uints_alloc() { let mut slice_box: Box<[PackedRgba]> = vec![Srgba::new(1, 2, 3, 4).into(), Srgba::new(5, 6, 7, 8).into()].into_boxed_slice(); let mut vec: Vec = vec![Srgba::new(1, 2, 3, 4).into(), Srgba::new(5, 6, 7, 8).into()]; - let mut array: [PackedRgba; 2] = - [Srgba::new(1, 2, 3, 4).into(), Srgba::new(5, 6, 7, 8).into()]; - let _: &[u32] = slice.into_uints(); let _: &[u32] = (&slice_box).into_uints(); let _: &[u32] = (&vec).into_uints(); - let _: &[u32] = (&array).into_uints(); - let _: &mut [u32] = slice_mut.into_uints(); let _: &mut [u32] = (&mut slice_box).into_uints(); let _: &mut [u32] = (&mut vec).into_uints(); - let _: &mut [u32] = (&mut array).into_uints(); let _: Box<[u32]> = slice_box.into_uints(); let _: Vec = vec.into_uints(); - let _: [u32; 2] = array.into_uints(); } #[test] @@ -492,25 +516,33 @@ mod test { let slice: &[PackedRgba] = &[Srgba::new(1, 2, 3, 4).into(), Srgba::new(5, 6, 7, 8).into()]; let slice_mut: &mut [PackedRgba] = &mut [Srgba::new(1, 2, 3, 4).into(), Srgba::new(5, 6, 7, 8).into()]; + let mut array: [PackedRgba; 2] = + [Srgba::new(1, 2, 3, 4).into(), Srgba::new(5, 6, 7, 8).into()]; + + let _ = <&[u32]>::uints_from(slice); + let _ = <&[u32]>::uints_from(&array); + + let _ = <&mut [u32]>::uints_from(slice_mut); + let _ = <&mut [u32]>::uints_from(&mut array); + + let _ = <[u32; 2]>::uints_from(array); + } + + #[cfg(feature = "alloc")] + #[test] + fn uints_from_alloc() { let mut slice_box: Box<[PackedRgba]> = vec![Srgba::new(1, 2, 3, 4).into(), Srgba::new(5, 6, 7, 8).into()].into_boxed_slice(); let mut vec: Vec = vec![Srgba::new(1, 2, 3, 4).into(), Srgba::new(5, 6, 7, 8).into()]; - let mut array: [PackedRgba; 2] = - [Srgba::new(1, 2, 3, 4).into(), Srgba::new(5, 6, 7, 8).into()]; - let _ = <&[u32]>::uints_from(slice); let _ = <&[u32]>::uints_from(&slice_box); let _ = <&[u32]>::uints_from(&vec); - let _ = <&[u32]>::uints_from(&array); - let _ = <&mut [u32]>::uints_from(slice_mut); let _ = <&mut [u32]>::uints_from(&mut slice_box); let _ = <&mut [u32]>::uints_from(&mut vec); - let _ = <&mut [u32]>::uints_from(&mut array); let _ = Box::<[u32]>::uints_from(slice_box); let _ = Vec::::uints_from(vec); - let _ = <[u32; 2]>::uints_from(array); } } diff --git a/palette/src/cast/uint.rs b/palette/src/cast/uint.rs index 1b0525d1c..fc2ff022f 100644 --- a/palette/src/cast/uint.rs +++ b/palette/src/cast/uint.rs @@ -358,20 +358,20 @@ where /// vec![0xFF17C64C, 0xFF5D12D6].into_boxed_slice() /// ) /// ``` -#[cfg(feature = "std")] +#[cfg(feature = "alloc")] #[inline] -pub fn into_uint_slice_box(values: Box<[T]>) -> Box<[T::Uint]> +pub fn into_uint_slice_box(values: alloc::boxed::Box<[T]>) -> alloc::boxed::Box<[T::Uint]> where T: UintCast, { assert_eq!(core::mem::size_of::(), core::mem::size_of::()); assert_eq!(core::mem::align_of::(), core::mem::align_of::()); - let raw: *mut [T::Uint] = into_uint_slice_mut(Box::leak(values)); + let raw: *mut [T::Uint] = into_uint_slice_mut(alloc::boxed::Box::leak(values)); // Safety: The requirements of implementing `UintCast`, as well as the size // and alignment asserts, ensures that reading `T` as `T::Uint` is safe. - unsafe { Box::from_raw(raw) } + unsafe { alloc::boxed::Box::from_raw(raw) } } /// Cast from a boxed slice of unsigned integers to a boxed slice of colors. @@ -389,20 +389,20 @@ where /// colors /// ) /// ``` -#[cfg(feature = "std")] +#[cfg(feature = "alloc")] #[inline] -pub fn from_uint_slice_box(values: Box<[T::Uint]>) -> Box<[T]> +pub fn from_uint_slice_box(values: alloc::boxed::Box<[T::Uint]>) -> alloc::boxed::Box<[T]> where T: UintCast, { assert_eq!(core::mem::size_of::(), core::mem::size_of::()); assert_eq!(core::mem::align_of::(), core::mem::align_of::()); - let raw: *mut [T] = from_uint_slice_mut(Box::leak(values)); + let raw: *mut [T] = from_uint_slice_mut(alloc::boxed::Box::leak(values)); // Safety: The requirements of implementing `UintCast`, as well as the size // and alignment asserts, ensures that reading `T::Uint` as `T` is safe. - unsafe { Box::from_raw(raw) } + unsafe { alloc::boxed::Box::from_raw(raw) } } /// Cast from a `Vec` of colors to a `Vec` of unsigned integers. @@ -420,9 +420,9 @@ where /// vec![0xFF17C64C, 0xFF5D12D6] /// ) /// ``` -#[cfg(feature = "std")] +#[cfg(feature = "alloc")] #[inline] -pub fn into_uint_vec(values: Vec) -> Vec +pub fn into_uint_vec(values: alloc::vec::Vec) -> alloc::vec::Vec where T: UintCast, { @@ -435,7 +435,9 @@ where // Safety: The requirements of implementing `UintCast`, as well as the size // and alignment asserts, ensures that reading `T` as `T::Uint` is safe. // Length and capacity are the same because the size is the same. - unsafe { Vec::from_raw_parts(raw.cast::(), values.len(), values.capacity()) } + unsafe { + alloc::vec::Vec::from_raw_parts(raw.cast::(), values.len(), values.capacity()) + } } /// Cast from a `Vec` of unsigned integers to a `Vec` of colors. @@ -453,9 +455,9 @@ where /// colors /// ) /// ``` -#[cfg(feature = "std")] +#[cfg(feature = "alloc")] #[inline] -pub fn from_uint_vec(values: Vec) -> Vec +pub fn from_uint_vec(values: alloc::vec::Vec) -> alloc::vec::Vec where T: UintCast, { @@ -468,5 +470,5 @@ where // Safety: The requirements of implementing `UintCast`, as well as the size // and alignment asserts, ensures that reading `T::Uint` as `T` is safe. // Length and capacity are the same because the size is the same. - unsafe { Vec::from_raw_parts(raw.cast::(), values.len(), values.capacity()) } + unsafe { alloc::vec::Vec::from_raw_parts(raw.cast::(), values.len(), values.capacity()) } } diff --git a/palette/src/chromatic_adaptation.rs b/palette/src/chromatic_adaptation.rs index bae19db09..24e56bf3f 100644 --- a/palette/src/chromatic_adaptation.rs +++ b/palette/src/chromatic_adaptation.rs @@ -215,6 +215,7 @@ where } } +#[cfg(feature = "approx")] #[cfg(test)] mod test { use super::{AdaptFrom, AdaptInto, Method, TransformMatrix}; diff --git a/palette/src/color_difference.rs b/palette/src/color_difference.rs index ec879dc63..a200bf70b 100644 --- a/palette/src/color_difference.rs +++ b/palette/src/color_difference.rs @@ -496,6 +496,7 @@ pub trait ImprovedDeltaE: DeltaE { fn improved_delta_e(self, other: Self) -> Self::Scalar; } +#[cfg(feature = "approx")] #[cfg(test)] mod test { use core::str::FromStr; diff --git a/palette/src/convert/from_into_color.rs b/palette/src/convert/from_into_color.rs index 35d2dae7d..a0655cb0b 100644 --- a/palette/src/convert/from_into_color.rs +++ b/palette/src/convert/from_into_color.rs @@ -1,6 +1,6 @@ use crate::Clamp; -#[cfg(feature = "std")] +#[cfg(feature = "alloc")] use crate::cast::{self, ArrayCast}; use super::FromColorUnclamped; @@ -60,8 +60,8 @@ where } } -#[cfg(feature = "std")] -impl FromColor> for Vec +#[cfg(feature = "alloc")] +impl FromColor> for alloc::vec::Vec where T: ArrayCast, U: ArrayCast + FromColor, @@ -79,13 +79,13 @@ where /// let srgb = Vec::::from_color(lch); /// ``` #[inline] - fn from_color(color: Vec) -> Self { + fn from_color(color: alloc::vec::Vec) -> Self { cast::map_vec_in_place(color, U::from_color) } } -#[cfg(feature = "std")] -impl FromColor> for Box<[U]> +#[cfg(feature = "alloc")] +impl FromColor> for alloc::boxed::Box<[U]> where T: ArrayCast, U: ArrayCast + FromColor, @@ -103,7 +103,7 @@ where /// let srgb = Box::<[Srgb]>::from_color(lch); /// ``` #[inline] - fn from_color(color: Box<[T]>) -> Self { + fn from_color(color: alloc::boxed::Box<[T]>) -> Self { cast::map_slice_box_in_place(color, U::from_color) } } diff --git a/palette/src/convert/from_into_color_unclamped.rs b/palette/src/convert/from_into_color_unclamped.rs index c54f9daf7..7a3c4009d 100644 --- a/palette/src/convert/from_into_color_unclamped.rs +++ b/palette/src/convert/from_into_color_unclamped.rs @@ -1,6 +1,6 @@ pub use palette_derive::FromColorUnclamped; -#[cfg(feature = "std")] +#[cfg(feature = "alloc")] use crate::cast::{self, ArrayCast}; /// A trait for unchecked conversion of one color from another. @@ -25,8 +25,8 @@ pub trait FromColorUnclamped: Sized { fn from_color_unclamped(val: T) -> Self; } -#[cfg(feature = "std")] -impl FromColorUnclamped> for Vec +#[cfg(feature = "alloc")] +impl FromColorUnclamped> for alloc::vec::Vec where T: ArrayCast, U: ArrayCast + FromColorUnclamped, @@ -44,13 +44,13 @@ where /// let srgb = Vec::::from_color_unclamped(lch); /// ``` #[inline] - fn from_color_unclamped(color: Vec) -> Self { + fn from_color_unclamped(color: alloc::vec::Vec) -> Self { cast::map_vec_in_place(color, U::from_color_unclamped) } } -#[cfg(feature = "std")] -impl FromColorUnclamped> for Box<[U]> +#[cfg(feature = "alloc")] +impl FromColorUnclamped> for alloc::boxed::Box<[U]> where T: ArrayCast, U: ArrayCast + FromColorUnclamped, @@ -68,7 +68,7 @@ where /// let srgb = Box::<[Srgb]>::from_color_unclamped(lch); /// ``` #[inline] - fn from_color_unclamped(color: Box<[T]>) -> Self { + fn from_color_unclamped(color: alloc::boxed::Box<[T]>) -> Self { cast::map_slice_box_in_place(color, U::from_color_unclamped) } } diff --git a/palette/src/encoding/srgb.rs b/palette/src/encoding/srgb.rs index bb90a9e19..3adee8483 100644 --- a/palette/src/encoding/srgb.rs +++ b/palette/src/encoding/srgb.rs @@ -152,24 +152,29 @@ impl FromLinear for Srgb { #[cfg(test)] mod test { - use crate::{ - encoding::{FromLinear, IntoLinear, Srgb}, - matrix::{matrix_inverse, rgb_to_xyz_matrix}, - rgb::RgbSpace, - }; - - #[test] - fn rgb_to_xyz() { - let dynamic = rgb_to_xyz_matrix::(); - let constant = Srgb::rgb_to_xyz_matrix().unwrap(); - assert_relative_eq!(dynamic[..], constant[..], epsilon = 0.0000001); - } + use crate::encoding::{FromLinear, IntoLinear, Srgb}; + + #[cfg(feature = "approx")] + mod conversion { + use crate::{ + encoding::Srgb, + matrix::{matrix_inverse, rgb_to_xyz_matrix}, + rgb::RgbSpace, + }; + + #[test] + fn rgb_to_xyz() { + let dynamic = rgb_to_xyz_matrix::(); + let constant = Srgb::rgb_to_xyz_matrix().unwrap(); + assert_relative_eq!(dynamic[..], constant[..], epsilon = 0.0000001); + } - #[test] - fn xyz_to_rgb() { - let dynamic = matrix_inverse(rgb_to_xyz_matrix::()); - let constant = Srgb::xyz_to_rgb_matrix().unwrap(); - assert_relative_eq!(dynamic[..], constant[..], epsilon = 0.0000001); + #[test] + fn xyz_to_rgb() { + let dynamic = matrix_inverse(rgb_to_xyz_matrix::()); + let constant = Srgb::xyz_to_rgb_matrix().unwrap(); + assert_relative_eq!(dynamic[..], constant[..], epsilon = 0.0000001); + } } #[test] diff --git a/palette/src/hsl.rs b/palette/src/hsl.rs index b6bd839c2..f478a88ba 100644 --- a/palette/src/hsl.rs +++ b/palette/src/hsl.rs @@ -532,58 +532,65 @@ unsafe impl bytemuck::Pod for Hsl where T: bytemuck::Pod {} #[cfg(test)] mod test { use super::Hsl; - use crate::{FromColor, Hsv, Srgb}; + + #[cfg(feature = "alloc")] + use crate::Srgb; test_convert_into_from_xyz!(Hsl); - #[test] - fn red() { - let a = Hsl::from_color(Srgb::new(1.0, 0.0, 0.0)); - let b = Hsl::new_srgb(0.0, 1.0, 0.5); - let c = Hsl::from_color(Hsv::new_srgb(0.0, 1.0, 1.0)); + #[cfg(feature = "approx")] + mod conversion { + use crate::{FromColor, Hsl, Hsv, Srgb}; - assert_relative_eq!(a, b); - assert_relative_eq!(a, c); - } + #[test] + fn red() { + let a = Hsl::from_color(Srgb::new(1.0, 0.0, 0.0)); + let b = Hsl::new_srgb(0.0, 1.0, 0.5); + let c = Hsl::from_color(Hsv::new_srgb(0.0, 1.0, 1.0)); - #[test] - fn orange() { - let a = Hsl::from_color(Srgb::new(1.0, 0.5, 0.0)); - let b = Hsl::new_srgb(30.0, 1.0, 0.5); - let c = Hsl::from_color(Hsv::new_srgb(30.0, 1.0, 1.0)); + assert_relative_eq!(a, b); + assert_relative_eq!(a, c); + } - assert_relative_eq!(a, b); - assert_relative_eq!(a, c); - } + #[test] + fn orange() { + let a = Hsl::from_color(Srgb::new(1.0, 0.5, 0.0)); + let b = Hsl::new_srgb(30.0, 1.0, 0.5); + let c = Hsl::from_color(Hsv::new_srgb(30.0, 1.0, 1.0)); - #[test] - fn green() { - let a = Hsl::from_color(Srgb::new(0.0, 1.0, 0.0)); - let b = Hsl::new_srgb(120.0, 1.0, 0.5); - let c = Hsl::from_color(Hsv::new_srgb(120.0, 1.0, 1.0)); + assert_relative_eq!(a, b); + assert_relative_eq!(a, c); + } - assert_relative_eq!(a, b); - assert_relative_eq!(a, c); - } + #[test] + fn green() { + let a = Hsl::from_color(Srgb::new(0.0, 1.0, 0.0)); + let b = Hsl::new_srgb(120.0, 1.0, 0.5); + let c = Hsl::from_color(Hsv::new_srgb(120.0, 1.0, 1.0)); - #[test] - fn blue() { - let a = Hsl::from_color(Srgb::new(0.0, 0.0, 1.0)); - let b = Hsl::new_srgb(240.0, 1.0, 0.5); - let c = Hsl::from_color(Hsv::new_srgb(240.0, 1.0, 1.0)); + assert_relative_eq!(a, b); + assert_relative_eq!(a, c); + } - assert_relative_eq!(a, b); - assert_relative_eq!(a, c); - } + #[test] + fn blue() { + let a = Hsl::from_color(Srgb::new(0.0, 0.0, 1.0)); + let b = Hsl::new_srgb(240.0, 1.0, 0.5); + let c = Hsl::from_color(Hsv::new_srgb(240.0, 1.0, 1.0)); - #[test] - fn purple() { - let a = Hsl::from_color(Srgb::new(0.5, 0.0, 1.0)); - let b = Hsl::new_srgb(270.0, 1.0, 0.5); - let c = Hsl::from_color(Hsv::new_srgb(270.0, 1.0, 1.0)); + assert_relative_eq!(a, b); + assert_relative_eq!(a, c); + } - assert_relative_eq!(a, b); - assert_relative_eq!(a, c); + #[test] + fn purple() { + let a = Hsl::from_color(Srgb::new(0.5, 0.0, 1.0)); + let b = Hsl::new_srgb(270.0, 1.0, 0.5); + let c = Hsl::from_color(Hsv::new_srgb(270.0, 1.0, 1.0)); + + assert_relative_eq!(a, b); + assert_relative_eq!(a, c); + } } #[test] @@ -608,10 +615,10 @@ mod test { fn check_min_max_components() { use crate::encoding::Srgb; - assert_relative_eq!(Hsl::::min_saturation(), 0.0); - assert_relative_eq!(Hsl::::min_lightness(), 0.0); - assert_relative_eq!(Hsl::::max_saturation(), 1.0); - assert_relative_eq!(Hsl::::max_lightness(), 1.0); + assert_eq!(Hsl::::min_saturation(), 0.0); + assert_eq!(Hsl::::min_lightness(), 0.0); + assert_eq!(Hsl::::max_saturation(), 1.0); + assert_eq!(Hsl::::max_lightness(), 1.0); } struct_of_arrays_tests!( @@ -622,6 +629,7 @@ mod test { ); mod alpha { + #[cfg(feature = "alloc")] use crate::{encoding::Srgb, hsl::Hsla}; struct_of_arrays_tests!( diff --git a/palette/src/hsluv.rs b/palette/src/hsluv.rs index aac306bb1..13b90e8da 100644 --- a/palette/src/hsluv.rs +++ b/palette/src/hsluv.rs @@ -257,13 +257,16 @@ unsafe impl bytemuck::Pod for Hsluv where T: bytemuck::Po #[cfg(test)] mod test { use super::Hsluv; - use crate::{white_point::D65, FromColor, Lchuv, LuvHue, Saturate}; + use crate::white_point::D65; test_convert_into_from_xyz!(Hsluv); + #[cfg(feature = "approx")] #[cfg_attr(miri, ignore)] #[test] fn lchuv_round_trip() { + use crate::{FromColor, Lchuv, LuvHue}; + for hue in (0..=20).map(|x| x as f64 * 18.0) { for sat in (0..=20).map(|x| x as f64 * 5.0) { for l in (1..=20).map(|x| x as f64 * 5.0) { @@ -311,8 +314,11 @@ mod test { _hsl3 -= 0.1; } + #[cfg(feature = "approx")] #[test] fn saturate() { + use crate::Saturate; + for sat in (0..=10).map(|s| s as f64 * 10.0) { for a in (0..=10).map(|l| l as f64 * 10.0) { let hsl = Hsluv::::new(150.0, sat, a); @@ -332,10 +338,10 @@ mod test { #[test] fn check_min_max_components() { - assert_relative_eq!(Hsluv::::min_saturation(), 0.0); - assert_relative_eq!(Hsluv::::min_l(), 0.0); - assert_relative_eq!(Hsluv::::max_saturation(), 100.0); - assert_relative_eq!(Hsluv::::max_l(), 100.0); + assert_eq!(Hsluv::::min_saturation(), 0.0); + assert_eq!(Hsluv::::min_l(), 0.0); + assert_eq!(Hsluv::::max_saturation(), 100.0); + assert_eq!(Hsluv::::max_l(), 100.0); } struct_of_arrays_tests!( @@ -346,6 +352,7 @@ mod test { ); mod alpha { + #[cfg(feature = "alloc")] use crate::{hsluv::Hsluva, white_point::D65}; struct_of_arrays_tests!( diff --git a/palette/src/hsv.rs b/palette/src/hsv.rs index bde8f7f10..1a5bb01f4 100644 --- a/palette/src/hsv.rs +++ b/palette/src/hsv.rs @@ -539,58 +539,65 @@ unsafe impl bytemuck::Pod for Hsv where T: bytemuck::Pod {} #[cfg(test)] mod test { use super::Hsv; - use crate::{FromColor, Hsl, Srgb}; + + #[cfg(feature = "alloc")] + use crate::Srgb; test_convert_into_from_xyz!(Hsv); - #[test] - fn red() { - let a = Hsv::from_color(Srgb::new(1.0, 0.0, 0.0)); - let b = Hsv::new_srgb(0.0, 1.0, 1.0); - let c = Hsv::from_color(Hsl::new_srgb(0.0, 1.0, 0.5)); + #[cfg(feature = "approx")] + mod conversion { + use crate::{FromColor, Hsl, Hsv, Srgb}; - assert_relative_eq!(a, b); - assert_relative_eq!(a, c); - } + #[test] + fn red() { + let a = Hsv::from_color(Srgb::new(1.0, 0.0, 0.0)); + let b = Hsv::new_srgb(0.0, 1.0, 1.0); + let c = Hsv::from_color(Hsl::new_srgb(0.0, 1.0, 0.5)); - #[test] - fn orange() { - let a = Hsv::from_color(Srgb::new(1.0, 0.5, 0.0)); - let b = Hsv::new_srgb(30.0, 1.0, 1.0); - let c = Hsv::from_color(Hsl::new_srgb(30.0, 1.0, 0.5)); + assert_relative_eq!(a, b); + assert_relative_eq!(a, c); + } - assert_relative_eq!(a, b); - assert_relative_eq!(a, c); - } + #[test] + fn orange() { + let a = Hsv::from_color(Srgb::new(1.0, 0.5, 0.0)); + let b = Hsv::new_srgb(30.0, 1.0, 1.0); + let c = Hsv::from_color(Hsl::new_srgb(30.0, 1.0, 0.5)); - #[test] - fn green() { - let a = Hsv::from_color(Srgb::new(0.0, 1.0, 0.0)); - let b = Hsv::new_srgb(120.0, 1.0, 1.0); - let c = Hsv::from_color(Hsl::new_srgb(120.0, 1.0, 0.5)); + assert_relative_eq!(a, b); + assert_relative_eq!(a, c); + } - assert_relative_eq!(a, b); - assert_relative_eq!(a, c); - } + #[test] + fn green() { + let a = Hsv::from_color(Srgb::new(0.0, 1.0, 0.0)); + let b = Hsv::new_srgb(120.0, 1.0, 1.0); + let c = Hsv::from_color(Hsl::new_srgb(120.0, 1.0, 0.5)); - #[test] - fn blue() { - let a = Hsv::from_color(Srgb::new(0.0, 0.0, 1.0)); - let b = Hsv::new_srgb(240.0, 1.0, 1.0); - let c = Hsv::from_color(Hsl::new_srgb(240.0, 1.0, 0.5)); + assert_relative_eq!(a, b); + assert_relative_eq!(a, c); + } - assert_relative_eq!(a, b); - assert_relative_eq!(a, c); - } + #[test] + fn blue() { + let a = Hsv::from_color(Srgb::new(0.0, 0.0, 1.0)); + let b = Hsv::new_srgb(240.0, 1.0, 1.0); + let c = Hsv::from_color(Hsl::new_srgb(240.0, 1.0, 0.5)); - #[test] - fn purple() { - let a = Hsv::from_color(Srgb::new(0.5, 0.0, 1.0)); - let b = Hsv::new_srgb(270.0, 1.0, 1.0); - let c = Hsv::from_color(Hsl::new_srgb(270.0, 1.0, 0.5)); + assert_relative_eq!(a, b); + assert_relative_eq!(a, c); + } - assert_relative_eq!(a, b); - assert_relative_eq!(a, c); + #[test] + fn purple() { + let a = Hsv::from_color(Srgb::new(0.5, 0.0, 1.0)); + let b = Hsv::new_srgb(270.0, 1.0, 1.0); + let c = Hsv::from_color(Hsl::new_srgb(270.0, 1.0, 0.5)); + + assert_relative_eq!(a, b); + assert_relative_eq!(a, c); + } } #[test] @@ -615,10 +622,10 @@ mod test { fn check_min_max_components() { use crate::encoding::Srgb; - assert_relative_eq!(Hsv::::min_saturation(), 0.0,); - assert_relative_eq!(Hsv::::min_value(), 0.0,); - assert_relative_eq!(Hsv::::max_saturation(), 1.0,); - assert_relative_eq!(Hsv::::max_value(), 1.0,); + assert_eq!(Hsv::::min_saturation(), 0.0,); + assert_eq!(Hsv::::min_value(), 0.0,); + assert_eq!(Hsv::::max_saturation(), 1.0,); + assert_eq!(Hsv::::max_value(), 1.0,); } struct_of_arrays_tests!( @@ -629,6 +636,7 @@ mod test { ); mod alpha { + #[cfg(feature = "alloc")] use crate::{encoding::Srgb, hsv::Hsva}; struct_of_arrays_tests!( diff --git a/palette/src/hues.rs b/palette/src/hues.rs index e25fc75d6..2fdfbcaef 100644 --- a/palette/src/hues.rs +++ b/palette/src/hues.rs @@ -249,11 +249,11 @@ macro_rules! make_hues { } } - #[cfg(feature = "std")] - impl $name> { + #[cfg(feature = "alloc")] + impl $name> { /// Create a struct with a vector with a minimum capacity. See [`Vec::with_capacity`] for details. pub fn with_capacity(capacity: usize) -> Self { - Self(Vec::with_capacity(capacity)) + Self(alloc::vec::Vec::with_capacity(capacity)) } /// Push an additional hue onto the hue vector. See [`Vec::push`] for details. @@ -272,7 +272,7 @@ macro_rules! make_hues { } /// Return an iterator that moves hues out of the specified range. - pub fn drain(&mut self, range: R) -> $iter_name> + pub fn drain(&mut self, range: R) -> $iter_name> where R: core::ops::RangeBounds + Clone, { @@ -795,130 +795,136 @@ impl_uniform!(UniformOklabHue, OklabHue); #[cfg(test)] mod test { - use crate::{ - angle::{SignedAngle, UnsignedAngle}, - OklabHue, RgbHue, - }; - - #[test] - fn oklabhue_ab_roundtrip() { - for degree in [0.0_f64, 90.0, 30.0, 330.0, 120.0, 240.0] { - let hue = OklabHue::from_degrees(degree); - let (a, b) = hue.into_cartesian(); - let roundtrip_hue = OklabHue::from_cartesian(a * 10000.0, b * 10000.0); - assert_abs_diff_eq!(roundtrip_hue, hue); - } - } - - #[test] - fn normalize_angle_0_360() { - let inp = [ - -1000.0_f32, - -900.0, - -360.5, - -360.0, - -359.5, - -240.0, - -180.5, - -180.0, - -179.5, - -90.0, - -0.5, - 0.0, - 0.5, - 90.0, - 179.5, - 180.0, - 180.5, - 240.0, - 359.5, - 360.0, - 360.5, - 900.0, - 1000.0, - ]; - - let expected = [ - 80.0_f32, 180.0, 359.5, 0.0, 0.5, 120.0, 179.5, 180.0, 180.5, 270.0, 359.5, 0.0, 0.5, - 90.0, 179.5, 180.0, 180.5, 240.0, 359.5, 0.0, 0.5, 180.0, 280.0, - ]; - - let result: Vec = inp - .iter() - .map(|x| (*x).normalize_unsigned_angle()) - .collect(); - for (res, exp) in result.iter().zip(expected.iter()) { - assert_relative_eq!(res, exp); - } - } - - #[test] - fn normalize_angle_180_180() { - let inp = [ - -1000.0_f32, - -900.0, - -360.5, - -360.0, - -359.5, - -240.0, - -180.5, - -180.0, - -179.5, - -90.0, - -0.5, - 0.0, - 0.5, - 90.0, - 179.5, - 180.0, - 180.5, - 240.0, - 359.5, - 360.0, - 360.5, - 900.0, - 1000.0, - ]; - - let expected = [ - 80.0, 180.0, -0.5, 0.0, 0.5, 120.0, 179.5, 180.0, -179.5, -90.0, -0.5, 0.0, 0.5, 90.0, - 179.5, 180.0, -179.5, -120.0, -0.5, 0.0, 0.5, 180.0, -80.0, - ]; - - let result: Vec = inp.iter().map(|x| (*x).normalize_signed_angle()).collect(); - for (res, exp) in result.iter().zip(expected.iter()) { - assert_relative_eq!(res, exp); + #[cfg(feature = "approx")] + mod math { + use crate::{ + angle::{SignedAngle, UnsignedAngle}, + OklabHue, RgbHue, + }; + + #[test] + fn oklabhue_ab_roundtrip() { + for degree in [0.0_f64, 90.0, 30.0, 330.0, 120.0, 240.0] { + let hue = OklabHue::from_degrees(degree); + let (a, b) = hue.into_cartesian(); + let roundtrip_hue = OklabHue::from_cartesian(a * 10000.0, b * 10000.0); + assert_abs_diff_eq!(roundtrip_hue, hue); + } + } + + #[test] + fn normalize_angle_0_360() { + let inp = [ + -1000.0_f32, + -900.0, + -360.5, + -360.0, + -359.5, + -240.0, + -180.5, + -180.0, + -179.5, + -90.0, + -0.5, + 0.0, + 0.5, + 90.0, + 179.5, + 180.0, + 180.5, + 240.0, + 359.5, + 360.0, + 360.5, + 900.0, + 1000.0, + ]; + + let expected = [ + 80.0_f32, 180.0, 359.5, 0.0, 0.5, 120.0, 179.5, 180.0, 180.5, 270.0, 359.5, 0.0, + 0.5, 90.0, 179.5, 180.0, 180.5, 240.0, 359.5, 0.0, 0.5, 180.0, 280.0, + ]; + + let result: Vec = inp + .iter() + .map(|x| (*x).normalize_unsigned_angle()) + .collect(); + for (res, exp) in result.iter().zip(expected.iter()) { + assert_relative_eq!(res, exp); + } + } + + #[test] + fn normalize_angle_180_180() { + let inp = [ + -1000.0_f32, + -900.0, + -360.5, + -360.0, + -359.5, + -240.0, + -180.5, + -180.0, + -179.5, + -90.0, + -0.5, + 0.0, + 0.5, + 90.0, + 179.5, + 180.0, + 180.5, + 240.0, + 359.5, + 360.0, + 360.5, + 900.0, + 1000.0, + ]; + + let expected = [ + 80.0, 180.0, -0.5, 0.0, 0.5, 120.0, 179.5, 180.0, -179.5, -90.0, -0.5, 0.0, 0.5, + 90.0, 179.5, 180.0, -179.5, -120.0, -0.5, 0.0, 0.5, 180.0, -80.0, + ]; + + let result: Vec = inp.iter().map(|x| (*x).normalize_signed_angle()).collect(); + for (res, exp) in result.iter().zip(expected.iter()) { + assert_relative_eq!(res, exp); + } + } + + #[test] + fn float_conversion() { + for i in -180..180 { + let hue = RgbHue::from(4.0 * i as f32); + + let degs = hue.into_degrees(); + assert!(degs > -180.0 && degs <= 180.0); + + let pos_degs = hue.into_positive_degrees(); + assert!((0.0..360.0).contains(&pos_degs)); + + assert_relative_eq!(RgbHue::from(degs), RgbHue::from(pos_degs)); + } } } - #[test] - fn float_conversion() { - for i in -180..180 { - let hue = RgbHue::from(4.0 * i as f32); - - let degs = hue.into_degrees(); - assert!(degs > -180.0 && degs <= 180.0); + #[cfg(feature = "serializing")] + mod serde { + use crate::RgbHue; - let pos_degs = hue.into_positive_degrees(); - assert!((0.0..360.0).contains(&pos_degs)); + #[test] + fn serialize() { + let serialized = ::serde_json::to_string(&RgbHue::from_degrees(10.2)).unwrap(); - assert_relative_eq!(RgbHue::from(degs), RgbHue::from(pos_degs)); + assert_eq!(serialized, "10.2"); } - } - #[cfg(feature = "serializing")] - #[test] - fn serialize() { - let serialized = ::serde_json::to_string(&RgbHue::from_degrees(10.2)).unwrap(); + #[test] + fn deserialize() { + let deserialized: RgbHue = ::serde_json::from_str("10.2").unwrap(); - assert_eq!(serialized, "10.2"); - } - - #[cfg(feature = "serializing")] - #[test] - fn deserialize() { - let deserialized: RgbHue = ::serde_json::from_str("10.2").unwrap(); - - assert_eq!(deserialized, RgbHue::from_degrees(10.2)); + assert_eq!(deserialized, RgbHue::from_degrees(10.2)); + } } } diff --git a/palette/src/hwb.rs b/palette/src/hwb.rs index f3ff0086f..1e7d8df14 100644 --- a/palette/src/hwb.rs +++ b/palette/src/hwb.rs @@ -365,69 +365,81 @@ unsafe impl bytemuck::Pod for Hwb where T: bytemuck::Pod {} #[cfg(test)] mod test { use super::Hwb; - use crate::{Clamp, FromColor, Srgb}; + + #[cfg(feature = "alloc")] + use crate::Srgb; test_convert_into_from_xyz!(Hwb); - #[test] - fn red() { - let a = Hwb::from_color(Srgb::new(1.0, 0.0, 0.0)); - let b = Hwb::new_srgb(0.0, 0.0, 0.0); - assert_relative_eq!(a, b); - } + #[cfg(feature = "approx")] + mod conversion { + use crate::{FromColor, Hwb, Srgb}; - #[test] - fn orange() { - let a = Hwb::from_color(Srgb::new(1.0, 0.5, 0.0)); - let b = Hwb::new_srgb(30.0, 0.0, 0.0); - assert_relative_eq!(a, b); - } + #[test] + fn red() { + let a = Hwb::from_color(Srgb::new(1.0, 0.0, 0.0)); + let b = Hwb::new_srgb(0.0, 0.0, 0.0); + assert_relative_eq!(a, b); + } - #[test] - fn green() { - let a = Hwb::from_color(Srgb::new(0.0, 1.0, 0.0)); - let b = Hwb::new_srgb(120.0, 0.0, 0.0); - assert_relative_eq!(a, b); - } + #[test] + fn orange() { + let a = Hwb::from_color(Srgb::new(1.0, 0.5, 0.0)); + let b = Hwb::new_srgb(30.0, 0.0, 0.0); + assert_relative_eq!(a, b); + } - #[test] - fn blue() { - let a = Hwb::from_color(Srgb::new(0.0, 0.0, 1.0)); - let b = Hwb::new_srgb(240.0, 0.0, 0.0); - assert_relative_eq!(a, b); - } + #[test] + fn green() { + let a = Hwb::from_color(Srgb::new(0.0, 1.0, 0.0)); + let b = Hwb::new_srgb(120.0, 0.0, 0.0); + assert_relative_eq!(a, b); + } - #[test] - fn purple() { - let a = Hwb::from_color(Srgb::new(0.5, 0.0, 1.0)); - let b = Hwb::new_srgb(270.0, 0.0, 0.0); - assert_relative_eq!(a, b); - } + #[test] + fn blue() { + let a = Hwb::from_color(Srgb::new(0.0, 0.0, 1.0)); + let b = Hwb::new_srgb(240.0, 0.0, 0.0); + assert_relative_eq!(a, b); + } - #[test] - fn clamp_invalid() { - let expected = Hwb::new_srgb(240.0, 0.0, 0.0); - let clamped = Hwb::new_srgb(240.0, -3.0, -4.0).clamp(); - assert_relative_eq!(expected, clamped); + #[test] + fn purple() { + let a = Hwb::from_color(Srgb::new(0.5, 0.0, 1.0)); + let b = Hwb::new_srgb(270.0, 0.0, 0.0); + assert_relative_eq!(a, b); + } } - #[test] - fn clamp_none() { - let expected = Hwb::new_srgb(240.0, 0.3, 0.7); - let clamped = Hwb::new_srgb(240.0, 0.3, 0.7).clamp(); - assert_relative_eq!(expected, clamped); - } - #[test] - fn clamp_over_one() { - let expected = Hwb::new_srgb(240.0, 0.2, 0.8); - let clamped = Hwb::new_srgb(240.0, 5.0, 20.0).clamp(); - assert_relative_eq!(expected, clamped); - } - #[test] - fn clamp_under_one() { - let expected = Hwb::new_srgb(240.0, 0.3, 0.1); - let clamped = Hwb::new_srgb(240.0, 0.3, 0.1).clamp(); - assert_relative_eq!(expected, clamped); + #[cfg(feature = "approx")] + mod clamp { + use crate::{Clamp, Hwb}; + + #[test] + fn clamp_invalid() { + let expected = Hwb::new_srgb(240.0, 0.0, 0.0); + let clamped = Hwb::new_srgb(240.0, -3.0, -4.0).clamp(); + assert_relative_eq!(expected, clamped); + } + + #[test] + fn clamp_none() { + let expected = Hwb::new_srgb(240.0, 0.3, 0.7); + let clamped = Hwb::new_srgb(240.0, 0.3, 0.7).clamp(); + assert_relative_eq!(expected, clamped); + } + #[test] + fn clamp_over_one() { + let expected = Hwb::new_srgb(240.0, 0.2, 0.8); + let clamped = Hwb::new_srgb(240.0, 5.0, 20.0).clamp(); + assert_relative_eq!(expected, clamped); + } + #[test] + fn clamp_under_one() { + let expected = Hwb::new_srgb(240.0, 0.3, 0.1); + let clamped = Hwb::new_srgb(240.0, 0.3, 0.1).clamp(); + assert_relative_eq!(expected, clamped); + } } raw_pixel_conversion_tests!(Hwb: hue, whiteness, blackness); @@ -437,10 +449,10 @@ mod test { fn check_min_max_components() { use crate::encoding::Srgb; - assert_relative_eq!(Hwb::::min_whiteness(), 0.0,); - assert_relative_eq!(Hwb::::min_blackness(), 0.0,); - assert_relative_eq!(Hwb::::max_whiteness(), 1.0,); - assert_relative_eq!(Hwb::::max_blackness(), 1.0,); + assert_eq!(Hwb::::min_whiteness(), 0.0,); + assert_eq!(Hwb::::min_blackness(), 0.0,); + assert_eq!(Hwb::::max_whiteness(), 1.0,); + assert_eq!(Hwb::::max_blackness(), 1.0,); } struct_of_arrays_tests!( @@ -451,6 +463,7 @@ mod test { ); mod alpha { + #[cfg(feature = "alloc")] use crate::{encoding::Srgb, hwb::Hwba}; struct_of_arrays_tests!( diff --git a/palette/src/lab.rs b/palette/src/lab.rs index 7fc1daf2a..961bab216 100644 --- a/palette/src/lab.rs +++ b/palette/src/lab.rs @@ -388,29 +388,33 @@ unsafe impl bytemuck::Pod for Lab where T: bytemuck::Pod mod test { use super::Lab; use crate::white_point::D65; - use crate::{FromColor, LinSrgb}; test_convert_into_from_xyz!(Lab); - #[test] - fn red() { - let a = Lab::from_color(LinSrgb::new(1.0, 0.0, 0.0)); - let b = Lab::new(53.23288, 80.09246, 67.2031); - assert_relative_eq!(a, b, epsilon = 0.01); - } + #[cfg(feature = "approx")] + mod conversion { + use crate::{FromColor, Lab, LinSrgb}; - #[test] - fn green() { - let a = Lab::from_color(LinSrgb::new(0.0, 1.0, 0.0)); - let b = Lab::new(87.73704, -86.184654, 83.18117); - assert_relative_eq!(a, b, epsilon = 0.01); - } + #[test] + fn red() { + let a = Lab::from_color(LinSrgb::new(1.0, 0.0, 0.0)); + let b = Lab::new(53.23288, 80.09246, 67.2031); + assert_relative_eq!(a, b, epsilon = 0.01); + } - #[test] - fn blue() { - let a = Lab::from_color(LinSrgb::new(0.0, 0.0, 1.0)); - let b = Lab::new(32.302586, 79.19668, -107.863686); - assert_relative_eq!(a, b, epsilon = 0.01); + #[test] + fn green() { + let a = Lab::from_color(LinSrgb::new(0.0, 1.0, 0.0)); + let b = Lab::new(87.73704, -86.184654, 83.18117); + assert_relative_eq!(a, b, epsilon = 0.01); + } + + #[test] + fn blue() { + let a = Lab::from_color(LinSrgb::new(0.0, 0.0, 1.0)); + let b = Lab::new(32.302586, 79.19668, -107.863686); + assert_relative_eq!(a, b, epsilon = 0.01); + } } #[test] @@ -432,12 +436,12 @@ mod test { #[test] fn check_min_max_components() { - assert_relative_eq!(Lab::::min_l(), 0.0); - assert_relative_eq!(Lab::::min_a(), -128.0); - assert_relative_eq!(Lab::::min_b(), -128.0); - assert_relative_eq!(Lab::::max_l(), 100.0); - assert_relative_eq!(Lab::::max_a(), 127.0); - assert_relative_eq!(Lab::::max_b(), 127.0); + assert_eq!(Lab::::min_l(), 0.0); + assert_eq!(Lab::::min_a(), -128.0); + assert_eq!(Lab::::min_b(), -128.0); + assert_eq!(Lab::::max_l(), 100.0); + assert_eq!(Lab::::max_a(), 127.0); + assert_eq!(Lab::::max_b(), 127.0); } struct_of_arrays_tests!( @@ -448,6 +452,7 @@ mod test { ); mod alpha { + #[cfg(feature = "alloc")] use crate::{lab::Laba, white_point::D65}; struct_of_arrays_tests!( diff --git a/palette/src/lch.rs b/palette/src/lch.rs index ee6556c2e..c0c18807f 100644 --- a/palette/src/lch.rs +++ b/palette/src/lch.rs @@ -336,11 +336,13 @@ unsafe impl bytemuck::Pod for Lch where T: bytemuck::Pod #[cfg(test)] mod test { + use crate::{white_point::D65, Lch}; + + #[cfg(all(feature = "alloc", feature = "approx"))] use crate::{ color_difference::{DeltaE, ImprovedDeltaE}, convert::IntoColorUnclamped, - white_point::D65, - Lab, Lch, + Lab, }; test_convert_into_from_xyz!(Lch); @@ -366,15 +368,20 @@ mod test { #[test] fn check_min_max_components() { - assert_relative_eq!(Lch::::min_l(), 0.0); - assert_relative_eq!(Lch::::max_l(), 100.0); - assert_relative_eq!(Lch::::min_chroma(), 0.0); - assert_relative_eq!(Lch::::max_chroma(), 128.0); + assert_eq!(Lch::::min_l(), 0.0); + assert_eq!(Lch::::max_l(), 100.0); + assert_eq!(Lch::::min_chroma(), 0.0); + assert_eq!(Lch::::max_chroma(), 128.0); + + #[cfg(feature = "approx")] assert_relative_eq!(Lch::::max_extended_chroma(), 181.01933598375618); } + #[cfg(feature = "approx")] #[test] fn delta_e_large_hue_diff() { + use crate::color_difference::DeltaE; + let lhs1 = Lch::::new(50.0, 64.0, -730.0); let rhs1 = Lch::new(50.0, 64.0, 730.0); @@ -389,6 +396,7 @@ mod test { } // Lab and Lch have the same delta E. + #[cfg(all(feature = "alloc", feature = "approx"))] #[test] fn lab_delta_e_equality() { let mut lab_colors: Vec> = Vec::new(); @@ -418,6 +426,7 @@ mod test { // Lab and Lch have the same delta E, so should also have the same improved // delta E. + #[cfg(all(feature = "alloc", feature = "approx"))] #[test] fn lab_improved_delta_e_equality() { let mut lab_colors: Vec> = Vec::new(); @@ -453,6 +462,7 @@ mod test { ); mod alpha { + #[cfg(feature = "alloc")] use crate::{lch::Lcha, white_point::D65}; struct_of_arrays_tests!( diff --git a/palette/src/lchuv.rs b/palette/src/lchuv.rs index 2fa0b061b..bf55999bd 100644 --- a/palette/src/lchuv.rs +++ b/palette/src/lchuv.rs @@ -310,10 +310,10 @@ mod test { #[test] fn check_min_max_components() { - assert_relative_eq!(Lchuv::::min_l(), 0.0); - assert_relative_eq!(Lchuv::::max_l(), 100.0); - assert_relative_eq!(Lchuv::::min_chroma(), 0.0); - assert_relative_eq!(Lchuv::::max_chroma(), 180.0); + assert_eq!(Lchuv::::min_l(), 0.0); + assert_eq!(Lchuv::::max_l(), 100.0); + assert_eq!(Lchuv::::min_chroma(), 0.0); + assert_eq!(Lchuv::::max_chroma(), 180.0); } struct_of_arrays_tests!( @@ -324,6 +324,7 @@ mod test { ); mod alpha { + #[cfg(feature = "alloc")] use crate::{lchuv::Lchuva, white_point::D65}; struct_of_arrays_tests!( diff --git a/palette/src/lib.rs b/palette/src/lib.rs index 995140b2e..2901d2e98 100644 --- a/palette/src/lib.rs +++ b/palette/src/lib.rs @@ -253,6 +253,9 @@ #![doc(html_root_url = "https://docs.rs/palette/0.7.3/")] #![warn(missing_docs)] +#[cfg(feature = "alloc")] +extern crate alloc; + #[cfg(any(feature = "std", test))] extern crate core; diff --git a/palette/src/luma/luma.rs b/palette/src/luma/luma.rs index 464f92b93..d04e0fc72 100644 --- a/palette/src/luma/luma.rs +++ b/palette/src/luma/luma.rs @@ -890,8 +890,8 @@ mod test { #[test] fn check_min_max_components() { - assert_relative_eq!(Luma::::min_luma(), 0.0); - assert_relative_eq!(Luma::::max_luma(), 1.0); + assert_eq!(Luma::::min_luma(), 0.0); + assert_eq!(Luma::::max_luma(), 1.0); } struct_of_arrays_tests!( @@ -902,6 +902,7 @@ mod test { ); mod alpha { + #[cfg(feature = "alloc")] use crate::{encoding::Srgb, luma::Lumaa}; struct_of_arrays_tests!( diff --git a/palette/src/luv.rs b/palette/src/luv.rs index 4060fc5c7..8f5722e32 100644 --- a/palette/src/luv.rs +++ b/palette/src/luv.rs @@ -313,29 +313,33 @@ unsafe impl bytemuck::Pod for Luv where T: bytemuck::Pod mod test { use super::Luv; use crate::white_point::D65; - use crate::{FromColor, LinSrgb}; test_convert_into_from_xyz!(Luv); - #[test] - fn red() { - let u = Luv::from_color(LinSrgb::new(1.0, 0.0, 0.0)); - let v = Luv::new(53.237116, 175.0098, 37.7650); - assert_relative_eq!(u, v, epsilon = 0.01); - } + #[cfg(feature = "approx")] + mod conversion { + use crate::{FromColor, LinSrgb, Luv}; - #[test] - fn green() { - let u = Luv::from_color(LinSrgb::new(0.0, 1.0, 0.0)); - let v = Luv::new(87.73703, -83.07975, 107.40136); - assert_relative_eq!(u, v, epsilon = 0.01); - } + #[test] + fn red() { + let u = Luv::from_color(LinSrgb::new(1.0, 0.0, 0.0)); + let v = Luv::new(53.237116, 175.0098, 37.7650); + assert_relative_eq!(u, v, epsilon = 0.01); + } - #[test] - fn blue() { - let u = Luv::from_color(LinSrgb::new(0.0, 0.0, 1.0)); - let v = Luv::new(32.30087, -9.40241, -130.35109); - assert_relative_eq!(u, v, epsilon = 0.01); + #[test] + fn green() { + let u = Luv::from_color(LinSrgb::new(0.0, 1.0, 0.0)); + let v = Luv::new(87.73703, -83.07975, 107.40136); + assert_relative_eq!(u, v, epsilon = 0.01); + } + + #[test] + fn blue() { + let u = Luv::from_color(LinSrgb::new(0.0, 0.0, 1.0)); + let v = Luv::new(32.30087, -9.40241, -130.35109); + assert_relative_eq!(u, v, epsilon = 0.01); + } } #[test] @@ -373,12 +377,12 @@ mod test { #[test] fn check_min_max_components() { - assert_relative_eq!(Luv::::min_l(), 0.0); - assert_relative_eq!(Luv::::min_u(), -84.0); - assert_relative_eq!(Luv::::min_v(), -135.0); - assert_relative_eq!(Luv::::max_l(), 100.0); - assert_relative_eq!(Luv::::max_u(), 176.0); - assert_relative_eq!(Luv::::max_v(), 108.0); + assert_eq!(Luv::::min_l(), 0.0); + assert_eq!(Luv::::min_u(), -84.0); + assert_eq!(Luv::::min_v(), -135.0); + assert_eq!(Luv::::max_l(), 100.0); + assert_eq!(Luv::::max_u(), 176.0); + assert_eq!(Luv::::max_v(), 108.0); } struct_of_arrays_tests!( @@ -389,6 +393,7 @@ mod test { ); mod alpha { + #[cfg(feature = "alloc")] use crate::{luv::Luva, white_point::D65}; struct_of_arrays_tests!( diff --git a/palette/src/luv_bounds.rs b/palette/src/luv_bounds.rs index 4e41365bd..2f56f0568 100644 --- a/palette/src/luv_bounds.rs +++ b/palette/src/luv_bounds.rs @@ -124,6 +124,7 @@ impl LuvBounds { } } +#[cfg(feature = "approx")] #[cfg(test)] mod tests { use super::BoundaryLine; @@ -136,12 +137,12 @@ mod tests { }; assert_relative_eq!(line.intersect_length_at_angle(0.0).unwrap(), 1.0); assert_relative_eq!( - line.intersect_length_at_angle(std::f64::consts::FRAC_PI_4) + line.intersect_length_at_angle(core::f64::consts::FRAC_PI_4) .unwrap(), - std::f64::consts::FRAC_1_SQRT_2 + core::f64::consts::FRAC_1_SQRT_2 ); assert_eq!( - line.intersect_length_at_angle(-std::f64::consts::FRAC_PI_4), + line.intersect_length_at_angle(-core::f64::consts::FRAC_PI_4), None ); @@ -151,12 +152,12 @@ mod tests { }; assert_eq!(line.intersect_length_at_angle(0.0), None); assert_relative_eq!( - line.intersect_length_at_angle(std::f64::consts::FRAC_PI_2) + line.intersect_length_at_angle(core::f64::consts::FRAC_PI_2) .unwrap(), 2.0 ); assert_relative_eq!( - line.intersect_length_at_angle(2.0 * std::f64::consts::FRAC_PI_3) + line.intersect_length_at_angle(2.0 * core::f64::consts::FRAC_PI_3) .unwrap(), 4.0 / 3.0f64.sqrt() ); @@ -174,6 +175,6 @@ mod tests { slope: 1.0, intercept: 2.0, }; - assert_relative_eq!(line.distance_to_origin(), std::f64::consts::SQRT_2); + assert_relative_eq!(line.distance_to_origin(), core::f64::consts::SQRT_2); } } diff --git a/palette/src/macros/casting.rs b/palette/src/macros/casting.rs index 0d74da658..268d853ce 100644 --- a/palette/src/macros/casting.rs +++ b/palette/src/macros/casting.rs @@ -261,22 +261,22 @@ macro_rules! impl_array_casts { } } - #[cfg(feature = "std")] - impl<$($ty_param)+> From>> for Box<[$array_item; $array_len]> + #[cfg(feature = "alloc")] + impl<$($ty_param)+> From>> for alloc::boxed::Box<[$array_item; $array_len]> $(where $($where)+)? { #[inline] - fn from(color: Box<$self_ty<$($self_ty_param),+>>) -> Self { + fn from(color: alloc::boxed::Box<$self_ty<$($self_ty_param),+>>) -> Self { crate::cast::into_array_box(color) } } - #[cfg(feature = "std")] - impl<$($ty_param)+> From> for Box<$self_ty<$($self_ty_param),+>> + #[cfg(feature = "alloc")] + impl<$($ty_param)+> From> for alloc::boxed::Box<$self_ty<$($self_ty_param),+>> $(where $($where)+)? { #[inline] - fn from(array: Box<[$array_item; $array_len]>) -> Self{ + fn from(array: alloc::boxed::Box<[$array_item; $array_len]>) -> Self{ crate::cast::from_array_box(array) } } diff --git a/palette/src/macros/clamp.rs b/palette/src/macros/clamp.rs index 55daaa19b..db8c93616 100644 --- a/palette/src/macros/clamp.rs +++ b/palette/src/macros/clamp.rs @@ -239,7 +239,7 @@ macro_rules! assert_ranges { }; assert!(!color.is_within_bounds()); - assert_relative_eq!(clamped, expected); + assert_eq!(clamped, expected); } println!("ok") @@ -279,7 +279,7 @@ macro_rules! assert_ranges { let clamped = color.clamp(); assert!(color.is_within_bounds()); - assert_relative_eq!(clamped, color); + assert_eq!(clamped, color); } println!("ok") @@ -326,7 +326,7 @@ macro_rules! assert_ranges { }; assert!(!color.is_within_bounds()); - assert_relative_eq!(clamped, expected); + assert_eq!(clamped, expected); } println!("ok") diff --git a/palette/src/macros/struct_of_arrays.rs b/palette/src/macros/struct_of_arrays.rs index c377caf41..82200a617 100644 --- a/palette/src/macros/struct_of_arrays.rs +++ b/palette/src/macros/struct_of_arrays.rs @@ -399,12 +399,12 @@ macro_rules! impl_struct_of_arrays_methods { } } - #[cfg(feature = "std")] - impl<$($phantom_ty,)? T> $self_ty<$($phantom_ty,)? Vec> { + #[cfg(feature = "alloc")] + impl<$($phantom_ty,)? T> $self_ty<$($phantom_ty,)? alloc::vec::Vec> { /// Create a struct of vectors with a minimum capacity. See [`Vec::with_capacity`] for details. #[inline(always)] pub fn with_capacity(capacity: usize) -> Self { - $(let $element = Vec::with_capacity(capacity);)+ + $(let $element = alloc::vec::Vec::with_capacity(capacity);)+ Self { $($element,)+ @@ -437,7 +437,7 @@ macro_rules! impl_struct_of_arrays_methods { /// Return an iterator that moves colors out of the specified range. #[inline(always)] - pub fn drain(&mut self, range: R) -> Iter $(, $phantom_ty)?> + pub fn drain(&mut self, range: R) -> Iter $(, $phantom_ty)?> where R: core::ops::RangeBounds + Clone, { @@ -496,14 +496,14 @@ macro_rules! impl_struct_of_arrays_methods { } } - #[cfg(feature = "std")] - impl<$($phantom_ty,)? T, A> crate::Alpha<$self_ty<$($phantom_ty,)? Vec>, Vec> { + #[cfg(feature = "alloc")] + impl<$($phantom_ty,)? T, A> crate::Alpha<$self_ty<$($phantom_ty,)? alloc::vec::Vec>, alloc::vec::Vec> { /// Create a struct of vectors with a minimum capacity. See [`Vec::with_capacity`] for details. #[inline(always)] pub fn with_capacity(capacity: usize) -> Self { crate::Alpha { color: $self_ty::with_capacity(capacity), - alpha: Vec::with_capacity(capacity), + alpha: alloc::vec::Vec::with_capacity(capacity), } } @@ -535,7 +535,7 @@ macro_rules! impl_struct_of_arrays_methods { /// Return an iterator that moves colors out of the specified range. #[inline(always)] - pub fn drain(&mut self, range: R) -> crate::alpha::Iter $(, $phantom_ty)?>, std::vec::Drain> + pub fn drain(&mut self, range: R) -> crate::alpha::Iter $(, $phantom_ty)?>, alloc::vec::Drain> where R: core::ops::RangeBounds + Clone, { @@ -603,13 +603,13 @@ macro_rules! impl_struct_of_arrays_methods_hue { } } - #[cfg(feature = "std")] - impl<$($phantom_ty,)? T> $self_ty<$($phantom_ty,)? Vec> { + #[cfg(feature = "alloc")] + impl<$($phantom_ty,)? T> $self_ty<$($phantom_ty,)? alloc::vec::Vec> { /// Create a struct of vectors with a minimum capacity. See [`Vec::with_capacity`] for details. #[inline(always)] pub fn with_capacity(capacity: usize) -> Self { - let hue = Vec::with_capacity(capacity); - $(let $element = Vec::with_capacity(capacity);)+ + let hue = alloc::vec::Vec::with_capacity(capacity); + $(let $element = alloc::vec::Vec::with_capacity(capacity);)+ Self {hue: hue.into() $(, $element)+ $(, $phantom: core::marker::PhantomData)?} } @@ -643,7 +643,7 @@ macro_rules! impl_struct_of_arrays_methods_hue { /// Return an iterator that moves colors out of the specified range. #[inline(always)] - pub fn drain(&mut self, range: R) -> Iter $(, $phantom_ty)?> + pub fn drain(&mut self, range: R) -> Iter $(, $phantom_ty)?> where R: core::ops::RangeBounds + Clone, { @@ -703,14 +703,14 @@ macro_rules! impl_struct_of_arrays_methods_hue { } } - #[cfg(feature = "std")] - impl<$($phantom_ty,)? T, A> crate::Alpha<$self_ty<$($phantom_ty,)? Vec>, Vec> { + #[cfg(feature = "alloc")] + impl<$($phantom_ty,)? T, A> crate::Alpha<$self_ty<$($phantom_ty,)? alloc::vec::Vec>, alloc::vec::Vec> { /// Create a struct of vectors with a minimum capacity. See [`Vec::with_capacity`] for details. #[inline(always)] pub fn with_capacity(capacity: usize) -> Self { crate::Alpha { color: $self_ty::with_capacity(capacity), - alpha: Vec::with_capacity(capacity), + alpha: alloc::vec::Vec::with_capacity(capacity), } } @@ -742,7 +742,7 @@ macro_rules! impl_struct_of_arrays_methods_hue { /// Return an iterator that moves colors out of the specified range. #[inline(always)] - pub fn drain(&mut self, range: R) -> crate::alpha::Iter $(, $phantom_ty)?>, std::vec::Drain> + pub fn drain(&mut self, range: R) -> crate::alpha::Iter $(, $phantom_ty)?>, alloc::vec::Drain> where R: core::ops::RangeBounds + Clone, { @@ -758,6 +758,7 @@ macro_rules! impl_struct_of_arrays_methods_hue { #[cfg(test)] macro_rules! struct_of_arrays_tests { ($color_ty: ident $(<$phantom_ty:ident>)?, $($values:expr),+) => { + #[cfg(feature = "alloc")] #[test] fn collect() { let vec_of_colors = vec![$($values),+]; @@ -767,6 +768,7 @@ macro_rules! struct_of_arrays_tests { assert_eq!(vec_of_colors, vec![$($values),+]); } + #[cfg(feature = "alloc")] #[test] fn extend() { let vec_of_colors = vec![$($values),+]; @@ -779,6 +781,7 @@ macro_rules! struct_of_arrays_tests { assert_eq!(vec_of_colors, vec![$($values),+]); } + #[cfg(feature = "alloc")] #[test] fn pop_push() { let vec_of_colors = vec![$($values),+]; @@ -792,6 +795,7 @@ macro_rules! struct_of_arrays_tests { assert_eq!(vec_of_colors, vec![$($values),+]); } + #[cfg(feature = "alloc")] #[test] fn clear() { let vec_of_colors = vec![$($values),+]; @@ -804,6 +808,7 @@ macro_rules! struct_of_arrays_tests { assert_eq!(vec_of_colors, vec![]); } + #[cfg(feature = "alloc")] #[test] fn drain() { let vec_of_colors = vec![$($values),+]; @@ -817,6 +822,7 @@ macro_rules! struct_of_arrays_tests { assert_eq!(vec_of_colors2, vec![]); } + #[cfg(feature = "alloc")] #[test] fn modify() { let vec_of_colors = vec![$($values),+]; diff --git a/palette/src/matrix.rs b/palette/src/matrix.rs index ea33be3c4..e26000425 100644 --- a/palette/src/matrix.rs +++ b/palette/src/matrix.rs @@ -218,6 +218,7 @@ fn mat3_from_primaries(r: Xyz, g: Xyz, b: Xyz) -> Mat ] } +#[cfg(feature = "approx")] #[cfg(test)] mod test { use super::{matrix_inverse, multiply_3x3, multiply_xyz, rgb_to_xyz_matrix}; diff --git a/palette/src/num.rs b/palette/src/num.rs index da1f00e86..4338e8cb2 100644 --- a/palette/src/num.rs +++ b/palette/src/num.rs @@ -532,7 +532,7 @@ macro_rules! impl_float { } } - #[cfg(feature = "std")] + #[cfg(any(feature = "std", all(test, not(feature = "libm"))))] impl Trigonometry for $ty { #[inline] fn sin(self) -> Self { @@ -575,7 +575,7 @@ macro_rules! impl_float { } } - #[cfg(feature = "std")] + #[cfg(any(feature = "std", all(test, not(feature = "libm"))))] impl Abs for $ty { #[inline] fn abs(self) -> Self { @@ -583,7 +583,7 @@ macro_rules! impl_float { } } - #[cfg(feature = "std")] + #[cfg(any(feature = "std", all(test, not(feature = "libm"))))] impl Sqrt for $ty { #[inline] fn sqrt(self) -> Self { @@ -591,7 +591,7 @@ macro_rules! impl_float { } } - #[cfg(feature = "std")] + #[cfg(any(feature = "std", all(test, not(feature = "libm"))))] impl Cbrt for $ty { #[inline] fn cbrt(self) -> Self { @@ -599,7 +599,7 @@ macro_rules! impl_float { } } - #[cfg(feature = "std")] + #[cfg(any(feature = "std", all(test, not(feature = "libm"))))] impl Powf for $ty { #[inline] fn powf(self, exp: Self) -> Self { @@ -607,7 +607,7 @@ macro_rules! impl_float { } } - #[cfg(feature = "std")] + #[cfg(any(feature = "std", all(test, not(feature = "libm"))))] impl Powi for $ty { #[inline] fn powi(self, exp: i32) -> Self { @@ -615,7 +615,7 @@ macro_rules! impl_float { } } - #[cfg(feature = "std")] + #[cfg(any(feature = "std", all(test, not(feature = "libm"))))] impl Recip for $ty { #[inline] fn recip(self) -> Self { @@ -623,7 +623,7 @@ macro_rules! impl_float { } } - #[cfg(feature = "std")] + #[cfg(any(feature = "std", all(test, not(feature = "libm"))))] impl Exp for $ty { #[inline] fn exp(self) -> Self { @@ -631,7 +631,7 @@ macro_rules! impl_float { } } - #[cfg(feature = "std")] + #[cfg(any(feature = "std", all(test, not(feature = "libm"))))] impl Hypot for $ty { #[inline] fn hypot(self, other: Self) -> Self { @@ -639,7 +639,7 @@ macro_rules! impl_float { } } - #[cfg(feature = "std")] + #[cfg(any(feature = "std", all(test, not(feature = "libm"))))] impl Round for $ty { #[inline] fn round(self) -> Self { @@ -691,7 +691,7 @@ macro_rules! impl_float { } } - #[cfg(feature = "std")] + #[cfg(any(feature = "std", all(test, not(feature = "libm"))))] impl MulAdd for $ty { #[inline] fn mul_add(self, m: Self, a: Self) -> Self { diff --git a/palette/src/ok_utils.rs b/palette/src/ok_utils.rs index 8ac7eded3..2fa2cdb11 100644 --- a/palette/src/ok_utils.rs +++ b/palette/src/ok_utils.rs @@ -1,5 +1,6 @@ //! Traits and functions used in Ok* color spaces +#[cfg(feature = "approx")] #[cfg(test)] use crate::{angle::RealAngle, num::Trigonometry, OklabHue}; @@ -351,6 +352,7 @@ where } } +#[cfg(feature = "approx")] #[cfg(test)] impl OklabHue where @@ -487,6 +489,7 @@ where (l_r.clone().powi(2) + k_1 * &l_r) / (k_3 * (l_r + k_2)) } +#[cfg(feature = "approx")] #[cfg(test)] mod tests { @@ -518,7 +521,7 @@ mod tests { .into_format(); let grey50oklab = Oklab::from_color_unclamped(grey50srgb); println!("grey 50% oklab lightness: {}", grey50oklab.l); - assert!(relative_eq!(toe(grey50oklab.l), 0.5, epsilon = 1e-3)); + assert_relative_eq!(toe(grey50oklab.l), 0.5, epsilon = 1e-3); } #[cfg_attr(miri, ignore)] diff --git a/palette/src/okhsl.rs b/palette/src/okhsl.rs index 599b9daf4..b5f60ebc8 100644 --- a/palette/src/okhsl.rs +++ b/palette/src/okhsl.rs @@ -242,146 +242,153 @@ unsafe impl bytemuck::Pod for Okhsl where T: bytemuck::Pod {} #[cfg(test)] mod tests { - use core::str::FromStr; - use crate::{ convert::{FromColorUnclamped, IntoColorUnclamped}, encoding, rgb::Rgb, - visual::{VisualColor, VisuallyEqual}, - LinSrgb, Okhsl, Oklab, Srgb, + Okhsl, Oklab, Srgb, }; test_convert_into_from_xyz!(Okhsl); - #[cfg_attr(miri, ignore)] - #[test] - fn test_roundtrip_okhsl_oklab_is_original() { - let colors = [ - ( - "red", - Oklab::from_color_unclamped(LinSrgb::new(1.0, 0.0, 0.0)), - ), - ( - "green", - Oklab::from_color_unclamped(LinSrgb::new(0.0, 1.0, 0.0)), - ), - ( - "cyan", - Oklab::from_color_unclamped(LinSrgb::new(0.0, 1.0, 1.0)), - ), - ( - "magenta", - Oklab::from_color_unclamped(LinSrgb::new(1.0, 0.0, 1.0)), - ), - ( - "black", - Oklab::from_color_unclamped(LinSrgb::new(0.0, 0.0, 0.0)), - ), - ( - "grey", - Oklab::from_color_unclamped(LinSrgb::new(0.5, 0.5, 0.5)), - ), - ( - "yellow", - Oklab::from_color_unclamped(LinSrgb::new(1.0, 1.0, 0.0)), - ), - ( - "blue", - Oklab::from_color_unclamped(LinSrgb::new(0.0, 0.0, 1.0)), - ), - ( - "white", - Oklab::from_color_unclamped(LinSrgb::new(1.0, 1.0, 1.0)), - ), - ]; - - // unlike in okhwb we are using f64 here, which actually works. - // So we can afford a small tolerance. - // For some reason the roundtrip of Okhsl seems to produce a greater - // divergence than the round trip of Okhsv (1e-8 vs 1e-10) - const EPSILON: f64 = 1e-8; - - for (name, color) in colors { - let rgb: Rgb = - crate::Srgb::::from_color_unclamped(color).into_format(); - println!( - "\n\ - roundtrip of {} (#{:x} / {:?})\n\ - =================================================", - name, rgb, color - ); + #[cfg(feature = "approx")] + mod conversion { + use core::str::FromStr; - println!("Color is white: {}", color.is_white(EPSILON)); + use crate::{ + convert::FromColorUnclamped, + visual::{VisualColor, VisuallyEqual}, + LinSrgb, Okhsl, Oklab, Srgb, + }; - let okhsl = Okhsl::from_color_unclamped(color); - println!("Okhsl: {:?}", okhsl); - let roundtrip_color = Oklab::from_color_unclamped(okhsl); - assert!( - Oklab::visually_eq(roundtrip_color, color, EPSILON), - "'{}' failed.\n{:?}\n!=\n{:?}", - name, - roundtrip_color, - color - ); + #[cfg_attr(miri, ignore)] + #[test] + fn test_roundtrip_okhsl_oklab_is_original() { + let colors = [ + ( + "red", + Oklab::from_color_unclamped(LinSrgb::new(1.0, 0.0, 0.0)), + ), + ( + "green", + Oklab::from_color_unclamped(LinSrgb::new(0.0, 1.0, 0.0)), + ), + ( + "cyan", + Oklab::from_color_unclamped(LinSrgb::new(0.0, 1.0, 1.0)), + ), + ( + "magenta", + Oklab::from_color_unclamped(LinSrgb::new(1.0, 0.0, 1.0)), + ), + ( + "black", + Oklab::from_color_unclamped(LinSrgb::new(0.0, 0.0, 0.0)), + ), + ( + "grey", + Oklab::from_color_unclamped(LinSrgb::new(0.5, 0.5, 0.5)), + ), + ( + "yellow", + Oklab::from_color_unclamped(LinSrgb::new(1.0, 1.0, 0.0)), + ), + ( + "blue", + Oklab::from_color_unclamped(LinSrgb::new(0.0, 0.0, 1.0)), + ), + ( + "white", + Oklab::from_color_unclamped(LinSrgb::new(1.0, 1.0, 1.0)), + ), + ]; + + // unlike in okhwb we are using f64 here, which actually works. + // So we can afford a small tolerance. + // For some reason the roundtrip of Okhsl seems to produce a greater + // divergence than the round trip of Okhsv (1e-8 vs 1e-10) + const EPSILON: f64 = 1e-8; + + for (name, color) in colors { + let rgb: Srgb = Srgb::::from_color_unclamped(color).into_format(); + println!( + "\n\ + roundtrip of {} (#{:x} / {:?})\n\ + =================================================", + name, rgb, color + ); + + println!("Color is white: {}", color.is_white(EPSILON)); + + let okhsl = Okhsl::from_color_unclamped(color); + println!("Okhsl: {:?}", okhsl); + let roundtrip_color = Oklab::from_color_unclamped(okhsl); + assert!( + Oklab::visually_eq(roundtrip_color, color, EPSILON), + "'{}' failed.\n{:?}\n!=\n{:?}", + name, + roundtrip_color, + color + ); + } } - } - #[test] - fn test_blue() { - let lab = Oklab::new( - 0.45201371519623734_f64, - -0.03245697990291002, - -0.3115281336419824, - ); - let okhsl = Okhsl::::from_color_unclamped(lab); - assert!( - abs_diff_eq!( + #[test] + fn test_blue() { + let lab = Oklab::new( + 0.45201371519623734_f64, + -0.03245697990291002, + -0.3115281336419824, + ); + let okhsl = Okhsl::::from_color_unclamped(lab); + assert!( + abs_diff_eq!( + okhsl.hue.into_raw_degrees(), + 360.0 * 0.7334778365225699, + epsilon = 1e-10 + ), + "{}\n!=\n{}", okhsl.hue.into_raw_degrees(), - 360.0 * 0.7334778365225699, - epsilon = 1e-10 - ), - "{}\n!=\n{}", - okhsl.hue.into_raw_degrees(), - 360.0 * 0.7334778365225699 - ); - assert!( - abs_diff_eq!(okhsl.saturation, 0.9999999897262261, epsilon = 1e-8), - "{}\n!=\n{}", - okhsl.saturation, - 0.9999999897262261 - ); - assert!( - abs_diff_eq!(okhsl.lightness, 0.366565335813274, epsilon = 1e-10), - "{}\n!=\n{}", - okhsl.lightness, - 0.366565335813274 - ); - } + 360.0 * 0.7334778365225699 + ); + assert!( + abs_diff_eq!(okhsl.saturation, 0.9999999897262261, epsilon = 1e-8), + "{}\n!=\n{}", + okhsl.saturation, + 0.9999999897262261 + ); + assert!( + abs_diff_eq!(okhsl.lightness, 0.366565335813274, epsilon = 1e-10), + "{}\n!=\n{}", + okhsl.lightness, + 0.366565335813274 + ); + } - #[test] - fn test_srgb_to_okhsl() { - let red_hex = "#834941"; - let rgb: Srgb = Srgb::from_str(red_hex).unwrap().into_format(); - let lin_rgb = LinSrgb::::from_color_unclamped(rgb); - let oklab = Oklab::from_color_unclamped(lin_rgb); - println!( - "RGB: {:?}\n\ + #[test] + fn test_srgb_to_okhsl() { + let red_hex = "#834941"; + let rgb: Srgb = Srgb::from_str(red_hex).unwrap().into_format(); + let lin_rgb = LinSrgb::::from_color_unclamped(rgb); + let oklab = Oklab::from_color_unclamped(lin_rgb); + println!( + "RGB: {:?}\n\ LinRgb: {:?}\n\ Oklab: {:?}", - rgb, lin_rgb, oklab - ); - let okhsl = Okhsl::from_color_unclamped(oklab); - - // test data from Ok Color picker - assert_relative_eq!( - okhsl.hue.into_raw_degrees(), - 360.0 * 0.07992730371382328, - epsilon = 1e-10, - max_relative = 1e-13 - ); - assert_relative_eq!(okhsl.saturation, 0.4629217183454986, epsilon = 1e-10); - assert_relative_eq!(okhsl.lightness, 0.3900998146147427, epsilon = 1e-10); + rgb, lin_rgb, oklab + ); + let okhsl = Okhsl::from_color_unclamped(oklab); + + // test data from Ok Color picker + assert_relative_eq!( + okhsl.hue.into_raw_degrees(), + 360.0 * 0.07992730371382328, + epsilon = 1e-10, + max_relative = 1e-13 + ); + assert_relative_eq!(okhsl.saturation, 0.4629217183454986, epsilon = 1e-10); + assert_relative_eq!(okhsl.lightness, 0.3900998146147427, epsilon = 1e-10); + } } #[test] @@ -397,7 +404,7 @@ mod tests { fn test_okhsl_to_srgb_saturated_black() { let okhsl = Okhsl::new(0.0_f32, 1.0, 0.0); let rgb = Srgb::from_color_unclamped(okhsl); - assert_relative_eq!(rgb, Srgb::new(0.0, 0.0, 0.0)); + assert_eq!(rgb, Srgb::new(0.0, 0.0, 0.0)); } #[test] @@ -429,6 +436,7 @@ mod tests { ); mod alpha { + #[cfg(feature = "alloc")] use crate::okhsl::Okhsla; struct_of_arrays_tests!( diff --git a/palette/src/okhsv.rs b/palette/src/okhsv.rs index 9027668c9..468416bdd 100644 --- a/palette/src/okhsv.rs +++ b/palette/src/okhsv.rs @@ -286,214 +286,224 @@ where #[cfg(test)] mod tests { - use core::str::FromStr; - - use crate::convert::FromColorUnclamped; - use crate::rgb::Rgb; - use crate::visual::VisuallyEqual; - use crate::{encoding, Clamp, IsWithinBounds, LinSrgb, Okhsv, Oklab, OklabHue, Srgb}; + use crate::{convert::FromColorUnclamped, Clamp, IsWithinBounds, LinSrgb, Okhsv, Oklab}; test_convert_into_from_xyz!(Okhsv); - #[cfg_attr(miri, ignore)] - #[test] - fn test_roundtrip_okhsv_oklab_is_original() { - let colors = [ - ( - "red", - Oklab::from_color_unclamped(LinSrgb::new(1.0, 0.0, 0.0)), - ), - ( - "green", - Oklab::from_color_unclamped(LinSrgb::new(0.0, 1.0, 0.0)), - ), - ( - "cyan", - Oklab::from_color_unclamped(LinSrgb::new(0.0, 1.0, 1.0)), - ), - ( - "magenta", - Oklab::from_color_unclamped(LinSrgb::new(1.0, 0.0, 1.0)), - ), - ( - "white", - Oklab::from_color_unclamped(LinSrgb::new(1.0, 1.0, 1.0)), - ), - ( - "black", - Oklab::from_color_unclamped(LinSrgb::new(0.0, 0.0, 0.0)), - ), - ( - "grey", - Oklab::from_color_unclamped(LinSrgb::new(0.5, 0.5, 0.5)), - ), - ( - "yellow", - Oklab::from_color_unclamped(LinSrgb::new(1.0, 1.0, 0.0)), - ), - ( - "blue", - Oklab::from_color_unclamped(LinSrgb::new(0.0, 0.0, 1.0)), - ), - ]; - - // unlike in okhwb we are using f64 here, which actually works. - // So we can afford a small tolerance - const EPSILON: f64 = 1e-10; - - for (name, color) in colors { - let rgb: Rgb = - crate::Srgb::::from_color_unclamped(color).into_format(); - println!( - "\n\ - roundtrip of {} (#{:x} / {:?})\n\ - =================================================", - name, rgb, color - ); + #[cfg(feature = "approx")] + mod conversion { + use core::str::FromStr; - let okhsv = Okhsv::from_color_unclamped(color); - println!("Okhsv: {:?}", okhsv); - let roundtrip_color = Oklab::from_color_unclamped(okhsv); - assert!( - Oklab::visually_eq(roundtrip_color, color, EPSILON), - "'{}' failed.\n{:?}\n!=\n{:?}", - name, - roundtrip_color, - color - ); + use crate::{ + convert::FromColorUnclamped, encoding, rgb::Rgb, visual::VisuallyEqual, LinSrgb, Okhsv, + Oklab, OklabHue, Srgb, + }; + + #[cfg_attr(miri, ignore)] + #[test] + fn test_roundtrip_okhsv_oklab_is_original() { + let colors = [ + ( + "red", + Oklab::from_color_unclamped(LinSrgb::new(1.0, 0.0, 0.0)), + ), + ( + "green", + Oklab::from_color_unclamped(LinSrgb::new(0.0, 1.0, 0.0)), + ), + ( + "cyan", + Oklab::from_color_unclamped(LinSrgb::new(0.0, 1.0, 1.0)), + ), + ( + "magenta", + Oklab::from_color_unclamped(LinSrgb::new(1.0, 0.0, 1.0)), + ), + ( + "white", + Oklab::from_color_unclamped(LinSrgb::new(1.0, 1.0, 1.0)), + ), + ( + "black", + Oklab::from_color_unclamped(LinSrgb::new(0.0, 0.0, 0.0)), + ), + ( + "grey", + Oklab::from_color_unclamped(LinSrgb::new(0.5, 0.5, 0.5)), + ), + ( + "yellow", + Oklab::from_color_unclamped(LinSrgb::new(1.0, 1.0, 0.0)), + ), + ( + "blue", + Oklab::from_color_unclamped(LinSrgb::new(0.0, 0.0, 1.0)), + ), + ]; + + // unlike in okhwb we are using f64 here, which actually works. + // So we can afford a small tolerance + const EPSILON: f64 = 1e-10; + + for (name, color) in colors { + let rgb: Rgb = + crate::Srgb::::from_color_unclamped(color).into_format(); + println!( + "\n\ + roundtrip of {} (#{:x} / {:?})\n\ + =================================================", + name, rgb, color + ); + + let okhsv = Okhsv::from_color_unclamped(color); + println!("Okhsv: {:?}", okhsv); + let roundtrip_color = Oklab::from_color_unclamped(okhsv); + assert!( + Oklab::visually_eq(roundtrip_color, color, EPSILON), + "'{}' failed.\n{:?}\n!=\n{:?}", + name, + roundtrip_color, + color + ); + } } - } - /// Compares results to results for a run of - /// https://github.com/bottosson/bottosson.github.io/blob/3d3f17644d7f346e1ce1ca08eb8b01782eea97af/misc/ok_color.h - /// Not to the ideal values, which should be - /// hue: as is - /// saturation: 1.0 - /// value: 1.0 - #[test] - fn blue() { - let lin_srgb_blue = LinSrgb::new(0.0, 0.0, 1.0); - let oklab_blue_64 = Oklab::::from_color_unclamped(lin_srgb_blue); - let okhsv_blue_64 = Okhsv::from_color_unclamped(oklab_blue_64); - - println!("Okhsv f64: {:?}\n", okhsv_blue_64); - // HSV values of the reference implementation (in C) - // 1 iteration : 264.0520206380550121, 0.9999910912349018, 0.9999999646150918 - // 2 iterations: 264.0520206380550121, 0.9999999869716002, 0.9999999646150844 - // 3 iterations: 264.0520206380550121, 0.9999999869716024, 0.9999999646150842 - #[allow(clippy::excessive_precision)] - let expected_hue = OklabHue::new(264.0520206380550121); - let expected_saturation = 0.9999910912349018; - let expected_value = 0.9999999646150918; - - // compare to the reference implementation values - assert_abs_diff_eq!(okhsv_blue_64.hue, expected_hue, epsilon = 1e-12); - assert_abs_diff_eq!( - okhsv_blue_64.saturation, - expected_saturation, - epsilon = 1e-12 - ); - assert_abs_diff_eq!(okhsv_blue_64.value, expected_value, epsilon = 1e-12); - } + /// Compares results to results for a run of + /// https://github.com/bottosson/bottosson.github.io/blob/3d3f17644d7f346e1ce1ca08eb8b01782eea97af/misc/ok_color.h + /// Not to the ideal values, which should be + /// hue: as is + /// saturation: 1.0 + /// value: 1.0 + #[test] + fn blue() { + let lin_srgb_blue = LinSrgb::new(0.0, 0.0, 1.0); + let oklab_blue_64 = Oklab::::from_color_unclamped(lin_srgb_blue); + let okhsv_blue_64 = Okhsv::from_color_unclamped(oklab_blue_64); + + println!("Okhsv f64: {:?}\n", okhsv_blue_64); + // HSV values of the reference implementation (in C) + // 1 iteration : 264.0520206380550121, 0.9999910912349018, 0.9999999646150918 + // 2 iterations: 264.0520206380550121, 0.9999999869716002, 0.9999999646150844 + // 3 iterations: 264.0520206380550121, 0.9999999869716024, 0.9999999646150842 + #[allow(clippy::excessive_precision)] + let expected_hue = OklabHue::new(264.0520206380550121); + let expected_saturation = 0.9999910912349018; + let expected_value = 0.9999999646150918; + + // compare to the reference implementation values + assert_abs_diff_eq!(okhsv_blue_64.hue, expected_hue, epsilon = 1e-12); + assert_abs_diff_eq!( + okhsv_blue_64.saturation, + expected_saturation, + epsilon = 1e-12 + ); + assert_abs_diff_eq!(okhsv_blue_64.value, expected_value, epsilon = 1e-12); + } - #[test] - fn test_srgb_to_okhsv() { - let red_hex = "#ff0004"; - let rgb: Srgb = Rgb::::from_str(red_hex) - .unwrap() - .into_format(); - let okhsv = Okhsv::from_color_unclamped(rgb); - assert_relative_eq!(okhsv.saturation, 1.0, epsilon = 1e-3); - assert_relative_eq!(okhsv.value, 1.0, epsilon = 1e-3); - assert_relative_eq!( - okhsv.hue.into_raw_degrees(), - 29.0, - epsilon = 1e-3, - max_relative = 1e-3 - ); - } + #[test] + fn test_srgb_to_okhsv() { + let red_hex = "#ff0004"; + let rgb: Srgb = Rgb::::from_str(red_hex) + .unwrap() + .into_format(); + let okhsv = Okhsv::from_color_unclamped(rgb); + assert_relative_eq!(okhsv.saturation, 1.0, epsilon = 1e-3); + assert_relative_eq!(okhsv.value, 1.0, epsilon = 1e-3); + assert_relative_eq!( + okhsv.hue.into_raw_degrees(), + 29.0, + epsilon = 1e-3, + max_relative = 1e-3 + ); + } - #[test] - fn test_okhsv_to_srgb() { - let okhsv = Okhsv::new(0.0_f32, 0.5, 0.5); - let rgb = Srgb::from_color_unclamped(okhsv); - let rgb8: Rgb = rgb.into_format(); - let hex_str = format!("{:x}", rgb8); - assert_eq!(hex_str, "7a4355"); - } + #[test] + fn test_okhsv_to_srgb() { + let okhsv = Okhsv::new(0.0_f32, 0.5, 0.5); + let rgb = Srgb::from_color_unclamped(okhsv); + let rgb8: Rgb = rgb.into_format(); + let hex_str = format!("{:x}", rgb8); + assert_eq!(hex_str, "7a4355"); + } - #[test] - fn test_okhsv_to_srgb_saturated_black() { - let okhsv = Okhsv::new(0.0_f32, 1.0, 0.0); - let rgb = Srgb::from_color_unclamped(okhsv); - assert_relative_eq!(rgb, Srgb::new(0.0, 0.0, 0.0)); - } + #[test] + fn test_okhsv_to_srgb_saturated_black() { + let okhsv = Okhsv::new(0.0_f32, 1.0, 0.0); + let rgb = Srgb::from_color_unclamped(okhsv); + assert_relative_eq!(rgb, Srgb::new(0.0, 0.0, 0.0)); + } - #[test] - fn black_eq_different_black() { - assert!(Okhsv::visually_eq( - Okhsv::from_color_unclamped(Oklab::new(0.0, 1.0, 0.0)), - Okhsv::from_color_unclamped(Oklab::new(0.0, 0.0, 1.0)), - 1e-12 - )); + #[test] + fn black_eq_different_black() { + assert!(Okhsv::visually_eq( + Okhsv::from_color_unclamped(Oklab::new(0.0, 1.0, 0.0)), + Okhsv::from_color_unclamped(Oklab::new(0.0, 0.0, 1.0)), + 1e-12 + )); + } } - #[test] - fn white_eq_different_white() { - assert!(Okhsv::visually_eq( - Okhsv::new(240.0, 0.0, 1.0), - Okhsv::new(24.0, 0.0, 1.0), - 1e-12 - )); - } + #[cfg(feature = "approx")] + mod visual_eq { + use crate::{visual::VisuallyEqual, Okhsv}; + + #[test] + fn white_eq_different_white() { + assert!(Okhsv::visually_eq( + Okhsv::new(240.0, 0.0, 1.0), + Okhsv::new(24.0, 0.0, 1.0), + 1e-12 + )); + } - #[test] - fn white_ne_grey_or_black() { - assert!(!Okhsv::visually_eq( - Okhsv::new(0.0, 0.0, 0.0), - Okhsv::new(0.0, 0.0, 1.0), - 1e-12 - )); - assert!(!Okhsv::visually_eq( - Okhsv::new(0.0, 0.0, 0.3), - Okhsv::new(0.0, 0.0, 1.0), - 1e-12 - )); - } + #[test] + fn white_ne_grey_or_black() { + assert!(!Okhsv::visually_eq( + Okhsv::new(0.0, 0.0, 0.0), + Okhsv::new(0.0, 0.0, 1.0), + 1e-12 + )); + assert!(!Okhsv::visually_eq( + Okhsv::new(0.0, 0.0, 0.3), + Okhsv::new(0.0, 0.0, 1.0), + 1e-12 + )); + } - #[test] - fn color_neq_different_color() { - assert!(!Okhsv::visually_eq( - Okhsv::new(10.0, 0.01, 0.5), - Okhsv::new(11.0, 0.01, 0.5), - 1e-12 - )); - assert!(!Okhsv::visually_eq( - Okhsv::new(10.0, 0.01, 0.5), - Okhsv::new(10.0, 0.02, 0.5), - 1e-12 - )); - assert!(!Okhsv::visually_eq( - Okhsv::new(10.0, 0.01, 0.5), - Okhsv::new(10.0, 0.01, 0.6), - 1e-12 - )); - } + #[test] + fn color_neq_different_color() { + assert!(!Okhsv::visually_eq( + Okhsv::new(10.0, 0.01, 0.5), + Okhsv::new(11.0, 0.01, 0.5), + 1e-12 + )); + assert!(!Okhsv::visually_eq( + Okhsv::new(10.0, 0.01, 0.5), + Okhsv::new(10.0, 0.02, 0.5), + 1e-12 + )); + assert!(!Okhsv::visually_eq( + Okhsv::new(10.0, 0.01, 0.5), + Okhsv::new(10.0, 0.01, 0.6), + 1e-12 + )); + } - #[test] - fn grey_vs_grey() { - // greys of different lightness are not equal - assert!(!Okhsv::visually_eq( - Okhsv::new(0.0, 0.0, 0.3), - Okhsv::new(0.0, 0.0, 0.4), - 1e-12 - )); - // greys of same lightness but different hue are equal - assert!(Okhsv::visually_eq( - Okhsv::new(0.0, 0.0, 0.3), - Okhsv::new(12.0, 0.0, 0.3), - 1e-12 - )); + #[test] + fn grey_vs_grey() { + // greys of different lightness are not equal + assert!(!Okhsv::visually_eq( + Okhsv::new(0.0, 0.0, 0.3), + Okhsv::new(0.0, 0.0, 0.4), + 1e-12 + )); + // greys of same lightness but different hue are equal + assert!(Okhsv::visually_eq( + Okhsv::new(0.0, 0.0, 0.3), + Okhsv::new(12.0, 0.0, 0.3), + 1e-12 + )); + } } #[test] @@ -550,6 +560,7 @@ mod tests { ); mod alpha { + #[cfg(feature = "alloc")] use crate::okhsv::Okhsva; struct_of_arrays_tests!( diff --git a/palette/src/okhwb.rs b/palette/src/okhwb.rs index 8d5098942..0b9f3aa1c 100644 --- a/palette/src/okhwb.rs +++ b/palette/src/okhwb.rs @@ -173,106 +173,111 @@ unsafe impl bytemuck::Pod for Okhwb where T: bytemuck::Pod {} #[cfg(test)] mod tests { - use crate::convert::FromColorUnclamped; - use crate::rgb::Rgb; - use crate::visual::VisuallyEqual; - use crate::{encoding, LinSrgb, Okhsv, Okhwb, Oklab}; + use crate::Okhwb; test_convert_into_from_xyz!(Okhwb); - #[cfg_attr(miri, ignore)] - #[test] - fn test_roundtrip_okhwb_oklab_is_original() { - let colors = [ - ( - "red", - Oklab::from_color_unclamped(LinSrgb::new(1.0, 0.0, 0.0)), - ), - ( - "green", - Oklab::from_color_unclamped(LinSrgb::new(0.0, 1.0, 0.0)), - ), - ( - "cyan", - Oklab::from_color_unclamped(LinSrgb::new(0.0, 1.0, 1.0)), - ), - ( - "magenta", - Oklab::from_color_unclamped(LinSrgb::new(1.0, 0.0, 1.0)), - ), - ( - "white", - Oklab::from_color_unclamped(LinSrgb::new(1.0, 1.0, 1.0)), - ), - ( - "black", - Oklab::from_color_unclamped(LinSrgb::new(0.0, 0.0, 0.0)), - ), - ( - "grey", - Oklab::from_color_unclamped(LinSrgb::new(0.5, 0.5, 0.5)), - ), - ( - "yellow", - Oklab::from_color_unclamped(LinSrgb::new(1.0, 1.0, 0.0)), - ), - ( - "blue", - Oklab::from_color_unclamped(LinSrgb::new(0.0, 0.0, 1.0)), - ), - ]; - - const EPSILON: f64 = 1e-14; - - for (name, color) in colors { - let rgb: Rgb = - crate::Srgb::::from_color_unclamped(color).into_format(); - println!( - "\n\ - roundtrip of {} (#{:x} / {:?})\n\ - =================================================", - name, rgb, color - ); - - let okhsv = Okhsv::from_color_unclamped(color); - println!("Okhsv: {:?}", okhsv); - let okhwb_from_okhsv = Okhwb::from_color_unclamped(okhsv); - let okhwb = Okhwb::from_color_unclamped(color); - println!("Okhwb: {:?}", okhwb); - assert!( + #[cfg(feature = "approx")] + mod conversion { + use crate::{ + convert::FromColorUnclamped, encoding, rgb::Rgb, visual::VisuallyEqual, LinSrgb, Okhsv, + Okhwb, Oklab, + }; + + #[cfg_attr(miri, ignore)] + #[test] + fn test_roundtrip_okhwb_oklab_is_original() { + let colors = [ + ( + "red", + Oklab::from_color_unclamped(LinSrgb::new(1.0, 0.0, 0.0)), + ), + ( + "green", + Oklab::from_color_unclamped(LinSrgb::new(0.0, 1.0, 0.0)), + ), + ( + "cyan", + Oklab::from_color_unclamped(LinSrgb::new(0.0, 1.0, 1.0)), + ), + ( + "magenta", + Oklab::from_color_unclamped(LinSrgb::new(1.0, 0.0, 1.0)), + ), + ( + "white", + Oklab::from_color_unclamped(LinSrgb::new(1.0, 1.0, 1.0)), + ), + ( + "black", + Oklab::from_color_unclamped(LinSrgb::new(0.0, 0.0, 0.0)), + ), + ( + "grey", + Oklab::from_color_unclamped(LinSrgb::new(0.5, 0.5, 0.5)), + ), + ( + "yellow", + Oklab::from_color_unclamped(LinSrgb::new(1.0, 1.0, 0.0)), + ), + ( + "blue", + Oklab::from_color_unclamped(LinSrgb::new(0.0, 0.0, 1.0)), + ), + ]; + + const EPSILON: f64 = 1e-14; + + for (name, color) in colors { + let rgb: Rgb = + crate::Srgb::::from_color_unclamped(color).into_format(); + println!( + "\n\ + roundtrip of {} (#{:x} / {:?})\n\ + =================================================", + name, rgb, color + ); + + let okhsv = Okhsv::from_color_unclamped(color); + println!("Okhsv: {:?}", okhsv); + let okhwb_from_okhsv = Okhwb::from_color_unclamped(okhsv); + let okhwb = Okhwb::from_color_unclamped(color); + println!("Okhwb: {:?}", okhwb); + assert!( Okhwb::visually_eq(okhwb, okhwb_from_okhsv, EPSILON), "Okhwb \n{:?} is not visually equal to Okhwb from Okhsv \n{:?}\nwithin EPSILON {}", okhwb, okhwb_from_okhsv, EPSILON ); - let okhsv_from_okhwb = Okhsv::from_color_unclamped(okhwb); - assert!( + let okhsv_from_okhwb = Okhsv::from_color_unclamped(okhwb); + assert!( Okhsv::visually_eq(okhsv, okhsv_from_okhwb, EPSILON), "Okhsv \n{:?} is not visually equal to Okhsv from Okhsv from Okhwb \n{:?}\nwithin EPSILON {}", okhsv, okhsv_from_okhwb, EPSILON ); - let roundtrip_color = Oklab::from_color_unclamped(okhwb); - let oklab_from_okhsv = Oklab::from_color_unclamped(okhsv); - assert!( - Oklab::visually_eq(roundtrip_color, oklab_from_okhsv, EPSILON), - "roundtrip color \n{:?} does not match \n{:?}\nwithin EPSILON {}", - roundtrip_color, - oklab_from_okhsv, - EPSILON - ); - assert!( - Oklab::visually_eq(roundtrip_color, color, EPSILON), - "'{}' failed.\n\ + let roundtrip_color = Oklab::from_color_unclamped(okhwb); + let oklab_from_okhsv = Oklab::from_color_unclamped(okhsv); + assert!( + Oklab::visually_eq(roundtrip_color, oklab_from_okhsv, EPSILON), + "roundtrip color \n{:?} does not match \n{:?}\nwithin EPSILON {}", + roundtrip_color, + oklab_from_okhsv, + EPSILON + ); + assert!( + Oklab::visually_eq(roundtrip_color, color, EPSILON), + "'{}' failed.\n\ {:?}\n\ !=\n\ \n{:?}\n", - name, - roundtrip_color, - color - ); + name, + roundtrip_color, + color + ); + } } } @@ -284,6 +289,7 @@ mod tests { ); mod alpha { + #[cfg(feature = "alloc")] use crate::okhwb::Okhwba; struct_of_arrays_tests!( diff --git a/palette/src/oklab.rs b/palette/src/oklab.rs index fe4368cc4..e63948f08 100644 --- a/palette/src/oklab.rs +++ b/palette/src/oklab.rs @@ -536,118 +536,127 @@ unsafe impl bytemuck::Pod for Oklab where T: bytemuck::Pod {} #[cfg(test)] mod test { - use core::str::FromStr; + use crate::Oklab; - use crate::rgb::Rgb; - use crate::visual::VisuallyEqual; - use crate::{FromColor, Lab, LinSrgb, Srgb}; + test_convert_into_from_xyz!(Oklab); - use super::*; + #[cfg(feature = "approx")] + mod conversion { + use core::str::FromStr; - test_convert_into_from_xyz!(Oklab); + use crate::{ + convert::FromColorUnclamped, rgb::Rgb, visual::VisuallyEqual, white_point::D65, + FromColor, Lab, LinSrgb, Oklab, Srgb, + }; - /// Asserts that, for any color space, the lightness of pure white is converted to `l == 1.0` - #[test] - fn lightness_of_white_is_one() { - let rgb: Srgb = Rgb::from_str("#ffffff").unwrap().into_format(); - let lin_rgb = LinSrgb::from_color_unclamped(rgb); - let oklab = Oklab::from_color_unclamped(lin_rgb); - println!("white {rgb:?} == {oklab:?}"); - assert_abs_diff_eq!(oklab.l, 1.0, epsilon = 1e-7); - assert_abs_diff_eq!(oklab.a, 0.0, epsilon = 1e-7); - assert_abs_diff_eq!(oklab.b, 0.0, epsilon = 1e-7); - - let lab: Lab = Lab::from_components((100.0, 0.0, 0.0)); - let rgb: Srgb = Srgb::from_color_unclamped(lab); - let oklab = Oklab::from_color_unclamped(lab); - println!("white {lab:?} == {rgb:?} == {oklab:?}"); - assert_abs_diff_eq!(oklab.l, 1.0, epsilon = 1e-4); - assert_abs_diff_eq!(oklab.a, 0.0, epsilon = 1e-4); - assert_abs_diff_eq!(oklab.b, 0.0, epsilon = 1e-4); - } + /// Asserts that, for any color space, the lightness of pure white is converted to `l == 1.0` + #[test] + fn lightness_of_white_is_one() { + let rgb: Srgb = Rgb::from_str("#ffffff").unwrap().into_format(); + let lin_rgb = LinSrgb::from_color_unclamped(rgb); + let oklab = Oklab::from_color_unclamped(lin_rgb); + println!("white {rgb:?} == {oklab:?}"); + assert_abs_diff_eq!(oklab.l, 1.0, epsilon = 1e-7); + assert_abs_diff_eq!(oklab.a, 0.0, epsilon = 1e-7); + assert_abs_diff_eq!(oklab.b, 0.0, epsilon = 1e-7); + + let lab: Lab = Lab::from_components((100.0, 0.0, 0.0)); + let rgb: Srgb = Srgb::from_color_unclamped(lab); + let oklab = Oklab::from_color_unclamped(lab); + println!("white {lab:?} == {rgb:?} == {oklab:?}"); + assert_abs_diff_eq!(oklab.l, 1.0, epsilon = 1e-4); + assert_abs_diff_eq!(oklab.a, 0.0, epsilon = 1e-4); + assert_abs_diff_eq!(oklab.b, 0.0, epsilon = 1e-4); + } - #[test] - fn blue_srgb() { - // use f64 to be comparable to javascript - let rgb: Srgb = Rgb::from_str("#0000ff").unwrap().into_format(); - let lin_rgb = LinSrgb::from_color_unclamped(rgb); - let oklab = Oklab::from_color_unclamped(lin_rgb); - - // values from Ok Color Picker, which seems to use Björn Ottosson's original - // algorithm (from the direct srgb2oklab conversion, not via the XYZ color space) - assert!(abs_diff_eq!(oklab.l, 0.4520137183853429, epsilon = 1e-9)); - assert!(abs_diff_eq!(oklab.a, -0.03245698416876397, epsilon = 1e-9)); - assert!(abs_diff_eq!(oklab.b, -0.3115281476783751, epsilon = 1e-9)); - } + #[test] + fn blue_srgb() { + // use f64 to be comparable to javascript + let rgb: Srgb = Rgb::from_str("#0000ff").unwrap().into_format(); + let lin_rgb = LinSrgb::from_color_unclamped(rgb); + let oklab = Oklab::from_color_unclamped(lin_rgb); + + // values from Ok Color Picker, which seems to use Björn Ottosson's original + // algorithm (from the direct srgb2oklab conversion, not via the XYZ color space) + assert_abs_diff_eq!(oklab.l, 0.4520137183853429, epsilon = 1e-9); + assert_abs_diff_eq!(oklab.a, -0.03245698416876397, epsilon = 1e-9); + assert_abs_diff_eq!(oklab.b, -0.3115281476783751, epsilon = 1e-9); + } - #[test] - fn red() { - let a = Oklab::from_color(LinSrgb::new(1.0, 0.0, 0.0)); - // from https://github.com/bottosson/bottosson.github.io/blob/master/misc/ok_color.h - let b = Oklab::new(0.6279553606145516, 0.22486306106597395, 0.1258462985307351); - assert!(Oklab::visually_eq(a, b, 1e-8)); - } + #[test] + fn red() { + let a = Oklab::from_color(LinSrgb::new(1.0, 0.0, 0.0)); + // from https://github.com/bottosson/bottosson.github.io/blob/master/misc/ok_color.h + let b = Oklab::new(0.6279553606145516, 0.22486306106597395, 0.1258462985307351); + assert!(Oklab::visually_eq(a, b, 1e-8)); + } - #[test] - fn green() { - let a = Oklab::from_color(LinSrgb::new(0.0, 1.0, 0.0)); - // from https://github.com/bottosson/bottosson.github.io/blob/master/misc/ok_color.h - let b = Oklab::new( - 0.8664396115356694, - -0.23388757418790812, - 0.17949847989672985, - ); - assert!(Oklab::visually_eq(a, b, 1e-8)); - } + #[test] + fn green() { + let a = Oklab::from_color(LinSrgb::new(0.0, 1.0, 0.0)); + // from https://github.com/bottosson/bottosson.github.io/blob/master/misc/ok_color.h + let b = Oklab::new( + 0.8664396115356694, + -0.23388757418790812, + 0.17949847989672985, + ); + assert!(Oklab::visually_eq(a, b, 1e-8)); + } - #[test] - fn blue() { - let a = Oklab::from_color(LinSrgb::new(0.0, 0.0, 1.0)); - println!("Oklab blue: {:?}", a); - // from https://github.com/bottosson/bottosson.github.io/blob/master/misc/ok_color.h - let b = Oklab::new(0.4520137183853429, -0.0324569841687640, -0.3115281476783751); - assert!(Oklab::visually_eq(a, b, 1e-8)); + #[test] + fn blue() { + let a = Oklab::from_color(LinSrgb::new(0.0, 0.0, 1.0)); + println!("Oklab blue: {:?}", a); + // from https://github.com/bottosson/bottosson.github.io/blob/master/misc/ok_color.h + let b = Oklab::new(0.4520137183853429, -0.0324569841687640, -0.3115281476783751); + assert!(Oklab::visually_eq(a, b, 1e-8)); + } } - #[test] - fn black_eq_different_black() { - assert!(Oklab::visually_eq( - Oklab::new(0.0, 1.0, 0.0), - Oklab::new(0.0, 0.0, 1.0), - 1e-8 - )); - } + #[cfg(feature = "approx")] + mod visually_eq { + use crate::{visual::VisuallyEqual, Oklab}; + + #[test] + fn black_eq_different_black() { + assert!(Oklab::visually_eq( + Oklab::new(0.0, 1.0, 0.0), + Oklab::new(0.0, 0.0, 1.0), + 1e-8 + )); + } - #[test] - fn white_eq_different_white() { - assert!(Oklab::visually_eq( - Oklab::new(1.0, 1.0, 0.0), - Oklab::new(1.0, 0.0, 1.0), - 1e-8 - )); - } + #[test] + fn white_eq_different_white() { + assert!(Oklab::visually_eq( + Oklab::new(1.0, 1.0, 0.0), + Oklab::new(1.0, 0.0, 1.0), + 1e-8 + )); + } - #[test] - fn white_ne_black() { - assert!(!Oklab::visually_eq( - Oklab::new(1.0, 1.0, 0.0), - Oklab::new(0.0, 0.0, 1.0), - 1e-8 - )); - assert!(!Oklab::visually_eq( - Oklab::new(1.0, 1.0, 0.0), - Oklab::new(0.0, 1.0, 0.0), - 1e-8 - )); - } + #[test] + fn white_ne_black() { + assert!(!Oklab::visually_eq( + Oklab::new(1.0, 1.0, 0.0), + Oklab::new(0.0, 0.0, 1.0), + 1e-8 + )); + assert!(!Oklab::visually_eq( + Oklab::new(1.0, 1.0, 0.0), + Oklab::new(0.0, 1.0, 0.0), + 1e-8 + )); + } - #[test] - fn non_bw_neq_different_non_bw() { - assert!(!Oklab::visually_eq( - Oklab::new(0.3, 1.0, 0.0), - Oklab::new(0.3, 0.0, 1.0), - 1e-8 - )); + #[test] + fn non_bw_neq_different_non_bw() { + assert!(!Oklab::visually_eq( + Oklab::new(0.3, 1.0, 0.0), + Oklab::new(0.3, 0.0, 1.0), + 1e-8 + )); + } } #[test] @@ -677,6 +686,7 @@ mod test { ); mod alpha { + #[cfg(feature = "alloc")] use crate::oklab::Oklaba; struct_of_arrays_tests!( diff --git a/palette/src/oklab/random.rs b/palette/src/oklab/random.rs index 0b1405c74..4d3349e42 100644 --- a/palette/src/oklab/random.rs +++ b/palette/src/oklab/random.rs @@ -1,4 +1,4 @@ -use std::ops::{Add, Mul, Sub}; +use core::ops::{Add, Mul, Sub}; use crate::{num::One, Oklab}; diff --git a/palette/src/oklch.rs b/palette/src/oklch.rs index 7f9f2b679..69b696a06 100644 --- a/palette/src/oklch.rs +++ b/palette/src/oklch.rs @@ -150,79 +150,84 @@ unsafe impl bytemuck::Pod for Oklch where T: bytemuck::Pod {} #[cfg(test)] mod test { - use crate::convert::FromColorUnclamped; - use crate::rgb::Rgb; - use crate::visual::{VisualColor, VisuallyEqual}; - use crate::{encoding, LinSrgb, Oklab, Oklch}; + use crate::Oklch; test_convert_into_from_xyz!(Oklch); - #[cfg_attr(miri, ignore)] - #[test] - fn test_roundtrip_oklch_oklab_is_original() { - let colors = [ - ( - "red", - Oklab::from_color_unclamped(LinSrgb::new(1.0, 0.0, 0.0)), - ), - ( - "green", - Oklab::from_color_unclamped(LinSrgb::new(0.0, 1.0, 0.0)), - ), - ( - "cyan", - Oklab::from_color_unclamped(LinSrgb::new(0.0, 1.0, 1.0)), - ), - ( - "magenta", - Oklab::from_color_unclamped(LinSrgb::new(1.0, 0.0, 1.0)), - ), - ( - "black", - Oklab::from_color_unclamped(LinSrgb::new(0.0, 0.0, 0.0)), - ), - ( - "grey", - Oklab::from_color_unclamped(LinSrgb::new(0.5, 0.5, 0.5)), - ), - ( - "yellow", - Oklab::from_color_unclamped(LinSrgb::new(1.0, 1.0, 0.0)), - ), - ( - "blue", - Oklab::from_color_unclamped(LinSrgb::new(0.0, 0.0, 1.0)), - ), - ( - "white", - Oklab::from_color_unclamped(LinSrgb::new(1.0, 1.0, 1.0)), - ), - ]; - - const EPSILON: f64 = 1e-14; - - for (name, color) in colors { - let rgb: Rgb = - crate::Srgb::::from_color_unclamped(color).into_format(); - println!( - "\n\ - roundtrip of {} (#{:x} / {:?})\n\ - =================================================", - name, rgb, color - ); - - println!("Color is white: {}", color.is_white(EPSILON)); - - let oklch = Oklch::from_color_unclamped(color); - println!("Oklch: {:?}", oklch); - let roundtrip_color = Oklab::from_color_unclamped(oklch); - assert!( - Oklab::visually_eq(roundtrip_color, color, EPSILON), - "'{}' failed.\n{:?}\n!=\n{:?}", - name, - roundtrip_color, - color - ); + #[cfg(feature = "approx")] + mod conversion { + use crate::{ + convert::FromColorUnclamped, + visual::{VisualColor, VisuallyEqual}, + LinSrgb, Oklab, Oklch, Srgb, + }; + + #[cfg_attr(miri, ignore)] + #[test] + fn test_roundtrip_oklch_oklab_is_original() { + let colors = [ + ( + "red", + Oklab::from_color_unclamped(LinSrgb::new(1.0, 0.0, 0.0)), + ), + ( + "green", + Oklab::from_color_unclamped(LinSrgb::new(0.0, 1.0, 0.0)), + ), + ( + "cyan", + Oklab::from_color_unclamped(LinSrgb::new(0.0, 1.0, 1.0)), + ), + ( + "magenta", + Oklab::from_color_unclamped(LinSrgb::new(1.0, 0.0, 1.0)), + ), + ( + "black", + Oklab::from_color_unclamped(LinSrgb::new(0.0, 0.0, 0.0)), + ), + ( + "grey", + Oklab::from_color_unclamped(LinSrgb::new(0.5, 0.5, 0.5)), + ), + ( + "yellow", + Oklab::from_color_unclamped(LinSrgb::new(1.0, 1.0, 0.0)), + ), + ( + "blue", + Oklab::from_color_unclamped(LinSrgb::new(0.0, 0.0, 1.0)), + ), + ( + "white", + Oklab::from_color_unclamped(LinSrgb::new(1.0, 1.0, 1.0)), + ), + ]; + + const EPSILON: f64 = 1e-14; + + for (name, color) in colors { + let rgb: Srgb = Srgb::::from_color_unclamped(color).into_format(); + println!( + "\n\ + roundtrip of {} (#{:x} / {:?})\n\ + =================================================", + name, rgb, color + ); + + println!("Color is white: {}", color.is_white(EPSILON)); + + let oklch = Oklch::from_color_unclamped(color); + println!("Oklch: {:?}", oklch); + let roundtrip_color = Oklab::from_color_unclamped(oklch); + assert!( + Oklab::visually_eq(roundtrip_color, color, EPSILON), + "'{}' failed.\n{:?}\n!=\n{:?}", + name, + roundtrip_color, + color + ); + } } } @@ -243,9 +248,9 @@ mod test { #[test] fn check_min_max_components() { - assert_relative_eq!(Oklch::::min_l(), 0.0); - assert_relative_eq!(Oklch::::max_l(), 1.0); - assert_relative_eq!(Oklch::::min_chroma(), 0.0); + assert_eq!(Oklch::::min_l(), 0.0); + assert_eq!(Oklch::::max_l(), 1.0); + assert_eq!(Oklch::::min_chroma(), 0.0); } #[cfg(feature = "serializing")] @@ -273,6 +278,7 @@ mod test { ); mod alpha { + #[cfg(feature = "alloc")] use crate::oklch::Oklcha; struct_of_arrays_tests!( diff --git a/palette/src/random_sampling/cone.rs b/palette/src/random_sampling/cone.rs index 49f851cae..ea8b3f927 100644 --- a/palette/src/random_sampling/cone.rs +++ b/palette/src/random_sampling/cone.rs @@ -122,7 +122,7 @@ where #[cfg(test)] mod test { - use super::{invert_hsl_sample, sample_hsl, sample_hsv, HslSample, HsvSample}; + use super::{sample_hsl, sample_hsv, HslSample, HsvSample}; #[cfg(feature = "random")] #[test] @@ -161,10 +161,12 @@ mod test { ); } - #[cfg(feature = "random")] + #[cfg(all(feature = "random", feature = "approx"))] #[allow(clippy::excessive_precision)] #[test] fn hsl_sampling() { + use super::invert_hsl_sample; + // Sanity check that sampling and inverting from sample are equivalent macro_rules! test_hsl { ( $x:expr, $y:expr ) => {{ diff --git a/palette/src/relative_contrast.rs b/palette/src/relative_contrast.rs index 1fcc0084c..727fbed98 100644 --- a/palette/src/relative_contrast.rs +++ b/palette/src/relative_contrast.rs @@ -124,6 +124,7 @@ where } } +#[cfg(feature = "approx")] #[cfg(test)] #[allow(deprecated)] mod test { diff --git a/palette/src/rgb/channels.rs b/palette/src/rgb/channels.rs index 95235efd9..1b3d493f2 100644 --- a/palette/src/rgb/channels.rs +++ b/palette/src/rgb/channels.rs @@ -82,6 +82,7 @@ impl ComponentOrder, [T; 4]> for Rgba { } } +#[cfg(feature = "approx")] #[cfg(test)] mod test { use super::{Abgr, Argb, Bgra, Rgba}; diff --git a/palette/src/rgb/rgb.rs b/palette/src/rgb/rgb.rs index 73c9a1c80..fffe63e69 100644 --- a/palette/src/rgb/rgb.rs +++ b/palette/src/rgb/rgb.rs @@ -1489,12 +1489,12 @@ mod test { #[test] fn check_min_max_components() { - assert_relative_eq!(Rgb::::min_red(), 0.0); - assert_relative_eq!(Rgb::::min_green(), 0.0); - assert_relative_eq!(Rgb::::min_blue(), 0.0); - assert_relative_eq!(Rgb::::max_red(), 1.0); - assert_relative_eq!(Rgb::::max_green(), 1.0); - assert_relative_eq!(Rgb::::max_blue(), 1.0); + assert_eq!(Rgb::::min_red(), 0.0); + assert_eq!(Rgb::::min_green(), 0.0); + assert_eq!(Rgb::::min_blue(), 0.0); + assert_eq!(Rgb::::max_red(), 1.0); + assert_eq!(Rgb::::max_green(), 1.0); + assert_eq!(Rgb::::max_blue(), 1.0); } struct_of_arrays_tests!( @@ -1505,6 +1505,7 @@ mod test { ); mod alpha { + #[cfg(feature = "alloc")] use crate::{encoding::Srgb, rgb::Rgba}; struct_of_arrays_tests!( diff --git a/palette/src/stimulus.rs b/palette/src/stimulus.rs index b6be6a00d..ca16919ea 100644 --- a/palette/src/stimulus.rs +++ b/palette/src/stimulus.rs @@ -271,7 +271,6 @@ convert_uint_to_uint!(u128; via f64 (u8, u16, u32, u64);); #[cfg(test)] mod test { use crate::stimulus::IntoStimulus; - use approx::assert_relative_eq; #[test] fn float_to_uint() { @@ -295,11 +294,11 @@ mod test { 1.0, 1.4, f32::from_bits(0x4b44_0000), - std::f32::MAX, - std::f32::MIN, - std::f32::NAN, - std::f32::INFINITY, - std::f32::NEG_INFINITY, + core::f32::MAX, + core::f32::MIN, + core::f32::NAN, + core::f32::INFINITY, + core::f32::NEG_INFINITY, ]; let expected = vec![ @@ -334,11 +333,11 @@ mod test { 1.0, 1.4, f64::from_bits(0x4334_0000_0000_0000), - std::f64::MAX, - std::f64::MIN, - std::f64::NAN, - std::f64::INFINITY, - std::f64::NEG_INFINITY, + core::f64::MAX, + core::f64::MIN, + core::f64::NAN, + core::f64::INFINITY, + core::f64::NEG_INFINITY, ]; let expected = vec![ @@ -351,6 +350,7 @@ mod test { } } + #[cfg(feature = "approx")] #[test] fn uint_to_float() { fn into_stimulus_old(n: u8) -> f32 { @@ -363,6 +363,7 @@ mod test { } } + #[cfg(feature = "approx")] #[test] fn uint_to_double() { fn into_stimulus_old(n: u8) -> f64 { diff --git a/palette/src/xyz.rs b/palette/src/xyz.rs index b79b850c0..f69556542 100644 --- a/palette/src/xyz.rs +++ b/palette/src/xyz.rs @@ -422,7 +422,6 @@ unsafe impl bytemuck::Pod for Xyz where T: bytemuck::Pod mod test { use super::Xyz; use crate::white_point::D65; - use crate::{FromColor, LinLuma, LinSrgb}; #[cfg(feature = "random")] use crate::white_point::WhitePoint; @@ -433,32 +432,37 @@ mod test { test_convert_into_from_xyz!(Xyz); - #[test] - fn luma() { - let a = Xyz::::from_color(LinLuma::new(0.5)); - let b = Xyz::new(0.475235, 0.5, 0.544415); - assert_relative_eq!(a, b, epsilon = 0.0001); - } + #[cfg(feature = "approx")] + mod conversion { + use crate::{white_point::D65, FromColor, LinLuma, LinSrgb, Xyz}; - #[test] - fn red() { - let a = Xyz::from_color(LinSrgb::new(1.0, 0.0, 0.0)); - let b = Xyz::new(0.41240, 0.21260, 0.01930); - assert_relative_eq!(a, b, epsilon = 0.0001); - } + #[test] + fn luma() { + let a = Xyz::::from_color(LinLuma::new(0.5)); + let b = Xyz::new(0.475235, 0.5, 0.544415); + assert_relative_eq!(a, b, epsilon = 0.0001); + } - #[test] - fn green() { - let a = Xyz::from_color(LinSrgb::new(0.0, 1.0, 0.0)); - let b = Xyz::new(0.35760, 0.71520, 0.11920); - assert_relative_eq!(a, b, epsilon = 0.0001); - } + #[test] + fn red() { + let a = Xyz::from_color(LinSrgb::new(1.0, 0.0, 0.0)); + let b = Xyz::new(0.41240, 0.21260, 0.01930); + assert_relative_eq!(a, b, epsilon = 0.0001); + } - #[test] - fn blue() { - let a = Xyz::from_color(LinSrgb::new(0.0, 0.0, 1.0)); - let b = Xyz::new(0.18050, 0.07220, 0.95030); - assert_relative_eq!(a, b, epsilon = 0.0001); + #[test] + fn green() { + let a = Xyz::from_color(LinSrgb::new(0.0, 1.0, 0.0)); + let b = Xyz::new(0.35760, 0.71520, 0.11920); + assert_relative_eq!(a, b, epsilon = 0.0001); + } + + #[test] + fn blue() { + let a = Xyz::from_color(LinSrgb::new(0.0, 0.0, 1.0)); + let b = Xyz::new(0.18050, 0.07220, 0.95030); + assert_relative_eq!(a, b, epsilon = 0.0001); + } } #[test] @@ -480,12 +484,12 @@ mod test { #[test] fn check_min_max_components() { - assert_relative_eq!(Xyz::::min_x(), 0.0); - assert_relative_eq!(Xyz::::min_y(), 0.0); - assert_relative_eq!(Xyz::::min_z(), 0.0); - assert_relative_eq!(Xyz::::max_x(), X_N); - assert_relative_eq!(Xyz::::max_y(), Y_N); - assert_relative_eq!(Xyz::::max_z(), Z_N); + assert_eq!(Xyz::::min_x(), 0.0); + assert_eq!(Xyz::::min_y(), 0.0); + assert_eq!(Xyz::::min_z(), 0.0); + assert_eq!(Xyz::::max_x(), X_N); + assert_eq!(Xyz::::max_y(), Y_N); + assert_eq!(Xyz::::max_z(), Z_N); } struct_of_arrays_tests!( @@ -496,6 +500,7 @@ mod test { ); mod alpha { + #[cfg(feature = "alloc")] use crate::{white_point::D65, xyz::Xyza}; struct_of_arrays_tests!( diff --git a/palette/src/yxy.rs b/palette/src/yxy.rs index 7f0951ebd..515ac64bb 100644 --- a/palette/src/yxy.rs +++ b/palette/src/yxy.rs @@ -298,36 +298,40 @@ unsafe impl bytemuck::Pod for Yxy where T: bytemuck::Pod mod test { use super::Yxy; use crate::white_point::D65; - use crate::{FromColor, LinLuma, LinSrgb}; test_convert_into_from_xyz!(Yxy); - #[test] - fn luma() { - let a = Yxy::::from_color(LinLuma::new(0.5)); - let b = Yxy::new(0.312727, 0.329023, 0.5); - assert_relative_eq!(a, b, epsilon = 0.000001); - } + #[cfg(feature = "approx")] + mod conversion { + use crate::{white_point::D65, FromColor, LinLuma, LinSrgb, Yxy}; - #[test] - fn red() { - let a = Yxy::from_color(LinSrgb::new(1.0, 0.0, 0.0)); - let b = Yxy::new(0.64, 0.33, 0.212673); - assert_relative_eq!(a, b, epsilon = 0.000001); - } + #[test] + fn luma() { + let a = Yxy::::from_color(LinLuma::new(0.5)); + let b = Yxy::new(0.312727, 0.329023, 0.5); + assert_relative_eq!(a, b, epsilon = 0.000001); + } - #[test] - fn green() { - let a = Yxy::from_color(LinSrgb::new(0.0, 1.0, 0.0)); - let b = Yxy::new(0.3, 0.6, 0.715152); - assert_relative_eq!(a, b, epsilon = 0.000001); - } + #[test] + fn red() { + let a = Yxy::from_color(LinSrgb::new(1.0, 0.0, 0.0)); + let b = Yxy::new(0.64, 0.33, 0.212673); + assert_relative_eq!(a, b, epsilon = 0.000001); + } - #[test] - fn blue() { - let a = Yxy::from_color(LinSrgb::new(0.0, 0.0, 1.0)); - let b = Yxy::new(0.15, 0.06, 0.072175); - assert_relative_eq!(a, b, epsilon = 0.000001); + #[test] + fn green() { + let a = Yxy::from_color(LinSrgb::new(0.0, 1.0, 0.0)); + let b = Yxy::new(0.3, 0.6, 0.715152); + assert_relative_eq!(a, b, epsilon = 0.000001); + } + + #[test] + fn blue() { + let a = Yxy::from_color(LinSrgb::new(0.0, 0.0, 1.0)); + let b = Yxy::new(0.15, 0.06, 0.072175); + assert_relative_eq!(a, b, epsilon = 0.000001); + } } #[test] @@ -349,12 +353,12 @@ mod test { #[test] fn check_min_max_components() { - assert_relative_eq!(Yxy::::min_x(), 0.0); - assert_relative_eq!(Yxy::::min_y(), 0.0); - assert_relative_eq!(Yxy::::min_luma(), 0.0); - assert_relative_eq!(Yxy::::max_x(), 1.0); - assert_relative_eq!(Yxy::::max_y(), 1.0); - assert_relative_eq!(Yxy::::max_luma(), 1.0); + assert_eq!(Yxy::::min_x(), 0.0); + assert_eq!(Yxy::::min_y(), 0.0); + assert_eq!(Yxy::::min_luma(), 0.0); + assert_eq!(Yxy::::max_x(), 1.0); + assert_eq!(Yxy::::max_y(), 1.0); + assert_eq!(Yxy::::max_luma(), 1.0); } struct_of_arrays_tests!( @@ -365,6 +369,7 @@ mod test { ); mod alpha { + #[cfg(feature = "alloc")] use crate::{white_point::D65, yxy::Yxya}; struct_of_arrays_tests!( diff --git a/scripts/id_rsa.enc b/scripts/id_rsa.enc deleted file mode 100644 index 195bd7b79..000000000 Binary files a/scripts/id_rsa.enc and /dev/null differ diff --git a/scripts/test_features.sh b/scripts/test_features.sh deleted file mode 100644 index 06d8e0def..000000000 --- a/scripts/test_features.sh +++ /dev/null @@ -1,45 +0,0 @@ -set -e - -#List of features to test -features="" - -#Features that will always be activated -required_features="std approx" - - -#Find features -walking_features=false -current_dependency="" - -while read -r line || [[ -n "$line" ]]; do - if [[ "$line" == "[features]" ]]; then - walking_features=true - elif [[ $walking_features == true ]] && [[ "$line" == "#ignore in feature test" ]]; then - walking_features=false - elif [[ $walking_features == true ]] && echo "$line" | grep -E "^\[.*\]" > /dev/null; then - walking_features=false - elif [[ $walking_features == true ]] && echo "$line" | grep -E ".*=.*" > /dev/null; then - feature="$(echo "$line" | cut -f1 -d"=")" - feature="$(echo -e "${feature}" | tr -d '[[:space:]]')" - if [[ "$feature" != "default" ]]; then - features="$features $feature" - fi - elif echo "$line" | grep -E "^\[dependencies\..*\]" > /dev/null; then - current_dependency="$(echo "$line" | sed 's/.*\[dependencies\.\([^]]*\)\].*/\1/g')" - elif [[ "$line" == "#feature" ]] && [[ "$current_dependency" != "" ]]; then - echo "found dependency feature '$current_dependency'" - features="$features $current_dependency" - fi -done < "Cargo.toml" - -echo -e "features: $features\n" - -#Test without any optional feature -echo testing with --no-default-features --features "$required_features" -cargo test --tests --no-default-features --features "$required_features" - -#Isolated test of each optional feature -for feature in $features; do - echo testing with --no-default-features --features "\"$feature $required_features\"" - cargo test --tests --no-default-features --features "$feature $required_features" -done