diff --git a/Cargo.lock b/Cargo.lock index 6c57d37..5092d5a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -102,6 +102,7 @@ dependencies = [ name = "codi-core" version = "0.1.0" dependencies = [ + "libm", "ordered-float", ] @@ -144,6 +145,12 @@ version = "0.2.153" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" +[[package]] +name = "libm" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" + [[package]] name = "memchr" version = "2.7.2" diff --git a/README.md b/README.md index f768e73..d1cf289 100644 --- a/README.md +++ b/README.md @@ -64,6 +64,3 @@ $ nix develop ./nix # devShell $ direnv allow # direnv with devShell $ nix flake check ./nix # run CI locally ``` - -## TODO -- [ ] No-std support: not easy because no_std doesn't have common float operations (thumbv6m-none-eabi target) diff --git a/codi-core/Cargo.toml b/codi-core/Cargo.toml index f522062..8343ed4 100644 --- a/codi-core/Cargo.toml +++ b/codi-core/Cargo.toml @@ -10,7 +10,12 @@ description.workspace = true readme.workspace = true [dependencies] -ordered-float = { version = "4.2.0" } +libm = "0.2.8" +ordered-float = { version = "4.2.0", default-features = false } + +[features] +default = ["std"] +std = [] [lints] workspace = true diff --git a/codi-core/src/color_dist.rs b/codi-core/src/color_dist.rs index 76be48a..3478411 100644 --- a/codi-core/src/color_dist.rs +++ b/codi-core/src/color_dist.rs @@ -1,3 +1,4 @@ +use libm::{hypotf, powf, sqrtf}; use ordered_float::NotNan; use crate::color_space::{Cielab, Rgb}; @@ -30,9 +31,9 @@ pub struct Euclidean; impl ColorDistance for Euclidean { fn dist(&self, c1: Rgb, c2: Rgb) -> NotNan { - let dist = (f32::from(c1.r) - f32::from(c2.r)).powi(2) - + (f32::from(c1.g) - f32::from(c2.g)).powi(2) - + (f32::from(c1.b) - f32::from(c2.b)).powi(2); + let dist = powf(f32::from(c1.r) - f32::from(c2.r), 2.0) + + powf(f32::from(c1.g) - f32::from(c2.g), 2.0) + + powf(f32::from(c1.b) - f32::from(c2.b), 2.0); NotNan::new(dist).unwrap() } } @@ -55,9 +56,9 @@ impl ColorDistance for EuclideanImproved { (f32::from(c1.g) - f32::from(c2.g)), (f32::from(c1.b) - f32::from(c2.b)), ); - let dist: f32 = (2.0 + red_mean / 256.0) * d_r.powi(2) - + 4.0 * d_g.powi(2) - + (2.0 + (255.0 - red_mean) / 256.0) * d_b.powi(2); + let dist: f32 = powf((2.0 + red_mean / 256.0) * d_r, 2.0) + + 4.0 * powf(d_g, 2.0) + + powf((2.0 + (255.0 - red_mean) / 256.0) * d_b, 2.0); NotNan::new(dist).unwrap() } } @@ -81,20 +82,19 @@ impl ColorDistance for CIE94 { let (delta_l, delta_a, delta_b) = (lab1.l - lab2.l, lab1.a - lab2.a, lab1.b - lab2.b); - let C1 = lab1.a.hypot(lab1.b.into_inner()); - let C2 = lab2.a.hypot(lab2.b.into_inner()); + let C1 = hypotf(*lab1.a, *lab1.b); + let C2 = hypotf(*lab2.a, *lab2.b); let Cab = C1 - C2; let Sl = 1.0; let Sc = 1.0 + K1 * C1; let Sh = 1.0 + K2 * C1; // https://github.com/zschuessler/DeltaE/issues/9 - let Hab = (delta_a.powi(2) + delta_b.powi(2) - Cab.powi(2)) - .max(0.0) - .sqrt(); + let Hab = sqrtf((powf(*delta_a, 2.0) + powf(*delta_b, 2.0) - powf(Cab, 2.0)).max(0.0)); - let dist = - (delta_l / (kL * Sl)).powi(2) + (Cab / (kC * Sc)).powi(2) + (Hab / (kH * Sh)).powi(2); + let dist = powf(*delta_l / (kL * Sl), 2.0) + + powf(Cab / (kC * Sc), 2.0) + + powf(Hab / (kH * Sh), 2.0); NotNan::new(dist).unwrap() } } diff --git a/codi-core/src/color_space.rs b/codi-core/src/color_space.rs index 674e860..318d12c 100644 --- a/codi-core/src/color_space.rs +++ b/codi-core/src/color_space.rs @@ -1,3 +1,4 @@ +use libm::{cbrtf, powf, roundf}; use ordered_float::NotNan; const HEX_COLOR_LEN: usize = 6; @@ -33,6 +34,7 @@ impl core::fmt::Display for Error { } } +#[cfg(feature = "std")] impl std::error::Error for Error {} type Result = core::result::Result; @@ -134,7 +136,7 @@ impl From for Rgb { if col <= 0.003_130_8 { col * 12.92 } else { - col.powf(1.0 / 2.4) * 1.055 - 0.055 + powf(col, 1.0 / 2.4) * 1.055 - 0.055 } }; @@ -147,9 +149,9 @@ impl From for Rgb { ); Self { - r: (corrected.0).round() as u8, - g: (corrected.1).round() as u8, - b: (corrected.2).round() as u8, + r: roundf(corrected.0) as u8, + g: roundf(corrected.1) as u8, + b: roundf(corrected.2) as u8, } } } @@ -203,7 +205,7 @@ impl From for Xyz { if col <= 0.04045 { col / 12.92 } else { - ((col + 0.055) / 1.055).powf(2.4) + powf((col + 0.055) / 1.055, 2.4) } }; @@ -231,7 +233,7 @@ impl From for Xyz { fn from(value: Cielab) -> Self { let f_inv = |t: f32| { if t > LAB_XYZ_DELTA { - t.powi(3) + powf(t, 3.0) } else { 3.0 * LAB_XYZ_DELTA_POW2 * (t - 4.0 / 29.0) } @@ -265,9 +267,9 @@ impl From for Cielab { fn from(value: Xyz) -> Self { let f = |t: f32| { if t > LAB_XYZ_DELTA_POW3 { - t.cbrt() + cbrtf(t) } else { - 1.0 / 3.0 * t * LAB_XYZ_DELTA.powi(-2) + 4.0 / 29.0 + 1.0 / 3.0 * t * powf(LAB_XYZ_DELTA, -2.0) + 4.0 / 29.0 } }; diff --git a/codi-core/src/lib.rs b/codi-core/src/lib.rs index 6d7cca9..feb11d3 100644 --- a/codi-core/src/lib.rs +++ b/codi-core/src/lib.rs @@ -1,3 +1,5 @@ +#![cfg_attr(not(feature = "std"), no_std)] + pub mod color_dist; pub mod color_space; pub mod html_color; diff --git a/codi-core/src/math_utils.rs b/codi-core/src/math_utils.rs index 877aecf..e4bd8ae 100644 --- a/codi-core/src/math_utils.rs +++ b/codi-core/src/math_utils.rs @@ -6,7 +6,7 @@ pub fn matrix_mul( m2: &[[T; J]; K], ) -> [[T; J]; I] where - T: std::ops::Mul + std::ops::Add + Default + Copy, + T: core::ops::Mul + core::ops::Add + Default + Copy, { let mut res: [[T; J]; I] = [[T::default(); J]; I]; diff --git a/nix/flake.nix b/nix/flake.nix index ce879d0..ce6e9b3 100644 --- a/nix/flake.nix +++ b/nix/flake.nix @@ -17,7 +17,7 @@ rust = (pkgs.rust-bin.fromRustupToolchainFile ../rust-toolchain.toml) .override { - targets = []; + targets = ["thumbv6m-none-eabi"]; extensions = []; }; rust-nightly = pkgs.rust-bin.nightly."2024-02-01".default; @@ -66,6 +66,8 @@ doCheck = true; postCheck = '' + cargo build -p codi-core --target thumbv6m-none-eabi --no-default-features + cargo clippy --all-targets cargo fmt --check cargo doc