Skip to content

Commit d27db94

Browse files
Add UnalignedSlice to string conversions
1 parent f96b109 commit d27db94

File tree

2 files changed

+55
-0
lines changed

2 files changed

+55
-0
lines changed

src/data_types/owned_strs.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use super::chars::{Char16, NUL_16};
22
use super::strs::{CStr16, FromSliceWithNulError};
33
use crate::alloc_api::vec::Vec;
44
use crate::data_types::strs::EqStrUntilNul;
5+
use crate::data_types::UnalignedSlice;
56
use core::fmt;
67
use core::ops;
78

@@ -85,6 +86,22 @@ impl TryFrom<Vec<u16>> for CString16 {
8586
}
8687
}
8788

89+
impl<'a> TryFrom<&UnalignedSlice<'a, u16>> for CString16 {
90+
type Error = FromSliceWithNulError;
91+
92+
fn try_from(input: &UnalignedSlice<u16>) -> Result<Self, Self::Error> {
93+
let v = input.to_vec();
94+
CString16::try_from(v)
95+
}
96+
}
97+
98+
impl<'a> UnalignedSlice<'a, u16> {
99+
/// Copies `self` to a new [`CString16`].
100+
pub fn to_cstring16(&self) -> Result<CString16, FromSliceWithNulError> {
101+
CString16::try_from(self)
102+
}
103+
}
104+
88105
impl ops::Deref for CString16 {
89106
type Target = CStr16;
90107

src/data_types/strs.rs

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use super::chars::{Char16, Char8, NUL_16, NUL_8};
2+
use super::UnalignedSlice;
23
use core::fmt;
34
use core::iter::Iterator;
45
use core::marker::PhantomData;
@@ -261,6 +262,31 @@ impl CStr16 {
261262
})
262263
}
263264

265+
/// Create a [`CStr16`] from an [`UnalignedSlice`] using an aligned
266+
/// buffer for storage. The lifetime of the output is tied to `buf`,
267+
/// not `src`.
268+
pub fn from_unaligned_slice<'buf>(
269+
src: &UnalignedSlice<'_, u16>,
270+
buf: &'buf mut [MaybeUninit<u16>],
271+
) -> Result<&'buf CStr16, UnalignedCStr16Error> {
272+
// The input `buf` might be longer than needed, so get a
273+
// subslice of the required length.
274+
let buf = buf
275+
.get_mut(..src.len())
276+
.ok_or(UnalignedCStr16Error::BufferTooSmall)?;
277+
278+
src.copy_to_maybe_uninit(buf);
279+
let buf = unsafe {
280+
// Safety: `copy_buf` fully initializes the slice.
281+
MaybeUninit::slice_assume_init_ref(buf)
282+
};
283+
CStr16::from_u16_with_nul(buf).map_err(|e| match e {
284+
FromSliceWithNulError::InvalidChar(v) => UnalignedCStr16Error::InvalidChar(v),
285+
FromSliceWithNulError::InteriorNul(v) => UnalignedCStr16Error::InteriorNul(v),
286+
FromSliceWithNulError::NotNulTerminated => UnalignedCStr16Error::NotNulTerminated,
287+
})
288+
}
289+
264290
/// Returns the inner pointer to this C string
265291
pub fn as_ptr(&self) -> *const Char16 {
266292
self.0.as_ptr()
@@ -485,6 +511,18 @@ impl<'a> UnalignedCStr16<'a> {
485511
}
486512
}
487513

514+
impl<'a> UnalignedSlice<'a, u16> {
515+
/// Create a [`CStr16`] from an [`UnalignedSlice`] using an aligned
516+
/// buffer for storage. The lifetime of the output is tied to `buf`,
517+
/// not `self`.
518+
pub fn to_cstr16<'buf>(
519+
&self,
520+
buf: &'buf mut [MaybeUninit<u16>],
521+
) -> Result<&'buf CStr16, UnalignedCStr16Error> {
522+
CStr16::from_unaligned_slice(self, buf)
523+
}
524+
}
525+
488526
/// Trait that helps to compare Rust strings against CStr16 types.
489527
/// A generic implementation of this trait enables us that we only have to
490528
/// implement one direction (`left.eq_str_until_nul(&right)`) and we get

0 commit comments

Comments
 (0)