1use alloc::{
2 string::{String, ToString},
3 vec::Vec,
4};
5
6use crate::props::basic::ColorU;
7
8#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
29#[repr(C)]
30pub struct Void {
31 pub _reserved: u8,
34}
35
36impl Default for Void {
37 fn default() -> Self {
38 Self { _reserved: 0 }
39 }
40}
41
42impl Void {
43 pub const fn new() -> Self {
45 Self { _reserved: 0 }
46 }
47}
48
49impl From<()> for Void {
50 fn from(_: ()) -> Self {
51 Self::default()
52 }
53}
54
55impl From<Void> for () {
56 fn from(_: Void) -> Self {
57 ()
58 }
59}
60
61#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
67#[repr(C)]
68pub enum LayoutDebugMessageType {
69 Info,
70 Warning,
71 Error,
72 BoxProps,
74 CssGetter,
75 BfcLayout,
76 IfcLayout,
77 TableLayout,
78 DisplayType,
79 PositionCalculation,
80}
81
82impl Default for LayoutDebugMessageType {
83 fn default() -> Self {
84 Self::Info
85 }
86}
87
88#[derive(Debug, Default, Clone, PartialEq, PartialOrd)]
90#[repr(C)]
91pub struct LayoutDebugMessage {
92 pub message_type: LayoutDebugMessageType,
93 pub message: AzString,
94 pub location: AzString,
95}
96
97impl LayoutDebugMessage {
98 #[track_caller]
100 pub fn new(message_type: LayoutDebugMessageType, message: impl Into<String>) -> Self {
101 let location = core::panic::Location::caller();
102 Self {
103 message_type,
104 message: AzString::from_string(message.into()),
105 location: AzString::from_string(format!(
106 "{}:{}:{}",
107 location.file(),
108 location.line(),
109 location.column()
110 )),
111 }
112 }
113
114 #[track_caller]
116 pub fn info(message: impl Into<String>) -> Self {
117 Self::new(LayoutDebugMessageType::Info, message)
118 }
119
120 #[track_caller]
122 pub fn warning(message: impl Into<String>) -> Self {
123 Self::new(LayoutDebugMessageType::Warning, message)
124 }
125
126 #[track_caller]
128 pub fn error(message: impl Into<String>) -> Self {
129 Self::new(LayoutDebugMessageType::Error, message)
130 }
131
132 #[track_caller]
134 pub fn box_props(message: impl Into<String>) -> Self {
135 Self::new(LayoutDebugMessageType::BoxProps, message)
136 }
137
138 #[track_caller]
140 pub fn css_getter(message: impl Into<String>) -> Self {
141 Self::new(LayoutDebugMessageType::CssGetter, message)
142 }
143
144 #[track_caller]
146 pub fn bfc_layout(message: impl Into<String>) -> Self {
147 Self::new(LayoutDebugMessageType::BfcLayout, message)
148 }
149
150 #[track_caller]
152 pub fn ifc_layout(message: impl Into<String>) -> Self {
153 Self::new(LayoutDebugMessageType::IfcLayout, message)
154 }
155
156 #[track_caller]
158 pub fn table_layout(message: impl Into<String>) -> Self {
159 Self::new(LayoutDebugMessageType::TableLayout, message)
160 }
161
162 #[track_caller]
164 pub fn display_type(message: impl Into<String>) -> Self {
165 Self::new(LayoutDebugMessageType::DisplayType, message)
166 }
167}
168
169#[repr(C)]
170pub struct AzString {
171 pub vec: U8Vec,
172}
173
174impl_option!(
175 AzString,
176 OptionString,
177 copy = false,
178 [Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash]
179);
180
181pub type OptionAzString = OptionString;
183
184static DEFAULT_STR: &str = "";
185
186impl Default for AzString {
187 fn default() -> Self {
188 DEFAULT_STR.into()
189 }
190}
191
192impl<'a> From<&'a str> for AzString {
193 fn from(s: &'a str) -> Self {
194 s.to_string().into()
195 }
196}
197
198impl AsRef<str> for AzString {
199 fn as_ref<'a>(&'a self) -> &'a str {
200 self.as_str()
201 }
202}
203
204impl core::fmt::Debug for AzString {
205 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
206 self.as_str().fmt(f)
207 }
208}
209
210impl core::fmt::Display for AzString {
211 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
212 self.as_str().fmt(f)
213 }
214}
215
216impl AzString {
217 #[inline]
218 pub const fn from_const_str(s: &'static str) -> Self {
219 Self {
220 vec: U8Vec::from_const_slice(s.as_bytes()),
221 }
222 }
223
224 #[inline]
231 pub unsafe fn from_c_str(ptr: *const core::ffi::c_char) -> Self {
232 if ptr.is_null() {
233 return Self::default();
234 }
235 let c_str = core::ffi::CStr::from_ptr(ptr);
236 let bytes = c_str.to_bytes();
237 Self::copy_from_bytes(bytes.as_ptr(), 0, bytes.len())
238 }
239
240 #[inline]
243 pub fn copy_from_bytes(ptr: *const u8, start: usize, len: usize) -> Self {
244 Self {
245 vec: U8Vec::copy_from_bytes(ptr, start, len),
246 }
247 }
248
249 #[inline]
250 pub fn from_string(s: String) -> Self {
251 Self {
252 vec: U8Vec::from_vec(s.into_bytes()),
253 }
254 }
255
256 #[inline]
257 pub fn as_str(&self) -> &str {
258 unsafe { core::str::from_utf8_unchecked(self.vec.as_ref()) }
259 }
260
261 #[inline]
264 pub fn clone_self(&self) -> Self {
265 Self {
266 vec: self.vec.clone_self(),
267 }
268 }
269
270 #[inline]
271 pub fn into_library_owned_string(self) -> String {
272 match self.vec.destructor {
273 U8VecDestructor::NoDestructor | U8VecDestructor::External(_) => {
274 self.as_str().to_string()
275 }
276 U8VecDestructor::DefaultRust => {
277 let m = core::mem::ManuallyDrop::new(self);
278 unsafe { String::from_raw_parts(m.vec.ptr as *mut u8, m.vec.len, m.vec.cap) }
279 }
280 }
281 }
282
283 #[inline]
284 pub fn as_bytes(&self) -> &[u8] {
285 self.vec.as_ref()
286 }
287
288 #[inline]
289 pub fn into_bytes(self) -> U8Vec {
290 let m = core::mem::ManuallyDrop::new(self);
291 U8Vec {
292 ptr: m.vec.ptr,
293 len: m.vec.len,
294 cap: m.vec.cap,
295 destructor: m.vec.destructor,
296 run_destructor: m.vec.run_destructor,
297 }
298 }
299
300 #[inline]
302 pub fn len(&self) -> usize {
303 self.vec.len
304 }
305
306 #[inline]
308 pub fn is_empty(&self) -> bool {
309 self.vec.len == 0
310 }
311
312 #[inline]
318 pub fn to_c_str(&self) -> U8Vec {
319 let bytes = self.as_bytes();
320 let mut result = Vec::with_capacity(bytes.len() + 1);
321 result.extend_from_slice(bytes);
322 result.push(0); U8Vec::from_vec(result)
324 }
325
326 #[inline]
337 pub unsafe fn from_utf16_le(ptr: *const u8, len: usize) -> Self {
338 if ptr.is_null() || len == 0 {
339 return Self::default();
340 }
341
342 if len % 2 != 0 {
344 return Self::default();
345 }
346
347 let byte_slice = core::slice::from_raw_parts(ptr, len);
348 let code_units: Vec<u16> = byte_slice
349 .chunks_exact(2)
350 .map(|chunk| u16::from_le_bytes([chunk[0], chunk[1]]))
351 .collect();
352
353 match String::from_utf16(&code_units) {
354 Ok(s) => Self::from_string(s),
355 Err(_) => Self::default(),
356 }
357 }
358
359 #[inline]
370 pub unsafe fn from_utf16_be(ptr: *const u8, len: usize) -> Self {
371 if ptr.is_null() || len == 0 {
372 return Self::default();
373 }
374
375 if len % 2 != 0 {
377 return Self::default();
378 }
379
380 let byte_slice = core::slice::from_raw_parts(ptr, len);
381 let code_units: Vec<u16> = byte_slice
382 .chunks_exact(2)
383 .map(|chunk| u16::from_be_bytes([chunk[0], chunk[1]]))
384 .collect();
385
386 match String::from_utf16(&code_units) {
387 Ok(s) => Self::from_string(s),
388 Err(_) => Self::default(),
389 }
390 }
391
392 #[inline]
398 pub unsafe fn from_utf8_lossy(ptr: *const u8, len: usize) -> Self {
399 if ptr.is_null() || len == 0 {
400 return Self::default();
401 }
402
403 let byte_slice = core::slice::from_raw_parts(ptr, len);
404 let s = String::from_utf8_lossy(byte_slice).into_owned();
405 Self::from_string(s)
406 }
407
408 #[inline]
414 pub unsafe fn from_utf8(ptr: *const u8, len: usize) -> Self {
415 if ptr.is_null() || len == 0 {
416 return Self::default();
417 }
418
419 let byte_slice = core::slice::from_raw_parts(ptr, len);
420 match core::str::from_utf8(byte_slice) {
421 Ok(s) => Self::from_string(s.to_string()),
422 Err(_) => Self::default(),
423 }
424 }
425}
426
427impl From<String> for AzString {
428 fn from(input: String) -> AzString {
429 AzString::from_string(input)
430 }
431}
432
433impl PartialOrd for AzString {
434 fn partial_cmp(&self, rhs: &Self) -> Option<core::cmp::Ordering> {
435 self.as_str().partial_cmp(rhs.as_str())
436 }
437}
438
439impl Ord for AzString {
440 fn cmp(&self, rhs: &Self) -> core::cmp::Ordering {
441 self.as_str().cmp(rhs.as_str())
442 }
443}
444
445impl Clone for AzString {
446 fn clone(&self) -> Self {
447 self.clone_self()
448 }
449}
450
451impl PartialEq for AzString {
452 fn eq(&self, rhs: &Self) -> bool {
453 self.as_str().eq(rhs.as_str())
454 }
455}
456
457impl Eq for AzString {}
458
459impl core::hash::Hash for AzString {
460 fn hash<H>(&self, state: &mut H)
461 where
462 H: core::hash::Hasher,
463 {
464 self.as_str().hash(state)
465 }
466}
467
468impl core::ops::Deref for AzString {
469 type Target = str;
470
471 fn deref(&self) -> &str {
472 self.as_str()
473 }
474}
475
476impl_option!(
477 u8,
478 OptionU8,
479 [Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash]
480);
481
482impl_vec!(u8, U8Vec, U8VecDestructor, U8VecDestructorType, U8VecSlice, OptionU8);
483impl_vec_mut!(u8, U8Vec);
484impl_vec_debug!(u8, U8Vec);
485impl_vec_partialord!(u8, U8Vec);
486impl_vec_ord!(u8, U8Vec);
487impl_vec_clone!(u8, U8Vec, U8VecDestructor);
488impl_vec_partialeq!(u8, U8Vec);
489impl_vec_eq!(u8, U8Vec);
490impl_vec_hash!(u8, U8Vec);
491
492impl U8Vec {
493 #[inline]
496 pub fn copy_from_bytes(ptr: *const u8, start: usize, len: usize) -> Self {
497 if ptr.is_null() || len == 0 {
498 return Self::new();
499 }
500 let slice = unsafe { core::slice::from_raw_parts(ptr.add(start), len) };
501 Self::from_vec(slice.to_vec())
502 }
503}
504
505impl_option!(
506 U8Vec,
507 OptionU8Vec,
508 copy = false,
509 [Debug, Clone, PartialEq, Ord, PartialOrd, Eq, Hash]
510);
511
512impl_vec!(u16, U16Vec, U16VecDestructor, U16VecDestructorType, U16VecSlice, OptionU16);
513impl_vec_debug!(u16, U16Vec);
514impl_vec_partialord!(u16, U16Vec);
515impl_vec_ord!(u16, U16Vec);
516impl_vec_clone!(u16, U16Vec, U16VecDestructor);
517impl_vec_partialeq!(u16, U16Vec);
518impl_vec_eq!(u16, U16Vec);
519impl_vec_hash!(u16, U16Vec);
520
521impl_vec!(f32, F32Vec, F32VecDestructor, F32VecDestructorType, F32VecSlice, OptionF32);
522impl_vec_debug!(f32, F32Vec);
523impl_vec_partialord!(f32, F32Vec);
524impl_vec_clone!(f32, F32Vec, F32VecDestructor);
525impl_vec_partialeq!(f32, F32Vec);
526
527impl_vec!(u32, U32Vec, U32VecDestructor, U32VecDestructorType, U32VecSlice, OptionU32);
529impl_vec_mut!(u32, U32Vec);
530impl_vec_debug!(u32, U32Vec);
531impl_vec_partialord!(u32, U32Vec);
532impl_vec_ord!(u32, U32Vec);
533impl_vec_clone!(u32, U32Vec, U32VecDestructor);
534impl_vec_partialeq!(u32, U32Vec);
535impl_vec_eq!(u32, U32Vec);
536impl_vec_hash!(u32, U32Vec);
537
538impl_vec!(AzString, StringVec, StringVecDestructor, StringVecDestructorType, StringVecSlice, OptionString);
539impl_vec_debug!(AzString, StringVec);
540impl_vec_partialord!(AzString, StringVec);
541impl_vec_ord!(AzString, StringVec);
542impl_vec_clone!(AzString, StringVec, StringVecDestructor);
543impl_vec_partialeq!(AzString, StringVec);
544impl_vec_eq!(AzString, StringVec);
545impl_vec_hash!(AzString, StringVec);
546
547impl From<Vec<String>> for StringVec {
548 fn from(v: Vec<String>) -> StringVec {
549 let new_v: Vec<AzString> = v.into_iter().map(|s| s.into()).collect();
550 new_v.into()
551 }
552}
553
554impl_option!(
555 StringVec,
556 OptionStringVec,
557 copy = false,
558 [Debug, Clone, PartialOrd, PartialEq, Ord, Eq, Hash]
559);
560
561impl_option!(
562 u16,
563 OptionU16,
564 [Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash]
565);
566impl_option!(
567 u32,
568 OptionU32,
569 [Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash]
570);
571impl_option!(
572 u64,
573 OptionU64,
574 [Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash]
575);
576impl_option!(
577 usize,
578 OptionUsize,
579 [Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash]
580);
581impl_option!(
582 i16,
583 OptionI16,
584 [Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash]
585);
586impl_option!(
587 i32,
588 OptionI32,
589 [Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash]
590);
591impl_option!(bool, OptionBool, [Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash]);
592impl_option!(f32, OptionF32, [Debug, Copy, Clone, PartialEq, PartialOrd]);
593impl_option!(f64, OptionF64, [Debug, Copy, Clone, PartialEq, PartialOrd]);
594
595impl core::hash::Hash for OptionF32 {
597 fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
598 match self {
599 OptionF32::None => 0u8.hash(state),
600 OptionF32::Some(v) => {
601 1u8.hash(state);
602 v.to_bits().hash(state);
603 }
604 }
605 }
606}
607
608impl Eq for OptionF32 {}
609
610impl Ord for OptionF32 {
611 fn cmp(&self, other: &Self) -> core::cmp::Ordering {
612 match (self, other) {
613 (OptionF32::None, OptionF32::None) => core::cmp::Ordering::Equal,
614 (OptionF32::None, OptionF32::Some(_)) => core::cmp::Ordering::Less,
615 (OptionF32::Some(_), OptionF32::None) => core::cmp::Ordering::Greater,
616 (OptionF32::Some(a), OptionF32::Some(b)) => {
617 a.partial_cmp(b).unwrap_or(core::cmp::Ordering::Equal)
618 }
619 }
620 }
621}