Skip to main content

windows_strings/
hstring_builder.rs

1use super::*;
2
3/// Builder for preallocating immutable [`HSTRING`] values.
4pub struct HStringBuilder(*mut HStringHeader);
5
6impl HStringBuilder {
7    /// Creates a preallocated `HSTRING` value.
8    pub fn new(len: usize) -> Self {
9        let header = HStringHeader::alloc(len.try_into().unwrap());
10
11        if len > 0 {
12            unsafe { core::ptr::write_bytes((*header).data, 0, len) };
13        }
14
15        Self(header)
16    }
17
18    /// Shortens the string by removing any trailing 0 characters.
19    pub fn trim_end(&mut self) {
20        let mut new_len = self.len();
21        while new_len > 0 && self[new_len - 1] == 0 {
22            new_len -= 1;
23        }
24        if new_len == 0 {
25            unsafe {
26                HStringHeader::free(self.0);
27            }
28            self.0 = core::ptr::null_mut();
29        } else if let Some(header) = self.as_header_mut() {
30            header.len = new_len as u32;
31        }
32    }
33
34    /// Returns the mutable UTF-16 buffer as bytes.
35    pub fn as_bytes_mut(&mut self) -> &mut [u8] {
36        if let Some(header) = self.as_header() {
37            unsafe {
38                core::slice::from_raw_parts_mut(header.data as *mut _, header.len as usize * 2)
39            }
40        } else {
41            &mut []
42        }
43    }
44
45    fn as_header(&self) -> Option<&HStringHeader> {
46        unsafe { self.0.as_ref() }
47    }
48
49    fn as_header_mut(&mut self) -> Option<&mut HStringHeader> {
50        unsafe { self.0.as_mut() }
51    }
52}
53
54impl From<HStringBuilder> for HSTRING {
55    fn from(value: HStringBuilder) -> Self {
56        if let Some(header) = value.as_header() {
57            unsafe { header.data.offset(header.len as isize).write(0) };
58            let result = Self(value.0);
59            core::mem::forget(value);
60            result
61        } else {
62            Self::new()
63        }
64    }
65}
66
67impl core::ops::Deref for HStringBuilder {
68    type Target = [u16];
69
70    fn deref(&self) -> &[u16] {
71        if let Some(header) = self.as_header() {
72            unsafe { core::slice::from_raw_parts(header.data, header.len as usize) }
73        } else {
74            &[]
75        }
76    }
77}
78
79impl core::ops::DerefMut for HStringBuilder {
80    fn deref_mut(&mut self) -> &mut [u16] {
81        if let Some(header) = self.as_header() {
82            unsafe { core::slice::from_raw_parts_mut(header.data, header.len as usize) }
83        } else {
84            &mut []
85        }
86    }
87}
88
89impl Drop for HStringBuilder {
90    fn drop(&mut self) {
91        unsafe {
92            HStringHeader::free(self.0);
93        }
94    }
95}
96
97impl core::fmt::Debug for HStringBuilder {
98    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
99        write!(
100            f,
101            "\"{}\"",
102            Decode(|| core::char::decode_utf16(self.iter().copied()))
103        )
104    }
105}