diff --git a/Cargo.toml b/Cargo.toml index 6665f6a..0956bb5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,7 +14,8 @@ serde_test = { version = "1.0", optional = true } [features] default = ["std"] -std = [] +std = ["alloc"] +alloc = [] [[test]] name = "tests" diff --git a/README.md b/README.md index 092e439..b7dc1bb 100644 --- a/README.md +++ b/README.md @@ -17,17 +17,20 @@ ascii = "1.0" Most of `AsciiChar` and `AsciiStr` can be used without `std` by disabling the default features. The owned string type `AsciiString` and the conversion trait -`IntoAsciiString` as well as all methods referring to these types and -`CStr` and `CString` are unavailable. -The `Error` trait is also unavailable, but `description()` is made -available as an inherent method for `ToAsciiCharError` and `AsAsciiStrError`. +`IntoAsciiString` as well as all methods referring to these types can be +re-enabled by enabling the `alloc` feature. -To use the `ascii` crate in `core`-only mode in your cargo project just add the -following dependency declaration in `Cargo.toml`: +Methods referring to `CStr` and `CString` are also unavailable. +The `Error` trait also only exists in `std`, but `description()` is made +available as an inherent method for `ToAsciiCharError` and `AsAsciiStrError` +in `#![no_std]`-mode. + +To use the `ascii` crate in `#![no_std]` mode in your cargo project, +just add the following dependency declaration in `Cargo.toml`: ```toml [dependencies] -ascii = { version = "1.0", default-features = false } +ascii = { version = "1.0", default-features = false, features = ["alloc"] } ``` ## Minimum supported Rust version diff --git a/src/ascii_str.rs b/src/ascii_str.rs index 836f983..e33b28f 100644 --- a/src/ascii_str.rs +++ b/src/ascii_str.rs @@ -1,3 +1,7 @@ +#[cfg(feature = "alloc")] +use alloc::borrow::ToOwned; +#[cfg(feature = "alloc")] +use alloc::boxed::Box; use core::fmt; use core::ops::{Index, IndexMut}; use core::ops::{Range, RangeFrom, RangeFull, RangeInclusive, RangeTo, RangeToInclusive}; @@ -8,7 +12,7 @@ use std::error::Error; use std::ffi::CStr; use ascii_char::AsciiChar; -#[cfg(feature = "std")] +#[cfg(feature = "alloc")] use ascii_string::AsciiString; /// [`AsciiStr`] represents a byte or string slice that only contains ASCII characters. @@ -77,7 +81,7 @@ impl AsciiStr { } /// Copies the content of this `AsciiStr` into an owned `AsciiString`. - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] #[must_use] pub fn to_ascii_string(&self) -> AsciiString { AsciiString::from(self.slice.to_vec()) @@ -283,7 +287,7 @@ impl AsciiStr { } /// Returns a copy of this string where letters 'a' to 'z' are mapped to 'A' to 'Z'. - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] #[must_use] pub fn to_ascii_uppercase(&self) -> AsciiString { let mut ascii_string = self.to_ascii_string(); @@ -292,7 +296,7 @@ impl AsciiStr { } /// Returns a copy of this string where letters 'A' to 'Z' are mapped to 'a' to 'z'. - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] #[must_use] pub fn to_ascii_lowercase(&self) -> AsciiString { let mut ascii_string = self.to_ascii_string(); @@ -336,7 +340,7 @@ impl_partial_eq! {str} impl_partial_eq! {[u8]} impl_partial_eq! {[AsciiChar]} -#[cfg(feature = "std")] +#[cfg(feature = "alloc")] impl ToOwned for AsciiStr { type Owned = AsciiString; @@ -391,7 +395,7 @@ impl<'a> From<&'a mut [AsciiChar]> for &'a mut AsciiStr { unsafe { &mut *ptr } } } -#[cfg(feature = "std")] +#[cfg(feature = "alloc")] impl From> for Box { #[inline] fn from(owned: Box<[AsciiChar]>) -> Box { @@ -451,7 +455,7 @@ impl<'a> From<&'a AsciiStr> for &'a str { } macro_rules! widen_box { ($wider: ty) => { - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] impl From> for Box<$wider> { #[inline] fn from(owned: Box) -> Box<$wider> { @@ -1218,6 +1222,10 @@ impl AsAsciiStr for CStr { #[cfg(test)] mod tests { use super::{AsAsciiStr, AsAsciiStrError, AsMutAsciiStr, AsciiStr}; + #[cfg(feature = "alloc")] + use alloc::string::{String, ToString}; + #[cfg(feature = "alloc")] + use alloc::vec::Vec; use AsciiChar; /// Ensures that common types, `str`, `[u8]`, `AsciiStr` and their @@ -1330,7 +1338,7 @@ mod tests { } #[test] - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn as_mut_ascii_str() { macro_rules! err {{$i:expr} => {Err(AsAsciiStrError($i))}} let mut s: String = "abčd".to_string(); @@ -1409,7 +1417,7 @@ mod tests { } #[test] - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] fn to_ascii_case() { let bytes = ([b'a', b'@', b'A'], [b'A', b'@', b'a']); let a = bytes.0.as_ascii_str().unwrap(); diff --git a/src/ascii_string.rs b/src/ascii_string.rs index 6e0fc99..740abf0 100644 --- a/src/ascii_string.rs +++ b/src/ascii_string.rs @@ -1,11 +1,17 @@ -use std::any::Any; -use std::borrow::{Borrow, BorrowMut, Cow}; +use alloc::borrow::{Borrow, BorrowMut, Cow, ToOwned}; +use alloc::fmt; +use alloc::string::String; +use alloc::vec::Vec; +#[cfg(feature = "std")] +use core::any::Any; +use core::iter::FromIterator; +use core::mem; +use core::ops::{Add, AddAssign, Deref, DerefMut, Index, IndexMut}; +use core::str::FromStr; +#[cfg(feature = "std")] use std::error::Error; +#[cfg(feature = "std")] use std::ffi::{CStr, CString}; -use std::iter::FromIterator; -use std::ops::{Add, AddAssign, Deref, DerefMut, Index, IndexMut}; -use std::str::FromStr; -use std::{fmt, mem}; use ascii_char::AsciiChar; use ascii_str::{AsAsciiStr, AsAsciiStrError, AsciiStr}; @@ -699,6 +705,7 @@ impl fmt::Display for FromAsciiError { fmt::Display::fmt(&self.error, fmtr) } } +#[cfg(feature = "std")] impl Error for FromAsciiError { #[inline] #[allow(deprecated)] // TODO: Remove deprecation once the earliest version we support deprecates this method. @@ -799,7 +806,8 @@ impl_into_ascii_string! {String} impl_into_ascii_string! {'a, &'a str} /// # Notes -/// The trailing null byte `CString` has will be removed during this conversion +/// The trailing null byte `CString` has will be removed during this conversion. +#[cfg(feature = "std")] impl IntoAsciiString for CString { #[inline] unsafe fn into_ascii_string_unchecked(self) -> AsciiString { @@ -826,6 +834,7 @@ impl IntoAsciiString for CString { } /// Note that the trailing null byte will be removed in the conversion. +#[cfg(feature = "std")] impl<'a> IntoAsciiString for &'a CStr { #[inline] unsafe fn into_ascii_string_unchecked(self) -> AsciiString { @@ -885,9 +894,14 @@ where #[cfg(test)] mod tests { - use super::{AsciiString, IntoAsciiString}; + use super::AsciiString; + #[cfg(feature = "std")] + use super::IntoAsciiString; + use alloc::str::FromStr; + use alloc::string::{String, ToString}; + use alloc::vec::Vec; + #[cfg(feature = "std")] use std::ffi::CString; - use std::str::FromStr; use AsciiChar; #[test] @@ -912,6 +926,7 @@ mod tests { } #[test] + #[cfg(feature = "std")] fn from_cstring() { let cstring = CString::new("baz").unwrap(); let ascii_str = cstring.clone().into_ascii_string().unwrap(); @@ -932,6 +947,7 @@ mod tests { } #[test] + #[cfg(feature = "std")] fn fmt_ascii_string() { let s = "abc".to_string().into_ascii_string().unwrap(); assert_eq!(format!("{}", s), "abc".to_string()); @@ -940,7 +956,7 @@ mod tests { #[test] fn write_fmt() { - use std::{fmt, str}; + use alloc::{fmt, str}; let mut s0 = AsciiString::new(); fmt::write(&mut s0, format_args!("Hello World")).unwrap(); diff --git a/src/lib.rs b/src/lib.rs index 6161c2a..a5ab819 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -54,6 +54,9 @@ // In preparation for feature `unsafe_block_in_unsafe_fn` (https://github.com/rust-lang/rust/issues/71668) #![allow(unused_unsafe)] +#[cfg(feature = "alloc")] +#[cfg_attr(test, macro_use)] +extern crate alloc; #[cfg(feature = "std")] extern crate core; @@ -65,7 +68,7 @@ extern crate serde_test; mod ascii_char; mod ascii_str; -#[cfg(feature = "std")] +#[cfg(feature = "alloc")] mod ascii_string; mod free_functions; #[cfg(feature = "serde")] @@ -74,6 +77,6 @@ mod serialization; pub use ascii_char::{AsciiChar, ToAsciiChar, ToAsciiCharError}; pub use ascii_str::{AsAsciiStr, AsAsciiStrError, AsMutAsciiStr, AsciiStr}; pub use ascii_str::{Chars, CharsMut, CharsRef}; -#[cfg(feature = "std")] +#[cfg(feature = "alloc")] pub use ascii_string::{AsciiString, FromAsciiError, IntoAsciiString}; pub use free_functions::{caret_decode, caret_encode};