Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,9 @@ edition = "2018"
license = "MIT OR Apache-2.0"

[dependencies]
byteorder = "1"
byteorder = { version = "1", default-features = false}

[features]
default = ["std"]
std = []
alloc = []
2 changes: 1 addition & 1 deletion benches/encode_char.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::<u16>();
let byte_count = code_units.len() * core::mem::size_of::<u16>();
let mut buf = [0u8; 4];
LE::write_u16_into(code_units, &mut buf[..byte_count]);
vec.extend_from_slice(&buf[..byte_count]);
Expand Down
3 changes: 1 addition & 2 deletions src/error.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
//! Implementations for [`Utf16Error`].

use std::error::Error;
use std::fmt;

use crate::Utf16Error;
Expand All @@ -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.
Expand Down
9 changes: 5 additions & 4 deletions src/iters.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand All @@ -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);
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -110,14 +110,15 @@ where
#[inline]
fn next_back(&mut self) -> Option<Self::Item> {
let c = self.chars.next_back()?;
let pos = self.index + self.chars.chunks.len() * std::mem::size_of::<u16>();
let pos = self.index + self.chars.chunks.len() * core::mem::size_of::<u16>();
Some((pos, c))
}
}

impl<'a, E> FusedIterator for WStrCharIndices<'a, E> where E: ByteOrder {}

#[cfg(test)]
#[cfg(feature = "std")]
mod tests {
use crate::WStr;

Expand Down
17 changes: 15 additions & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@
//! # }
//! ```

#![cfg_attr(not(feature = "std"), no_std)]

#![warn(
missing_docs,
missing_debug_implementations,
Expand All @@ -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)]
Expand Down Expand Up @@ -129,6 +141,7 @@ pub struct Utf16Error {
/// let s1: WString<LE> = From::from("hello");
/// assert_eq!(s0, s1);
/// ```
#[cfg(any(feature = "alloc", feature = "std"))]
#[derive(Debug, Eq, PartialEq, Hash)]
pub struct WString<E: 'static + ByteOrder> {
buf: Vec<u8>,
Expand Down
23 changes: 14 additions & 9 deletions src/slicing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::*;
Expand All @@ -22,7 +24,7 @@ mod private {
impl SealedSliceIndex for RangeInclusive<usize> {}
impl SealedSliceIndex for RangeToInclusive<usize> {}
}
/// 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.
Expand Down Expand Up @@ -137,14 +139,14 @@ where
unsafe fn get_unchecked(self, slice: &WStr<E>) -> &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<E>) -> &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]
Expand Down Expand Up @@ -186,13 +188,13 @@ where
#[inline]
unsafe fn get_unchecked(self, slice: &WStr<E>) -> &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<E>) -> &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]
Expand Down Expand Up @@ -235,14 +237,14 @@ where
unsafe fn get_unchecked(self, slice: &WStr<E>) -> &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<E>) -> &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]
Expand Down Expand Up @@ -384,6 +386,7 @@ where
}
}

#[cfg(any(feature = "alloc", feature = "std"))]
impl<I, E> Index<I> for WString<E>
where
I: SliceIndex<WStr<E>>,
Expand All @@ -397,6 +400,7 @@ where
}
}

#[cfg(any(feature = "alloc", feature = "std"))]
impl<I, E> IndexMut<I> for WString<E>
where
I: SliceIndex<WStr<E>>,
Expand All @@ -409,6 +413,7 @@ where
}

#[cfg(test)]
#[cfg(any(feature = "alloc", feature = "std"))]
mod tests {
use super::*;

Expand Down
16 changes: 10 additions & 6 deletions src/utf16.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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<E: ByteOrder>(raw: &[u8]) -> Result<(), Utf16Error> {
let base_ptr = raw.as_ptr() as usize;
let mut chunks = raw.chunks_exact(std::mem::size_of::<u16>());
let mut chunks = raw.chunks_exact(core::mem::size_of::<u16>());

while let Some(chunk) = chunks.next() {
let code_point_ptr = chunk.as_ptr() as usize;
Expand All @@ -74,7 +74,7 @@ pub(crate) fn validate_raw_utf16<E: ByteOrder>(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::<u16>() as u8),
error_len: Some(core::mem::size_of::<u16>() as u8),
});
}

Expand All @@ -84,7 +84,7 @@ pub(crate) fn validate_raw_utf16<E: ByteOrder>(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::<u16>() as u8),
error_len: Some(core::mem::size_of::<u16>() as u8),
});
}
}
Expand Down Expand Up @@ -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));
Expand Down Expand Up @@ -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::<u16>();
let l1 = 'c'.len_utf16() * core::mem::size_of::<u16>();
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::<u16>();
let l1 = '\u{10000}'.len_utf16() * core::mem::size_of::<u16>();
assert_eq!(l0, l1);
assert_eq!(l0, 4);
}
Expand Down
16 changes: 13 additions & 3 deletions src/wstr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};

Expand Down Expand Up @@ -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()
}
Expand All @@ -299,19 +301,27 @@ where
}
}

impl<E> fmt::Display for WStr<E>
#[cfg(any(feature = "alloc", feature = "std"))]
impl<E> core::fmt::Display for WStr<E>
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";
Expand Down
Loading