From 4399b9552f202416901562ed2137d925cc13f35c Mon Sep 17 00:00:00 2001
From: Daniel Olano <daniel@olanod.com>
Date: Fri, 31 May 2024 12:12:53 +0200
Subject: [PATCH 1/5] Make create no_std compatible

---
 Cargo.toml                    | 2 ++
 color/lib.rs                  | 6 +++---
 src/color.rs                  | 2 +-
 src/cow_rc_str.rs             | 7 ++++---
 src/lib.rs                    | 4 +++-
 src/macros.rs                 | 4 ++--
 src/parser.rs                 | 8 +++++---
 src/rules_and_declarations.rs | 4 ++--
 src/serializer.rs             | 5 +++--
 src/size_of_tests.rs          | 4 ++--
 src/tokenizer.rs              | 7 +++++--
 src/unicode_range.rs          | 4 ++--
 12 files changed, 34 insertions(+), 23 deletions(-)

diff --git a/Cargo.toml b/Cargo.toml
index f783f19f..729a0396 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -32,10 +32,12 @@ inherits = "release"
 debug = true
 
 [features]
+default = ["std"]
 bench = []
 dummy_match_byte = []
 # Useful for skipping tests when execution is slow, e.g., under miri
 skip_long_tests = []
+std = []
 
 [workspace]
 members = [".", "./macros", "./color"]
diff --git a/color/lib.rs b/color/lib.rs
index 5b116c23..070a9524 100644
--- a/color/lib.rs
+++ b/color/lib.rs
@@ -1,7 +1,7 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
+#![cfg_attr(not(test), no_std)]
 #![deny(missing_docs)]
 
 //! Fairly complete css-color implementation.
@@ -11,13 +11,13 @@
 #[cfg(test)]
 mod tests;
 
+use core::f32::consts::PI;
+use core::fmt;
 use cssparser::color::{
     clamp_floor_256_f32, clamp_unit_f32, parse_hash_color, serialize_color_alpha,
     PredefinedColorSpace, OPAQUE,
 };
 use cssparser::{match_ignore_ascii_case, CowRcStr, ParseError, Parser, ToCss, Token};
-use std::f32::consts::PI;
-use std::fmt;
 
 /// Return the named color with the given name.
 ///
diff --git a/src/color.rs b/src/color.rs
index 978936e0..f220b80c 100644
--- a/src/color.rs
+++ b/src/color.rs
@@ -15,7 +15,7 @@
 pub const OPAQUE: f32 = 1.0;
 
 use crate::{BasicParseError, Parser, ToCss, Token};
-use std::fmt;
+use core::fmt;
 
 /// Clamp a 0..1 number to a 0..255 range to u8.
 ///
diff --git a/src/cow_rc_str.rs b/src/cow_rc_str.rs
index 03631f47..b220be93 100644
--- a/src/cow_rc_str.rs
+++ b/src/cow_rc_str.rs
@@ -2,9 +2,10 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-use std::borrow::{Borrow, Cow};
-use std::rc::Rc;
-use std::{cmp, fmt, hash, marker, mem, ops, ptr, slice, str};
+use alloc::borrow::{Borrow, Cow};
+use alloc::rc::Rc;
+use alloc::string::String;
+use core::{cmp, fmt, hash, marker, mem, ops, ptr, slice, str};
 
 /// A string that is either shared (heap-allocated and reference-counted) or borrowed.
 ///
diff --git a/src/lib.rs b/src/lib.rs
index dc44fb74..a74d6afc 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -1,7 +1,7 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
+#![cfg_attr(not(feature = "std"), no_std)]
 #![crate_name = "cssparser"]
 #![crate_type = "rlib"]
 #![cfg_attr(feature = "bench", feature(test))]
@@ -67,6 +67,8 @@ fn parse_border_spacing(_context: &ParserContext, input: &mut Parser)
 
 #![recursion_limit = "200"] // For color::parse_color_keyword
 
+extern crate alloc;
+
 pub use crate::cow_rc_str::CowRcStr;
 pub use crate::from_bytes::{stylesheet_encoding, EncodingSupport};
 #[doc(hidden)]
diff --git a/src/macros.rs b/src/macros.rs
index 67d83658..13fbd3d3 100644
--- a/src/macros.rs
+++ b/src/macros.rs
@@ -2,7 +2,7 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-use std::mem::MaybeUninit;
+use core::mem::MaybeUninit;
 
 /// Expands to a `match` expression with string patterns,
 /// matching case-insensitively in the ASCII range.
@@ -191,7 +191,7 @@ pub fn _cssparser_internal_to_lowercase<'a>(
         // `buffer` was initialized to a copy of `input`
         // (which is `&str` so well-formed UTF-8)
         // then ASCII-lowercased (which preserves UTF-8 well-formedness):
