From 07e45348cfded7e467ce0e2d1e6a95aa3a13f5ee Mon Sep 17 00:00:00 2001 From: Mark Barbone Date: Sun, 24 Jun 2018 23:10:53 -0400 Subject: [PATCH 01/16] `std` feature added; tests don't work on `no_std` yet though --- palette/Cargo.toml | 6 ++++-- palette/build/named.rs | 2 +- palette/examples/readme_examples.rs | 7 ++++++- palette/src/alpha.rs | 8 ++++---- palette/src/blend/pre_alpha.rs | 2 +- palette/src/convert.rs | 8 ++++---- palette/src/encoding/gamma.rs | 2 +- palette/src/encoding/linear.rs | 2 +- palette/src/encoding/pixel/mod.rs | 16 ++++++++-------- palette/src/encoding/pixel/raw.rs | 4 ++-- palette/src/gradient.rs | 3 +++ palette/src/hsl.rs | 6 +++--- palette/src/hsv.rs | 6 +++--- palette/src/hues.rs | 6 +++--- palette/src/hwb.rs | 6 +++--- palette/src/lab.rs | 4 ++-- palette/src/lch.rs | 4 ++-- palette/src/lib.rs | 17 ++++++++++++----- palette/src/luma/luma.rs | 10 +++++----- palette/src/matrix.rs | 2 +- palette/src/rgb/mod.rs | 2 +- palette/src/rgb/rgb.rs | 12 ++++++------ palette/src/xyz.rs | 4 ++-- palette/src/yxy.rs | 4 ++-- 24 files changed, 80 insertions(+), 63 deletions(-) diff --git a/palette/Cargo.toml b/palette/Cargo.toml index a9a799d6b..aacd02bfb 100644 --- a/palette/Cargo.toml +++ b/palette/Cargo.toml @@ -13,16 +13,17 @@ license = "MIT OR Apache-2.0" build = "build/main.rs" [features] -default = ["named_from_str"] +default = ["named_from_str", "std"] named_from_str = ["named", "phf", "phf_codegen"] named = [] +std = ["num-traits/std", "serde/std"] #internal strict = [] [dependencies] palette_derive = {version = "0.4.0", path = "../palette_derive"} -num-traits = "0.2" +num-traits = {version = "0.2", default-features = false} approx = "0.2" [dependencies.phf] @@ -32,6 +33,7 @@ optional = true [dependencies.serde] #feature version = "1" +default-features = false features = ["serde_derive"] optional = true diff --git a/palette/build/named.rs b/palette/build/named.rs index 83e93b586..306c899d2 100644 --- a/palette/build/named.rs +++ b/palette/build/named.rs @@ -32,7 +32,7 @@ pub fn build() { .expect(&format!("couldn't get blue for {}", name)); writeln!(writer, "\n///
", name).unwrap(); - writeln!(writer, "pub const {}: ::rgb::Srgb = ::rgb::Srgb {{ red: {}, green: {}, blue: {}, standard: ::std::marker::PhantomData }};", name.to_uppercase(), red, green, blue).unwrap(); + writeln!(writer, "pub const {}: ::rgb::Srgb = ::rgb::Srgb {{ red: {}, green: {}, blue: {}, standard: ::core::marker::PhantomData }};", name.to_uppercase(), red, green, blue).unwrap(); entries.push((name.to_owned(), name.to_uppercase())); } diff --git a/palette/examples/readme_examples.rs b/palette/examples/readme_examples.rs index 905ba26e5..d588f56a9 100644 --- a/palette/examples/readme_examples.rs +++ b/palette/examples/readme_examples.rs @@ -4,7 +4,9 @@ extern crate palette; use image::{GenericImage, RgbImage}; -use palette::{Gradient, LinSrgb, Mix, Pixel, Srgb}; +use palette::{LinSrgb, Mix, Pixel, Srgb}; +#[cfg(feature = "std")] +use palette::Gradient; mod color_spaces { use palette::{Hue, Lch, LinSrgb, Srgb}; @@ -44,6 +46,7 @@ mod manipulation { } } +#[cfg(feature = "std")] mod gradients { use palette::{Gradient, Hsv, LinSrgb}; use display_gradients; @@ -81,6 +84,7 @@ fn display_colors(filename: &str, colors: &[Srgb]) { } } +#[cfg(feature = "std")] fn display_gradients + Clone, B: Mix + Clone>( filename: &str, grad1: Gradient, @@ -127,5 +131,6 @@ fn display_gradients + Clone, B: Mix + Clone> fn main() { color_spaces::run(); manipulation::run(); + #[cfg(feature = "std")] gradients::run(); } diff --git a/palette/src/alpha.rs b/palette/src/alpha.rs index fe0f20120..4fc13e6cc 100644 --- a/palette/src/alpha.rs +++ b/palette/src/alpha.rs @@ -1,5 +1,5 @@ -use std::ops::{Add, Deref, DerefMut, Div, Mul, Sub}; -use std::fmt; +use core::ops::{Add, Deref, DerefMut, Div, Mul, Sub}; +use core::fmt; use num_traits::Float; @@ -338,7 +338,7 @@ where C: fmt::LowerHex, { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let size = f.width().unwrap_or(::std::mem::size_of::() * 2); + let size = f.width().unwrap_or(::core::mem::size_of::() * 2); write!( f, "{:0width$x}{:0width$x}", @@ -355,7 +355,7 @@ where C: fmt::UpperHex, { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let size = f.width().unwrap_or(::std::mem::size_of::() * 2); + let size = f.width().unwrap_or(::core::mem::size_of::() * 2); write!( f, "{:0width$X}{:0width$X}", diff --git a/palette/src/blend/pre_alpha.rs b/palette/src/blend/pre_alpha.rs index ac1338eb7..a9fb4e5ec 100644 --- a/palette/src/blend/pre_alpha.rs +++ b/palette/src/blend/pre_alpha.rs @@ -1,4 +1,4 @@ -use std::ops::{Add, Deref, DerefMut, Div, Mul, Sub}; +use core::ops::{Add, Deref, DerefMut, Div, Mul, Sub}; use approx::{AbsDiffEq, RelativeEq, UlpsEq}; use num_traits::Float; diff --git a/palette/src/convert.rs b/palette/src/convert.rs index 29b055ae0..69a4db53d 100644 --- a/palette/src/convert.rs +++ b/palette/src/convert.rs @@ -1,7 +1,6 @@ use num_traits::Float; -use std::error::Error; -use std::fmt::{self, Debug, Display, Formatter}; +use core::fmt::{self, Display, Formatter}; use {Component, Limited, Hsl, Hsv, Hwb, Lab, Lch, Xyz, Yxy}; use white_point::{D65, WhitePoint}; use rgb::{Rgb, RgbSpace}; @@ -521,7 +520,8 @@ impl OutOfBounds { } } -impl Error for OutOfBounds { +#[cfg(feature = "std")] +impl ::std::error::Error for OutOfBounds { fn description(&self) -> &str { "Color conversion is out of bounds" } @@ -761,7 +761,7 @@ impl_into_color_rgb!(Hwb, from_hwb); #[cfg(test)] mod tests { - use std::marker::PhantomData; + use core::marker::PhantomData; use num_traits::Float; use Component; use Linear; diff --git a/palette/src/encoding/gamma.rs b/palette/src/encoding/gamma.rs index 900da9877..a027e1df0 100644 --- a/palette/src/encoding/gamma.rs +++ b/palette/src/encoding/gamma.rs @@ -1,6 +1,6 @@ //! Gamma encoding. -use std::marker::PhantomData; +use core::marker::PhantomData; use num_traits::Float; diff --git a/palette/src/encoding/linear.rs b/palette/src/encoding/linear.rs index 255b46b11..01ccb9f34 100644 --- a/palette/src/encoding/linear.rs +++ b/palette/src/encoding/linear.rs @@ -1,6 +1,6 @@ //! Linear encoding -use std::marker::PhantomData; +use core::marker::PhantomData; use num_traits::Float; use rgb::{RgbSpace, RgbStandard}; diff --git a/palette/src/encoding/pixel/mod.rs b/palette/src/encoding/pixel/mod.rs index 63c8cfe75..cfd396969 100644 --- a/palette/src/encoding/pixel/mod.rs +++ b/palette/src/encoding/pixel/mod.rs @@ -124,13 +124,13 @@ pub unsafe trait Pixel: Sized { #[inline] fn into_raw>(self) -> P { assert_eq!(P::CHANNELS, Self::CHANNELS); - assert_eq!(::std::mem::size_of::

