Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add named color iterators and remove phf macro dependency #422

Merged
merged 1 commit into from
Nov 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions codegen/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,7 @@ publish = false
anyhow = "1.0.86"
proc-macro2 = "1.0.86"
quote = "1.0.37"
phf = "0.11.2"
phf_codegen = "0.11.2"


19 changes: 12 additions & 7 deletions codegen/src/named.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,14 +101,19 @@ fn build_colors(colors: &[ColorEntry]) -> TokenStream {
}

fn build_from_str(entries: &[ColorEntry]) -> TokenStream {
let entries = entries
.iter()
.map(|ColorEntry { name, constant, .. }| quote! {#name => #constant});
let mut map = phf_codegen::Map::new();

for entry in entries {
map.entry(&*entry.name, &entry.constant.to_string());
}

let phf_entries: TokenStream = map
.build()
.to_string()
.parse()
.expect("phf should generate a valid token stream");

quote! {
#[cfg(feature = "named_from_str")]
pub(crate) static COLORS: ::phf::Map<&'static str, crate::rgb::Srgb<u8>> = phf::phf_map! {
#(#entries),*
};
pub(crate) static COLORS: ::phf::Map<&'static str, crate::rgb::Srgb<u8>> = #phf_entries;
}
}
2 changes: 1 addition & 1 deletion no_std_test/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ bench = false
[features]
nightly = []
# Avoids getting these features included in other packages in the same workspace.
all_features = ["palette/libm", "palette/named_from_str"]
all_features = ["palette/libm", "palette/named"]

[dependencies.libc]
version = "0.2"
Expand Down
7 changes: 4 additions & 3 deletions palette/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,16 @@ rust-version = "1.61.0"

[features]
default = ["named_from_str", "std", "approx"]
named_from_str = ["named", "phf"]
named = []
named = ["phf"]
random = ["rand"]
serializing = ["serde", "std"]
find-crate = ["palette_derive/find-crate"]
std = ["alloc", "approx?/std"]
alloc = []

# Deprecated. Alias for `"named"`.
named_from_str = ["named"]

[lib]
bench = false

Expand All @@ -49,7 +51,6 @@ libm = { version = "0.2.1", default-features = false, optional = true }
version = "0.11.0"
optional = true
default-features = false
features = ["macros"]

[dependencies.rand]
version = "0.8"
Expand Down
5 changes: 4 additions & 1 deletion palette/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@ features = ["libm"] # Uses libm instead of std for floating point math
These features are enabled by default:

* `"named"` - Enables color constants, located in the `named` module.
* `"named_from_str"` - Enables `named::from_str`, which maps name strings to colors.
* `"std"` - Enables use of the standard library. Also enables `"alloc"`.
* `"alloc"` - Enables implementations for allocating types, such as `Vec` or `Box`.
* `"approx"` - Enables approximate comparison using [`approx`].
Expand All @@ -56,6 +55,10 @@ These features are disabled by default:
* `"wide"` - Enables support for using SIMD types from [`wide`].
* `"find-crate"` - Enables derives to find the `palette` crate when it's renamed in `Cargo.toml`.

These features have been deprecated:

* `"named_from_str"` - Alias for `"named"`, still enabled by default. <strike>Enables `named::from_str`, which maps name strings to colors.</strike>

### Using palette in an embedded environment

Palette supports `#![no_std]` environments by disabling the `"std"` feature. It uses [`libm`], via the `"libm"` feature, to provide the floating-point operations that are typically in `std`, and the `"alloc"` feature to provide features that use allocating types. However, serializing with `serde` is not available without the standard library.
Expand Down
167 changes: 146 additions & 21 deletions palette/src/named.rs
Original file line number Diff line number Diff line change
@@ -1,39 +1,164 @@
//! A collection of named color constants. Can be toggled with the `"named"` and
//! `"named_from_str"` Cargo features.
//! A collection of named color constants. Can be toggled with the `"named"`
//! Cargo features.
//!
//! They are taken from the [SVG keyword
//! colors](https://www.w3.org/TR/SVG11/types.html#ColorKeywords) (same as in
//! CSS3) and they can be used as if they were pixel values:
//! colors](https://www.w3.org/TR/SVG11/types.html#ColorKeywords). These are
//! also part of the CSS3 standard.
//!
//! ```
//! use palette::Srgb;
//! use palette::named;
//!
//! //From constant
//! let from_const = Srgb::<f32>::from_format(named::OLIVE).into_linear();
#![cfg_attr(feature = "named_from_str", doc = "")]
#![cfg_attr(feature = "named_from_str", doc = "//From name string")]
#![cfg_attr(
feature = "named_from_str",
doc = "let olive = named::from_str(\"olive\").expect(\"unknown color\");"
)]
#![cfg_attr(
feature = "named_from_str",
doc = "let from_str = Srgb::<f32>::from_format(olive).into_linear();"
)]
#![cfg_attr(feature = "named_from_str", doc = "")]
#![cfg_attr(feature = "named_from_str", doc = "assert_eq!(from_const, from_str);")]
//! let from_const = named::OLIVE;
//!
//! //From name string
//! let from_str = named::from_str("olive").expect("unknown color");
//!
//! assert_eq!(from_const, from_str);
//! ```

