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
181static DEFAULT_STR: &str = "";
182
183impl Default for AzString {
184 fn default() -> Self {
185 DEFAULT_STR.into()
186 }
187}
188
189impl<'a> From<&'a str> for AzString {
190 fn from(s: &'a str) -> Self {
191 s.to_string().into()
192 }
193}
194
195impl AsRef<str> for AzString {
196 fn as_ref<'a>(&'a self) -> &'a str {
197 self.as_str()
198 }
199}
200
201impl core::fmt::Debug for AzString {
202 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
203 self.as_str().fmt(f)
204 }
205}
206
207impl core::fmt::Display for AzString {
208 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
209 self.as_str().fmt(f)
210 }
211}
212
213impl AzString {
214 #[inline]
215 pub const fn from_const_str(s: &'static str) -> Self {
216 Self {
217 vec: U8Vec::from_const_slice(s.as_bytes()),
218 }
219 }
220
221 #[inline]
228 pub unsafe fn from_c_str(ptr: *const i8) -> Self {
229 if ptr.is_null() {
230 return Self::default();
231 }
232 let c_str = core::ffi::CStr::from_ptr(ptr);
233 let bytes = c_str.to_bytes();
234 Self::copy_from_bytes(bytes.as_ptr(), 0, bytes.len())
235 }
236
237 #[inline]
240 pub fn copy_from_bytes(ptr: *const u8, start: usize, len: usize) -> Self {
241 Self {
242 vec: U8Vec::copy_from_bytes(ptr, start, len),
243 }
244 }
245
246 #[inline]
247 pub fn from_string(s: String) -> Self {
248 Self {
249 vec: U8Vec::from_vec(s.into_bytes()),
250 }
251 }
252
253 #[inline]
254 pub fn as_str(&self) -> &str {
255 unsafe { core::str::from_utf8_unchecked(self.vec.as_ref()) }
256 }
257
258 #[inline]
261 pub fn clone_self(&self) -> Self {
262 Self {
263 vec: self.vec.clone_self(),
264 }
265 }
266
267 #[inline]
268 pub fn into_library_owned_string(self) -> String {
269 match self.vec.destructor {
270 U8VecDestructor::NoDestructor | U8VecDestructor::External(_) => {
271 self.as_str().to_string()
272 }
273 U8VecDestructor::DefaultRust => {
274 let m = core::mem::ManuallyDrop::new(self);
275 unsafe { String::from_raw_parts(m.vec.ptr as *mut u8, m.vec.len, m.vec.cap) }
276 }
277 }
278 }
279
280 #[inline]
281 pub fn as_bytes(&self) -> &[u8] {
282 self.vec.as_ref()
283 }
284
285 #[inline]
286 pub fn into_bytes(self) -> U8Vec {
287 let m = core::mem::ManuallyDrop::new(self);
288 U8Vec {
289 ptr: m.vec.ptr,
290 len: m.vec.len,
291 cap: m.vec.cap,
292 destructor: m.vec.destructor,
293 run_destructor: m.vec.run_destructor,
294 }
295 }
296
297 #[inline]
299 pub fn len(&self) -> usize {
300 self.vec.len
301 }
302
303 #[inline]
305 pub fn is_empty(&self) -> bool {
306 self.vec.len == 0
307 }
308
309 #[inline]
315 pub fn to_c_str(&self) -> U8Vec {
316 let bytes = self.as_bytes();
317 let mut result = Vec::with_capacity(bytes.len() + 1);
318 result.extend_from_slice(bytes);
319 result.push(0); U8Vec::from_vec(result)
321 }
322
323 #[inline]
334 pub unsafe fn from_utf16_le(ptr: *const u8, len: usize) -> Self {
335 if ptr.is_null() || len == 0 {
336 return Self::default();
337 }
338
339 if len % 2 != 0 {
341 return Self::default();
342 }
343
344 let byte_slice = core::slice::from_raw_parts(ptr, len);
345 let code_units: Vec<u16> = byte_slice
346 .chunks_exact(2)
347 .map(|chunk| u16::from_le_bytes([chunk[0], chunk[1]]))
348 .collect();
349
350 match String::from_utf16(&code_units) {
351 Ok(s) => Self::from_string(s),
352 Err(_) => Self::default(),
353 }
354 }
355
356 #[inline]
367 pub unsafe fn from_utf16_be(ptr: *const u8, len: usize) -> Self {
368 if ptr.is_null() || len == 0 {
369 return Self::default();
370 }
371
372 if len % 2 != 0 {
374 return Self::default();
375 }
376
377 let byte_slice = core::slice::from_raw_parts(ptr, len);
378 let code_units: Vec<u16> = byte_slice
379 .chunks_exact(2)
380 .map(|chunk| u16::from_be_bytes([chunk[0], chunk[1]]))
381 .collect();
382
383 match String::from_utf16(&code_units) {
384 Ok(s) => Self::from_string(s),
385 Err(_) => Self::default(),
386 }
387 }
388
389 #[inline]
395 pub unsafe fn from_utf8_lossy(ptr: *const u8, len: usize) -> Self {
396 if ptr.is_null() || len == 0 {
397 return Self::default();
398 }
399
400 let byte_slice = core::slice::from_raw_parts(ptr, len);
401 let s = String::from_utf8_lossy(byte_slice).into_owned();
402 Self::from_string(s)
403 }
404
405 #[inline]
411 pub unsafe fn from_utf8(ptr: *const u8, len: usize) -> Self {
412 if ptr.is_null() || len == 0 {
413 return Self::default();
414 }
415
416 let byte_slice = core::slice::from_raw_parts(ptr, len);
417 match core::str::from_utf8(byte_slice) {
418 Ok(s) => Self::from_string(s.to_string()),
419 Err(_) => Self::default(),
420 }
421 }
422}
423
424impl From<String> for AzString {
425 fn from(input: String) -> AzString {
426 AzString::from_string(input)
427 }
428}
429
430impl PartialOrd for AzString {
431 fn partial_cmp(&self, rhs: &Self) -> Option<core::cmp::Ordering> {
432 self.as_str().partial_cmp(rhs.as_str())
433 }
434}
435
436impl Ord for AzString {
437 fn cmp(&self, rhs: &Self) -> core::cmp::Ordering {
438 self.as_str().cmp(rhs.as_str())
439 }
440}
441
442impl Clone for AzString {
443 fn clone(&self) -> Self {
444 self.clone_self()
445 }
446}
447
448impl PartialEq for AzString {
449 fn eq(&self, rhs: &Self) -> bool {
450 self.as_str().eq(rhs.as_str())
451 }
452}
453
454impl Eq for AzString {}
455
456impl core::hash::Hash for AzString {
457 fn hash<H>(&self, state: &mut H)
458 where
459 H: core::hash::Hasher,
460 {
461 self.as_str().hash(state)
462 }
463}
464
465impl core::ops::Deref for AzString {
466 type Target = str;
467
468 fn deref(&self) -> &str {
469 self.as_str()
470 }
471}
472
473impl_vec!(u8, U8Vec, U8VecDestructor, U8VecDestructorType);
474impl_vec_mut!(u8, U8Vec);
475impl_vec_debug!(u8, U8Vec);
476impl_vec_partialord!(u8, U8Vec);
477impl_vec_ord!(u8, U8Vec);
478impl_vec_clone!(u8, U8Vec, U8VecDestructor);
479impl_vec_partialeq!(u8, U8Vec);
480impl_vec_eq!(u8, U8Vec);
481impl_vec_hash!(u8, U8Vec);
482
483impl U8Vec {
484 #[inline]
487 pub fn copy_from_bytes(ptr: *const u8, start: usize, len: usize) -> Self {
488 if ptr.is_null() || len == 0 {
489 return Self::new();
490 }
491 let slice = unsafe { core::slice::from_raw_parts(ptr.add(start), len) };
492 Self::from_vec(slice.to_vec())
493 }
494}
495
496impl_option!(
497 U8Vec,
498 OptionU8Vec,
499 copy = false,
500 [Debug, Clone, PartialEq, Ord, PartialOrd, Eq, Hash]
501);
502
503impl_vec!(u16, U16Vec, U16VecDestructor, U16VecDestructorType);
504impl_vec_debug!(u16, U16Vec);
505impl_vec_partialord!(u16, U16Vec);
506impl_vec_ord!(u16, U16Vec);
507impl_vec_clone!(u16, U16Vec, U16VecDestructor);
508impl_vec_partialeq!(u16, U16Vec);
509impl_vec_eq!(u16, U16Vec);
510impl_vec_hash!(u16, U16Vec);
511
512impl_vec!(f32, F32Vec, F32VecDestructor, F32VecDestructorType);
513impl_vec_debug!(f32, F32Vec);
514impl_vec_partialord!(f32, F32Vec);
515impl_vec_clone!(f32, F32Vec, F32VecDestructor);
516impl_vec_partialeq!(f32, F32Vec);
517
518impl_vec!(u32, U32Vec, U32VecDestructor, U32VecDestructorType);
520impl_vec_mut!(u32, U32Vec);
521impl_vec_debug!(u32, U32Vec);
522impl_vec_partialord!(u32, U32Vec);
523impl_vec_ord!(u32, U32Vec);
524impl_vec_clone!(u32, U32Vec, U32VecDestructor);
525impl_vec_partialeq!(u32, U32Vec);
526impl_vec_eq!(u32, U32Vec);
527impl_vec_hash!(u32, U32Vec);
528
529impl_vec!(
530 AzString,
531 StringVec,
532 StringVecDestructor,
533 StringVecDestructorType
534);
535impl_vec_debug!(AzString, StringVec);
536impl_vec_partialord!(AzString, StringVec);
537impl_vec_ord!(AzString, StringVec);
538impl_vec_clone!(AzString, StringVec, StringVecDestructor);
539impl_vec_partialeq!(AzString, StringVec);
540impl_vec_eq!(AzString, StringVec);
541impl_vec_hash!(AzString, StringVec);
542
543impl From<Vec<String>> for StringVec {
544 fn from(v: Vec<String>) -> StringVec {
545 let new_v: Vec<AzString> = v.into_iter().map(|s| s.into()).collect();
546 new_v.into()
547 }
548}
549
550impl_option!(
551 StringVec,
552 OptionStringVec,
553 copy = false,
554 [Debug, Clone, PartialOrd, PartialEq, Ord, Eq, Hash]
555);
556
557impl_option!(
558 u16,
559 OptionU16,
560 [Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash]
561);
562impl_option!(
563 u32,
564 OptionU32,
565 [Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash]
566);
567impl_option!(
568 u64,
569 OptionU64,
570 [Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash]
571);
572impl_option!(
573 usize,
574 OptionUsize,
575 [Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash]
576);
577impl_option!(
578 i16,
579 OptionI16,
580 [Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash]
581);
582impl_option!(
583 i32,
584 OptionI32,
585 [Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash]
586);
587impl_option!(f32, OptionF32, [Debug, Copy, Clone, PartialEq, PartialOrd]);
588impl_option!(f64, OptionF64, [Debug, Copy, Clone, PartialEq, PartialOrd]);
589
590impl core::hash::Hash for OptionF32 {
592 fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
593 match self {
594 OptionF32::None => 0u8.hash(state),
595 OptionF32::Some(v) => {
596 1u8.hash(state);
597 v.to_bits().hash(state);
598 }
599 }
600 }
601}
602
603impl Eq for OptionF32 {}
604
605impl Ord for OptionF32 {
606 fn cmp(&self, other: &Self) -> core::cmp::Ordering {
607 match (self, other) {
608 (OptionF32::None, OptionF32::None) => core::cmp::Ordering::Equal,
609 (OptionF32::None, OptionF32::Some(_)) => core::cmp::Ordering::Less,
610 (OptionF32::Some(_), OptionF32::None) => core::cmp::Ordering::Greater,
611 (OptionF32::Some(a), OptionF32::Some(b)) => {
612 a.partial_cmp(b).unwrap_or(core::cmp::Ordering::Equal)
613 }
614 }
615 }
616}