-        unsafe { ::std::str::from_utf8_unchecked(buffer) }
+        unsafe { ::core::str::from_utf8_unchecked(buffer) }
     }
 
     Some(
diff --git a/src/parser.rs b/src/parser.rs
index 0a432912..84cf673c 100644
--- a/src/parser.rs
+++ b/src/parser.rs
@@ -4,10 +4,11 @@
 
 use crate::cow_rc_str::CowRcStr;
 use crate::tokenizer::{SourceLocation, SourcePosition, Token, Tokenizer};
+use alloc::vec::Vec;
+use core::fmt;
+use core::ops::BitOr;
+use core::ops::Range;
 use smallvec::SmallVec;
-use std::fmt;
-use std::ops::BitOr;
-use std::ops::Range;
 
 /// A capture of the internal state of a `Parser` (including the position within the input),
 /// obtained from the `Parser::position` method.
@@ -224,6 +225,7 @@ impl<E: fmt::Display> fmt::Display for ParseError<'_, E> {
     }
 }
 
+#[cfg(feature = "std")]
 impl<E: fmt::Display + fmt::Debug> std::error::Error for ParseError<'_, E> {}
 
 /// The owned input for a parser.
diff --git a/src/rules_and_declarations.rs b/src/rules_and_declarations.rs
index 188e354e..b750f6a1 100644
--- a/src/rules_and_declarations.rs
+++ b/src/rules_and_declarations.rs
@@ -199,7 +199,7 @@ pub struct RuleBodyParser<'i, 't, 'a, P, I, E> {
     /// The parser given to `DeclarationListParser::new`
     pub parser: &'a mut P,
 
-    _phantom: std::marker::PhantomData<(I, E)>,
+    _phantom: core::marker::PhantomData<(I, E)>,
 }
 
 /// A parser for a rule body item.
@@ -235,7 +235,7 @@ impl<'i, 't, 'a, P, I, E> RuleBodyParser<'i, 't, 'a, P, I, E> {
         Self {
             input,
             parser,
-            _phantom: std::marker::PhantomData,
+            _phantom: core::marker::PhantomData,
         }
     }
 }
diff --git a/src/serializer.rs b/src/serializer.rs
index 5df73954..e880ff0f 100644
--- a/src/serializer.rs
+++ b/src/serializer.rs
@@ -3,9 +3,10 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 use crate::match_byte;
+use alloc::string::String;
+use core::fmt::{self, Write};
+use core::str;
 use dtoa_short::Notation;
-use std::fmt::{self, Write};
-use std::str;
 
 use super::Token;
 
