From 8bcd2a4a6af994e5a63395976cfaceb5acc43c31 Mon Sep 17 00:00:00 2001 From: Erica Marigold Date: Sat, 16 May 2026 07:09:26 +0100 Subject: [PATCH 1/6] feat: make `std` reliance an optional feature --- Cargo.toml | 4 +++- src/format.rs | 7 ++++--- src/lib.rs | 2 +- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 54121b5..fd85f97 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,7 +9,9 @@ repository = "https://github.com/tjol/sprintf-rs" keywords = ["printf", "text", "string"] categories = ["template-engine", "wasm"] -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html +[features] +default = ["std"] +std = [] [dependencies] thiserror = "2.0" diff --git a/src/format.rs b/src/format.rs index 10b82f1..6a7bff0 100644 --- a/src/format.rs +++ b/src/format.rs @@ -1,5 +1,5 @@ -use std::convert::{TryFrom, TryInto}; -use std::ffi::{CStr, CString}; +use core::convert::{TryFrom, TryInto}; +use core::ffi::CStr; use crate::{ parser::{ConversionSpecifier, ConversionType, NumericParam}, @@ -580,7 +580,8 @@ impl Printf for &CStr { } } -impl Printf for CString { +#[cfg(not(feature = "std"))] +impl Printf for std::ffi::CString { fn format(&self, spec: &ConversionSpecifier) -> Result { self.as_c_str().format(spec) } diff --git a/src/lib.rs b/src/lib.rs index cf45a4f..e5ad170 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -50,7 +50,7 @@ pub enum PrintfError { Unknown, } -pub type Result = std::result::Result; +pub type Result = core::result::Result; /// Format a string. (Roughly equivalent to `vsnprintf` or `vasprintf` in C) /// From 34082bd30567d36229b1ad3b22c0db763e56eec3 Mon Sep 17 00:00:00 2001 From: Erica Marigold Date: Sat, 16 May 2026 07:10:35 +0100 Subject: [PATCH 2/6] fix: inverted conditional for `CString` impl --- src/format.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/format.rs b/src/format.rs index 6a7bff0..8b53300 100644 --- a/src/format.rs +++ b/src/format.rs @@ -580,7 +580,7 @@ impl Printf for &CStr { } } -#[cfg(not(feature = "std"))] +#[cfg(feature = "std")] impl Printf for std::ffi::CString { fn format(&self, spec: &ConversionSpecifier) -> Result { self.as_c_str().format(spec) From 38ffe849656744018590491a235797f77138e470 Mon Sep 17 00:00:00 2001 From: Erica Marigold Date: Sat, 16 May 2026 07:15:43 +0100 Subject: [PATCH 3/6] fix: enable `std` feature for `thiserror` conditionally --- Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index fd85f97..80eb3ff 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,10 +11,10 @@ categories = ["template-engine", "wasm"] [features] default = ["std"] -std = [] +std = ["thiserror/std"] [dependencies] -thiserror = "2.0" +thiserror = { version = "2.0", default-features = false } [dev-dependencies] libc = "0.2" From 5de55898de3cf09b37551440b006b31c85143f8c Mon Sep 17 00:00:00 2001 From: Erica Marigold Date: Sat, 16 May 2026 07:20:25 +0100 Subject: [PATCH 4/6] chore(README): update note regarding `std` use --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 32c0a08..00f72b1 100644 --- a/README.md +++ b/README.md @@ -5,8 +5,8 @@ This crate was created out of a desire to provide C printf-style formatting in a WASM program, where there is no libc. -**Note:** *You're probably better off using standard Rust string formatting -instead of this crate unless you specificaly need printf compatibility.* +**Note:** _You're probably better off using standard Rust string formatting +instead of this crate unless you specificaly need printf compatibility._ This crate implements a dynamically type-checked function `vsprintf` and macro `sprintf!`. @@ -20,5 +20,5 @@ assert_eq!(s, "3 + 9 = 12\n"); ``` `libc` is a dev dependency as it is used in the tests to compare results. This -crate depends on `std` for string formatting, memory allocation, and -floating-point maths. +crate depends on `std` for providing an implementation for `CString` values as +arguments, but this can be avoided by disabling the `std` feature. From c47b2d5e6203412255d2d12dbe2bb40644e8b337 Mon Sep 17 00:00:00 2001 From: Erica Marigold Date: Sat, 16 May 2026 08:03:00 +0100 Subject: [PATCH 5/6] feat: use `no_std` feature instead of `std` feature --- Cargo.toml | 6 ++++-- src/format.rs | 4 ++-- src/lib.rs | 25 +++++++++++++++++++++++++ src/parser.rs | 1 + 4 files changed, 32 insertions(+), 4 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 80eb3ff..cff37c1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,11 +10,13 @@ keywords = ["printf", "text", "string"] categories = ["template-engine", "wasm"] [features] -default = ["std"] -std = ["thiserror/std"] +default = ["thiserror/std", "num-traits/std"] +no_std = ["num-traits/libm"] [dependencies] +cfg-if = "1.0" thiserror = { version = "2.0", default-features = false } +num-traits = { version = "0.2", default-features = false } [dev-dependencies] libc = "0.2" diff --git a/src/format.rs b/src/format.rs index 8b53300..b11de01 100644 --- a/src/format.rs +++ b/src/format.rs @@ -1,6 +1,7 @@ use core::convert::{TryFrom, TryInto}; use core::ffi::CStr; +use crate::compat::*; use crate::{ parser::{ConversionSpecifier, ConversionType, NumericParam}, PrintfError, Result, @@ -580,8 +581,7 @@ impl Printf for &CStr { } } -#[cfg(feature = "std")] -impl Printf for std::ffi::CString { +impl Printf for CString { fn format(&self, spec: &ConversionSpecifier) -> Result { self.as_c_str().format(spec) } diff --git a/src/lib.rs b/src/lib.rs index e5ad170..2bcdf30 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,3 +1,5 @@ +#![cfg_attr(feature = "no_std", no_std)] + //! Libc s(n)printf clone written in Rust, so you can use printf-style //! formatting without a libc (e.g. in WebAssembly). //! @@ -25,11 +27,34 @@ use thiserror::Error; mod format; pub mod parser; +use compat::*; pub use format::Printf; use parser::{parse_format_string, FormatElement}; #[doc(hidden)] pub use parser::{ConversionSpecifier, ConversionType, NumericParam}; +pub(crate) mod compat { + cfg_if::cfg_if! { + if #[cfg(feature = "no_std")] { + extern crate alloc; + + pub use alloc::ffi::CString; + pub use alloc::format; + pub use alloc::string::String; + pub use alloc::borrow::ToOwned; + pub use alloc::vec::Vec; + + pub use num_traits::Float; + } else { + pub use std::ffi::CString; + pub use std::format; + pub use std::string::String; + pub use std::borrow::ToOwned; + pub use std::vec::Vec; + } + } +} + /// Error type #[derive(Debug, Clone, Copy, Error, PartialEq, Eq)] pub enum PrintfError { diff --git a/src/parser.rs b/src/parser.rs index d5c29b8..e74485c 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -1,5 +1,6 @@ //! Parse printf format strings +use crate::compat::*; use crate::{PrintfError, Result}; /// A part of a format string: either a string of characters to be included From d3752cc7af8a8a5166482cd8604a2516816f47cf Mon Sep 17 00:00:00 2001 From: Erica Marigold Date: Sat, 16 May 2026 08:05:17 +0100 Subject: [PATCH 6/6] chore(README): update `std` reliance note to match changes --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 00f72b1..74b8afd 100644 --- a/README.md +++ b/README.md @@ -20,5 +20,5 @@ assert_eq!(s, "3 + 9 = 12\n"); ``` `libc` is a dev dependency as it is used in the tests to compare results. This -crate depends on `std` for providing an implementation for `CString` values as -arguments, but this can be avoided by disabling the `std` feature. +crate depends on `std` by default, but the default features can be disabled and +the `no_std` feature can be enabled as an alternative.