1use super::*;
8
9
10pub type NonNullFREData = NonNull<c_void>;
11pub type NonNullHandle = NonNull<c_void>;
12
13
14#[derive(Debug, Clone, Copy, PartialEq, Eq)]
15#[repr(transparent)]
16pub struct NonNegativeInt(i32);
17impl NonNegativeInt {
18 pub const MIN: Self = Self(0);
19 pub const MAX: Self = Self(i32::MAX);
20 pub fn new (value: i32) -> Option<Self> {
21 if value >= 0 {
22 Some(Self(value))
23 } else {
24 None
25 }
26 }
27 pub fn get (self) -> i32 {self.0}
28}
29impl Default for NonNegativeInt {
30 fn default() -> Self {Self::MIN}
31}
32
33
34#[derive(Debug, Clone, PartialEq, Eq)]
39pub struct UCStr(UCStrValue);
40#[derive(Debug, Clone, PartialEq, Eq)]
41enum UCStrValue {
42 Static(&'static CStr),
43 Heap(Arc<CStr>),
44}
45impl UCStr {
46 pub const fn from_literal (literal: &'static CStr) -> Result<Self, Utf8Error> {
47 match literal.to_str() {
48 Ok(_) => Ok(Self(UCStrValue::Static(literal))),
49 Err(e) => Err(e),
50 }
51 }
52 pub const unsafe fn from_literal_unchecked (literal: &'static CStr) -> Self {
53 debug_assert!(literal.to_str().is_ok());
54 Self(UCStrValue::Static(literal))
55 }
56 #[inline]
57 pub fn as_str (&self) -> &str {
58 let s = match self.0 {
59 UCStrValue::Static(s) => s.to_bytes(),
60 UCStrValue::Heap(ref s) => s.to_bytes(),
61 };
62 unsafe {str::from_utf8_unchecked(s)}
63 }
64 pub fn as_c_str (&self) -> &CStr {
65 match self.0 {
66 UCStrValue::Static(s) => s,
67 UCStrValue::Heap(ref s) => s.as_ref(),
68 }
69 }
70 pub fn as_ptr (&self) -> FREStr {
72 match self.0 {
73 UCStrValue::Static(s) => s.as_ptr() as FREStr,
74 UCStrValue::Heap(ref s) => s.as_ptr() as FREStr,
75 }
76 }
77 pub fn to_c_string (&self) -> CString {
78 match self.0 {
79 UCStrValue::Static(s) => s.to_owned(),
80 UCStrValue::Heap(ref s) => s.as_ref().to_owned(),
81 }
82 }
83}
84impl From<UCStr> for CString {
85 fn from(value: UCStr) -> Self {value.to_c_string()}
86}
87impl From<UCStr> for String {
88 fn from(value: UCStr) -> Self {value.to_string()}
89}
90impl TryFrom<String> for UCStr {
91 type Error = NulError;
92 fn try_from(value: String) -> Result<Self, NulError> {
93 CString::new(value).map(|s|{
94 let s = s.into();
95 Self(UCStrValue::Heap(s))
96 })
97 }
98}
99impl TryFrom<&str> for UCStr {
100 type Error = NulError;
101 fn try_from(value: &str) -> Result<Self, NulError> {
102 CString::new(value).map(|s|{
103 let s = s.into();
104 Self(UCStrValue::Heap(s))
105 })
106 }
107}
108impl TryFrom<CString> for UCStr {
109 type Error = Utf8Error;
110 fn try_from(value: CString) -> Result<Self, Utf8Error> {
111 value.to_str()?;
112 let s = value.into();
113 Ok(Self(UCStrValue::Heap(s)))
114 }
115}
116impl TryFrom<&CStr> for UCStr {
117 type Error = Utf8Error;
118 fn try_from(value: &CStr) -> Result<Self, Utf8Error> {
119 value.to_str().map(|_|{
120 let s = value.to_owned().into();
121 Self(UCStrValue::Heap(s))
122 })
123 }
124}
125impl PartialEq<str> for UCStr {
126 #[inline]
127 fn eq(&self, other: &str) -> bool { self.as_str() == other }
128}
129impl PartialEq<UCStr> for str {
130 #[inline]
131 fn eq(&self, other: &UCStr) -> bool { self == other.as_str() }
132}
133impl PartialOrd for UCStr {
134 #[inline]
135 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> { self.as_str().partial_cmp(other.as_str()) }
136}
137impl Ord for UCStr {
138 #[inline]
139 fn cmp(&self, other: &Self) -> std::cmp::Ordering { self.as_str().cmp(other.as_str()) }
140}
141impl std::hash::Hash for UCStr {
142 #[inline]
143 fn hash<H: std::hash::Hasher>(&self, state: &mut H) { self.as_str().hash(state) }
144}
145impl AsRef<str> for UCStr {
146 fn as_ref(&self) -> &str { self.as_str() }
147}
148impl AsRef<CStr> for UCStr {
149 fn as_ref(&self) -> &CStr { self.as_c_str() }
150}
151impl std::borrow::Borrow<str> for UCStr {
152 #[inline]
153 fn borrow(&self) -> &str { self.as_str() }
154}
155impl Display for UCStr {
156 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { Display::fmt(self.as_str(), f) }
157}
158impl Default for UCStr {
159 fn default() -> Self {Self(UCStrValue::Static(c""))}
160}
161
162
163pub trait ToUcstrLossy {
164 fn to_ucstr_lossy(&self) -> UCStr;
165}
166macro_rules! impl_to_ucstr_lossy {
167 {ref $self:ident: $ty:ty
169 $body:block
170 $(<$($gps:tt)+)?
171 } => {
172 impl $(<$($gps)+)? ToUcstrLossy for & $ty {fn to_ucstr_lossy(&self) -> UCStr {<$ty as ToUcstrLossy>::to_ucstr_lossy(*self)}}
173 impl $(<$($gps)+)? ToUcstrLossy for &mut $ty {fn to_ucstr_lossy(&self) -> UCStr {<$ty as ToUcstrLossy>::to_ucstr_lossy(*self)}}
174 impl $(<$($gps)+)? ToUcstrLossy for $ty {fn to_ucstr_lossy(&self) -> UCStr {let $self = self; $body}}
175 };
176}
177impl_to_ucstr_lossy! {ref this: UCStr {
178 this.clone()
179}}
180impl_to_ucstr_lossy! {ref this: str {
181 this.replace('\0', "�")
182 .try_into()
183 .unwrap()
184}}
185impl_to_ucstr_lossy! {ref this: String {
186 this.as_str().to_ucstr_lossy()
187}}
188impl_to_ucstr_lossy! {ref this: CStr {
189 let s = this.to_string_lossy();
190 let bytes = s.as_bytes();
191 let mut v = Vec::with_capacity(bytes.len()+1);
192 v.extend_from_slice(bytes);
193 v.push(0);
194 let s = unsafe {CString::from_vec_unchecked(v)};
195 UCStr(UCStrValue::Heap(s.into()))
196}}
197impl_to_ucstr_lossy! {ref this: CString {
198 this.as_c_str().to_ucstr_lossy()
199}}
200impl<'a, O: AsObject<'a>> ToUcstrLossy for O {
201 fn to_ucstr_lossy(&self) -> UCStr {
202 self.to_string()
203 .as_str()
204 .to_ucstr_lossy()
205 }
206}
207impl<'a> ToUcstrLossy for & as3::Object<'a> {fn to_ucstr_lossy(&self) -> UCStr {<as3::Object as ToUcstrLossy>::to_ucstr_lossy(*self)}}
208impl<'a> ToUcstrLossy for &mut as3::Object<'a> {fn to_ucstr_lossy(&self) -> UCStr {<as3::Object as ToUcstrLossy>::to_ucstr_lossy(*self)}}
209impl_to_ucstr_lossy! {ref this: Option<O> {
211 if let Some(object) = this {
212 object.to_ucstr_lossy()
213 } else {crate::ucstringify!(null)}
214} <'a, O: AsObject<'a>> }
215impl_to_ucstr_lossy! {ref this: [O] {
216 this.iter()
217 .map(|object|object.to_string())
218 .collect::<Vec<String>>()
219 .join(", ")
220 .as_str()
221 .to_ucstr_lossy()
222} <'a, O: AsObject<'a>> }
223impl_to_ucstr_lossy! {ref this: [Option<O>] {
224 this.iter()
225 .map(|object|{
226 if let Some(object) = object {
227 object.to_string()
228 } else {String::from("null")}
229 })
230 .collect::<Vec<String>>()
231 .join(", ")
232 .as_str()
233 .to_ucstr_lossy()
234} <'a, O: AsObject<'a>> }
235impl_to_ucstr_lossy! {ref this: [O; LEN] {
236 this.as_slice().to_ucstr_lossy()
237} <'a, O: AsObject<'a>,
238const LEN: usize> }
239impl_to_ucstr_lossy! {ref this: [Option<O>; LEN] {
240 this.as_slice().to_ucstr_lossy()
241} <'a, O: AsObject<'a>,
242const LEN: usize> }
243impl_to_ucstr_lossy! {ref this: Vec<O> {
244 this.as_slice().to_ucstr_lossy()
245} <'a, O: AsObject<'a>> }
246impl_to_ucstr_lossy! {ref this: Vec<Option<O>> {
247 this.as_slice().to_ucstr_lossy()
248} <'a, O: AsObject<'a>> }
249