(), ::std::mem::size_of::()); - assert_eq!(::std::mem::align_of::

(), ::std::mem::align_of::()); + assert_eq!(::core::mem::size_of::

(), ::core::mem::size_of::()); + assert_eq!(::core::mem::align_of::

(), ::core::mem::align_of::()); - let converted = unsafe { ::std::ptr::read(&self as *const Self as *const P) }; + let converted = unsafe { ::core::ptr::read(&self as *const Self as *const P) }; // Just to be sure... - ::std::mem::forget(self); + ::core::mem::forget(self); converted } @@ -168,7 +168,7 @@ pub unsafe trait Pixel: Sized { fn from_raw_slice(slice: &[T]) -> &[Self] { assert_eq!(slice.len() % Self::CHANNELS, 0); let new_length = slice.len() / Self::CHANNELS; - unsafe { ::std::slice::from_raw_parts(slice.as_ptr() as *const Self, new_length) } + unsafe { ::core::slice::from_raw_parts(slice.as_ptr() as *const Self, new_length) } } /// Cast a mutable slice of raw color components to a mutable slice of colors. @@ -193,7 +193,7 @@ pub unsafe trait Pixel: Sized { fn from_raw_slice_mut(slice: &mut [T]) -> &mut [Self] { assert_eq!(slice.len() % Self::CHANNELS, 0); let new_length = slice.len() / Self::CHANNELS; - unsafe { ::std::slice::from_raw_parts_mut(slice.as_mut_ptr() as *mut Self, new_length) } + unsafe { ::core::slice::from_raw_parts_mut(slice.as_mut_ptr() as *mut Self, new_length) } } /// Cast a slice of colors to a slice of raw color components. @@ -210,7 +210,7 @@ pub unsafe trait Pixel: Sized { #[inline] fn into_raw_slice(slice: &[Self]) -> &[T] { let new_length = slice.len() * Self::CHANNELS; - unsafe { ::std::slice::from_raw_parts(slice.as_ptr() as *const T, new_length) } + unsafe { ::core::slice::from_raw_parts(slice.as_ptr() as *const T, new_length) } } /// Cast a mutable slice of colors to a mutable slice of raw color components. @@ -234,6 +234,6 @@ pub unsafe trait Pixel: Sized { #[inline] fn into_raw_slice_mut(slice: &mut [Self]) -> &mut [T] { let new_length = slice.len() * Self::CHANNELS; - unsafe { ::std::slice::from_raw_parts_mut(slice.as_mut_ptr() as *mut T, new_length) } + unsafe { ::core::slice::from_raw_parts_mut(slice.as_mut_ptr() as *mut T, new_length) } } } diff --git a/palette/src/encoding/pixel/raw.rs b/palette/src/encoding/pixel/raw.rs index 3389fb348..b1945b097 100644 --- a/palette/src/encoding/pixel/raw.rs +++ b/palette/src/encoding/pixel/raw.rs @@ -81,12 +81,12 @@ unsafe impl RawPixel for [T] { #[inline] unsafe fn from_raw_parts<'a>(pointer: *const T, length: usize) -> &'a Self { - ::std::slice::from_raw_parts(pointer, length) + ::core::slice::from_raw_parts(pointer, length) } #[inline] unsafe fn from_raw_parts_mut<'a>(pointer: *mut T, length: usize) -> &'a mut Self { - ::std::slice::from_raw_parts_mut(pointer, length) + ::core::slice::from_raw_parts_mut(pointer, length) } #[inline] diff --git a/palette/src/gradient.rs b/palette/src/gradient.rs index bffadbc86..a274b24c2 100644 --- a/palette/src/gradient.rs +++ b/palette/src/gradient.rs @@ -1,4 +1,7 @@ //!Types for interpolation between multiple colors. +//! +//!This module is only available if the `std` feature is enabled (this is the +//!default). use num_traits::{Float, One, Zero}; use std::cmp::max; diff --git a/palette/src/hsl.rs b/palette/src/hsl.rs index 325b7f35f..a41dc56bd 100644 --- a/palette/src/hsl.rs +++ b/palette/src/hsl.rs @@ -1,9 +1,9 @@ use approx::{AbsDiffEq, RelativeEq, UlpsEq}; use num_traits::Float; -use std::any::TypeId; -use std::marker::PhantomData; -use std::ops::{Add, Sub}; +use core::any::TypeId; +use core::marker::PhantomData; +use core::ops::{Add, Sub}; use encoding::pixel::RawPixel; use encoding::{Linear, Srgb}; diff --git a/palette/src/hsv.rs b/palette/src/hsv.rs index 0a1de52a2..97beb64c4 100644 --- a/palette/src/hsv.rs +++ b/palette/src/hsv.rs @@ -1,9 +1,9 @@ use approx::{AbsDiffEq, RelativeEq, UlpsEq}; use num_traits::Float; -use std::any::TypeId; -use std::marker::PhantomData; -use std::ops::{Add, Sub}; +use core::any::TypeId; +use core::marker::PhantomData; +use core::ops::{Add, Sub}; use encoding::pixel::RawPixel; use encoding::{Linear, Srgb}; diff --git a/palette/src/hues.rs b/palette/src/hues.rs index 7839f3232..c48130336 100644 --- a/palette/src/hues.rs +++ b/palette/src/hues.rs @@ -1,8 +1,8 @@ use num_traits::Float; -use std::f64::consts::PI; -use std::cmp::PartialEq; -use std::ops::{Add, Sub}; +use core::f64::consts::PI; +use core::cmp::PartialEq; +use core::ops::{Add, Sub}; use cast; diff --git a/palette/src/hwb.rs b/palette/src/hwb.rs index c8ada0428..6f216f979 100644 --- a/palette/src/hwb.rs +++ b/palette/src/hwb.rs @@ -1,9 +1,9 @@ use approx::{AbsDiffEq, RelativeEq, UlpsEq}; use num_traits::Float; -use std::any::TypeId; -use std::marker::PhantomData; -use std::ops::{Add, Sub}; +use core::any::TypeId; +use core::marker::PhantomData; +use core::ops::{Add, Sub}; use encoding::pixel::RawPixel; use encoding::Srgb; diff --git a/palette/src/lab.rs b/palette/src/lab.rs index a3f58d3d9..c97b73e15 100644 --- a/palette/src/lab.rs +++ b/palette/src/lab.rs @@ -1,7 +1,7 @@ use num_traits::Float; -use std::marker::PhantomData; -use std::ops::{Add, Div, Mul, Sub}; +use core::marker::PhantomData; +use core::ops::{Add, Div, Mul, Sub}; use encoding::pixel::RawPixel; use white_point::{D65, WhitePoint}; diff --git a/palette/src/lch.rs b/palette/src/lch.rs index c869efc93..df5199087 100644 --- a/palette/src/lch.rs +++ b/palette/src/lch.rs @@ -1,7 +1,7 @@ use num_traits::Float; -use std::marker::PhantomData; -use std::ops::{Add, Sub}; +use core::marker::PhantomData; +use core::ops::{Add, Sub}; use encoding::pixel::RawPixel; use white_point::{D65, WhitePoint}; diff --git a/palette/src/lib.rs b/palette/src/lib.rs index fa1a9431e..3d5aa1538 100644 --- a/palette/src/lib.rs +++ b/palette/src/lib.rs @@ -135,10 +135,15 @@ //! process reversed. //! +#![cfg_attr(not(feature = "std"), no_std)] + #![doc(html_root_url = "https://docs.rs/palette/0.4.0/palette/")] #![cfg_attr(feature = "strict", deny(missing_docs))] #![cfg_attr(feature = "strict", deny(warnings))] +#[cfg(feature = "std")] +extern crate core; + #[cfg_attr(test, macro_use)] extern crate approx; @@ -170,6 +175,7 @@ pub use palette_derive::*; pub use alpha::Alpha; pub use blend::Blend; +#[cfg(feature = "std")] pub use gradient::Gradient; pub use hsl::{Hsl, Hsla}; @@ -203,7 +209,7 @@ macro_rules! assert_ranges { unlimited {$($unlimited:ident: $unlimited_from:expr => $unlimited_to:expr),*} ) => ( { - use std::iter::repeat; + use core::iter::repeat; use Limited; { @@ -342,6 +348,7 @@ macro_rules! assert_ranges { mod macros; pub mod blend; +#[cfg(feature = "std")] pub mod gradient; #[cfg(feature = "named")] @@ -867,7 +874,7 @@ impl Component for u8 { const LIMITED: bool = true; fn max_intensity() -> Self { - std::u8::MAX + core::u8::MAX } fn convert(&self) -> T { @@ -886,7 +893,7 @@ impl Component for u16 { const LIMITED: bool = true; fn max_intensity() -> Self { - std::u16::MAX + core::u16::MAX } fn convert(&self) -> T { @@ -905,7 +912,7 @@ impl Component for u32 { const LIMITED: bool = true; fn max_intensity() -> Self { - std::u32::MAX + core::u32::MAX } fn convert(&self) -> T { @@ -924,7 +931,7 @@ impl Component for u64 { const LIMITED: bool = true; fn max_intensity() -> Self { - std::u64::MAX + core::u64::MAX } fn convert(&self) -> T { diff --git a/palette/src/luma/luma.rs b/palette/src/luma/luma.rs index bef0cb8fd..470753082 100644 --- a/palette/src/luma/luma.rs +++ b/palette/src/luma/luma.rs @@ -1,6 +1,6 @@ -use std::fmt; -use std::marker::PhantomData; -use std::ops::{Add, Div, Mul, Sub}; +use core::fmt; +use core::marker::PhantomData; +use core::ops::{Add, Div, Mul, Sub}; use approx::{AbsDiffEq, RelativeEq, UlpsEq}; @@ -611,7 +611,7 @@ where S: LumaStandard, { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let size = f.width().unwrap_or(::std::mem::size_of::() * 2); + let size = f.width().unwrap_or(::core::mem::size_of::() * 2); write!(f, "{:0width$x}", self.luma, width = size) } } @@ -622,7 +622,7 @@ where S: LumaStandard, { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let size = f.width().unwrap_or(::std::mem::size_of::() * 2); + let size = f.width().unwrap_or(::core::mem::size_of::() * 2); write!(f, "{:0width$X}", self.luma, width = size) } } diff --git a/palette/src/matrix.rs b/palette/src/matrix.rs index a0ddc9681..9343baac8 100644 --- a/palette/src/matrix.rs +++ b/palette/src/matrix.rs @@ -3,7 +3,7 @@ use num_traits::Float; -use std::marker::PhantomData; +use core::marker::PhantomData; use {Component, Xyz}; use white_point::WhitePoint; diff --git a/palette/src/rgb/mod.rs b/palette/src/rgb/mod.rs index 384cefa72..a4d7dcc3e 100644 --- a/palette/src/rgb/mod.rs +++ b/palette/src/rgb/mod.rs @@ -1,7 +1,7 @@ //!RGB types, spaces and standards. use num_traits::Float; -use std::any::Any; +use core::any::Any; use {Component, Yxy}; use white_point::WhitePoint; diff --git a/palette/src/rgb/rgb.rs b/palette/src/rgb/rgb.rs index e74c6fcf4..0dff40c42 100644 --- a/palette/src/rgb/rgb.rs +++ b/palette/src/rgb/rgb.rs @@ -1,7 +1,7 @@ -use std::any::TypeId; -use std::fmt; -use std::marker::PhantomData; -use std::ops::{Add, Div, Mul, Sub}; +use core::any::TypeId; +use core::fmt; +use core::marker::PhantomData; +use core::ops::{Add, Div, Mul, Sub}; use approx::{AbsDiffEq, RelativeEq, UlpsEq}; use num_traits::Float; @@ -827,7 +827,7 @@ where S: RgbStandard, { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let size = f.width().unwrap_or(::std::mem::size_of::() * 2); + let size = f.width().unwrap_or(::core::mem::size_of::() * 2); write!( f, "{:0width$x}{:0width$x}{:0width$x}", @@ -845,7 +845,7 @@ where S: RgbStandard, { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let size = f.width().unwrap_or(::std::mem::size_of::() * 2); + let size = f.width().unwrap_or(::core::mem::size_of::() * 2); write!( f, "{:0width$X}{:0width$X}{:0width$X}", diff --git a/palette/src/xyz.rs b/palette/src/xyz.rs index 6f3e0bf31..66e393e92 100644 --- a/palette/src/xyz.rs +++ b/palette/src/xyz.rs @@ -1,7 +1,7 @@ use num_traits::Float; -use std::marker::PhantomData; -use std::ops::{Add, Div, Mul, Sub}; +use core::marker::PhantomData; +use core::ops::{Add, Div, Mul, Sub}; use encoding::pixel::RawPixel; use luma::LumaStandard; diff --git a/palette/src/yxy.rs b/palette/src/yxy.rs index 57eabb2a3..ef0f76b64 100644 --- a/palette/src/yxy.rs +++ b/palette/src/yxy.rs @@ -1,7 +1,7 @@ use num_traits::Float; -use std::marker::PhantomData; -use std::ops::{Add, Div, Mul, Sub}; +use core::marker::PhantomData; +use core::ops::{Add, Div, Mul, Sub}; use clamp; use encoding::pixel::RawPixel; From 9f7285405a2b055eedf208b335939d0982ac503d Mon Sep 17 00:00:00 2001 From: Mark Barbone Date: Mon, 25 Jun 2018 15:16:27 -0400 Subject: [PATCH 02/16] Further work on adding #![no_std] support, including a floating point hack --- palette/Cargo.toml | 4 +- palette/src/alpha.rs | 2 +- palette/src/blend/blend.rs | 4 +- palette/src/blend/equations.rs | 3 +- palette/src/blend/mod.rs | 2 +- palette/src/blend/pre_alpha.rs | 2 +- palette/src/chromatic_adaptation.rs | 2 +- palette/src/convert.rs | 4 +- palette/src/encoding/gamma.rs | 2 +- palette/src/encoding/linear.rs | 2 +- palette/src/encoding/mod.rs | 2 +- palette/src/encoding/srgb.rs | 2 +- palette/src/equality.rs | 2 +- palette/src/float.rs | 117 +++++++++++++++++++++++++++ palette/src/gradient.rs | 4 +- palette/src/hsl.rs | 2 +- palette/src/hsv.rs | 2 +- palette/src/hues.rs | 2 +- palette/src/hwb.rs | 2 +- palette/src/lab.rs | 2 +- palette/src/lch.rs | 2 +- palette/src/lib.rs | 6 +- palette/src/luma/luma.rs | 2 +- palette/src/matrix.rs | 2 +- palette/src/rgb/mod.rs | 2 +- palette/src/rgb/rgb.rs | 2 +- palette/src/white_point.rs | 2 +- palette/src/xyz.rs | 2 +- palette/src/yxy.rs | 2 +- palette_derive/src/convert/shared.rs | 2 +- palette_derive/src/util.rs | 2 + 31 files changed, 159 insertions(+), 31 deletions(-) create mode 100644 palette/src/float.rs diff --git a/palette/Cargo.toml b/palette/Cargo.toml index aacd02bfb..5ef8ecf0e 100644 --- a/palette/Cargo.toml +++ b/palette/Cargo.toml @@ -16,7 +16,7 @@ build = "build/main.rs" default = ["named_from_str", "std"] named_from_str = ["named", "phf", "phf_codegen"] named = [] -std = ["num-traits/std", "serde/std"] +std = ["num-traits/std", "serde/std", "approx/std"] #internal strict = [] @@ -24,7 +24,7 @@ strict = [] [dependencies] palette_derive = {version = "0.4.0", path = "../palette_derive"} num-traits = {version = "0.2", default-features = false} -approx = "0.2" +approx = {version = "0.2", default-features = false} [dependencies.phf] version = "0.7" diff --git a/palette/src/alpha.rs b/palette/src/alpha.rs index 4fc13e6cc..819131d16 100644 --- a/palette/src/alpha.rs +++ b/palette/src/alpha.rs @@ -1,7 +1,7 @@ use core::ops::{Add, Deref, DerefMut, Div, Mul, Sub}; use core::fmt; -use num_traits::Float; +use float::Float; use approx::{AbsDiffEq, RelativeEq, UlpsEq}; diff --git a/palette/src/blend/blend.rs b/palette/src/blend/blend.rs index d67eb1803..b42c9d599 100644 --- a/palette/src/blend/blend.rs +++ b/palette/src/blend/blend.rs @@ -1,4 +1,6 @@ -use num_traits::{Float, One, Zero}; +use num_traits::{One, Zero}; +use float::Float; +use num_traits::float::FloatCore; use {cast, clamp, ComponentWise}; use blend::{BlendFunction, PreAlpha}; diff --git a/palette/src/blend/equations.rs b/palette/src/blend/equations.rs index 5e267f6e2..eb65880fd 100644 --- a/palette/src/blend/equations.rs +++ b/palette/src/blend/equations.rs @@ -1,4 +1,5 @@ -use num_traits::Float; +use float::Float; +use num_traits::float::FloatCore; use {Blend, ComponentWise}; use blend::{BlendFunction, PreAlpha}; diff --git a/palette/src/blend/mod.rs b/palette/src/blend/mod.rs index 72c1b15c0..d675dde9e 100644 --- a/palette/src/blend/mod.rs +++ b/palette/src/blend/mod.rs @@ -36,7 +36,7 @@ //!which may result in loss of some color information in some cases. One such //!case is that a completely transparent resultant color will become black. -use num_traits::Float; +use float::Float; use ComponentWise; diff --git a/palette/src/blend/pre_alpha.rs b/palette/src/blend/pre_alpha.rs index a9fb4e5ec..e595ce17d 100644 --- a/palette/src/blend/pre_alpha.rs +++ b/palette/src/blend/pre_alpha.rs @@ -1,6 +1,6 @@ use core::ops::{Add, Deref, DerefMut, Div, Mul, Sub}; use approx::{AbsDiffEq, RelativeEq, UlpsEq}; -use num_traits::Float; +use float::Float; use {clamp, Alpha, Blend, ComponentWise, Mix, Pixel}; use encoding::pixel::RawPixel; diff --git a/palette/src/chromatic_adaptation.rs b/palette/src/chromatic_adaptation.rs index be2a84263..ef8488cfa 100644 --- a/palette/src/chromatic_adaptation.rs +++ b/palette/src/chromatic_adaptation.rs @@ -22,7 +22,7 @@ //!//Should print {x: 0.257963, y: 0.139776,z: 0.058825} //!println!("{:?}", c) //!``` -use num_traits::Float; +use float::Float; use {cast, Component, FromColor, IntoColor, Xyz}; use white_point::WhitePoint; diff --git a/palette/src/convert.rs b/palette/src/convert.rs index 69a4db53d..acaefa874 100644 --- a/palette/src/convert.rs +++ b/palette/src/convert.rs @@ -1,4 +1,4 @@ -use num_traits::Float; +use float::Float; use core::fmt::{self, Display, Formatter}; use {Component, Limited, Hsl, Hsv, Hwb, Lab, Lch, Xyz, Yxy}; @@ -762,7 +762,7 @@ impl_into_color_rgb!(Hwb, from_hwb); #[cfg(test)] mod tests { use core::marker::PhantomData; - use num_traits::Float; + use num_traits::float::FloatCore as Float; use Component; use Linear; use rgb::{Rgb, RgbSpace}; diff --git a/palette/src/encoding/gamma.rs b/palette/src/encoding/gamma.rs index a027e1df0..e270167dd 100644 --- a/palette/src/encoding/gamma.rs +++ b/palette/src/encoding/gamma.rs @@ -2,7 +2,7 @@ use core::marker::PhantomData; -use num_traits::Float; +use float::Float; use cast; use rgb::{RgbSpace, RgbStandard}; diff --git a/palette/src/encoding/linear.rs b/palette/src/encoding/linear.rs index 01ccb9f34..28fbea974 100644 --- a/palette/src/encoding/linear.rs +++ b/palette/src/encoding/linear.rs @@ -2,7 +2,7 @@ use core::marker::PhantomData; -use num_traits::Float; +use float::Float; use rgb::{RgbSpace, RgbStandard}; use luma::LumaStandard; use encoding::TransferFn; diff --git a/palette/src/encoding/mod.rs b/palette/src/encoding/mod.rs index 244bdc92f..a8ebba26f 100644 --- a/palette/src/encoding/mod.rs +++ b/palette/src/encoding/mod.rs @@ -1,6 +1,6 @@ //! Various encoding traits, types and standards. -use num_traits::Float; +use float::Float; pub use self::srgb::Srgb; pub use self::gamma::{F2p2, Gamma}; diff --git a/palette/src/encoding/srgb.rs b/palette/src/encoding/srgb.rs index efb5dd8df..522a8ede1 100644 --- a/palette/src/encoding/srgb.rs +++ b/palette/src/encoding/srgb.rs @@ -1,6 +1,6 @@ //! The sRGB standard. -use num_traits::Float; +use float::Float; use rgb::{Primaries, RgbSpace, RgbStandard}; use luma::LumaStandard; diff --git a/palette/src/equality.rs b/palette/src/equality.rs index 5e6a57439..95de209dd 100644 --- a/palette/src/equality.rs +++ b/palette/src/equality.rs @@ -1,4 +1,4 @@ -use num_traits::Float; +use float::Float; use approx::{AbsDiffEq, RelativeEq, UlpsEq}; diff --git a/palette/src/float.rs b/palette/src/float.rs new file mode 100644 index 000000000..15ad4bfa9 --- /dev/null +++ b/palette/src/float.rs @@ -0,0 +1,117 @@ +//!Floating point traits +//! +//!This module is work-around for the lack of floating point operations under `#![no_std]`. If you +//!haven't disabled the `std` feature, it shouldn't affect you. +//! +//!Because conversions between different color encodings requrire floating point functions such as +//!`powf`, `sin`, `cos`, etc. which are unavailable without the standard library, it looks for +//!externally linked symbols that implement these functions. +//! +//!These external functions are needed without the standard library: +//!```rust +//!extern "C" { +//! // The square root of `x` +//! // Should be compatible with `x.sqrt()` from the standard library +//! fn sqrtf32(x: f32) -> f32; +//! fn sqrtf64(x: f64) -> f64; +//! // `x` to the power of `y` +//! // Should be compatible with `x.powf(y)` from the standard library +//! fn powf32(x: f32, y: f32) -> f32; +//! fn powf64(x: f64, y: f64) -> f64; +//! // The sine of `x` radians +//! // Should be compatible with `x.sin()` from the standard library +//! fn sinf32(x: f32) -> f32; +//! fn sinf64(x: f64) -> f64; +//! // The cosine of `x` radians +//! // Should be compatible with `x.cos()` from the standard library +//! fn cosf32(x: f32) -> f32; +//! fn cosf64(x: f64) -> f64; +//! // Inverse tangent +//! // Should be compatible with `y.atan2(x)` from the standard library +//! fn atan2f32(y: f32, x: f32) -> f32; +//! fn atan2f64(y: f64, x: f64) -> f64; +//!} +//!``` +//! +//!There are different ways to deal with it: +//! * Implement it yourself +//! * Use `core::intrinsics` +//! * Provide interfaces to a different math library (e.g. Julia's `libm`) +//! * Don't use the features that need these functions and enable LTO (this is not guaranteed to be +//! stable between patch releases) + +#[cfg(feature = "std")] +pub use num_traits::Float; + +#[cfg(not(feature = "std"))] +pub use self::no_std_float_hack::Float; + +#[cfg(not(feature = "std"))] +mod no_std_float_hack { + pub trait Float: ::num_traits::float::FloatCore { + fn sqrt(self) -> Self; + fn powf(self, other: Self) -> Self; + fn sin(self) -> Self; + fn cos(self) -> Self; + fn atan2(self, other: Self) -> Self; + } + + extern "C" { + // The square root of `x` + // Should be compatible with `x.sqrt()` from the standard library + fn sqrtf32(x: f32) -> f32; + fn sqrtf64(x: f64) -> f64; + // `x` to the power of `y` + // Should be compatible with `x.powf(y)` from the standard library + fn powf32(x: f32, y: f32) -> f32; + fn powf64(x: f64, y: f64) -> f64; + // The sine of `x` radians + // Should be compatible with `x.sin()` from the standard library + fn sinf32(x: f32) -> f32; + fn sinf64(x: f64) -> f64; + // The cosine of `x` radians + // Should be compatible with `x.cos()` from the standard library + fn cosf32(x: f32) -> f32; + fn cosf64(x: f64) -> f64; + // Inverse tangent + // Should be compatible with `y.atan2(x)` from the standard library + fn atan2f32(y: f32, x: f32) -> f32; + fn atan2f64(y: f64, x: f64) -> f64; + } + + impl Float for f32 { + fn sqrt(self) -> f32 { + unsafe { sqrtf32(self) } + } + fn powf(self, other: f32) -> f32 { + unsafe { powf32(self, other) } + } + fn sin(self) -> f32 { + unsafe { sinf32(self) } + } + fn cos(self) -> f32 { + unsafe { cosf32(self) } + } + fn atan2(self, other: f32) -> f32 { + unsafe { atan2f32(self, other) } + } + } + + impl Float for f64 { + fn sqrt(self) -> f64 { + unsafe { sqrtf64(self) } + } + fn powf(self, other: f64) -> f64 { + unsafe { powf64(self, other) } + } + fn sin(self) -> f64 { + unsafe { sinf64(self) } + } + fn cos(self) -> f64 { + unsafe { cosf64(self) } + } + fn atan2(self, other: f64) -> f64 { + unsafe { atan2f64(self, other) } + } + } +} diff --git a/palette/src/gradient.rs b/palette/src/gradient.rs index a274b24c2..ac8d5d6ab 100644 --- a/palette/src/gradient.rs +++ b/palette/src/gradient.rs @@ -3,7 +3,9 @@ //!This module is only available if the `std` feature is enabled (this is the //!default). -use num_traits::{Float, One, Zero}; +use num_traits::{One, Zero}; +use float::Float; +use num_traits::float::FloatCore; use std::cmp::max; use approx::{AbsDiffEq, RelativeEq, UlpsEq}; diff --git a/palette/src/hsl.rs b/palette/src/hsl.rs index a41dc56bd..01deb6b0d 100644 --- a/palette/src/hsl.rs +++ b/palette/src/hsl.rs @@ -1,5 +1,5 @@ use approx::{AbsDiffEq, RelativeEq, UlpsEq}; -use num_traits::Float; +use float::Float; use core::any::TypeId; use core::marker::PhantomData; diff --git a/palette/src/hsv.rs b/palette/src/hsv.rs index 97beb64c4..abe174a90 100644 --- a/palette/src/hsv.rs +++ b/palette/src/hsv.rs @@ -1,5 +1,5 @@ use approx::{AbsDiffEq, RelativeEq, UlpsEq}; -use num_traits::Float; +use float::Float; use core::any::TypeId; use core::marker::PhantomData; diff --git a/palette/src/hues.rs b/palette/src/hues.rs index c48130336..8fc9a1c1d 100644 --- a/palette/src/hues.rs +++ b/palette/src/hues.rs @@ -1,4 +1,4 @@ -use num_traits::Float; +use float::Float; use core::f64::consts::PI; use core::cmp::PartialEq; diff --git a/palette/src/hwb.rs b/palette/src/hwb.rs index 6f216f979..5c9e75b3e 100644 --- a/palette/src/hwb.rs +++ b/palette/src/hwb.rs @@ -1,5 +1,5 @@ use approx::{AbsDiffEq, RelativeEq, UlpsEq}; -use num_traits::Float; +use float::Float; use core::any::TypeId; use core::marker::PhantomData; diff --git a/palette/src/lab.rs b/palette/src/lab.rs index c97b73e15..d31be695c 100644 --- a/palette/src/lab.rs +++ b/palette/src/lab.rs @@ -1,4 +1,4 @@ -use num_traits::Float; +use float::Float; use core::marker::PhantomData; use core::ops::{Add, Div, Mul, Sub}; diff --git a/palette/src/lch.rs b/palette/src/lch.rs index df5199087..288b9fb6e 100644 --- a/palette/src/lch.rs +++ b/palette/src/lch.rs @@ -1,4 +1,4 @@ -use num_traits::Float; +use float::Float; use core::marker::PhantomData; use core::ops::{Add, Sub}; diff --git a/palette/src/lib.rs b/palette/src/lib.rs index 3d5aa1538..50ff791d3 100644 --- a/palette/src/lib.rs +++ b/palette/src/lib.rs @@ -161,7 +161,8 @@ extern crate serde; #[cfg(all(test, feature = "serde"))] extern crate serde_json; -use num_traits::{Float, NumCast, ToPrimitive, Zero}; +use num_traits::{NumCast, ToPrimitive, Zero}; +use float::Float; use approx::{AbsDiffEq, RelativeEq, UlpsEq}; @@ -344,6 +345,7 @@ macro_rules! assert_ranges { ); } + #[macro_use] mod macros; @@ -374,6 +376,8 @@ mod equality; mod matrix; pub mod white_point; +pub mod float; + macro_rules! make_color { ($( #[$variant_comment:meta] diff --git a/palette/src/luma/luma.rs b/palette/src/luma/luma.rs index 470753082..bcaf4f8e1 100644 --- a/palette/src/luma/luma.rs +++ b/palette/src/luma/luma.rs @@ -4,7 +4,7 @@ use core::ops::{Add, Div, Mul, Sub}; use approx::{AbsDiffEq, RelativeEq, UlpsEq}; -use num_traits::Float; +use float::Float; use blend::PreAlpha; use clamp; diff --git a/palette/src/matrix.rs b/palette/src/matrix.rs index 9343baac8..afc7d9b29 100644 --- a/palette/src/matrix.rs +++ b/palette/src/matrix.rs @@ -1,7 +1,7 @@ //!This module provides simple matrix operations on 3x3 matrix to aid in chromatic adaptation and //!conversion calculations. -use num_traits::Float; +use float::Float; use core::marker::PhantomData; diff --git a/palette/src/rgb/mod.rs b/palette/src/rgb/mod.rs index a4d7dcc3e..5fe5832f9 100644 --- a/palette/src/rgb/mod.rs +++ b/palette/src/rgb/mod.rs @@ -1,6 +1,6 @@ //!RGB types, spaces and standards. -use num_traits::Float; +use float::Float; use core::any::Any; use {Component, Yxy}; diff --git a/palette/src/rgb/rgb.rs b/palette/src/rgb/rgb.rs index 0dff40c42..b40c27dfd 100644 --- a/palette/src/rgb/rgb.rs +++ b/palette/src/rgb/rgb.rs @@ -4,7 +4,7 @@ use core::marker::PhantomData; use core::ops::{Add, Div, Mul, Sub}; use approx::{AbsDiffEq, RelativeEq, UlpsEq}; -use num_traits::Float; +use float::Float; use alpha::Alpha; use blend::PreAlpha; diff --git a/palette/src/white_point.rs b/palette/src/white_point.rs index 5c61210f6..ff0c412c7 100644 --- a/palette/src/white_point.rs +++ b/palette/src/white_point.rs @@ -6,7 +6,7 @@ //! unacceptable results when attempting to color-correct a photograph taken with incandescent //! lighting. -use num_traits::Float; +use float::Float; use {cast, Component, Xyz}; diff --git a/palette/src/xyz.rs b/palette/src/xyz.rs index 66e393e92..3ff3a9d1e 100644 --- a/palette/src/xyz.rs +++ b/palette/src/xyz.rs @@ -1,4 +1,4 @@ -use num_traits::Float; +use float::Float; use core::marker::PhantomData; use core::ops::{Add, Div, Mul, Sub}; diff --git a/palette/src/yxy.rs b/palette/src/yxy.rs index ef0f76b64..78083627c 100644 --- a/palette/src/yxy.rs +++ b/palette/src/yxy.rs @@ -1,4 +1,4 @@ -use num_traits::Float; +use float::Float; use core::marker::PhantomData; use core::ops::{Add, Div, Mul, Sub}; diff --git a/palette_derive/src/convert/shared.rs b/palette_derive/src/convert/shared.rs index aabfd559f..eed1b7bef 100644 --- a/palette_derive/src/convert/shared.rs +++ b/palette_derive/src/convert/shared.rs @@ -82,7 +82,7 @@ pub fn add_component_where_clause(component: &Type, generics: &mut Generics, int generics .make_where_clause() .predicates - .push(parse_quote!(#component: #component_trait_path + _num_traits::Float)); + .push(parse_quote!(#component: #component_trait_path + _FloatTrait)); } pub fn add_white_point_where_clause(white_point: &Type, generics: &mut Generics, internal: bool) { diff --git a/palette_derive/src/util.rs b/palette_derive/src/util.rs index dcdbb3e29..903d73a34 100644 --- a/palette_derive/src/util.rs +++ b/palette_derive/src/util.rs @@ -17,6 +17,7 @@ pub fn bundle_impl( #[allow(non_snake_case, unused_attributes, unused_qualifications)] mod #const_name { extern crate num_traits as _num_traits; + use float::Float as _FloatTrait; use super::#type_name; #block } @@ -27,6 +28,7 @@ pub fn bundle_impl( mod #const_name { extern crate palette as _palette; extern crate num_traits as _num_traits; + use _palette::float::Float as _FloatTrait; use super::#type_name; #block } From 64ab2de329ac828277ef4a153ab692d76e72774f Mon Sep 17 00:00:00 2001 From: Mark Barbone Date: Mon, 25 Jun 2018 15:53:31 -0400 Subject: [PATCH 03/16] WIP `no_std` support -- some small cleanup --- palette/src/blend/equations.rs | 1 + palette/src/convert.rs | 2 +- palette/src/gradient.rs | 1 - 3 files changed, 2 insertions(+), 2 deletions(-) diff --git a/palette/src/blend/equations.rs b/palette/src/blend/equations.rs index eb65880fd..86b576550 100644 --- a/palette/src/blend/equations.rs +++ b/palette/src/blend/equations.rs @@ -1,4 +1,5 @@ use float::Float; +#[cfg(not(feature = "std"))] use num_traits::float::FloatCore; use {Blend, ComponentWise}; diff --git a/palette/src/convert.rs b/palette/src/convert.rs index acaefa874..e441bf69e 100644 --- a/palette/src/convert.rs +++ b/palette/src/convert.rs @@ -762,7 +762,7 @@ impl_into_color_rgb!(Hwb, from_hwb); #[cfg(test)] mod tests { use core::marker::PhantomData; - use num_traits::float::FloatCore as Float; + use float::Float; use Component; use Linear; use rgb::{Rgb, RgbSpace}; diff --git a/palette/src/gradient.rs b/palette/src/gradient.rs index ac8d5d6ab..504e097b9 100644 --- a/palette/src/gradient.rs +++ b/palette/src/gradient.rs @@ -5,7 +5,6 @@ use num_traits::{One, Zero}; use float::Float; -use num_traits::float::FloatCore; use std::cmp::max; use approx::{AbsDiffEq, RelativeEq, UlpsEq}; From fe2273acc39a257dc2bd2a38f723782644dc9e04 Mon Sep 17 00:00:00 2001 From: Mark Barbone Date: Mon, 25 Jun 2018 22:24:19 -0400 Subject: [PATCH 04/16] Changed `#![no_std]` api to use floating point functions from `mish` and `m` --- palette/Cargo.toml | 4 +- palette/src/blend/blend.rs | 1 + palette/src/float.rs | 87 ++++++++------------------------------ palette/src/lib.rs | 5 +++ 4 files changed, 27 insertions(+), 70 deletions(-) diff --git a/palette/Cargo.toml b/palette/Cargo.toml index 5ef8ecf0e..0d6774b21 100644 --- a/palette/Cargo.toml +++ b/palette/Cargo.toml @@ -14,7 +14,7 @@ build = "build/main.rs" [features] default = ["named_from_str", "std"] -named_from_str = ["named", "phf", "phf_codegen"] +named_from_str = ["named", "phf", "phf_codegen", "std"] named = [] std = ["num-traits/std", "serde/std", "approx/std"] @@ -25,6 +25,8 @@ strict = [] palette_derive = {version = "0.4.0", path = "../palette_derive"} num-traits = {version = "0.2", default-features = false} approx = {version = "0.2", default-features = false} +mish = {version = "0.2"} +m = {version = "0.1"} [dependencies.phf] version = "0.7" diff --git a/palette/src/blend/blend.rs b/palette/src/blend/blend.rs index b42c9d599..111c3669b 100644 --- a/palette/src/blend/blend.rs +++ b/palette/src/blend/blend.rs @@ -1,5 +1,6 @@ use num_traits::{One, Zero}; use float::Float; +#[cfg(not(feature = "std"))] use num_traits::float::FloatCore; use {cast, clamp, ComponentWise}; diff --git a/palette/src/float.rs b/palette/src/float.rs index 15ad4bfa9..bebc44afa 100644 --- a/palette/src/float.rs +++ b/palette/src/float.rs @@ -1,44 +1,13 @@ //!Floating point traits //! //!This module is work-around for the lack of floating point operations under `#![no_std]`. If you -//!haven't disabled the `std` feature, it shouldn't affect you. +//!haven't disabled the `std` feature, it just re-exports `num_traits::Float`. //! -//!Because conversions between different color encodings requrire floating point functions such as -//!`powf`, `sin`, `cos`, etc. which are unavailable without the standard library, it looks for -//!externally linked symbols that implement these functions. +//!However, without `std`, it's a custom trait that's implemented for `f32` and `f64` using the +//!`mish` and `m` crates. //! -//!These external functions are needed without the standard library: -//!```rust -//!extern "C" { -//! // The square root of `x` -//! // Should be compatible with `x.sqrt()` from the standard library -//! fn sqrtf32(x: f32) -> f32; -//! fn sqrtf64(x: f64) -> f64; -//! // `x` to the power of `y` -//! // Should be compatible with `x.powf(y)` from the standard library -//! fn powf32(x: f32, y: f32) -> f32; -//! fn powf64(x: f64, y: f64) -> f64; -//! // The sine of `x` radians -//! // Should be compatible with `x.sin()` from the standard library -//! fn sinf32(x: f32) -> f32; -//! fn sinf64(x: f64) -> f64; -//! // The cosine of `x` radians -//! // Should be compatible with `x.cos()` from the standard library -//! fn cosf32(x: f32) -> f32; -//! fn cosf64(x: f64) -> f64; -//! // Inverse tangent -//! // Should be compatible with `y.atan2(x)` from the standard library -//! fn atan2f32(y: f32, x: f32) -> f32; -//! fn atan2f64(y: f64, x: f64) -> f64; -//!} -//!``` -//! -//!There are different ways to deal with it: -//! * Implement it yourself -//! * Use `core::intrinsics` -//! * Provide interfaces to a different math library (e.g. Julia's `libm`) -//! * Don't use the features that need these functions and enable LTO (this is not guaranteed to be -//! stable between patch releases) +//!Because new floating point functions may be needed in patch releases, the specifics of which +//!operations are included in the trait are semver-exempt on `no_std`. #[cfg(feature = "std")] pub use num_traits::Float; @@ -48,6 +17,9 @@ pub use self::no_std_float_hack::Float; #[cfg(not(feature = "std"))] mod no_std_float_hack { + use m; + use mish; + pub trait Float: ::num_traits::float::FloatCore { fn sqrt(self) -> Self; fn powf(self, other: Self) -> Self; @@ -56,62 +28,39 @@ mod no_std_float_hack { fn atan2(self, other: Self) -> Self; } - extern "C" { - // The square root of `x` - // Should be compatible with `x.sqrt()` from the standard library - fn sqrtf32(x: f32) -> f32; - fn sqrtf64(x: f64) -> f64; - // `x` to the power of `y` - // Should be compatible with `x.powf(y)` from the standard library - fn powf32(x: f32, y: f32) -> f32; - fn powf64(x: f64, y: f64) -> f64; - // The sine of `x` radians - // Should be compatible with `x.sin()` from the standard library - fn sinf32(x: f32) -> f32; - fn sinf64(x: f64) -> f64; - // The cosine of `x` radians - // Should be compatible with `x.cos()` from the standard library - fn cosf32(x: f32) -> f32; - fn cosf64(x: f64) -> f64; - // Inverse tangent - // Should be compatible with `y.atan2(x)` from the standard library - fn atan2f32(y: f32, x: f32) -> f32; - fn atan2f64(y: f64, x: f64) -> f64; - } - impl Float for f32 { fn sqrt(self) -> f32 { - unsafe { sqrtf32(self) } + mish::sqrt(self) } fn powf(self, other: f32) -> f32 { - unsafe { powf32(self, other) } + mish::powf(self, other) } fn sin(self) -> f32 { - unsafe { sinf32(self) } + mish::sin(self) } fn cos(self) -> f32 { - unsafe { cosf32(self) } + mish::cos(self) } fn atan2(self, other: f32) -> f32 { - unsafe { atan2f32(self, other) } + ::atan2(self, other) } } impl Float for f64 { fn sqrt(self) -> f64 { - unsafe { sqrtf64(self) } + mish::sqrt(self) } fn powf(self, other: f64) -> f64 { - unsafe { powf64(self, other) } + mish::powf(self, other) } fn sin(self) -> f64 { - unsafe { sinf64(self) } + mish::sin(self) } fn cos(self) -> f64 { - unsafe { cosf64(self) } + mish::cos(self) } fn atan2(self, other: f64) -> f64 { - unsafe { atan2f64(self, other) } + ::atan2(self, other) } } } diff --git a/palette/src/lib.rs b/palette/src/lib.rs index 50ff791d3..f5c5589ba 100644 --- a/palette/src/lib.rs +++ b/palette/src/lib.rs @@ -152,6 +152,11 @@ extern crate palette_derive; extern crate num_traits; +#[cfg(not(feature = "std"))] +extern crate m; +#[cfg(not(feature = "std"))] +extern crate mish; + #[cfg(feature = "phf")] extern crate phf; From df60673fcf190d215371c7299fb322222d9efedc Mon Sep 17 00:00:00 2001 From: Mark Barbone Date: Mon, 25 Jun 2018 22:28:25 -0400 Subject: [PATCH 05/16] [WIP no_std] Fixed some tests --- palette_derive/src/util.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/palette_derive/src/util.rs b/palette_derive/src/util.rs index 903d73a34..3b73914f6 100644 --- a/palette_derive/src/util.rs +++ b/palette_derive/src/util.rs @@ -28,7 +28,7 @@ pub fn bundle_impl( mod #const_name { extern crate palette as _palette; extern crate num_traits as _num_traits; - use _palette::float::Float as _FloatTrait; + use self::_palette::float::Float as _FloatTrait; use super::#type_name; #block } From 59f3248ca5e77498b60df7049163dc6bc570a5a9 Mon Sep 17 00:00:00 2001 From: Mark Barbone Date: Mon, 9 Jul 2018 13:02:51 -0400 Subject: [PATCH 06/16] [WIP no_std] Fixed warnings coming from deriving Pixel --- palette_derive/src/util.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/palette_derive/src/util.rs b/palette_derive/src/util.rs index 3b73914f6..7a1f8f947 100644 --- a/palette_derive/src/util.rs +++ b/palette_derive/src/util.rs @@ -14,9 +14,8 @@ pub fn bundle_impl( if internal { quote!{ - #[allow(non_snake_case, unused_attributes, unused_qualifications)] + #[allow(non_snake_case, unused_attributes, unused_qualifications, unused_imports)] mod #const_name { - extern crate num_traits as _num_traits; use float::Float as _FloatTrait; use super::#type_name; #block @@ -24,10 +23,9 @@ pub fn bundle_impl( } } else { quote!{ - #[allow(non_snake_case, unused_attributes, unused_qualifications)] + #[allow(non_snake_case, unused_attributes, unused_qualifications, unused_imports)] mod #const_name { extern crate palette as _palette; - extern crate num_traits as _num_traits; use self::_palette::float::Float as _FloatTrait; use super::#type_name; #block From ee3c2b787aab84a8352f52bebe6b7604ee40d2a8 Mon Sep 17 00:00:00 2001 From: Mark Barbone Date: Mon, 9 Jul 2018 13:43:36 -0400 Subject: [PATCH 07/16] Implement "soft_float" feature and add README note about no_std --- README.md | 34 +++++++++- palette/Cargo.toml | 6 +- palette/src/float.rs | 151 ++++++++++++++++++++++++++++++++++++++----- palette/src/lib.rs | 5 -- 4 files changed, 172 insertions(+), 24 deletions(-) diff --git a/README.md b/README.md index 0cfe55424..f36769e49 100644 --- a/README.md +++ b/README.md @@ -20,16 +20,29 @@ Add the following lines to your `Cargo.toml` file: palette = "0.4" ``` -### Optional Features +### Features These features are enabled by default: * `"named"` - Enables color constants, located in the `named` module. -* `"named_from_str"` - Enables the `named::from_str`, which maps name string to colors. +* `"named_from_str"` - Enables the `named::from_str`, which maps name string to colors. This requires the standard library. +* `"std"` - Enables use of the standard library. These features are disabled by default: * `"serde"` - Enables color serializing and deserializing. +* `"soft_float"` - Without the standard library, this enables use of software floating-point libraries for certain floating point operations. + +### Without the standard library + +Here is an example `Cargo.toml` entry for using palette on `#![no_std]`: + +```toml +[dependencies.palette] +version = "0.4" +default-feature = false +features = ["soft_float"] +``` ## It's Never "Just RGB" @@ -113,6 +126,23 @@ This library is only meant for color manipulation and conversion. It's not a ful [pixel_module]: https://ogeon.github.io/docs/palette/master/palette/pixel/index.html +## Using palette in an embedded environment + +Palette supports `#![no_std]` environments by disabling the `"std"` feature. However, there are some things that are unavailable without the standard library: + +* Gradients are unavailable, because they depend heavily on Vectors +* The `"named_from_str"` feature requires the standard library as well +* Floating point operations must be provided by the library user + +### Floating-point operations + +Converting colors requires a lot of floating-point math on the colors, such as trigonometry for HSV, exponents for gamma-correction, etc. These operations are typically provided by the standard library, and aren't available in an embedded environment. Because of this, a library user has two options for supplying the necessary functions: + +* If you enable the `"soft_float"` feature, software implementations will be used. This comes with the caveat that it's potentially slower and less precise than otherwise. +* Without the `"soft_float"` feature, palette expects to link to external definitions of the required operations. You'll need to provide these using `extern "C"` declarations. + +For more information, see the [`float` module docs](https://ogeon.github.io/docs/palette/master/palette/float/index.html). + ## Contributing All sorts of contributions are welcome, no matter how huge or tiny, so take a look at [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines, if you are interested. diff --git a/palette/Cargo.toml b/palette/Cargo.toml index 0d6774b21..14321be42 100644 --- a/palette/Cargo.toml +++ b/palette/Cargo.toml @@ -17,6 +17,7 @@ default = ["named_from_str", "std"] named_from_str = ["named", "phf", "phf_codegen", "std"] named = [] std = ["num-traits/std", "serde/std", "approx/std"] +soft_float = ["mish", "m"] #internal strict = [] @@ -25,8 +26,9 @@ strict = [] palette_derive = {version = "0.4.0", path = "../palette_derive"} num-traits = {version = "0.2", default-features = false} approx = {version = "0.2", default-features = false} -mish = {version = "0.2"} -m = {version = "0.1"} + +mish = {version = "0.2", optional = true} +m = {version = "0.1", optional = true} [dependencies.phf] version = "0.7" diff --git a/palette/src/float.rs b/palette/src/float.rs index bebc44afa..eab97743f 100644 --- a/palette/src/float.rs +++ b/palette/src/float.rs @@ -1,26 +1,82 @@ -//!Floating point traits -//! -//!This module is work-around for the lack of floating point operations under `#![no_std]`. If you -//!haven't disabled the `std` feature, it just re-exports `num_traits::Float`. +//! Floating point traits //! -//!However, without `std`, it's a custom trait that's implemented for `f32` and `f64` using the -//!`mish` and `m` crates. +//! This module is work-around for the lack of floating point operations under `#![no_std]`. If you +//! haven't disabled the `std` feature, it just re-exports `num_traits::Float`. //! -//!Because new floating point functions may be needed in patch releases, the specifics of which -//!operations are included in the trait are semver-exempt on `no_std`. +//! However, without `std`, it's a custom trait with a subset of the methods from +//!`num_traits::Float`, implemented for `f32` and `f64`. +//! +//! If you are using this on `no_std`, there are two options to supply the necessary floating point +//! operations: +//! +//! * By enabling the `soft_float` feature, these functions are supplied using the `mish` and `m` +//! crates. This comes with the caveat that as software implementations, they're likely to be +//! slower and less precise than potential hardware versions. +//! * Without the `soft_float` feature, it is necessary to supply the required operations via +//! `extern "C"` declarations. This might be beneficial if, for example, you're using a platform +//! that has hard float operations and you need it to be faster. It's recommended to enable LTO in +//! this case, to minimize any overhead. These are the functions it expects to link against: +//! ```rust,ignore +//! extern "C" { +//! // Computes the square root of `x` +//! // Should be compatible with `x.sqrt()` from the standard library +//! fn sqrtf32(x: f32) -> f32; +//! fn sqrtf64(x: f64) -> f64; +//! // Computes `x` to the power of `y` +//! // Should be compatible with `x.powf(y)` from the standard library +//! fn powf32(x: f32, y: f32) -> f32; +//! fn powf64(x: f64, y: f64) -> f64; +//! // Computes the sine of `x` radians +//! // Should be compatible with `x.sin()` from the standard library +//! fn sinf32(x: f32) -> f32; +//! fn sinf64(x: f64) -> f64; +//! // Computes the cosine of `x` radians +//! // Should be compatible with `x.cos()` from the standard library +//! fn cosf32(x: f32) -> f32; +//! fn cosf64(x: f64) -> f64; +//! // Computes the inverse tangent of `y / x`, in the corresponding quadrant +//! // Should be compatible with `y.atan2(x)` from the standard library +//! fn atan2f32(y: f32, x: f32) -> f32; +//! fn atan2f64(y: f64, x: f64) -> f64; +//! } +//! ``` +//! +//! Because new floating point functions may be needed in patch releases, the specifics of which +//! operations are included in the trait (and likewise in the list of required `extern "C"` functions) +//! are semver-exempt on `no_std`. #[cfg(feature = "std")] pub use num_traits::Float; #[cfg(not(feature = "std"))] -pub use self::no_std_float_hack::Float; +pub use self::no_std_float_trait::Float; #[cfg(not(feature = "std"))] -mod no_std_float_hack { - use m; - use mish; +mod no_std_float_trait { + #[cfg(feature = "soft_float")] + extern crate m; + #[cfg(feature = "soft_float")] + extern crate mish; + + use num_traits::float::FloatCore; - pub trait Float: ::num_traits::float::FloatCore { + /// This is the trait that represents a floating-point number under `no_std`. It has a subset + /// of the operations that are in `num_traits::Float`, including all of the + /// `num_traits::float::FloatCore` opterations. For documentation of specific functions in this + /// trait, see the [`num_traits::Float` docs][num_traits]. + /// + /// It's implemented for `f32` and `f64`. See the [module docs][module] for details. + /// + /// # Compatibility between versions + /// + /// Because of the possibility of needing more floating point operations in point releases, this + /// trait is semver-exempt with respect to adding new functions. (If you really need to + /// implement it for your own `MyFloat` type, pin a specific version in your `Cargo.toml`.) + /// However, removing methods from this trait is still considered a breaking change. + /// + /// [num_traits]: https://docs.rs/num-traits/0.2.5/num_traits/float/trait.Float.html + /// [module]: index.html + pub trait Float: FloatCore { fn sqrt(self) -> Self; fn powf(self, other: Self) -> Self; fn sin(self) -> Self; @@ -28,6 +84,7 @@ mod no_std_float_hack { fn atan2(self, other: Self) -> Self; } + #[cfg(feature = "soft_float")] impl Float for f32 { fn sqrt(self) -> f32 { mish::sqrt(self) @@ -42,10 +99,11 @@ mod no_std_float_hack { mish::cos(self) } fn atan2(self, other: f32) -> f32 { - ::atan2(self, other) + m::Float::atan2(self, other) } } + #[cfg(feature = "soft_float")] impl Float for f64 { fn sqrt(self) -> f64 { mish::sqrt(self) @@ -60,7 +118,70 @@ mod no_std_float_hack { mish::cos(self) } fn atan2(self, other: f64) -> f64 { - ::atan2(self, other) + // f64 atan2 isn't implemented in `m` yet + m::Float::atan2(self as f32, other as f32).into() + } + } + + #[cfg(not(feature = "soft_float"))] + extern "C" { + // Computes the square root of `x` + // Should be compatible with `x.sqrt()` from the standard library + fn sqrtf32(x: f32) -> f32; + fn sqrtf64(x: f64) -> f64; + // Computes `x` to the power of `y` + // Should be compatible with `x.powf(y)` from the standard library + fn powf32(x: f32, y: f32) -> f32; + fn powf64(x: f64, y: f64) -> f64; + // Computes the sine of `x` radians + // Should be compatible with `x.sin()` from the standard library + fn sinf32(x: f32) -> f32; + fn sinf64(x: f64) -> f64; + // Computes the cosine of `x` radians + // Should be compatible with `x.cos()` from the standard library + fn cosf32(x: f32) -> f32; + fn cosf64(x: f64) -> f64; + // Computes the inverse tangent of `y / x`, in the corresponding quadrant + // Should be compatible with `y.atan2(x)` from the standard library + fn atan2f32(y: f32, x: f32) -> f32; + fn atan2f64(y: f64, x: f64) -> f64; + } + + #[cfg(not(feature = "soft_float"))] + impl Float for f32 { + fn sqrt(self) -> f32 { + unsafe { sqrtf32(self) } + } + fn powf(self, other: f32) -> f32 { + unsafe { powf32(self, other) } + } + fn sin(self) -> f32 { + unsafe { sinf32(self) } + } + fn cos(self) -> f32 { + unsafe { cosf32(self) } + } + fn atan2(self, other: f32) -> f32 { + unsafe { atan2f32(self, other) } + } + } + + #[cfg(not(feature = "soft_float"))] + impl Float for f64 { + fn sqrt(self) -> f64 { + unsafe { sqrtf64(self) } + } + fn powf(self, other: f64) -> f64 { + unsafe { powf64(self, other) } + } + fn sin(self) -> f64 { + unsafe { sinf64(self) } + } + fn cos(self) -> f64 { + unsafe { cosf64(self) } + } + fn atan2(self, other: f64) -> f64 { + unsafe { atan2f64(self, other) } } } } diff --git a/palette/src/lib.rs b/palette/src/lib.rs index f5c5589ba..50ff791d3 100644 --- a/palette/src/lib.rs +++ b/palette/src/lib.rs @@ -152,11 +152,6 @@ extern crate palette_derive; extern crate num_traits; -#[cfg(not(feature = "std"))] -extern crate m; -#[cfg(not(feature = "std"))] -extern crate mish; - #[cfg(feature = "phf")] extern crate phf; From cacfe2d0dd6c8966eb982e9cfb368cf974ba7a6d Mon Sep 17 00:00:00 2001 From: Mark Barbone Date: Mon, 9 Jul 2018 14:16:35 -0400 Subject: [PATCH 08/16] Add method docs for no_std float::Float trait --- palette/src/float.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/palette/src/float.rs b/palette/src/float.rs index eab97743f..ee40df7bf 100644 --- a/palette/src/float.rs +++ b/palette/src/float.rs @@ -77,10 +77,15 @@ mod no_std_float_trait { /// [num_traits]: https://docs.rs/num-traits/0.2.5/num_traits/float/trait.Float.html /// [module]: index.html pub trait Float: FloatCore { + /// `x.sqrt()` computes the square root of `x`. fn sqrt(self) -> Self; + /// `x.powf(y)` computes `x` to the power of `y`. fn powf(self, other: Self) -> Self; + /// `x.sin()` computes the sine of `x` radians. fn sin(self) -> Self; + /// `x.cos()` computes the cosine of `x` radians. fn cos(self) -> Self; + /// `y.atan2(x)` computes the inverse tangent of `y / x`, in the corresponding quadrant fn atan2(self, other: Self) -> Self; } From 0b189089a2cecf712a6e21efa3196a1d4fe91476 Mon Sep 17 00:00:00 2001 From: Mark Barbone Date: Mon, 9 Jul 2018 14:45:29 -0400 Subject: [PATCH 09/16] Make tests compile without the std feature --- palette/examples/gradient.rs | 12 +++++++++--- palette/src/convert.rs | 6 ++---- palette/src/lib.rs | 5 +++-- palette/tests/pointer_dataset/pointer_data.rs | 3 ++- scripts/test_features.sh | 2 +- 5 files changed, 17 insertions(+), 11 deletions(-) diff --git a/palette/examples/gradient.rs b/palette/examples/gradient.rs index 91af39d38..3bd722071 100644 --- a/palette/examples/gradient.rs +++ b/palette/examples/gradient.rs @@ -1,11 +1,17 @@ extern crate image; extern crate palette; -use palette::{Gradient, Lch, LinSrgb, Pixel, Srgb}; - -use image::{GenericImage, RgbImage}; +#[cfg(not(feature = "std"))] +fn main() { + println!("You can't use gradients without the standard library"); +} +#[cfg(feature = "std")] fn main() { + use palette::{Gradient, Lch, LinSrgb, Pixel, Srgb}; + + use image::{GenericImage, RgbImage}; + //A gradient of evenly spaced colors let grad1 = Gradient::new(vec![ LinSrgb::new(1.0, 0.1, 0.1), diff --git a/palette/src/convert.rs b/palette/src/convert.rs index e441bf69e..446e82cae 100644 --- a/palette/src/convert.rs +++ b/palette/src/convert.rs @@ -101,7 +101,6 @@ use encoding::Linear; /// ```rust /// #[macro_use] /// extern crate palette; -/// extern crate num_traits; /// #[macro_use] /// extern crate approx; /// @@ -109,7 +108,7 @@ use encoding::Linear; /// use palette::rgb::{Rgb, RgbSpace}; /// use palette::encoding::Linear; /// use palette::white_point::D65; -/// use num_traits::Float; +/// use palette::float::Float; /// /// /// sRGB, but with a reversed memory layout. /// #[derive(PartialEq, Debug, FromColor, Pixel)] @@ -348,7 +347,6 @@ where /// ```rust /// #[macro_use] /// extern crate palette; -/// extern crate num_traits; /// #[macro_use] /// extern crate approx; /// @@ -356,7 +354,7 @@ where /// use palette::rgb::{Rgb, RgbSpace}; /// use palette::encoding::Linear; /// use palette::white_point::D65; -/// use num_traits::Float; +/// use palette::float::Float; /// /// /// sRGB, but with a reversed memory layout. /// #[derive(Copy, Clone, IntoColor, Pixel)] diff --git a/palette/src/lib.rs b/palette/src/lib.rs index 50ff791d3..ed2758eb5 100644 --- a/palette/src/lib.rs +++ b/palette/src/lib.rs @@ -135,13 +135,14 @@ //! process reversed. //! -#![cfg_attr(not(feature = "std"), no_std)] +// Keep the standard library when running tests, too +#![cfg_attr(all(not(feature = "std"), not(test)), no_std)] #![doc(html_root_url = "https://docs.rs/palette/0.4.0/palette/")] #![cfg_attr(feature = "strict", deny(missing_docs))] #![cfg_attr(feature = "strict", deny(warnings))] -#[cfg(feature = "std")] +#[cfg(any(feature = "std", test))] extern crate core; #[cfg_attr(test, macro_use)] diff --git a/palette/tests/pointer_dataset/pointer_data.rs b/palette/tests/pointer_dataset/pointer_data.rs index e54439fcc..2a53482e7 100644 --- a/palette/tests/pointer_dataset/pointer_data.rs +++ b/palette/tests/pointer_dataset/pointer_data.rs @@ -11,7 +11,8 @@ u', v' 0.2008907213 0.4608888395 Note: The xyz and yxy conversions do not use the updated conversion formula. So they are not used. */ -use num_traits::{Float, NumCast, ToPrimitive}; +use num_traits::{NumCast, ToPrimitive}; +use palette::float::Float; use csv; use palette::{Component, IntoColor, Lab, Lch, Xyz}; use palette::white_point::WhitePoint; diff --git a/scripts/test_features.sh b/scripts/test_features.sh index 385773ac7..d302caaee 100644 --- a/scripts/test_features.sh +++ b/scripts/test_features.sh @@ -4,7 +4,7 @@ set -e features="" #Features that will always be activated -required_features="strict" +required_features="strict soft_float" #Find features From b5b96057d41dae3a7a367ea7d337824d47e14a3c Mon Sep 17 00:00:00 2001 From: Mark Barbone Date: Mon, 9 Jul 2018 17:58:11 -0400 Subject: [PATCH 10/16] Fix "unused import" warnings in palette/examples/readme_examples.rs with "std" disabled --- palette/examples/readme_examples.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/palette/examples/readme_examples.rs b/palette/examples/readme_examples.rs index d588f56a9..1f1400559 100644 --- a/palette/examples/readme_examples.rs +++ b/palette/examples/readme_examples.rs @@ -4,9 +4,9 @@ extern crate palette; use image::{GenericImage, RgbImage}; -use palette::{LinSrgb, Mix, Pixel, Srgb}; +use palette::{Pixel, Srgb}; #[cfg(feature = "std")] -use palette::Gradient; +use palette::{Gradient, LinSrgb, Mix}; mod color_spaces { use palette::{Hue, Lch, LinSrgb, Srgb}; From f23b8931df02815d26e261fb198369021867ed1d Mon Sep 17 00:00:00 2001 From: Mark Barbone Date: Mon, 9 Jul 2018 19:47:59 -0400 Subject: [PATCH 11/16] Change Lab conversions to use `.cbrt()` instead of `.powf(1/3)` --- palette/src/float.rs | 28 ++++++++++++++++++++++++++++ palette/src/lab.rs | 2 +- 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/palette/src/float.rs b/palette/src/float.rs index ee40df7bf..5d188c280 100644 --- a/palette/src/float.rs +++ b/palette/src/float.rs @@ -22,6 +22,10 @@ //! // Should be compatible with `x.sqrt()` from the standard library //! fn sqrtf32(x: f32) -> f32; //! fn sqrtf64(x: f64) -> f64; +//! // Computes the cube root of `x` +//! // Should be compatible with `x.cbrt()` from the standard library +//! fn cbrtf32(x: f32) -> f32; +//! fn cbrtf64(x: f64) -> f64; //! // Computes `x` to the power of `y` //! // Should be compatible with `x.powf(y)` from the standard library //! fn powf32(x: f32, y: f32) -> f32; @@ -79,6 +83,8 @@ mod no_std_float_trait { pub trait Float: FloatCore { /// `x.sqrt()` computes the square root of `x`. fn sqrt(self) -> Self; + /// `x.cbrt()` computes the cube root of `x`. + fn cbrt(self) -> Self; /// `x.powf(y)` computes `x` to the power of `y`. fn powf(self, other: Self) -> Self; /// `x.sin()` computes the sine of `x` radians. @@ -94,7 +100,13 @@ mod no_std_float_trait { fn sqrt(self) -> f32 { mish::sqrt(self) } + fn cbrt(self) -> f32 { + mish::cbrt_f32(self) + } fn powf(self, other: f32) -> f32 { + if self < 0. { // Can't raise a negative number to a fractional power + return f32::nan(); + } mish::powf(self, other) } fn sin(self) -> f32 { @@ -113,7 +125,13 @@ mod no_std_float_trait { fn sqrt(self) -> f64 { mish::sqrt(self) } + fn cbrt(self) -> f64 { + mish::cbrt_f32(self) + } fn powf(self, other: f64) -> f64 { + if self < 0. { // Can't raise a negative number to a fractional power + return f64::nan(); + } mish::powf(self, other) } fn sin(self) -> f64 { @@ -134,6 +152,10 @@ mod no_std_float_trait { // Should be compatible with `x.sqrt()` from the standard library fn sqrtf32(x: f32) -> f32; fn sqrtf64(x: f64) -> f64; + // Computes the cube root of `x` + // Should be compatible with `x.cbrt()` from the standard library + fn cbrtf32(x: f32) -> f32; + fn cbrtf64(x: f64) -> f64; // Computes `x` to the power of `y` // Should be compatible with `x.powf(y)` from the standard library fn powf32(x: f32, y: f32) -> f32; @@ -157,6 +179,9 @@ mod no_std_float_trait { fn sqrt(self) -> f32 { unsafe { sqrtf32(self) } } + fn cbrt(self) -> f32 { + unsafe { cbrtf32(self) } + } fn powf(self, other: f32) -> f32 { unsafe { powf32(self, other) } } @@ -176,6 +201,9 @@ mod no_std_float_trait { fn sqrt(self) -> f64 { unsafe { sqrtf64(self) } } + fn cbrt(self) -> f64 { + unsafe { cbrtf64(self) } + } fn powf(self, other: f64) -> f64 { unsafe { powf64(self, other) } } diff --git a/palette/src/lab.rs b/palette/src/lab.rs index d31be695c..4d04b8cb3 100644 --- a/palette/src/lab.rs +++ b/palette/src/lab.rs @@ -170,7 +170,7 @@ where let kappa: T = cast(841.0 / 108.0); let delta: T = cast(4.0 / 29.0); if c > epsilon { - c.powf(T::one() / cast(3.0)) + c.cbrt() } else { (kappa * c) + delta } From 8fa96e33582e02b48f1768003d963d20167e557a Mon Sep 17 00:00:00 2001 From: Mark Barbone Date: Tue, 10 Jul 2018 13:55:17 -0400 Subject: [PATCH 12/16] Workaround imprecise soft-float math --- palette/src/convert.rs | 2 +- palette/src/float.rs | 61 ++++++++++++++++--- palette/tests/color_checker_data/babel.rs | 7 ++- .../tests/color_checker_data/color_checker.rs | 7 ++- palette/tests/color_checker_data/mod.rs | 5 ++ palette/tests/convert/lab_lch.rs | 12 ++-- palette/tests/pointer_dataset/pointer_data.rs | 8 ++- 7 files changed, 77 insertions(+), 25 deletions(-) diff --git a/palette/src/convert.rs b/palette/src/convert.rs index 446e82cae..0dcbaf069 100644 --- a/palette/src/convert.rs +++ b/palette/src/convert.rs @@ -393,7 +393,7 @@ where /// ]; /// let hsv = Bgr::from_raw_slice(&buffer)[1].into(); /// -/// assert_relative_eq!(hsv, Hsv::new(90.0, 1.0, 0.5)); +/// assert_relative_eq!(hsv, Hsv::new(90.0, 1.0, 0.5), epsilon = 0.001); /// } /// ``` /// diff --git a/palette/src/float.rs b/palette/src/float.rs index 5d188c280..8164d102d 100644 --- a/palette/src/float.rs +++ b/palette/src/float.rs @@ -63,6 +63,7 @@ mod no_std_float_trait { extern crate mish; use num_traits::float::FloatCore; + use core::{f32, f64}; /// This is the trait that represents a floating-point number under `no_std`. It has a subset /// of the operations that are in `num_traits::Float`, including all of the @@ -98,22 +99,42 @@ mod no_std_float_trait { #[cfg(feature = "soft_float")] impl Float for f32 { fn sqrt(self) -> f32 { - mish::sqrt(self) + if self < 0. || self.is_nan() || self.is_infinite() { + f32::NAN + } else if self < 1. { + 1. / mish::sqrt(1. / self) + } else { + mish::sqrt(self) + } } fn cbrt(self) -> f32 { mish::cbrt_f32(self) } fn powf(self, other: f32) -> f32 { if self < 0. { // Can't raise a negative number to a fractional power - return f32::nan(); + return f32::NAN; + } + // mish::powf is more accurate with numbers larger than 1.0 + if self > 1.0 { + mish::powf(self, other) + } else if self == 0. { + return 0.; + } else { + 1. / mish::powf(1. / self, other) } - mish::powf(self, other) } fn sin(self) -> f32 { - mish::sin(self) + if self.is_nan() || self.is_infinite() { + return f32::NAN; + } + if self < 0. { + return -Float::sin(-self); + } + let x = self % (2.*f32::consts::PI); + mish::sin(f32::consts::PI - x) } fn cos(self) -> f32 { - mish::cos(self) + (f32::consts::FRAC_PI_2 - self).sin() } fn atan2(self, other: f32) -> f32 { m::Float::atan2(self, other) @@ -123,22 +144,42 @@ mod no_std_float_trait { #[cfg(feature = "soft_float")] impl Float for f64 { fn sqrt(self) -> f64 { - mish::sqrt(self) + if self < 0. || self.is_nan() || self.is_infinite() { + f64::NAN + } else if self < 1. { + 1. / mish::sqrt(1. / self) + } else { + mish::sqrt(self) + } } fn cbrt(self) -> f64 { mish::cbrt_f32(self) } fn powf(self, other: f64) -> f64 { if self < 0. { // Can't raise a negative number to a fractional power - return f64::nan(); + return f64::NAN; + } else if self == 0. { + return 0.; + } + // mish::powf is more accurate with numbers larger than 1.0 + if self > 1.0 { + mish::powf(self, other) + } else { + 1. / mish::powf(1. / self, other) } - mish::powf(self, other) } fn sin(self) -> f64 { - mish::sin(self) + if self.is_nan() || self.is_infinite() { + return f64::NAN; + } + if self < 0. { + return -Float::sin(-self); + } + let x = self % (2.*f64::consts::PI); + mish::sin(f64::consts::PI - x) } fn cos(self) -> f64 { - mish::cos(self) + (f64::consts::FRAC_PI_2 - self).sin() } fn atan2(self, other: f64) -> f64 { // f64 atan2 isn't implemented in `m` yet diff --git a/palette/tests/color_checker_data/babel.rs b/palette/tests/color_checker_data/babel.rs index b2a07ce97..de97c9865 100644 --- a/palette/tests/color_checker_data/babel.rs +++ b/palette/tests/color_checker_data/babel.rs @@ -10,6 +10,7 @@ use palette::{Xyz, Yxy, Lab, IntoColor}; use palette::white_point::D50; use super::load_data::{ColorCheckerRaw, load_babel}; +use super::MAX_ERROR; #[derive(Copy, Clone, PartialEq, Debug)] pub struct BabelData { @@ -53,9 +54,9 @@ lazy_static! { } fn check_equal(src: &BabelData, tgt: &BabelData) { - assert_relative_eq!(src.xyz, tgt.xyz, epsilon = 0.000000000001); - assert_relative_eq!(src.yxy, tgt.yxy, epsilon = 0.000000000001); - assert_relative_eq!(src.lab, tgt.lab, epsilon = 0.000000000001); + assert_relative_eq!(src.xyz, tgt.xyz, epsilon = MAX_ERROR); + assert_relative_eq!(src.yxy, tgt.yxy, epsilon = MAX_ERROR); + assert_relative_eq!(src.lab, tgt.lab, epsilon = MAX_ERROR); } pub fn run_from_yxy_tests() { diff --git a/palette/tests/color_checker_data/color_checker.rs b/palette/tests/color_checker_data/color_checker.rs index a992c9342..01cfcb6f7 100644 --- a/palette/tests/color_checker_data/color_checker.rs +++ b/palette/tests/color_checker_data/color_checker.rs @@ -10,6 +10,7 @@ use palette::{Xyz, Yxy, Lab, IntoColor}; use palette::white_point::D50; use super::load_data::{ColorCheckerRaw, load_color_checker}; +use super::MAX_ERROR; #[derive(Copy, Clone, PartialEq, Debug)] pub struct ColorCheckerData { @@ -53,9 +54,9 @@ lazy_static! { } fn check_equal(src: &ColorCheckerData, tgt: &ColorCheckerData) { - assert_relative_eq!(src.xyz, tgt.xyz, epsilon = 0.000000000001); - assert_relative_eq!(src.yxy, tgt.yxy, epsilon = 0.000000000001); - assert_relative_eq!(src.lab, tgt.lab, epsilon = 0.000000000001); + assert_relative_eq!(src.xyz, tgt.xyz, epsilon = MAX_ERROR); + assert_relative_eq!(src.yxy, tgt.yxy, epsilon = MAX_ERROR); + assert_relative_eq!(src.lab, tgt.lab, epsilon = MAX_ERROR); } pub fn run_from_yxy_tests() { diff --git a/palette/tests/color_checker_data/mod.rs b/palette/tests/color_checker_data/mod.rs index 4742e9f79..1477d00fd 100644 --- a/palette/tests/color_checker_data/mod.rs +++ b/palette/tests/color_checker_data/mod.rs @@ -2,6 +2,11 @@ mod babel; mod color_checker; mod load_data; +#[cfg(feature = "std")] +const MAX_ERROR: f64 = 0.000000000001; +#[cfg(not(feature = "std"))] +const MAX_ERROR: f64 = 0.001; + #[test] pub fn babel_from_yxy() { babel::run_from_yxy_tests(); diff --git a/palette/tests/convert/lab_lch.rs b/palette/tests/convert/lab_lch.rs index 914eac2a9..c854a20a2 100644 --- a/palette/tests/convert/lab_lch.rs +++ b/palette/tests/convert/lab_lch.rs @@ -7,8 +7,8 @@ fn lab_lch_green() { let expect_lab = lch.into_lab(); let expect_lch = lab.into_lch(); - assert_relative_eq!(lab, expect_lab, epsilon = 0.001); - assert_relative_eq!(lch, expect_lch, epsilon = 0.001); + assert_relative_eq!(lab, expect_lab, epsilon = 0.1); + assert_relative_eq!(lch, expect_lch, epsilon = 0.1); } #[test] @@ -19,8 +19,8 @@ fn lab_lch_magenta() { let expect_lab = lch.into_lab(); let expect_lch = lab.into_lch(); - assert_relative_eq!(lab, expect_lab, epsilon = 0.001); - assert_relative_eq!(lch, expect_lch, epsilon = 0.001); + assert_relative_eq!(lab, expect_lab, epsilon = 0.1); + assert_relative_eq!(lch, expect_lch, epsilon = 0.1); } #[test] @@ -31,6 +31,6 @@ fn lab_lch_blue() { let expect_lab = lch.into_lab(); let expect_lch = lab.into_lch(); - assert_relative_eq!(lab, expect_lab, epsilon = 0.001); - assert_relative_eq!(lch, expect_lch, epsilon = 0.001); + assert_relative_eq!(lab, expect_lab, epsilon = 0.1); + assert_relative_eq!(lch, expect_lch, epsilon = 0.1); } diff --git a/palette/tests/pointer_dataset/pointer_data.rs b/palette/tests/pointer_dataset/pointer_data.rs index 2a53482e7..aa1e1f35c 100644 --- a/palette/tests/pointer_dataset/pointer_data.rs +++ b/palette/tests/pointer_dataset/pointer_data.rs @@ -93,8 +93,12 @@ fn load_data() -> Vec { } fn check_equal(src: &PointerData, tgt: &PointerData) { - assert_relative_eq!(src.lch, tgt.lch, epsilon = 0.000000000001); - assert_relative_eq!(src.lab, tgt.lab, epsilon = 0.000000000001); + #[cfg(feature = "std")] + const MAX_ERROR: f64 = 0.000000000001; + #[cfg(not(feature = "std"))] + const MAX_ERROR: f64 = 1.0; + assert_relative_eq!(src.lch, tgt.lch, epsilon = MAX_ERROR); + assert_relative_eq!(src.lab, tgt.lab, epsilon = MAX_ERROR); } pub fn run_from_lch_tests() { From c0f7b263e0361c3b463f1a18fd46349222b07e89 Mon Sep 17 00:00:00 2001 From: Mark Barbone Date: Tue, 31 Jul 2018 15:28:18 -0400 Subject: [PATCH 13/16] Change to use libm instead of mish and m --- README.md | 17 +-- palette/Cargo.toml | 10 +- palette/README.md | 33 ++++- palette/src/alpha.rs | 8 +- palette/src/blend/pre_alpha.rs | 10 +- palette/src/float.rs | 230 ++++++--------------------------- palette/src/hsl.rs | 8 +- palette/src/hsv.rs | 8 +- palette/src/hues.rs | 6 +- palette/src/hwb.rs | 8 +- palette/src/lab.rs | 8 +- palette/src/lch.rs | 8 +- palette/src/lib.rs | 4 +- palette/src/luma/luma.rs | 8 +- palette/src/rgb/rgb.rs | 8 +- palette/src/xyz.rs | 8 +- palette/src/yxy.rs | 8 +- scripts/test_features.sh | 2 +- 18 files changed, 122 insertions(+), 270 deletions(-) diff --git a/README.md b/README.md index f36769e49..32bb56dd2 100644 --- a/README.md +++ b/README.md @@ -30,8 +30,7 @@ These features are enabled by default: These features are disabled by default: -* `"serde"` - Enables color serializing and deserializing. -* `"soft_float"` - Without the standard library, this enables use of software floating-point libraries for certain floating point operations. +* `"serializing"` - Enables color serializing and deserializing using `serde`. ### Without the standard library @@ -40,8 +39,7 @@ Here is an example `Cargo.toml` entry for using palette on `#![no_std]`: ```toml [dependencies.palette] version = "0.4" -default-feature = false -features = ["soft_float"] +default-features = false ``` ## It's Never "Just RGB" @@ -132,16 +130,11 @@ Palette supports `#![no_std]` environments by disabling the `"std"` feature. How * Gradients are unavailable, because they depend heavily on Vectors * The `"named_from_str"` feature requires the standard library as well -* Floating point operations must be provided by the library user +* Serialization using `serde` is unavailable -### Floating-point operations +It uses [`libm`] to provide the floating-point operations that are typically in `std`. -Converting colors requires a lot of floating-point math on the colors, such as trigonometry for HSV, exponents for gamma-correction, etc. These operations are typically provided by the standard library, and aren't available in an embedded environment. Because of this, a library user has two options for supplying the necessary functions: - -* If you enable the `"soft_float"` feature, software implementations will be used. This comes with the caveat that it's potentially slower and less precise than otherwise. -* Without the `"soft_float"` feature, palette expects to link to external definitions of the required operations. You'll need to provide these using `extern "C"` declarations. - -For more information, see the [`float` module docs](https://ogeon.github.io/docs/palette/master/palette/float/index.html). +[`libm`]: https://github.com/japaric/libm ## Contributing diff --git a/palette/Cargo.toml b/palette/Cargo.toml index 14321be42..995529cd6 100644 --- a/palette/Cargo.toml +++ b/palette/Cargo.toml @@ -16,8 +16,8 @@ build = "build/main.rs" default = ["named_from_str", "std"] named_from_str = ["named", "phf", "phf_codegen", "std"] named = [] -std = ["num-traits/std", "serde/std", "approx/std"] -soft_float = ["mish", "m"] +std = ["num-traits/std", "approx/std"] +serializing = ["serde", "std"] #internal strict = [] @@ -26,18 +26,14 @@ strict = [] palette_derive = {version = "0.4.0", path = "../palette_derive"} num-traits = {version = "0.2", default-features = false} approx = {version = "0.2", default-features = false} - -mish = {version = "0.2", optional = true} -m = {version = "0.1", optional = true} +libm = "0.1.2" [dependencies.phf] version = "0.7" optional = true [dependencies.serde] -#feature version = "1" -default-features = false features = ["serde_derive"] optional = true diff --git a/palette/README.md b/palette/README.md index 706342307..32bb56dd2 100644 --- a/palette/README.md +++ b/palette/README.md @@ -20,16 +20,27 @@ Add the following lines to your `Cargo.toml` file: palette = "0.4" ``` -### Optional Features +### Features These features are enabled by default: * `"named"` - Enables color constants, located in the `named` module. -* `"named_from_str"` - Enables the `named::from_str`, which maps name string to colors. +* `"named_from_str"` - Enables the `named::from_str`, which maps name string to colors. This requires the standard library. +* `"std"` - Enables use of the standard library. These features are disabled by default: -* `"serde"` - Enables color serializing and deserializing. +* `"serializing"` - Enables color serializing and deserializing using `serde`. + +### Without the standard library + +Here is an example `Cargo.toml` entry for using palette on `#![no_std]`: + +```toml +[dependencies.palette] +version = "0.4" +default-features = false +``` ## It's Never "Just RGB" @@ -109,12 +120,22 @@ The RGB gradient goes through gray, while the HSV gradients changes only the hue ## What It Isn't -This library is only meant for color manipulation and conversion. It's not a fully features image manipulation library. It will only handle colors, and not whole images. - -These are meant to work as bridges between Palette and other graphical libraries, but it has been limited only focus on single pixel operations to keep the scope at a manageable size. +This library is only meant for color manipulation and conversion. It's not a fully features image manipulation library. It will only handle colors, and not whole images. There are features that are meant to work as bridges between Palette and other graphical libraries, but the main features are limited to only focus on single pixel operations, to keep the scope at a manageable size. [pixel_module]: https://ogeon.github.io/docs/palette/master/palette/pixel/index.html +## Using palette in an embedded environment + +Palette supports `#![no_std]` environments by disabling the `"std"` feature. However, there are some things that are unavailable without the standard library: + +* Gradients are unavailable, because they depend heavily on Vectors +* The `"named_from_str"` feature requires the standard library as well +* Serialization using `serde` is unavailable + +It uses [`libm`] to provide the floating-point operations that are typically in `std`. + +[`libm`]: https://github.com/japaric/libm + ## Contributing All sorts of contributions are welcome, no matter how huge or tiny, so take a look at [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines, if you are interested. diff --git a/palette/src/alpha.rs b/palette/src/alpha.rs index 819131d16..101130b8a 100644 --- a/palette/src/alpha.rs +++ b/palette/src/alpha.rs @@ -11,11 +11,11 @@ use encoding::pixel::RawPixel; ///An alpha component wrapper for colors. #[derive(Clone, Copy, Debug, PartialEq)] -#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[cfg_attr(feature = "serializing", derive(Serialize, Deserialize))] #[repr(C)] pub struct Alpha { ///The color. - #[cfg_attr(feature = "serde", serde(flatten))] + #[cfg_attr(feature = "serializing", serde(flatten))] pub color: C, ///The transparency component. 0.0 is fully transparent and 1.0 is fully @@ -467,7 +467,7 @@ mod test { ); } - #[cfg(feature = "serde")] + #[cfg(feature = "serializing")] #[test] fn serialize() { let serialized = ::serde_json::to_string(&Rgba::::new(0.3, 0.8, 0.1, 0.5)).unwrap(); @@ -478,7 +478,7 @@ mod test { ); } - #[cfg(feature = "serde")] + #[cfg(feature = "serializing")] #[test] fn deserialize() { let deserialized: Rgba = diff --git a/palette/src/blend/pre_alpha.rs b/palette/src/blend/pre_alpha.rs index e595ce17d..43569f657 100644 --- a/palette/src/blend/pre_alpha.rs +++ b/palette/src/blend/pre_alpha.rs @@ -27,11 +27,11 @@ use encoding::pixel::RawPixel; ///Note that converting to and from premultiplied alpha will cause the alpha ///component to be clamped to [0.0, 1.0]. #[derive(Clone, Copy, PartialEq, Debug)] -#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[cfg_attr(feature = "serializing", derive(Serialize, Deserialize))] #[repr(C)] pub struct PreAlpha { ///The premultiplied color components (`original.color * original.alpha`). - #[cfg_attr(feature = "serde", serde(flatten))] + #[cfg_attr(feature = "serializing", serde(flatten))] pub color: C, ///The transparency component. 0.0 is fully transparent and 1.0 is fully @@ -319,13 +319,13 @@ impl DerefMut for PreAlpha { } #[cfg(test)] -#[cfg(feature = "serde")] +#[cfg(feature = "serializing")] mod test { use super::PreAlpha; use rgb::Rgb; use encoding::Srgb; - #[cfg(feature = "serde")] + #[cfg(feature = "serializing")] #[test] fn serialize() { let color = PreAlpha { @@ -338,7 +338,7 @@ mod test { assert_eq!(serialized, r#"{"red":0.3,"green":0.8,"blue":0.1,"alpha":0.5}"#); } - #[cfg(feature = "serde")] + #[cfg(feature = "serializing")] #[test] fn deserialize() { let expected = PreAlpha { diff --git a/palette/src/float.rs b/palette/src/float.rs index 8164d102d..35c1356a6 100644 --- a/palette/src/float.rs +++ b/palette/src/float.rs @@ -1,53 +1,13 @@ //! Floating point traits //! -//! This module is work-around for the lack of floating point operations under `#![no_std]`. If you -//! haven't disabled the `std` feature, it just re-exports `num_traits::Float`. +//! This module is work-around for the lack of floating point operations under +//! `#![no_std]`. If you haven't disabled the `std` feature, it just re-exports +//! `num_traits::Float`. //! -//! However, without `std`, it's a custom trait with a subset of the methods from -//!`num_traits::Float`, implemented for `f32` and `f64`. +//! However, without `std`, it's a custom trait with a subset of the methods +//! from `num_traits::Float`, implemented for `f32` and `f64` using [`libm`]. //! -//! If you are using this on `no_std`, there are two options to supply the necessary floating point -//! operations: -//! -//! * By enabling the `soft_float` feature, these functions are supplied using the `mish` and `m` -//! crates. This comes with the caveat that as software implementations, they're likely to be -//! slower and less precise than potential hardware versions. -//! * Without the `soft_float` feature, it is necessary to supply the required operations via -//! `extern "C"` declarations. This might be beneficial if, for example, you're using a platform -//! that has hard float operations and you need it to be faster. It's recommended to enable LTO in -//! this case, to minimize any overhead. These are the functions it expects to link against: -//! ```rust,ignore -//! extern "C" { -//! // Computes the square root of `x` -//! // Should be compatible with `x.sqrt()` from the standard library -//! fn sqrtf32(x: f32) -> f32; -//! fn sqrtf64(x: f64) -> f64; -//! // Computes the cube root of `x` -//! // Should be compatible with `x.cbrt()` from the standard library -//! fn cbrtf32(x: f32) -> f32; -//! fn cbrtf64(x: f64) -> f64; -//! // Computes `x` to the power of `y` -//! // Should be compatible with `x.powf(y)` from the standard library -//! fn powf32(x: f32, y: f32) -> f32; -//! fn powf64(x: f64, y: f64) -> f64; -//! // Computes the sine of `x` radians -//! // Should be compatible with `x.sin()` from the standard library -//! fn sinf32(x: f32) -> f32; -//! fn sinf64(x: f64) -> f64; -//! // Computes the cosine of `x` radians -//! // Should be compatible with `x.cos()` from the standard library -//! fn cosf32(x: f32) -> f32; -//! fn cosf64(x: f64) -> f64; -//! // Computes the inverse tangent of `y / x`, in the corresponding quadrant -//! // Should be compatible with `y.atan2(x)` from the standard library -//! fn atan2f32(y: f32, x: f32) -> f32; -//! fn atan2f64(y: f64, x: f64) -> f64; -//! } -//! ``` -//! -//! Because new floating point functions may be needed in patch releases, the specifics of which -//! operations are included in the trait (and likewise in the list of required `extern "C"` functions) -//! are semver-exempt on `no_std`. +//! [`libm`]: https://github.com/japaric/libm #[cfg(feature = "std")] pub use num_traits::Float; @@ -57,27 +17,29 @@ pub use self::no_std_float_trait::Float; #[cfg(not(feature = "std"))] mod no_std_float_trait { - #[cfg(feature = "soft_float")] - extern crate m; - #[cfg(feature = "soft_float")] - extern crate mish; + extern crate libm; + use self::libm::{F32Ext, F64Ext}; - use num_traits::float::FloatCore; use core::{f32, f64}; + use num_traits::float::FloatCore; - /// This is the trait that represents a floating-point number under `no_std`. It has a subset - /// of the operations that are in `num_traits::Float`, including all of the - /// `num_traits::float::FloatCore` opterations. For documentation of specific functions in this - /// trait, see the [`num_traits::Float` docs][num_traits]. + /// This is the trait that represents a floating-point number under + /// `no_std`. It has a subset of the operations that are in + /// `num_traits::Float`. + /// For more documentation of specific functions in this trait, see the + /// [`num_traits::Float` docs][num_traits]. /// - /// It's implemented for `f32` and `f64`. See the [module docs][module] for details. + /// It's implemented for `f32` and `f64`. See the [module docs][module] for + /// details. /// /// # Compatibility between versions /// - /// Because of the possibility of needing more floating point operations in point releases, this - /// trait is semver-exempt with respect to adding new functions. (If you really need to - /// implement it for your own `MyFloat` type, pin a specific version in your `Cargo.toml`.) - /// However, removing methods from this trait is still considered a breaking change. + /// Because of the possibility of needing more floating point operations in + /// point releases, this trait is semver-exempt with respect to adding + /// new functions. (If you really need to implement it for your own + /// `MyFloat` type, pin a specific version in your `Cargo.toml`.) However, + /// removing methods from this trait will still be considered a + /// breaking change. /// /// [num_traits]: https://docs.rs/num-traits/0.2.5/num_traits/float/trait.Float.html /// [module]: index.html @@ -92,170 +54,50 @@ mod no_std_float_trait { fn sin(self) -> Self; /// `x.cos()` computes the cosine of `x` radians. fn cos(self) -> Self; - /// `y.atan2(x)` computes the inverse tangent of `y / x`, in the corresponding quadrant + /// `y.atan2(x)` computes the inverse tangent of `y / x`, in the + /// corresponding quadrant fn atan2(self, other: Self) -> Self; } - #[cfg(feature = "soft_float")] - impl Float for f32 { - fn sqrt(self) -> f32 { - if self < 0. || self.is_nan() || self.is_infinite() { - f32::NAN - } else if self < 1. { - 1. / mish::sqrt(1. / self) - } else { - mish::sqrt(self) - } - } - fn cbrt(self) -> f32 { - mish::cbrt_f32(self) - } - fn powf(self, other: f32) -> f32 { - if self < 0. { // Can't raise a negative number to a fractional power - return f32::NAN; - } - // mish::powf is more accurate with numbers larger than 1.0 - if self > 1.0 { - mish::powf(self, other) - } else if self == 0. { - return 0.; - } else { - 1. / mish::powf(1. / self, other) - } - } - fn sin(self) -> f32 { - if self.is_nan() || self.is_infinite() { - return f32::NAN; - } - if self < 0. { - return -Float::sin(-self); - } - let x = self % (2.*f32::consts::PI); - mish::sin(f32::consts::PI - x) - } - fn cos(self) -> f32 { - (f32::consts::FRAC_PI_2 - self).sin() - } - fn atan2(self, other: f32) -> f32 { - m::Float::atan2(self, other) - } - } - - #[cfg(feature = "soft_float")] - impl Float for f64 { - fn sqrt(self) -> f64 { - if self < 0. || self.is_nan() || self.is_infinite() { - f64::NAN - } else if self < 1. { - 1. / mish::sqrt(1. / self) - } else { - mish::sqrt(self) - } - } - fn cbrt(self) -> f64 { - mish::cbrt_f32(self) - } - fn powf(self, other: f64) -> f64 { - if self < 0. { // Can't raise a negative number to a fractional power - return f64::NAN; - } else if self == 0. { - return 0.; - } - // mish::powf is more accurate with numbers larger than 1.0 - if self > 1.0 { - mish::powf(self, other) - } else { - 1. / mish::powf(1. / self, other) - } - } - fn sin(self) -> f64 { - if self.is_nan() || self.is_infinite() { - return f64::NAN; - } - if self < 0. { - return -Float::sin(-self); - } - let x = self % (2.*f64::consts::PI); - mish::sin(f64::consts::PI - x) - } - fn cos(self) -> f64 { - (f64::consts::FRAC_PI_2 - self).sin() - } - fn atan2(self, other: f64) -> f64 { - // f64 atan2 isn't implemented in `m` yet - m::Float::atan2(self as f32, other as f32).into() - } - } - - #[cfg(not(feature = "soft_float"))] - extern "C" { - // Computes the square root of `x` - // Should be compatible with `x.sqrt()` from the standard library - fn sqrtf32(x: f32) -> f32; - fn sqrtf64(x: f64) -> f64; - // Computes the cube root of `x` - // Should be compatible with `x.cbrt()` from the standard library - fn cbrtf32(x: f32) -> f32; - fn cbrtf64(x: f64) -> f64; - // Computes `x` to the power of `y` - // Should be compatible with `x.powf(y)` from the standard library - fn powf32(x: f32, y: f32) -> f32; - fn powf64(x: f64, y: f64) -> f64; - // Computes the sine of `x` radians - // Should be compatible with `x.sin()` from the standard library - fn sinf32(x: f32) -> f32; - fn sinf64(x: f64) -> f64; - // Computes the cosine of `x` radians - // Should be compatible with `x.cos()` from the standard library - fn cosf32(x: f32) -> f32; - fn cosf64(x: f64) -> f64; - // Computes the inverse tangent of `y / x`, in the corresponding quadrant - // Should be compatible with `y.atan2(x)` from the standard library - fn atan2f32(y: f32, x: f32) -> f32; - fn atan2f64(y: f64, x: f64) -> f64; - } - - #[cfg(not(feature = "soft_float"))] impl Float for f32 { fn sqrt(self) -> f32 { - unsafe { sqrtf32(self) } + F32Ext::cbrt(self) } fn cbrt(self) -> f32 { - unsafe { cbrtf32(self) } + F32Ext::sqrt(self) } fn powf(self, other: f32) -> f32 { - unsafe { powf32(self, other) } + F32Ext::powf(self, other) } fn sin(self) -> f32 { - unsafe { sinf32(self) } + F32Ext::sin(self) } fn cos(self) -> f32 { - unsafe { cosf32(self) } + F32Ext::cos(self) } fn atan2(self, other: f32) -> f32 { - unsafe { atan2f32(self, other) } + F32Ext::atan2(self, other) } } - #[cfg(not(feature = "soft_float"))] impl Float for f64 { fn sqrt(self) -> f64 { - unsafe { sqrtf64(self) } + F64Ext::sqrt(self) } fn cbrt(self) -> f64 { - unsafe { cbrtf64(self) } + F64Ext::cbrt(self) } fn powf(self, other: f64) -> f64 { - unsafe { powf64(self, other) } + F64Ext::powf(self, other) } fn sin(self) -> f64 { - unsafe { sinf64(self) } + F64Ext::sin(self) } fn cos(self) -> f64 { - unsafe { cosf64(self) } + F64Ext::cos(self) } fn atan2(self, other: f64) -> f64 { - unsafe { atan2f64(self, other) } + F64Ext::atan2(self, other) } } } diff --git a/palette/src/hsl.rs b/palette/src/hsl.rs index 01deb6b0d..7ade6277b 100644 --- a/palette/src/hsl.rs +++ b/palette/src/hsl.rs @@ -29,7 +29,7 @@ pub type Hsla = Alpha, T>; ///See [HSV](struct.Hsv.html) for a very similar color space, with brightness /// instead of lightness. #[derive(Debug, PartialEq, FromColor, Pixel)] -#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[cfg_attr(feature = "serializing", derive(Serialize, Deserialize))] #[palette_internal] #[palette_rgb_space = "S"] #[palette_white_point = "S::WhitePoint"] @@ -56,7 +56,7 @@ where ///The white point and RGB primaries this color is adapted to. The default ///is the sRGB standard. - #[cfg_attr(feature = "serde", serde(skip))] + #[cfg_attr(feature = "serializing", serde(skip))] #[palette_unsafe_zero_sized] pub space: PhantomData, } @@ -652,7 +652,7 @@ mod test { raw_pixel_conversion_tests!(Hsl: hue, saturation, lightness); raw_pixel_conversion_fail_tests!(Hsl: hue, saturation, lightness); - #[cfg(feature = "serde")] + #[cfg(feature = "serializing")] #[test] fn serialize() { let serialized = ::serde_json::to_string(&Hsl::new(0.3, 0.8, 0.1)).unwrap(); @@ -663,7 +663,7 @@ mod test { ); } - #[cfg(feature = "serde")] + #[cfg(feature = "serializing")] #[test] fn deserialize() { let deserialized: Hsl = diff --git a/palette/src/hsv.rs b/palette/src/hsv.rs index abe174a90..26fca96ac 100644 --- a/palette/src/hsv.rs +++ b/palette/src/hsv.rs @@ -25,7 +25,7 @@ pub type Hsva = Alpha, T>; ///and white (100% R, 100% G, 100% B) has the same brightness (or value), but ///not the same lightness. #[derive(Debug, PartialEq, FromColor, Pixel)] -#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[cfg_attr(feature = "serializing", derive(Serialize, Deserialize))] #[palette_internal] #[palette_white_point = "S::WhitePoint"] #[palette_rgb_space = "S"] @@ -53,7 +53,7 @@ where ///The white point and RGB primaries this color is adapted to. The default ///is the sRGB standard. - #[cfg_attr(feature = "serde", serde(skip))] + #[cfg_attr(feature = "serializing", serde(skip))] #[palette_unsafe_zero_sized] pub space: PhantomData, } @@ -663,7 +663,7 @@ mod test { raw_pixel_conversion_tests!(Hsv: hue, saturation, value); raw_pixel_conversion_fail_tests!(Hsv: hue, saturation, value); - #[cfg(feature = "serde")] + #[cfg(feature = "serializing")] #[test] fn serialize() { let serialized = ::serde_json::to_string(&Hsv::new(0.3, 0.8, 0.1)).unwrap(); @@ -671,7 +671,7 @@ mod test { assert_eq!(serialized, r#"{"hue":0.3,"saturation":0.8,"value":0.1}"#); } - #[cfg(feature = "serde")] + #[cfg(feature = "serializing")] #[test] fn deserialize() { let deserialized: Hsv = diff --git a/palette/src/hues.rs b/palette/src/hues.rs index 8fc9a1c1d..4df9f77cf 100644 --- a/palette/src/hues.rs +++ b/palette/src/hues.rs @@ -16,7 +16,7 @@ macro_rules! make_hues { /// also have some surprising effects if it's expected to act as a /// linear number. #[derive(Clone, Copy, Debug, Default)] - #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] + #[cfg_attr(feature = "serializing", derive(Serialize, Deserialize))] #[repr(C)] pub struct $name(T); @@ -314,7 +314,7 @@ mod test { } } - #[cfg(feature = "serde")] + #[cfg(feature = "serializing")] #[test] fn serialize() { let serialized = ::serde_json::to_string(&RgbHue::from_degrees(10.2)).unwrap(); @@ -322,7 +322,7 @@ mod test { assert_eq!(serialized, "10.2"); } - #[cfg(feature = "serde")] + #[cfg(feature = "serializing")] #[test] fn deserialize() { let deserialized: RgbHue = ::serde_json::from_str("10.2").unwrap(); diff --git a/palette/src/hwb.rs b/palette/src/hwb.rs index 5c9e75b3e..c04816c99 100644 --- a/palette/src/hwb.rs +++ b/palette/src/hwb.rs @@ -27,7 +27,7 @@ pub type Hwba = Alpha, T>; ///It is very intuitive for humans to use and many color-pickers are based on /// the HWB color system #[derive(Debug, PartialEq, FromColor, Pixel)] -#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[cfg_attr(feature = "serializing", derive(Serialize, Deserialize))] #[palette_internal] #[palette_rgb_space = "S"] #[palette_white_point = "S::WhitePoint"] @@ -59,7 +59,7 @@ where ///The white point and RGB primaries this color is adapted to. The default ///is the sRGB standard. - #[cfg_attr(feature = "serde", serde(skip))] + #[cfg_attr(feature = "serializing", serde(skip))] #[palette_unsafe_zero_sized] pub space: PhantomData, } @@ -621,7 +621,7 @@ mod test { raw_pixel_conversion_tests!(Hwb: hue, whiteness, blackness); raw_pixel_conversion_fail_tests!(Hwb: hue, whiteness, blackness); - #[cfg(feature = "serde")] + #[cfg(feature = "serializing")] #[test] fn serialize() { let serialized = ::serde_json::to_string(&Hwb::new(0.3, 0.8, 0.1)).unwrap(); @@ -629,7 +629,7 @@ mod test { assert_eq!(serialized, r#"{"hue":0.3,"whiteness":0.8,"blackness":0.1}"#); } - #[cfg(feature = "serde")] + #[cfg(feature = "serializing")] #[test] fn deserialize() { let deserialized: Hwb = diff --git a/palette/src/lab.rs b/palette/src/lab.rs index 4d04b8cb3..65ec364f6 100644 --- a/palette/src/lab.rs +++ b/palette/src/lab.rs @@ -25,7 +25,7 @@ pub type Laba = Alpha, T>; ///The parameters of L\*a\*b\* are quite different, compared to many other /// color spaces, so manipulating them manually may be unintuitive. #[derive(Debug, PartialEq, FromColor, Pixel)] -#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[cfg_attr(feature = "serializing", derive(Serialize, Deserialize))] #[palette_internal] #[palette_white_point = "Wp"] #[palette_component = "T"] @@ -48,7 +48,7 @@ where ///The white point associated with the color's illuminant and observer. ///D65 for 2 degree observer is used by default. - #[cfg_attr(feature = "serde", serde(skip))] + #[cfg_attr(feature = "serializing", serde(skip))] #[palette_unsafe_zero_sized] pub white_point: PhantomData, } @@ -547,7 +547,7 @@ mod test { raw_pixel_conversion_tests!(Lab: l, a, b); raw_pixel_conversion_fail_tests!(Lab: l, a, b); - #[cfg(feature = "serde")] + #[cfg(feature = "serializing")] #[test] fn serialize() { let serialized = ::serde_json::to_string(&Lab::new(0.3, 0.8, 0.1)).unwrap(); @@ -555,7 +555,7 @@ mod test { assert_eq!(serialized, r#"{"l":0.3,"a":0.8,"b":0.1}"#); } - #[cfg(feature = "serde")] + #[cfg(feature = "serializing")] #[test] fn deserialize() { let deserialized: Lab = ::serde_json::from_str(r#"{"l":0.3,"a":0.8,"b":0.1}"#).unwrap(); diff --git a/palette/src/lch.rs b/palette/src/lch.rs index 288b9fb6e..c9386ecf0 100644 --- a/palette/src/lch.rs +++ b/palette/src/lch.rs @@ -20,7 +20,7 @@ pub type Lcha = Alpha, T>; ///[HSV](struct.Hsv.html). This gives it the same ability to directly change ///the hue and colorfulness of a color, while preserving other visual aspects. #[derive(Debug, PartialEq, FromColor, Pixel)] -#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[cfg_attr(feature = "serializing", derive(Serialize, Deserialize))] #[palette_internal] #[palette_white_point = "Wp"] #[palette_component = "T"] @@ -48,7 +48,7 @@ where ///The white point associated with the color's illuminant and observer. ///D65 for 2 degree observer is used by default. - #[cfg_attr(feature = "serde", serde(skip))] + #[cfg_attr(feature = "serializing", serde(skip))] #[palette_unsafe_zero_sized] pub white_point: PhantomData, } @@ -444,7 +444,7 @@ mod test { raw_pixel_conversion_tests!(Lch: l, chroma, hue); raw_pixel_conversion_fail_tests!(Lch: l, chroma, hue); - #[cfg(feature = "serde")] + #[cfg(feature = "serializing")] #[test] fn serialize() { let serialized = ::serde_json::to_string(&Lch::new(0.3, 0.8, 0.1)).unwrap(); @@ -452,7 +452,7 @@ mod test { assert_eq!(serialized, r#"{"l":0.3,"chroma":0.8,"hue":0.1}"#); } - #[cfg(feature = "serde")] + #[cfg(feature = "serializing")] #[test] fn deserialize() { let deserialized: Lch = diff --git a/palette/src/lib.rs b/palette/src/lib.rs index ed2758eb5..5c9e5437e 100644 --- a/palette/src/lib.rs +++ b/palette/src/lib.rs @@ -156,10 +156,10 @@ extern crate num_traits; #[cfg(feature = "phf")] extern crate phf; -#[cfg(feature = "serde")] +#[cfg(feature = "serializing")] #[macro_use] extern crate serde; -#[cfg(all(test, feature = "serde"))] +#[cfg(all(test, feature = "serializing"))] extern crate serde_json; use num_traits::{NumCast, ToPrimitive, Zero}; diff --git a/palette/src/luma/luma.rs b/palette/src/luma/luma.rs index bcaf4f8e1..bb5824ee3 100644 --- a/palette/src/luma/luma.rs +++ b/palette/src/luma/luma.rs @@ -28,7 +28,7 @@ pub type Lumaa = Alpha, T>; ///XYZ](struct.Xyz.html). The lack of any form of hue representation limits ///the set of operations that can be performed on it. #[derive(Debug, PartialEq, FromColor, Pixel)] -#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[cfg_attr(feature = "serializing", derive(Serialize, Deserialize))] #[palette_internal] #[palette_white_point = "S::WhitePoint"] #[palette_component = "T"] @@ -43,7 +43,7 @@ where pub luma: T, /// The kind of RGB standard. sRGB is the default. - #[cfg_attr(feature = "serde", serde(skip))] + #[cfg_attr(feature = "serializing", serde(skip))] #[palette_unsafe_zero_sized] pub standard: PhantomData, } @@ -694,7 +694,7 @@ mod test { assert_eq!(format!("{:03X}", Luma::::new(1)), "001"); } - #[cfg(feature = "serde")] + #[cfg(feature = "serializing")] #[test] fn serialize() { let serialized = ::serde_json::to_string(&Luma::::new(0.3)).unwrap(); @@ -702,7 +702,7 @@ mod test { assert_eq!(serialized, r#"{"luma":0.3}"#); } - #[cfg(feature = "serde")] + #[cfg(feature = "serializing")] #[test] fn deserialize() { let deserialized: Luma = ::serde_json::from_str(r#"{"luma":0.3}"#).unwrap(); diff --git a/palette/src/rgb/rgb.rs b/palette/src/rgb/rgb.rs index b40c27dfd..35ca9eb3a 100644 --- a/palette/src/rgb/rgb.rs +++ b/palette/src/rgb/rgb.rs @@ -36,7 +36,7 @@ pub type Rgba = Alpha, T>; /// from a displayable RGB, such as sRGB. See the [`pixel`](pixel/index.html) /// module for encoding formats. #[derive(Debug, PartialEq, FromColor, Pixel)] -#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[cfg_attr(feature = "serializing", derive(Serialize, Deserialize))] #[palette_internal] #[palette_rgb_space = "S::Space"] #[palette_white_point = "::WhitePoint"] @@ -57,7 +57,7 @@ pub struct Rgb { pub blue: T, /// The kind of RGB standard. sRGB is the default. - #[cfg_attr(feature = "serde", serde(skip))] + #[cfg_attr(feature = "serializing", serde(skip))] #[palette_unsafe_zero_sized] pub standard: PhantomData, } @@ -969,7 +969,7 @@ mod test { ); } - #[cfg(feature = "serde")] + #[cfg(feature = "serializing")] #[test] fn serialize() { let serialized = ::serde_json::to_string(&Rgb::::new(0.3, 0.8, 0.1)).unwrap(); @@ -977,7 +977,7 @@ mod test { assert_eq!(serialized, r#"{"red":0.3,"green":0.8,"blue":0.1}"#); } - #[cfg(feature = "serde")] + #[cfg(feature = "serializing")] #[test] fn deserialize() { let deserialized: Rgb = diff --git a/palette/src/xyz.rs b/palette/src/xyz.rs index 3ff3a9d1e..84ab59859 100644 --- a/palette/src/xyz.rs +++ b/palette/src/xyz.rs @@ -26,7 +26,7 @@ pub type Xyza = Alpha, T>; ///Conversions and operations on this color space depend on the defined white /// point #[derive(Debug, PartialEq, FromColor, Pixel)] -#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[cfg_attr(feature = "serializing", derive(Serialize, Deserialize))] #[palette_internal] #[palette_white_point = "Wp"] #[palette_component = "T"] @@ -52,7 +52,7 @@ where ///The white point associated with the color's illuminant and observer. ///D65 for 2 degree observer is used by default. - #[cfg_attr(feature = "serde", serde(skip))] + #[cfg_attr(feature = "serializing", serde(skip))] #[palette_unsafe_zero_sized] pub white_point: PhantomData, } @@ -565,7 +565,7 @@ mod test { raw_pixel_conversion_tests!(Xyz: x, y, z); raw_pixel_conversion_fail_tests!(Xyz: x, y, z); - #[cfg(feature = "serde")] + #[cfg(feature = "serializing")] #[test] fn serialize() { let serialized = ::serde_json::to_string(&Xyz::new(0.3, 0.8, 0.1)).unwrap(); @@ -573,7 +573,7 @@ mod test { assert_eq!(serialized, r#"{"x":0.3,"y":0.8,"z":0.1}"#); } - #[cfg(feature = "serde")] + #[cfg(feature = "serializing")] #[test] fn deserialize() { let deserialized: Xyz = ::serde_json::from_str(r#"{"x":0.3,"y":0.8,"z":0.1}"#).unwrap(); diff --git a/palette/src/yxy.rs b/palette/src/yxy.rs index 78083627c..01f51feee 100644 --- a/palette/src/yxy.rs +++ b/palette/src/yxy.rs @@ -22,7 +22,7 @@ pub type Yxya = Alpha, T>; /// ///Conversions and operations on this color space depend on the white point. #[derive(Debug, PartialEq, FromColor, Pixel)] -#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[cfg_attr(feature = "serializing", derive(Serialize, Deserialize))] #[palette_internal] #[palette_white_point = "Wp"] #[palette_component = "T"] @@ -48,7 +48,7 @@ where ///The white point associated with the color's illuminant and observer. ///D65 for 2 degree observer is used by default. - #[cfg_attr(feature = "serde", serde(skip))] + #[cfg_attr(feature = "serializing", serde(skip))] #[palette_unsafe_zero_sized] pub white_point: PhantomData, } @@ -528,7 +528,7 @@ mod test { raw_pixel_conversion_tests!(Yxy: x, y, luma); raw_pixel_conversion_fail_tests!(Yxy: x, y, luma); - #[cfg(feature = "serde")] + #[cfg(feature = "serializing")] #[test] fn serialize() { let serialized = ::serde_json::to_string(&Yxy::new(0.3, 0.8, 0.1)).unwrap(); @@ -536,7 +536,7 @@ mod test { assert_eq!(serialized, r#"{"x":0.3,"y":0.8,"luma":0.1}"#); } - #[cfg(feature = "serde")] + #[cfg(feature = "serializing")] #[test] fn deserialize() { let deserialized: Yxy = ::serde_json::from_str(r#"{"x":0.3,"y":0.8,"luma":0.1}"#).unwrap(); diff --git a/scripts/test_features.sh b/scripts/test_features.sh index d302caaee..385773ac7 100644 --- a/scripts/test_features.sh +++ b/scripts/test_features.sh @@ -4,7 +4,7 @@ set -e features="" #Features that will always be activated -required_features="strict soft_float" +required_features="strict" #Find features From 70d9426f337961def59a342748673e429b906ec5 Mon Sep 17 00:00:00 2001 From: Mark Barbone Date: Wed, 1 Aug 2018 12:00:32 -0400 Subject: [PATCH 14/16] Tighten error margins back to previous margins --- palette/src/convert.rs | 2 +- palette/tests/color_checker_data/mod.rs | 3 --- palette/tests/convert/lab_lch.rs | 12 ++++++------ palette/tests/pointer_dataset/pointer_data.rs | 3 --- 4 files changed, 7 insertions(+), 13 deletions(-) diff --git a/palette/src/convert.rs b/palette/src/convert.rs index 0dcbaf069..446e82cae 100644 --- a/palette/src/convert.rs +++ b/palette/src/convert.rs @@ -393,7 +393,7 @@ where /// ]; /// let hsv = Bgr::from_raw_slice(&buffer)[1].into(); /// -/// assert_relative_eq!(hsv, Hsv::new(90.0, 1.0, 0.5), epsilon = 0.001); +/// assert_relative_eq!(hsv, Hsv::new(90.0, 1.0, 0.5)); /// } /// ``` /// diff --git a/palette/tests/color_checker_data/mod.rs b/palette/tests/color_checker_data/mod.rs index 1477d00fd..8a105662e 100644 --- a/palette/tests/color_checker_data/mod.rs +++ b/palette/tests/color_checker_data/mod.rs @@ -2,10 +2,7 @@ mod babel; mod color_checker; mod load_data; -#[cfg(feature = "std")] const MAX_ERROR: f64 = 0.000000000001; -#[cfg(not(feature = "std"))] -const MAX_ERROR: f64 = 0.001; #[test] pub fn babel_from_yxy() { diff --git a/palette/tests/convert/lab_lch.rs b/palette/tests/convert/lab_lch.rs index c854a20a2..914eac2a9 100644 --- a/palette/tests/convert/lab_lch.rs +++ b/palette/tests/convert/lab_lch.rs @@ -7,8 +7,8 @@ fn lab_lch_green() { let expect_lab = lch.into_lab(); let expect_lch = lab.into_lch(); - assert_relative_eq!(lab, expect_lab, epsilon = 0.1); - assert_relative_eq!(lch, expect_lch, epsilon = 0.1); + assert_relative_eq!(lab, expect_lab, epsilon = 0.001); + assert_relative_eq!(lch, expect_lch, epsilon = 0.001); } #[test] @@ -19,8 +19,8 @@ fn lab_lch_magenta() { let expect_lab = lch.into_lab(); let expect_lch = lab.into_lch(); - assert_relative_eq!(lab, expect_lab, epsilon = 0.1); - assert_relative_eq!(lch, expect_lch, epsilon = 0.1); + assert_relative_eq!(lab, expect_lab, epsilon = 0.001); + assert_relative_eq!(lch, expect_lch, epsilon = 0.001); } #[test] @@ -31,6 +31,6 @@ fn lab_lch_blue() { let expect_lab = lch.into_lab(); let expect_lch = lab.into_lch(); - assert_relative_eq!(lab, expect_lab, epsilon = 0.1); - assert_relative_eq!(lch, expect_lch, epsilon = 0.1); + assert_relative_eq!(lab, expect_lab, epsilon = 0.001); + assert_relative_eq!(lch, expect_lch, epsilon = 0.001); } diff --git a/palette/tests/pointer_dataset/pointer_data.rs b/palette/tests/pointer_dataset/pointer_data.rs index aa1e1f35c..1ed1c47ba 100644 --- a/palette/tests/pointer_dataset/pointer_data.rs +++ b/palette/tests/pointer_dataset/pointer_data.rs @@ -93,10 +93,7 @@ fn load_data() -> Vec { } fn check_equal(src: &PointerData, tgt: &PointerData) { - #[cfg(feature = "std")] const MAX_ERROR: f64 = 0.000000000001; - #[cfg(not(feature = "std"))] - const MAX_ERROR: f64 = 1.0; assert_relative_eq!(src.lch, tgt.lch, epsilon = MAX_ERROR); assert_relative_eq!(src.lab, tgt.lab, epsilon = MAX_ERROR); } From e9d060a394bb0d3a58807717035614a9929e67fb Mon Sep 17 00:00:00 2001 From: Mark Barbone Date: Wed, 1 Aug 2018 15:29:54 -0400 Subject: [PATCH 15/16] Temporary feature to disable libm --- palette/Cargo.toml | 4 ++-- palette/src/blend/blend.rs | 2 +- palette/src/blend/equations.rs | 2 +- palette/src/float.rs | 5 ++--- 4 files changed, 6 insertions(+), 7 deletions(-) diff --git a/palette/Cargo.toml b/palette/Cargo.toml index 995529cd6..8974a782a 100644 --- a/palette/Cargo.toml +++ b/palette/Cargo.toml @@ -16,7 +16,7 @@ build = "build/main.rs" default = ["named_from_str", "std"] named_from_str = ["named", "phf", "phf_codegen", "std"] named = [] -std = ["num-traits/std", "approx/std"] +std = ["approx/std"] serializing = ["serde", "std"] #internal @@ -24,7 +24,7 @@ strict = [] [dependencies] palette_derive = {version = "0.4.0", path = "../palette_derive"} -num-traits = {version = "0.2", default-features = false} +num-traits = {version = "0.2"} approx = {version = "0.2", default-features = false} libm = "0.1.2" diff --git a/palette/src/blend/blend.rs b/palette/src/blend/blend.rs index 111c3669b..1d3200f19 100644 --- a/palette/src/blend/blend.rs +++ b/palette/src/blend/blend.rs @@ -1,6 +1,6 @@ use num_traits::{One, Zero}; use float::Float; -#[cfg(not(feature = "std"))] +#[cfg(feature = "libm_works")] use num_traits::float::FloatCore; use {cast, clamp, ComponentWise}; diff --git a/palette/src/blend/equations.rs b/palette/src/blend/equations.rs index 86b576550..b3b412ca5 100644 --- a/palette/src/blend/equations.rs +++ b/palette/src/blend/equations.rs @@ -1,5 +1,5 @@ use float::Float; -#[cfg(not(feature = "std"))] +#[cfg(feature = "libm_works")] use num_traits::float::FloatCore; use {Blend, ComponentWise}; diff --git a/palette/src/float.rs b/palette/src/float.rs index 35c1356a6..e9b084d47 100644 --- a/palette/src/float.rs +++ b/palette/src/float.rs @@ -9,13 +9,12 @@ //! //! [`libm`]: https://github.com/japaric/libm -#[cfg(feature = "std")] pub use num_traits::Float; -#[cfg(not(feature = "std"))] +#[cfg(feature = "libm_works")] pub use self::no_std_float_trait::Float; -#[cfg(not(feature = "std"))] +#[cfg(feature = "libm_works")] mod no_std_float_trait { extern crate libm; use self::libm::{F32Ext, F64Ext}; From c729c30a6749332b99ff2172befb9b38eb8001ad Mon Sep 17 00:00:00 2001 From: Mark Barbone Date: Mon, 27 Aug 2018 17:37:19 -0400 Subject: [PATCH 16/16] Re-disable import warnings in derived blocks --- palette_derive/src/util.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/palette_derive/src/util.rs b/palette_derive/src/util.rs index 1dcb18048..2e10227a5 100644 --- a/palette_derive/src/util.rs +++ b/palette_derive/src/util.rs @@ -14,7 +14,7 @@ pub fn bundle_impl( if internal { quote!{ - #[allow(non_snake_case, unused_attributes, unused_qualifications)] + #[allow(non_snake_case, unused_attributes, unused_qualifications, unused_imports)] mod #const_name { use float::Float as _FloatTrait; use super::*; @@ -23,7 +23,7 @@ pub fn bundle_impl( } } else { quote!{ - #[allow(non_snake_case, unused_attributes, unused_qualifications)] + #[allow(non_snake_case, unused_attributes, unused_qualifications, unused_imports)] mod #const_name { extern crate palette as _palette; use self::_palette::float::Float as _FloatTrait;