netcorehost/pdcstring/
shared.rs

1use std::{
2    borrow::Borrow,
3    convert::TryFrom,
4    ffi::{OsStr, OsString},
5    fmt::{self, Debug, Display, Formatter},
6    ops::Deref,
7    str::FromStr,
8};
9
10use super::{
11    ContainsNul, MissingNulTerminator, PdCStrInner, PdCStrInnerImpl, PdCStringInner,
12    PdCStringInnerImpl, PdChar, PdUChar, ToStringError,
13};
14
15/// A platform-dependent c-like string type for interacting with the .NET hosting components.
16#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Default)]
17#[repr(transparent)]
18pub struct PdCString(pub(crate) PdCStringInnerImpl);
19
20impl PdCString {
21    #[inline]
22    pub(crate) fn from_inner(inner: PdCStringInnerImpl) -> Self {
23        Self(inner)
24    }
25    #[inline]
26    pub(crate) fn into_inner(self) -> PdCStringInnerImpl {
27        self.0
28    }
29
30    /// Construct a [`PdCString`] copy from an [`OsStr`], reencoding it in a platform-dependent manner.
31    #[inline]
32    pub fn from_os_str(s: impl AsRef<OsStr>) -> Result<Self, ContainsNul> {
33        PdCStringInner::from_os_str(s).map(Self::from_inner)
34    }
35    /// Constructs a new [`PdCString`] copied from a nul-terminated string pointer.
36    #[inline]
37    #[must_use]
38    pub unsafe fn from_str_ptr(ptr: *const PdChar) -> Self {
39        Self::from_inner(unsafe { PdCStringInner::from_str_ptr(ptr) })
40    }
41    /// Constructs a [`PdCString`] from a container of platform-dependent character data.
42    #[inline]
43    pub fn from_vec(vec: impl Into<Vec<PdUChar>>) -> Result<Self, ContainsNul> {
44        PdCStringInner::from_vec(vec).map(Self::from_inner)
45    }
46    /// Converts the string into a [`Vec`] without a nul terminator, consuming the string in the process.
47    #[inline]
48    #[must_use]
49    pub fn into_vec(self) -> Vec<PdUChar> {
50        PdCStringInner::into_vec(self.into_inner())
51    }
52    /// Converts the string into a [`Vec`], consuming the string in the process.
53    #[inline]
54    #[must_use]
55    pub fn into_vec_with_nul(self) -> Vec<PdUChar> {
56        PdCStringInner::into_vec_with_nul(self.into_inner())
57    }
58}
59
60/// A borrowed slice of a [`PdCString`].
61#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
62#[repr(transparent)]
63pub struct PdCStr(pub(crate) PdCStrInnerImpl);
64
65impl PdCStr {
66    #[inline]
67    pub(crate) fn from_inner(inner: &PdCStrInnerImpl) -> &Self {
68        // Safety:
69        // Safe because PdCStr has the same layout as PdCStrInnerImpl
70        unsafe { &*(std::ptr::from_ref::<PdCStrInnerImpl>(inner) as *const PdCStr) }
71    }
72    #[inline]
73    pub(crate) fn as_inner(&self) -> &PdCStrInnerImpl {
74        // Safety:
75        // Safe because PdCStr has the same layout as PdCStrInnerImpl
76        unsafe { &*(std::ptr::from_ref::<PdCStr>(self) as *const PdCStrInnerImpl) }
77    }
78
79    /// Returns a raw pointer to the string.
80    #[inline]
81    #[must_use]
82    pub fn as_ptr(&self) -> *const PdChar {
83        PdCStrInner::as_ptr(self.as_inner())
84    }
85    /// Constructs a [`PdCStr`] from a nul-terminated string pointer.
86    #[inline]
87    #[must_use]
88    pub unsafe fn from_str_ptr<'a>(ptr: *const PdChar) -> &'a Self {
89        Self::from_inner(unsafe { PdCStrInner::from_str_ptr(ptr) })
90    }
91    /// Constructs a [`PdCStr`] from a slice of characters with a terminating nul, checking for invalid interior nul values.
92    #[inline]
93    pub fn from_slice_with_nul(slice: &[PdUChar]) -> Result<&Self, MissingNulTerminator> {
94        PdCStrInner::from_slice_with_nul(slice).map(Self::from_inner)
95    }
96    /// Constructs a [`PdCStr`] from a slice of values without checking for a terminating or interior nul values.
97    #[inline]
98    #[must_use]
99    pub unsafe fn from_slice_with_nul_unchecked(slice: &[PdUChar]) -> &Self {
100        Self::from_inner(unsafe { PdCStrInner::from_slice_with_nul_unchecked(slice) })
101    }
102    /// Copys the string to an owned [`OsString`].
103    #[inline]
104    #[must_use]
105    pub fn to_os_string(&self) -> OsString {
106        PdCStrInner::to_os_string(self.as_inner())
107    }
108    /// Converts this string to a slice of the underlying elements.
109    /// The slice will **not** include the nul terminator.
110    #[inline]
111    #[must_use]
112    pub fn as_slice(&self) -> &[PdUChar] {
113        PdCStrInner::as_slice(self.as_inner())
114    }
115    /// Converts this string to a slice of the underlying elements, including the nul terminator.
116    #[inline]
117    #[must_use]
118    pub fn as_slice_with_nul(&self) -> &[PdUChar] {
119        PdCStrInner::as_slice_with_nul(self.as_inner())
120    }
121    /// Returns whether this string contains no data (i.e. is only the nul terminator).
122    #[inline]
123    #[must_use]
124    pub fn is_empty(&self) -> bool {
125        PdCStrInner::is_empty(self.as_inner())
126    }
127    /// Returns the length of the string as number of elements (not number of bytes) not including the nul terminator.
128    #[inline]
129    #[must_use]
130    pub fn len(&self) -> usize {
131        PdCStrInner::len(self.as_inner())
132    }
133    /// Copies the string to a [`String`] if it contains valid encoded data.
134    #[inline]
135    pub fn to_string(&self) -> Result<String, ToStringError> {
136        PdCStrInner::to_string(self.as_inner())
137    }
138    /// Decodes the string to a [`String`] even if it contains invalid data.
139    /// Any invalid sequences are replaced with U+FFFD REPLACEMENT CHARACTER, which looks like this: �. It will *not have a nul terminator.
140    #[inline]
141    #[must_use]
142    pub fn to_string_lossy(&self) -> String {
143        PdCStrInner::to_string_lossy(self.as_inner())
144    }
145}
146
147impl Borrow<PdCStr> for PdCString {
148    fn borrow(&self) -> &PdCStr {
149        PdCStr::from_inner(self.0.borrow())
150    }
151}
152
153impl AsRef<PdCStr> for PdCString {
154    fn as_ref(&self) -> &PdCStr {
155        self.borrow()
156    }
157}
158
159impl Deref for PdCString {
160    type Target = PdCStr;
161
162    fn deref(&self) -> &Self::Target {
163        self.borrow()
164    }
165}
166
167impl Display for PdCStr {
168    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
169        self.0.fmt(f)
170    }
171}
172
173impl<'a> From<&'a PdCString> for &'a PdCStr {
174    fn from(s: &'a PdCString) -> Self {
175        s.as_ref()
176    }
177}
178
179impl<'a> From<&'a PdCStr> for PdCString {
180    fn from(s: &'a PdCStr) -> Self {
181        s.to_owned()
182    }
183}
184
185impl FromStr for PdCString {
186    type Err = ContainsNul;
187
188    fn from_str(s: &str) -> Result<Self, Self::Err> {
189        PdCStringInner::from_str(s).map(Self::from_inner)
190    }
191}
192
193impl<'a> TryFrom<&'a str> for PdCString {
194    type Error = ContainsNul;
195
196    fn try_from(s: &'a str) -> Result<Self, Self::Error> {
197        Self::from_str(s)
198    }
199}
200
201impl<'a> TryFrom<&'a OsStr> for PdCString {
202    type Error = ContainsNul;
203
204    fn try_from(s: &'a OsStr) -> Result<Self, Self::Error> {
205        Self::from_os_str(s)
206    }
207}
208
209impl TryFrom<Vec<PdUChar>> for PdCString {
210    type Error = ContainsNul;
211
212    fn try_from(vec: Vec<PdUChar>) -> Result<Self, Self::Error> {
213        Self::from_vec(vec)
214    }
215}
216
217impl From<PdCString> for Vec<PdUChar> {
218    fn from(s: PdCString) -> Vec<PdUChar> {
219        s.into_vec()
220    }
221}
222
223impl AsRef<PdCStr> for PdCStr {
224    fn as_ref(&self) -> &Self {
225        self
226    }
227}
228
229impl ToOwned for PdCStr {
230    type Owned = PdCString;
231
232    fn to_owned(&self) -> Self::Owned {
233        PdCString::from_inner(self.0.to_owned())
234    }
235}