diff --git a/Cargo.toml b/Cargo.toml index 821d27c..c50954b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,4 +14,9 @@ edition = "2018" license = "MIT OR Apache-2.0" [dependencies] -byteorder = "1" \ No newline at end of file +byteorder = { version = "1", default-features = false} + +[features] +default = ["std"] +std = [] +alloc = [] \ No newline at end of file diff --git a/benches/encode_char.rs b/benches/encode_char.rs index f1d40e3..5c61ede 100644 --- a/benches/encode_char.rs +++ b/benches/encode_char.rs @@ -30,7 +30,7 @@ fn bench_encode_char_stdlib(b: &mut Bencher) { for ch in chars.iter().copied() { let mut buf_u16 = [0u16; 2]; let code_units = ch.encode_utf16(&mut buf_u16); - let byte_count = code_units.len() * std::mem::size_of::(); + let byte_count = code_units.len() * core::mem::size_of::(); let mut buf = [0u8; 4]; LE::write_u16_into(code_units, &mut buf[..byte_count]); vec.extend_from_slice(&buf[..byte_count]); diff --git a/src/error.rs b/src/error.rs index 1ea454f..919182a 100644 --- a/src/error.rs +++ b/src/error.rs @@ -1,6 +1,5 @@ //! Implementations for [`Utf16Error`]. -use std::error::Error; use std::fmt; use crate::Utf16Error; @@ -11,7 +10,7 @@ impl fmt::Display for Utf16Error { } } -impl Error for Utf16Error {} +impl std::error::Error for Utf16Error {} impl Utf16Error { /// Returns the index in given bytes up to which valid UTF-16 was verified. diff --git a/src/iters.rs b/src/iters.rs index b9298ed..169bfbe 100644 --- a/src/iters.rs +++ b/src/iters.rs @@ -5,7 +5,7 @@ use byteorder::ByteOrder; -use std::iter::FusedIterator; +use core::iter::FusedIterator; use crate::utf16::{decode_surrogates, is_leading_surrogate, is_trailing_surrogate, Utf16CharExt}; use crate::{WStrCharIndices, WStrChars}; @@ -24,7 +24,7 @@ where if !is_leading_surrogate(u) { // SAFETY: This is now guaranteed a valid Unicode code point. - Some(unsafe { std::char::from_u32_unchecked(u as u32) }) + Some(unsafe { core::char::from_u32_unchecked(u as u32) }) } else { let chunk = self.chunks.next().expect("missing trailing surrogate"); let u2 = E::read_u16(chunk); @@ -64,7 +64,7 @@ where if !is_trailing_surrogate(u) { // SAFETY: This is now guaranteed a valid Unicode code point. - Some(unsafe { std::char::from_u32_unchecked(u as u32) }) + Some(unsafe { core::char::from_u32_unchecked(u as u32) }) } else { let chunk = self.chunks.next_back().expect("missing leading surrogate"); let u2 = E::read_u16(chunk); @@ -110,7 +110,7 @@ where #[inline] fn next_back(&mut self) -> Option { let c = self.chars.next_back()?; - let pos = self.index + self.chars.chunks.len() * std::mem::size_of::(); + let pos = self.index + self.chars.chunks.len() * core::mem::size_of::(); Some((pos, c)) } } @@ -118,6 +118,7 @@ where impl<'a, E> FusedIterator for WStrCharIndices<'a, E> where E: ByteOrder {} #[cfg(test)] +#[cfg(feature = "std")] mod tests { use crate::WStr; diff --git a/src/lib.rs b/src/lib.rs index 212fa58..bac0923 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -65,6 +65,8 @@ //! # } //! ``` +#![cfg_attr(not(feature = "std"), no_std)] + #![warn( missing_docs, missing_debug_implementations, @@ -74,18 +76,28 @@ clippy::all )] -use std::marker::PhantomData; -use std::slice::ChunksExact; +#[cfg(feature = "alloc")] +extern crate alloc; + +#[cfg(feature = "alloc")] +use alloc::vec::Vec; + +use core::marker::PhantomData; +use core::slice::ChunksExact; use byteorder::ByteOrder; pub use byteorder::{BigEndian, LittleEndian, BE, LE}; +#[cfg(feature = "std")] mod error; + mod iters; mod slicing; mod utf16; mod wstr; + +#[cfg(any(feature = "alloc", feature = "std"))] mod wstring; #[doc(inline)] @@ -129,6 +141,7 @@ pub struct Utf16Error { /// let s1: WString = From::from("hello"); /// assert_eq!(s0, s1); /// ``` +#[cfg(any(feature = "alloc", feature = "std"))] #[derive(Debug, Eq, PartialEq, Hash)] pub struct WString { buf: Vec, diff --git a/src/slicing.rs b/src/slicing.rs index 8ebd9ba..4e509ed 100644 --- a/src/slicing.rs +++ b/src/slicing.rs @@ -2,13 +2,15 @@ //! //! This supports all slicing for [`WStr`] and [`WString`]. -use std::ops::{ +use core::ops::{ Index, IndexMut, Range, RangeFrom, RangeFull, RangeInclusive, RangeTo, RangeToInclusive, }; use byteorder::ByteOrder; -use crate::{WStr, WString}; +use crate::WStr; +#[cfg(any(feature = "alloc", feature = "std"))] +use crate::WString; mod private { use super::*; @@ -22,7 +24,7 @@ mod private { impl SealedSliceIndex for RangeInclusive {} impl SealedSliceIndex for RangeToInclusive {} } -/// Our own version of [`std::slice::SliceIndex`]. +/// Our own version of [`core::slice::SliceIndex`]. /// /// Since this is a sealed trait, we need to re-define this trait. This trait itself is /// sealed as well. @@ -137,14 +139,14 @@ where unsafe fn get_unchecked(self, slice: &WStr) -> &Self::Output { let ptr = slice.as_ptr().add(self.start); let len = self.end - self.start; - WStr::from_utf16_unchecked(std::slice::from_raw_parts(ptr, len)) + WStr::from_utf16_unchecked(core::slice::from_raw_parts(ptr, len)) } #[inline] unsafe fn get_unchecked_mut(self, slice: &mut WStr) -> &mut Self::Output { let ptr = slice.as_mut_ptr().add(self.start); let len = self.end - self.start; - WStr::from_utf16_unchecked_mut(std::slice::from_raw_parts_mut(ptr, len)) + WStr::from_utf16_unchecked_mut(core::slice::from_raw_parts_mut(ptr, len)) } #[inline] @@ -186,13 +188,13 @@ where #[inline] unsafe fn get_unchecked(self, slice: &WStr) -> &Self::Output { let ptr = slice.as_ptr(); - WStr::from_utf16_unchecked(std::slice::from_raw_parts(ptr, self.end)) + WStr::from_utf16_unchecked(core::slice::from_raw_parts(ptr, self.end)) } #[inline] unsafe fn get_unchecked_mut(self, slice: &mut WStr) -> &mut Self::Output { let ptr = slice.as_mut_ptr(); - WStr::from_utf16_unchecked_mut(std::slice::from_raw_parts_mut(ptr, self.end)) + WStr::from_utf16_unchecked_mut(core::slice::from_raw_parts_mut(ptr, self.end)) } #[inline] @@ -235,14 +237,14 @@ where unsafe fn get_unchecked(self, slice: &WStr) -> &Self::Output { let ptr = slice.as_ptr().add(self.start); let len = slice.len() - self.start; - WStr::from_utf16_unchecked(std::slice::from_raw_parts(ptr, len)) + WStr::from_utf16_unchecked(core::slice::from_raw_parts(ptr, len)) } #[inline] unsafe fn get_unchecked_mut(self, slice: &mut WStr) -> &mut Self::Output { let ptr = slice.as_mut_ptr().add(self.start); let len = slice.len() - self.start; - WStr::from_utf16_unchecked_mut(std::slice::from_raw_parts_mut(ptr, len)) + WStr::from_utf16_unchecked_mut(core::slice::from_raw_parts_mut(ptr, len)) } #[inline] @@ -384,6 +386,7 @@ where } } +#[cfg(any(feature = "alloc", feature = "std"))] impl Index for WString where I: SliceIndex>, @@ -397,6 +400,7 @@ where } } +#[cfg(any(feature = "alloc", feature = "std"))] impl IndexMut for WString where I: SliceIndex>, @@ -409,6 +413,7 @@ where } #[cfg(test)] +#[cfg(any(feature = "alloc", feature = "std"))] mod tests { use super::*; diff --git a/src/utf16.rs b/src/utf16.rs index feacce8..e161b3c 100644 --- a/src/utf16.rs +++ b/src/utf16.rs @@ -53,7 +53,7 @@ pub(crate) unsafe fn decode_surrogates(u: u16, u2: u16) -> char { ); let c = (((u - 0xD800) as u32) << 10 | (u2 - 0xDC00) as u32) + 0x1_0000; // SAFETY: This is now guaranteed a valid Unicode code point. - unsafe { std::char::from_u32_unchecked(c) } + unsafe { core::char::from_u32_unchecked(c) } } /// Checks that the raw bytes are valid UTF-16LE. @@ -65,7 +65,7 @@ pub(crate) unsafe fn decode_surrogates(u: u16, u2: u16) -> char { /// We compute `valid_up_to` lazily for performance, even though it's a little more verbose. pub(crate) fn validate_raw_utf16(raw: &[u8]) -> Result<(), Utf16Error> { let base_ptr = raw.as_ptr() as usize; - let mut chunks = raw.chunks_exact(std::mem::size_of::()); + let mut chunks = raw.chunks_exact(core::mem::size_of::()); while let Some(chunk) = chunks.next() { let code_point_ptr = chunk.as_ptr() as usize; @@ -74,7 +74,7 @@ pub(crate) fn validate_raw_utf16(raw: &[u8]) -> Result<(), Utf16Er if is_trailing_surrogate(code_point) { return Err(Utf16Error { valid_up_to: code_point_ptr - base_ptr, - error_len: Some(std::mem::size_of::() as u8), + error_len: Some(core::mem::size_of::() as u8), }); } @@ -84,7 +84,7 @@ pub(crate) fn validate_raw_utf16(raw: &[u8]) -> Result<(), Utf16Er if !is_trailing_surrogate(u2) { return Err(Utf16Error { valid_up_to: code_point_ptr - base_ptr, - error_len: Some(std::mem::size_of::() as u8), + error_len: Some(core::mem::size_of::() as u8), }); } } @@ -158,11 +158,15 @@ impl Utf16CharExt for char { } #[cfg(test)] +#[cfg(any(feature = "alloc", feature = "std"))] mod tests { use super::*; use crate::{WStr, LE}; + #[cfg(feature = "alloc")] + use alloc::vec; + #[test] fn test_is_leading_surrogate() { assert!(is_leading_surrogate(0xd800)); @@ -254,12 +258,12 @@ mod tests { #[test] fn test_utf16_char_ext_len_utf16_bytes() { let l0 = 'c'.encoded_utf16_len(); - let l1 = 'c'.len_utf16() * std::mem::size_of::(); + let l1 = 'c'.len_utf16() * core::mem::size_of::(); assert_eq!(l0, l1); assert_eq!(l0, 2); let l0 = '\u{10000}'.encoded_utf16_len(); - let l1 = '\u{10000}'.len_utf16() * std::mem::size_of::(); + let l1 = '\u{10000}'.len_utf16() * core::mem::size_of::(); assert_eq!(l0, l1); assert_eq!(l0, 4); } diff --git a/src/wstr.rs b/src/wstr.rs index 6f1af85..3b838b9 100644 --- a/src/wstr.rs +++ b/src/wstr.rs @@ -3,7 +3,8 @@ //! The type itself lives in the `lib.rs` file to avoid having to have a public alias, but //! implementations live here. -use std::fmt; +#[cfg(feature = "alloc")] +use alloc::string::String; use byteorder::{BigEndian, ByteOrder, LittleEndian}; @@ -278,6 +279,7 @@ where } /// Returns this [`WStr`] as a new owned [`String`]. + #[cfg(any(feature = "alloc", feature = "std"))] pub fn to_utf8(&self) -> String { self.chars().collect() } @@ -299,19 +301,27 @@ where } } -impl fmt::Display for WStr +#[cfg(any(feature = "alloc", feature = "std"))] +impl core::fmt::Display for WStr where E: ByteOrder, { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { write!(f, "{}", self.to_utf8()) } } #[cfg(test)] +#[cfg(any(feature = "alloc", feature = "std"))] mod tests { use super::*; + #[cfg(feature = "alloc")] + use alloc::vec::Vec; + + #[cfg(feature = "alloc")] + use alloc::format; + #[test] fn test_wstr_from_utf16le() { let b = b"h\x00e\x00l\x00l\x00o\x00"; diff --git a/src/wstring.rs b/src/wstring.rs index 4f0154d..0d12e48 100644 --- a/src/wstring.rs +++ b/src/wstring.rs @@ -3,8 +3,15 @@ //! The type itself lives in the `lib.rs` file to avoid having to have a public alias, but //! implementations live here. -use std::marker::PhantomData; -use std::ops::{Deref, DerefMut}; +#[cfg(feature = "alloc")] +use alloc::{ + vec::Vec, + string::String +}; + + +use core::marker::PhantomData; +use core::ops::{Deref, DerefMut}; use byteorder::{BigEndian, ByteOrder, LittleEndian}; @@ -195,7 +202,7 @@ where let next = idx + ch.encoded_utf16_len(); let len = self.len(); unsafe { - std::ptr::copy( + core::ptr::copy( self.buf.as_ptr().add(next), self.buf.as_mut_ptr().add(idx), len - next, @@ -223,7 +230,7 @@ where del_bytes += ch_len; } else if del_bytes > 0 { unsafe { - std::ptr::copy( + core::ptr::copy( self.buf.as_ptr().add(idx), self.buf.as_mut_ptr().add(idx - del_bytes), ch_len, @@ -264,12 +271,12 @@ where self.buf.reserve(len_bytes); unsafe { - std::ptr::copy( + core::ptr::copy( self.buf.as_ptr().add(idx), self.buf.as_mut_ptr().add(idx + len_bytes), orig_len - idx, ); - std::ptr::copy(bytes.as_ptr(), self.buf.as_mut_ptr().add(idx), len_bytes); + core::ptr::copy(bytes.as_ptr(), self.buf.as_mut_ptr().add(idx), len_bytes); self.buf.set_len(orig_len + len_bytes); } } @@ -412,7 +419,9 @@ where } #[cfg(test)] +#[cfg(any(feature = "std"))] mod tests { + use byteorder::{BE, LE}; use super::*;