diff --git a/src/size_of_tests.rs b/src/size_of_tests.rs
index edd2b439..4b1fdcc9 100644
--- a/src/size_of_tests.rs
+++ b/src/size_of_tests.rs
@@ -9,7 +9,7 @@ macro_rules! size_of_test {
     ($testname: ident, $t: ty, $expected_min_size: expr, $expected_max_size: expr) => {
         #[test]
         fn $testname() {
-            let new = ::std::mem::size_of::<$t>();
+            let new = ::core::mem::size_of::<$t>();
             if new < $expected_min_size {
                 panic!(
                     "Your changes have decreased the stack size of {} from {} to {}. \
@@ -39,7 +39,7 @@ macro_rules! size_of_test {
 
 // Some of these assume 64-bit
 size_of_test!(token, Token, 32);
-size_of_test!(std_cow_str, std::borrow::Cow<'static, str>, 24, 32);
+size_of_test!(std_cow_str, alloc::borrow::Cow<'static, str>, 24, 32);
 size_of_test!(cow_rc_str, CowRcStr, 16);
 
 size_of_test!(tokenizer, crate::tokenizer::Tokenizer, 72);
diff --git a/src/tokenizer.rs b/src/tokenizer.rs
index 2e86c66a..63269ecc 100644
--- a/src/tokenizer.rs
+++ b/src/tokenizer.rs
@@ -7,8 +7,11 @@
 use self::Token::*;
 use crate::cow_rc_str::CowRcStr;
 use crate::parser::ParserState;
-use std::char;
-use std::ops::Range;
+use alloc::borrow::ToOwned;
+use alloc::string::String;
+use alloc::vec::Vec;
+use core::char;
+use core::ops::Range;
 
 #[cfg(not(feature = "dummy_match_byte"))]
 use cssparser_macros::match_byte;
diff --git a/src/unicode_range.rs b/src/unicode_range.rs
index a4130ef0..ffa00442 100644
--- a/src/unicode_range.rs
+++ b/src/unicode_range.rs
@@ -6,8 +6,8 @@
 
 use crate::tokenizer::Token;
 use crate::{BasicParseError, Parser, ToCss};
-use std::char;
-use std::fmt;
+use core::char;
+use core::fmt;
 
 /// One contiguous range of code points.
 ///

From 79312b1aec8d81bb5006538bbe469833fa1dbec7 Mon Sep 17 00:00:00 2001
From: boquanfu <boquanfu@tencent.com>
Date: Fri, 7 Jun 2024 19:35:48 +0800
Subject: [PATCH 2/5] feat: complete no-std support

---
 Cargo.toml        |  5 +++--
 src/color.rs      |  6 +++---
 src/lib.rs        |  1 +
 src/math.rs       | 21 +++++++++++++++++++++
 src/serializer.rs |  2 +-
 src/tokenizer.rs  |  2 +-
 6 files changed, 30 insertions(+), 7 deletions(-)
 create mode 100644 src/math.rs

diff --git a/Cargo.toml b/Cargo.toml
index 729a0396..198387d4 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -23,9 +23,10 @@ encoding_rs = "0.8"
 cssparser-macros = { path = "./macros", version = "0.6.1" }
 dtoa-short = "0.3"
 itoa = "1.0"
-phf = { version = "0.11.2", features = ["macros"] }
+phf = { version = "0.11.2", features = ["macros"], default-features = false }
 serde = { version = "1.0", features = ["derive"], optional = true }
 smallvec = "1.0"
+libm = "0.2.8"
 
 [profile.profiling]
 inherits = "release"
@@ -37,7 +38,7 @@ bench = []
 dummy_match_byte = []
 # Useful for skipping tests when execution is slow, e.g., under miri
 skip_long_tests = []
-std = []
+std = ["phf/std"]
 
 [workspace]
 members = [".", "./macros", "./color"]
diff --git a/src/color.rs b/src/color.rs
index f220b80c..6124d30d 100644
--- a/src/color.rs
+++ b/src/color.rs
@@ -41,7 +41,7 @@ pub fn clamp_unit_f32(val: f32) -> u8 {
 /// Round and clamp a single number to a u8.
 #[inline]
 pub fn clamp_floor_256_f32(val: f32) -> u8 {
-    val.round().clamp(0., 255.) as u8
+    crate::math::f32_round(val).clamp(0., 255.) as u8
 }
 
 /// Serialize the alpha copmonent of a color according to the specification.
@@ -65,9 +65,9 @@ pub fn serialize_color_alpha(
     dest.write_str(if legacy_syntax { ", " } else { " / " })?;
 
     // Try first with two decimal places, then with three.
-    let mut rounded_alpha = (alpha * 100.).round() / 100.;
+    let mut rounded_alpha = crate::math::f32_round(alpha * 100.) / 100.;
     if clamp_unit_f32(rounded_alpha) != clamp_unit_f32(alpha) {
-        rounded_alpha = (alpha * 1000.).round() / 1000.;
+        rounded_alpha = crate::math::f32_round(alpha * 1000.) / 1000.;
     }
 
     rounded_alpha.to_css(dest)
diff --git a/src/lib.rs b/src/lib.rs
index a74d6afc..6e56ccfc 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -103,6 +103,7 @@ mod nth;
 mod parser;
 mod serializer;
 mod unicode_range;
+mod math;
 
 #[cfg(test)]
 mod size_of_tests;
diff --git a/src/math.rs b/src/math.rs
new file mode 100644
index 00000000..2d9ff1c6
--- /dev/null
+++ b/src/math.rs
@@ -0,0 +1,21 @@
+
+pub(crate) fn f32_trunc(val: f32) -> f32 {
+    #[cfg(feature = "std")]
+    { val.round() }
+    #[cfg(not(feature = "std"))]
+    { libm::roundf(val) }
+}
+
+pub(crate) fn f32_round(val: f32) -> f32 {
+    #[cfg(feature = "std")]
+    { val.round() }
+    #[cfg(not(feature = "std"))]
+    { libm::roundf(val) }
+}
+
+pub(crate) fn f64_pow(a: f64, b: f64) -> f64 {
+    #[cfg(feature = "std")]
+    { f64::powf(a, b) }
+    #[cfg(not(feature = "std"))]
+    { libm::pow(a, b) }
+}
diff --git a/src/serializer.rs b/src/serializer.rs
index e880ff0f..58b366c0 100644
--- a/src/serializer.rs
+++ b/src/serializer.rs
@@ -49,7 +49,7 @@ where
         dtoa_short::write(dest, value)?
     };
 
-    if int_value.is_none() && value.fract() == 0. && !notation.decimal_point && !notation.scientific
+    if int_value.is_none() && value == crate::math::f32_trunc(value) && !notation.decimal_point && !notation.scientific
     {
         dest.write_str(".0")?;
     }
diff --git a/src/tokenizer.rs b/src/tokenizer.rs
index 63269ecc..23a214a0 100644
--- a/src/tokenizer.rs
+++ b/src/tokenizer.rs
@@ -1083,7 +1083,7 @@ fn consume_numeric<'a>(tokenizer: &mut Tokenizer<'a>) -> Token<'a> {
                 break;
             }
         }
-        value *= f64::powf(10., sign * exponent);
+        value *= crate::math::f64_pow(10., sign * exponent);
     }
 
     let int_value = if is_integer {

From 2e0e98a84f9123e4df3677422874351a9f9154ad Mon Sep 17 00:00:00 2001
From: LastLeaf <bqfu@163.com>
Date: Mon, 17 Jun 2024 11:10:54 +0800
Subject: [PATCH 3/5] fix: update dep:dtoa-short to be no-std compatible

---
 Cargo.toml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Cargo.toml b/Cargo.toml
index 198387d4..1e933556 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -21,7 +21,7 @@ encoding_rs = "0.8"
 
 [dependencies]
 cssparser-macros = { path = "./macros", version = "0.6.1" }
-dtoa-short = "0.3"
+dtoa-short = "0.3.5"
 itoa = "1.0"
 phf = { version = "0.11.2", features = ["macros"], default-features = false }
 serde = { version = "1.0", features = ["derive"], optional = true }

From 806c2f91d0d16c61e9a06715bc59132baa956ffd Mon Sep 17 00:00:00 2001
From: LastLeaf <bqfu@163.com>
Date: Mon, 17 Jun 2024 21:40:47 +0800
Subject: [PATCH 4/5] feat: no-std for cssparser-color

---
 color/Cargo.toml | 7 +++++--
 color/lib.rs     | 9 ++++++++-
 2 files changed, 13 insertions(+), 3 deletions(-)

diff --git a/color/Cargo.toml b/color/Cargo.toml
index 47544815..dca31291 100644
--- a/color/Cargo.toml
+++ b/color/Cargo.toml
@@ -12,10 +12,13 @@ edition = "2021"
 path = "lib.rs"
 
 [dependencies]
-cssparser = { path = ".." }
-serde = { version = "1.0", features = ["derive"], optional = true }
+cssparser = { path = "..", default-features = false }
+serde = { version = "1.0", default-features = false, features = ["derive"], optional = true }
+libm = "0.2.8"
 
 [features]
+default = ["std"]
+std = ["cssparser/std", "serde/std"]
 serde = ["cssparser/serde", "dep:serde"]
 
 [dev-dependencies]
diff --git a/color/lib.rs b/color/lib.rs
index 070a9524..79903a5b 100644
--- a/color/lib.rs
+++ b/color/lib.rs
@@ -488,11 +488,18 @@ impl<'a> ToCss for ModernComponent<'a> {
     }
 }
 
+fn f32_floor(val: f32) -> f32 {
+    #[cfg(feature = "std")]
+    { val.floor() }
+    #[cfg(not(feature = "std"))]
+    { libm::floorf(val) }
+}
+
 // Guaratees hue in [0..360)
 fn normalize_hue(hue: f32) -> f32 {
     // <https://drafts.csswg.org/css-values/#angles>
     // Subtract an integer before rounding, to avoid some rounding errors:
-    hue - 360.0 * (hue / 360.0).floor()
+    hue - 360.0 * f32_floor(hue / 360.0)
 }
 
 /// A color with red, green, blue, and alpha components, in a byte each.

From 0d98d4611646f1ede0e37daa88012734a015e4bb Mon Sep 17 00:00:00 2001
From: Daniel Olano <daniel@olanod.com>
Date: Thu, 7 Nov 2024 19:10:21 +0100
Subject: [PATCH 5/5] Add missing license and inline anotations

---
 src/math.rs | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/src/math.rs b/src/math.rs
index 2d9ff1c6..4cf18ea8 100644
--- a/src/math.rs
+++ b/src/math.rs
@@ -1,4 +1,8 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
+#[inline]
 pub(crate) fn f32_trunc(val: f32) -> f32 {
     #[cfg(feature = "std")]
     { val.round() }
@@ -6,6 +10,7 @@ pub(crate) fn f32_trunc(val: f32) -> f32 {
     { libm::roundf(val) }
 }
 
+#[inline]
 pub(crate) fn f32_round(val: f32) -> f32 {
     #[cfg(feature = "std")]
     { val.round() }
@@ -13,6 +18,7 @@ pub(crate) fn f32_round(val: f32) -> f32 {
     { libm::roundf(val) }
 }
 
+#[inline]
 pub(crate) fn f64_pow(a: f64, b: f64) -> f64 {
     #[cfg(feature = "std")]
     { f64::powf(a, b) }