use crate::{Error, Result};
pub(crate) fn to_wide(s: &str) -> Result<Vec<u16>> {
if s.contains('\0') {
return Err(Error::InteriorNul);
}
let mut wide: Vec<u16> = Vec::with_capacity(s.len() + 1);
wide.extend(s.encode_utf16());
wide.push(0);
Ok(wide)
}
pub(crate) type WideSecret = zeroize::Zeroizing<Vec<u16>>;
pub(crate) fn opt_ptr(buf: Option<&[u16]>) -> *const u16 {
buf.map_or(std::ptr::null(), <[u16]>::as_ptr)
}
pub(crate) fn from_wide_buf(buf: &[u16]) -> String {
let len = buf.iter().position(|&c| c == 0).unwrap_or(buf.len());
String::from_utf16_lossy(&buf[..len])
}
pub(crate) unsafe fn from_pwstr(ptr: *const u16) -> Option<String> {
if ptr.is_null() {
return None;
}
let mut len = 0usize;
unsafe {
while *ptr.add(len) != 0 {
len += 1;
}
Some(String::from_utf16_lossy(std::slice::from_raw_parts(
ptr, len,
)))
}
}
pub(crate) fn len_u32(len: usize) -> u32 {
u32::try_from(len).unwrap_or(u32::MAX)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn to_wide_converts_and_validates() {
assert_eq!(to_wide("ab").unwrap(), vec![97, 98, 0]);
assert_eq!(to_wide("ü").unwrap(), vec![0xFC, 0]);
assert_eq!(to_wide("a\0b").unwrap_err(), Error::InteriorNul);
}
#[test]
fn from_wide_buf_stops_at_nul() {
assert_eq!(from_wide_buf(&[97, 98, 0, 99]), "ab");
assert_eq!(from_wide_buf(&[97, 98]), "ab");
}
#[test]
fn from_pwstr_roundtrip() {
let wide = to_wide("hello").unwrap();
assert_eq!(
unsafe { from_pwstr(wide.as_ptr()) }.as_deref(),
Some("hello")
);
assert_eq!(unsafe { from_pwstr(std::ptr::null()) }, None);
}
}