use core::{fmt, iter::FusedIterator};

pub use codegen::*;

mod codegen;

/// Get a SVG/CSS3 color by name. Can be toggled with the `"named_from_str"`
/// Cargo feature.
/// Get an SVG/CSS3 color by name.
///
/// The names are the same as the constants, but lower case.
#[cfg(feature = "named_from_str")]
pub fn from_str(name: &str) -> Option<crate::Srgb<u8>> {
COLORS.get(name).cloned()
COLORS.get(name).copied()
}

/// Get an iterator over all SVG/CSS3 names and colors in arbitrary order.
///
/// ```
/// use palette::Srgb;
///
/// let red = Srgb::new(255u8, 0, 0);
///
/// let red_entry = palette::named::entries().find(|(name, color)| *color == red);
/// assert_eq!(red_entry, Some(("red", red)));
/// ```
pub fn entries() -> Entries {
Entries {
iter: COLORS.entries(),
}
}

/// Get an iterator over all SVG/CSS3 color names in arbitrary order.
pub fn names() -> Names {
Names {
iter: COLORS.keys(),
}
}

/// Get an iterator over all SVG/CSS3 color values in arbitrary order.
pub fn colors() -> Colors {
Colors {
iter: COLORS.values(),
}
}

/// An iterator over SVG/CSS3 color entries.
#[derive(Clone)]
pub struct Entries {
iter: phf::map::Entries<'static, &'static str, crate::Srgb<u8>>,
}

impl fmt::Debug for Entries {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.iter.fmt(f)
}
}

impl Iterator for Entries {
type Item = (&'static str, crate::Srgb<u8>);

fn next(&mut self) -> Option<Self::Item> {
self.iter.next().map(|(&name, &color)| (name, color))
}

fn size_hint(&self) -> (usize, Option<usize>) {
self.iter.size_hint()
}
}

impl DoubleEndedIterator for Entries {
fn next_back(&mut self) -> Option<Self::Item> {
self.iter.next_back().map(|(&name, &color)| (name, color))
}
}

impl ExactSizeIterator for Entries {}

impl FusedIterator for Entries {}

/// An iterator over SVG/CSS3 color names.
#[derive(Clone)]
pub struct Names {
iter: phf::map::Keys<'static, &'static str, crate::Srgb<u8>>,
}

impl fmt::Debug for Names {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.iter.fmt(f)
}
}

impl Iterator for Names {
type Item = &'static str;

fn next(&mut self) -> Option<Self::Item> {
self.iter.next().copied()
}

fn size_hint(&self) -> (usize, Option<usize>) {
self.iter.size_hint()
}
}

impl DoubleEndedIterator for Names {
fn next_back(&mut self) -> Option<Self::Item> {
self.iter.next_back().copied()
}
}

impl ExactSizeIterator for Names {}

impl FusedIterator for Names {}

/// An iterator over SVG/CSS3 color values.
#[derive(Clone)]
pub struct Colors {
iter: phf::map::Values<'static, &'static str, crate::Srgb<u8>>,
}

impl fmt::Debug for Colors {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.iter.fmt(f)
}
}

impl Iterator for Colors {
type Item = crate::Srgb<u8>;

fn next(&mut self) -> Option<Self::Item> {
self.iter.next().copied()
}

fn size_hint(&self) -> (usize, Option<usize>) {
self.iter.size_hint()
}
}

impl DoubleEndedIterator for Colors {
fn next_back(&mut self) -> Option<Self::Item> {
self.iter.next_back().copied()
}
}

impl ExactSizeIterator for Colors {}

impl FusedIterator for Colors {}
Loading
Loading