From 79ee8030b555e34f59e418c353519dfdbe4ec220 Mon Sep 17 00:00:00 2001 From: Bruce Mitchener Date: Fri, 27 Dec 2024 12:23:48 -0500 Subject: [PATCH 1/2] Support `no_std` This increases the MSRV to 1.81 for `core::error`. --- .github/workflows/ci.yml | 26 +++++++++++++++++++------- Cargo.lock | 7 +++++++ Cargo.toml | 7 ++++++- src/angle.rs | 5 +++-- src/aspect_ratio.rs | 4 ++-- src/color.rs | 8 ++++++-- src/colors.rs | 2 +- src/directional_position.rs | 6 ++++-- src/enable_background.rs | 5 +++-- src/error.rs | 10 +++++++--- src/filter_functions.rs | 7 ++++--- src/font.rs | 8 ++++++-- src/funciri.rs | 1 + src/length.rs | 5 +++-- src/lib.rs | 3 +++ src/number.rs | 5 +++-- src/paint.rs | 3 ++- src/paint_order.rs | 6 ++++-- src/path.rs | 1 + src/stream.rs | 8 +++++--- src/transform.rs | 11 ++++++++--- src/transform_origin.rs | 11 ++++++----- src/viewbox.rs | 11 ++++++----- 23 files changed, 110 insertions(+), 50 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index db29d84..c2fa89c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -8,10 +8,12 @@ env: # If the compilation fails, then the version specified here needs to be bumped up to reality. # Be sure to also update the rust-version property in the workspace Cargo.toml file, # plus all the README.md files of the affected packages. - RUST_MIN_VER: "1.65" + RUST_MIN_VER: "1.81" # List of packages that will be checked with the minimum supported Rust version. # This should be limited to packages that are intended for publishing. RUST_MIN_VER_PKGS: "-p svgtypes" + # List of features that depend on the standard library and will be excluded from no_std checks. + FEATURES_DEPENDING_ON_STD: "std,default" # Rationale @@ -39,6 +41,10 @@ env: # The MSRV jobs run only cargo check because different clippy versions can disagree on goals and # running tests introduces dev dependencies which may require a higher MSRV than the bare package. # +# For no_std checks we target x86_64-unknown-none, because this target doesn't support std +# and as such will error out if our dependency tree accidentally tries to use std. +# https://doc.rust-lang.org/stable/rustc/platform-support/x86_64-unknown-none.html +# # We don't save caches in the merge-group cases, because those caches will never be re-used (apart # from the very rare cases where there are multiple PRs in the merge queue). # This is because GitHub doesn't share caches between merge queues and the main branch. @@ -105,11 +111,14 @@ jobs: with: save-if: ${{ github.event_name != 'merge_group' }} + - name: cargo clippy (no_std) + run: cargo hack clippy --workspace --locked --optional-deps --each-feature --ignore-unknown-features --features libm --exclude-features ${{ env.FEATURES_DEPENDING_ON_STD }} --target x86_64-unknown-none -- -D warnings + - name: cargo clippy - run: cargo hack clippy --workspace --locked --optional-deps --each-feature -- -D warnings + run: cargo hack clippy --workspace --locked --optional-deps --each-feature --ignore-unknown-features --features std -- -D warnings - name: cargo clippy (auxiliary) - run: cargo hack clippy --workspace --locked --optional-deps --each-feature --tests --examples -- -D warnings + run: cargo hack clippy --workspace --locked --optional-deps --each-feature --ignore-unknown-features --features std --tests --examples -- -D warnings clippy-stable-wasm: name: cargo clippy (wasm32) @@ -135,10 +144,10 @@ jobs: save-if: ${{ github.event_name != 'merge_group' }} - name: cargo clippy - run: cargo hack clippy --workspace --locked --target wasm32-unknown-unknown --optional-deps --each-feature -- -D warnings + run: cargo hack clippy --workspace --locked --target wasm32-unknown-unknown --optional-deps --each-feature --ignore-unknown-features --features std -- -D warnings - name: cargo clippy (auxiliary) - run: cargo hack clippy --workspace --locked --target wasm32-unknown-unknown --optional-deps --each-feature --tests --examples -- -D warnings + run: cargo hack clippy --workspace --locked --target wasm32-unknown-unknown --optional-deps --each-feature --ignore-unknown-features --features std --tests --examples -- -D warnings test-stable: name: cargo test @@ -216,8 +225,11 @@ jobs: with: save-if: ${{ github.event_name != 'merge_group' }} + - name: cargo check (no_std) + run: cargo hack check ${{ env.RUST_MIN_VER_PKGS }} --locked --optional-deps --each-feature --ignore-unknown-features --features libm --exclude-features ${{ env.FEATURES_DEPENDING_ON_STD }} --target x86_64-unknown-none + - name: cargo check - run: cargo hack check ${{ env.RUST_MIN_VER_PKGS }} --locked --optional-deps --each-feature + run: cargo hack check ${{ env.RUST_MIN_VER_PKGS }} --locked --optional-deps --each-feature --ignore-unknown-features --features std check-msrv-wasm: name: cargo check (msrv) (wasm32) @@ -242,7 +254,7 @@ jobs: save-if: ${{ github.event_name != 'merge_group' }} - name: cargo check - run: cargo hack check ${{ env.RUST_MIN_VER_PKGS }} --locked --target wasm32-unknown-unknown --optional-deps --each-feature + run: cargo hack check ${{ env.RUST_MIN_VER_PKGS }} --locked --target wasm32-unknown-unknown --optional-deps --each-feature --ignore-unknown-features --features std doc: name: cargo doc diff --git a/Cargo.lock b/Cargo.lock index fdd2b5f..64f8e3b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -29,9 +29,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "89234b2cc610a7dd927ebde6b41dd1a5d4214cffaef4cf1fb2195d592f92518f" dependencies = [ "arrayvec", + "libm", "smallvec", ] +[[package]] +name = "libm" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8355be11b20d696c8f18f6cc018c4e372165b1fa8126cef092399c9951984ffa" + [[package]] name = "siphasher" version = "1.0.1" diff --git a/Cargo.toml b/Cargo.toml index a564a07..1684ec2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,6 +16,11 @@ exclude = [".github", ".clippy.toml", ".gitignore", ".typos.toml", "benches/", " [workspace] members = ["benches"] +[features] +default = ["std"] +std = ["kurbo/std"] +libm = ["kurbo/libm"] + [dependencies] siphasher = "1.0" # perfect hash implementation for color names -kurbo = "0.11" # ArcTo to CurveTo(s) +kurbo = { version = "0.11", default-features = false } # ArcTo to CurveTo(s) diff --git a/src/angle.rs b/src/angle.rs index baab9b5..f0d5ae9 100644 --- a/src/angle.rs +++ b/src/angle.rs @@ -42,7 +42,7 @@ impl Angle { } } -impl std::str::FromStr for Angle { +impl core::str::FromStr for Angle { type Err = Error; #[inline] @@ -99,7 +99,8 @@ impl Stream<'_> { #[cfg(test)] mod tests { use super::*; - use std::str::FromStr; + use alloc::string::ToString; + use core::str::FromStr; macro_rules! test_p { ($name:ident, $text:expr, $result:expr) => ( diff --git a/src/aspect_ratio.rs b/src/aspect_ratio.rs index 869e64f..9e96812 100644 --- a/src/aspect_ratio.rs +++ b/src/aspect_ratio.rs @@ -41,7 +41,7 @@ pub struct AspectRatio { pub slice: bool, } -impl std::str::FromStr for AspectRatio { +impl core::str::FromStr for AspectRatio { type Err = Error; fn from_str(text: &str) -> Result { @@ -109,7 +109,7 @@ impl Default for AspectRatio { #[cfg(test)] mod tests { use super::*; - use std::str::FromStr; + use core::str::FromStr; macro_rules! test { ($name:ident, $text:expr, $result:expr) => ( diff --git a/src/color.rs b/src/color.rs index 186f4f9..ab197fa 100644 --- a/src/color.rs +++ b/src/color.rs @@ -3,6 +3,9 @@ use crate::{colors, ByteExt, Error, Stream}; +#[cfg(not(feature = "std"))] +use kurbo::common::FloatFuncs; + /// Representation of the [``] type. /// /// [``]: https://www.w3.org/TR/css-color-3/ @@ -75,7 +78,7 @@ impl Color { } } -impl std::str::FromStr for Color { +impl core::str::FromStr for Color { type Err = Error; /// Parses [CSS3](https://www.w3.org/TR/css-color-3/) `Color` from a string. @@ -304,7 +307,8 @@ fn f64_bound(min: f64, val: f64, max: f64) -> f64 { #[rustfmt::skip] #[cfg(test)] mod tests { - use std::str::FromStr; + use alloc::string::ToString; + use core::str::FromStr; use crate::Color; macro_rules! test { diff --git a/src/colors.rs b/src/colors.rs index 77141f8..20a7ae0 100644 --- a/src/colors.rs +++ b/src/colors.rs @@ -199,7 +199,7 @@ pub fn from_str(text: &str) -> Option { // // https://github.com/sfackler/rust-phf -use std::hash::Hasher; +use core::hash::Hasher; pub struct Map { pub key: u64, diff --git a/src/directional_position.rs b/src/directional_position.rs index 06faae7..487c2da 100644 --- a/src/directional_position.rs +++ b/src/directional_position.rs @@ -2,6 +2,8 @@ // SPDX-License-Identifier: Apache-2.0 OR MIT use crate::{Error, Length, LengthUnit, Stream}; +use alloc::string::ToString; +use alloc::vec; /// List of all SVG directional positions. #[derive(Clone, Copy, PartialEq, Eq, Debug)] @@ -52,7 +54,7 @@ impl From for Length { } } -impl std::str::FromStr for DirectionalPosition { +impl core::str::FromStr for DirectionalPosition { type Err = Error; #[inline] @@ -108,7 +110,7 @@ impl Stream<'_> { #[cfg(test)] mod tests { use super::*; - use std::str::FromStr; + use core::str::FromStr; macro_rules! test_p { ($name:ident, $text:expr, $result:expr) => ( diff --git a/src/enable_background.rs b/src/enable_background.rs index 1352588..c520a67 100644 --- a/src/enable_background.rs +++ b/src/enable_background.rs @@ -19,7 +19,7 @@ pub enum EnableBackground { }, } -impl std::str::FromStr for EnableBackground { +impl core::str::FromStr for EnableBackground { type Err = Error; fn from_str(text: &str) -> Result { @@ -71,7 +71,8 @@ impl std::str::FromStr for EnableBackground { #[cfg(test)] mod tests { use super::*; - use std::str::FromStr; + use alloc::string::ToString; + use core::str::FromStr; #[test] fn parse_1() { diff --git a/src/error.rs b/src/error.rs index 6699ab1..df11ef1 100644 --- a/src/error.rs +++ b/src/error.rs @@ -1,6 +1,10 @@ // Copyright 2018 the SVG Types Authors // SPDX-License-Identifier: Apache-2.0 OR MIT +use alloc::string::String; +use alloc::vec; +use alloc::vec::Vec; + /// List of all errors. #[derive(Debug, PartialEq, Eq)] pub enum Error { @@ -46,8 +50,8 @@ pub enum Error { InvalidNumber(usize), } -impl std::fmt::Display for Error { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { +impl core::fmt::Display for Error { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { match *self { Error::UnexpectedEndOfStream => { write!(f, "unexpected end of stream") @@ -93,7 +97,7 @@ impl std::fmt::Display for Error { } } -impl std::error::Error for Error { +impl core::error::Error for Error { fn description(&self) -> &str { "an SVG data parsing error" } diff --git a/src/filter_functions.rs b/src/filter_functions.rs index 1e94384..24ea7b5 100644 --- a/src/filter_functions.rs +++ b/src/filter_functions.rs @@ -73,8 +73,8 @@ impl From for FilterValueListParserError { } } -impl std::fmt::Display for FilterValueListParserError { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { +impl core::fmt::Display for FilterValueListParserError { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { match *self { FilterValueListParserError::PercentageValue(pos) => { write!(f, "a percentage value detected at position {}", pos) @@ -102,7 +102,7 @@ impl std::fmt::Display for FilterValueListParserError { } } -impl std::error::Error for FilterValueListParserError { +impl core::error::Error for FilterValueListParserError { fn description(&self) -> &str { "filter-value-list parsing error" } @@ -352,6 +352,7 @@ fn parse_filter_angle(s: &mut Stream<'_>) -> Result Result, Error> { @@ -36,7 +40,7 @@ pub enum FontFamily { } impl Display for FontFamily { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { let str = match self { FontFamily::Monospace => "monospace".to_string(), FontFamily::Serif => "serif".to_string(), diff --git a/src/funciri.rs b/src/funciri.rs index a3fd335..04d5451 100644 --- a/src/funciri.rs +++ b/src/funciri.rs @@ -112,6 +112,7 @@ impl<'a> Stream<'a> { #[cfg(test)] mod tests { use super::*; + use alloc::string::ToString; #[test] fn parse_iri_1() { diff --git a/src/length.rs b/src/length.rs index c67a049..85c505a 100644 --- a/src/length.rs +++ b/src/length.rs @@ -64,7 +64,7 @@ impl Default for Length { } } -impl std::str::FromStr for Length { +impl core::str::FromStr for Length { type Err = Error; #[inline] @@ -187,7 +187,8 @@ impl Iterator for LengthListParser<'_> { #[cfg(test)] mod tests { use super::*; - use std::str::FromStr; + use alloc::string::ToString; + use core::str::FromStr; macro_rules! test_p { ($name:ident, $text:expr, $result:expr) => ( diff --git a/src/lib.rs b/src/lib.rs index f6e3c61..95058a4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -51,11 +51,14 @@ None. */ +#![no_std] #![forbid(unsafe_code)] #![deny(missing_docs)] #![deny(missing_debug_implementations)] #![deny(missing_copy_implementations)] +extern crate alloc; + macro_rules! matches { ($expression:expr, $($pattern:tt)+) => { match $expression { diff --git a/src/number.rs b/src/number.rs index fad023b..3115826 100644 --- a/src/number.rs +++ b/src/number.rs @@ -1,7 +1,7 @@ // Copyright 2018 the SVG Types Authors // SPDX-License-Identifier: Apache-2.0 OR MIT -use std::str::FromStr; +use core::str::FromStr; use crate::{ByteExt, Error, Stream}; @@ -9,7 +9,7 @@ use crate::{ByteExt, Error, Stream}; #[derive(Clone, Copy, PartialEq, Debug)] pub struct Number(pub f64); -impl std::str::FromStr for Number { +impl core::str::FromStr for Number { type Err = Error; fn from_str(text: &str) -> Result { @@ -165,6 +165,7 @@ impl Iterator for NumberListParser<'_> { #[rustfmt::skip] #[cfg(test)] mod tests { + use alloc::string::ToString; use crate::Stream; macro_rules! test_p { diff --git a/src/paint.rs b/src/paint.rs index ba9bfc4..ff55805 100644 --- a/src/paint.rs +++ b/src/paint.rs @@ -1,7 +1,7 @@ // Copyright 2018 the SVG Types Authors // SPDX-License-Identifier: Apache-2.0 OR MIT -use std::str::FromStr; +use core::str::FromStr; use crate::{Color, Error, Stream}; @@ -119,6 +119,7 @@ impl<'a> Paint<'a> { #[cfg(test)] mod tests { use super::*; + use alloc::string::ToString; macro_rules! test { ($name:ident, $text:expr, $result:expr) => ( diff --git a/src/paint_order.rs b/src/paint_order.rs index 3999ced..2079c57 100644 --- a/src/paint_order.rs +++ b/src/paint_order.rs @@ -2,6 +2,8 @@ // SPDX-License-Identifier: Apache-2.0 OR MIT use crate::stream::Stream; +use alloc::vec; +use alloc::vec::Vec; /// [`paint-order`] property variants. /// @@ -45,7 +47,7 @@ impl From<[PaintOrderKind; 3]> for PaintOrder { } } -impl std::str::FromStr for PaintOrder { +impl core::str::FromStr for PaintOrder { type Err = (); /// Parses `PaintOrder` from a string. @@ -112,7 +114,7 @@ impl std::str::FromStr for PaintOrder { #[cfg(test)] mod tests { use super::*; - use std::str::FromStr; + use core::str::FromStr; #[test] fn parse_1() { diff --git a/src/path.rs b/src/path.rs index ca35bb3..ababfb1 100644 --- a/src/path.rs +++ b/src/path.rs @@ -2,6 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 OR MIT use crate::{Error, Stream}; +use alloc::vec::Vec; /// Representation of a path segment. /// diff --git a/src/stream.rs b/src/stream.rs index cd6e1b9..881e8ad 100644 --- a/src/stream.rs +++ b/src/stream.rs @@ -2,6 +2,8 @@ // SPDX-License-Identifier: Apache-2.0 OR MIT use crate::Error; +use alloc::borrow::ToOwned; +use alloc::vec; /// Extension methods for XML-subset only operations. pub(crate) trait ByteExt { @@ -169,7 +171,7 @@ impl<'a> Stream<'a> { } #[inline] - pub fn chars(&self) -> std::str::Chars<'a> { + pub fn chars(&self) -> core::str::Chars<'a> { self.text[self.pos..].chars() } @@ -349,14 +351,14 @@ impl<'a> Stream<'a> { } if !self.starts_with(text) { - let len = std::cmp::min(text.len(), self.text.len() - self.pos); + let len = core::cmp::min(text.len(), self.text.len() - self.pos); // Collect chars and do not slice a string, // because the `len` can be on the char boundary. // Which lead to a panic. let actual = self.text[self.pos..].chars().take(len).collect(); // Assume that all input `text` are valid UTF-8 strings, so unwrap is safe. - let expected = std::str::from_utf8(text).unwrap().to_owned(); + let expected = core::str::from_utf8(text).unwrap().to_owned(); return Err(Error::InvalidString( vec![actual, expected], diff --git a/src/transform.rs b/src/transform.rs index 9683c36..22f377b 100644 --- a/src/transform.rs +++ b/src/transform.rs @@ -1,10 +1,13 @@ // Copyright 2021 the SVG Types Authors // SPDX-License-Identifier: Apache-2.0 OR MIT -use std::f64; +use core::f64; use crate::{Error, Stream}; +#[cfg(not(feature = "std"))] +use kurbo::common::FloatFuncs; + /// Representation of the [``] type. /// /// [``]: https://www.w3.org/TR/SVG2/coords.html#InterfaceSVGTransform @@ -223,7 +226,7 @@ impl TransformListParser<'_> { } } -impl std::str::FromStr for Transform { +impl core::str::FromStr for Transform { type Err = Error; fn from_str(text: &str) -> Result { @@ -279,8 +282,10 @@ fn multiply(ts1: &Transform, ts2: &Transform) -> Transform { #[rustfmt::skip] #[cfg(test)] mod tests { - use std::str::FromStr; use super::*; + use alloc::format; + use alloc::string::ToString; + use core::str::FromStr; macro_rules! test { ($name:ident, $text:expr, $result:expr) => ( diff --git a/src/transform_origin.rs b/src/transform_origin.rs index 00ba839..f9acd33 100644 --- a/src/transform_origin.rs +++ b/src/transform_origin.rs @@ -73,8 +73,8 @@ pub enum TransformOriginError { ZIndexIsPercentage, } -impl std::fmt::Display for TransformOriginError { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { +impl core::fmt::Display for TransformOriginError { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { match *self { TransformOriginError::MissingParameters => { write!(f, "transform origin doesn't have enough parameters") @@ -89,13 +89,13 @@ impl std::fmt::Display for TransformOriginError { } } -impl std::error::Error for TransformOriginError { +impl core::error::Error for TransformOriginError { fn description(&self) -> &str { "a transform origin parsing error" } } -impl std::str::FromStr for TransformOrigin { +impl core::str::FromStr for TransformOrigin { type Err = TransformOriginError; fn from_str(text: &str) -> Result { @@ -192,7 +192,8 @@ impl std::str::FromStr for TransformOrigin { #[cfg(test)] mod tests { use super::*; - use std::str::FromStr; + use alloc::string::ToString; + use core::str::FromStr; macro_rules! test { ($name:ident, $text:expr, $result:expr) => ( diff --git a/src/viewbox.rs b/src/viewbox.rs index f1ed629..015ada3 100644 --- a/src/viewbox.rs +++ b/src/viewbox.rs @@ -13,8 +13,8 @@ pub enum ViewBoxError { InvalidSize, } -impl std::fmt::Display for ViewBoxError { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { +impl core::fmt::Display for ViewBoxError { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { match *self { ViewBoxError::InvalidNumber => { write!(f, "viewBox contains an invalid number") @@ -26,7 +26,7 @@ impl std::fmt::Display for ViewBoxError { } } -impl std::error::Error for ViewBoxError { +impl core::error::Error for ViewBoxError { fn description(&self) -> &str { "a viewBox parsing error" } @@ -51,7 +51,7 @@ impl ViewBox { } } -impl std::str::FromStr for ViewBox { +impl core::str::FromStr for ViewBox { type Err = ViewBoxError; fn from_str(text: &str) -> Result { @@ -82,7 +82,8 @@ impl std::str::FromStr for ViewBox { #[cfg(test)] mod tests { use super::*; - use std::str::FromStr; + use alloc::string::ToString; + use core::str::FromStr; macro_rules! test { ($name:ident, $text:expr, $result:expr) => ( From 094d2094cde4d2c1a6dfbe546892e8adc33bb1cc Mon Sep 17 00:00:00 2001 From: Nico Burns Date: Sun, 26 Oct 2025 13:10:07 +0000 Subject: [PATCH 2/2] Re-resolve cargo.lock Signed-off-by: Nico Burns --- Cargo.lock | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b3c63f5..426dbf2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -44,16 +44,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ce9729cc38c18d86123ab736fd2e7151763ba226ac2490ec092d1dd148825e32" dependencies = [ "arrayvec", - "libm", "euclid", + "libm", "smallvec", ] [[package]] name = "libm" -version = "0.2.11" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8355be11b20d696c8f18f6cc018c4e372165b1fa8126cef092399c9951984ffa" +checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de" [[package]] name = "num-traits" @@ -62,6 +62,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ "autocfg", + "libm", ] [[package]]