1use std::collections::{HashMap, HashSet};
2use std::hash::Hash;
3use std::marker::PhantomData;
4
5use rusteal_ffi::{FPropertyHandle, RustealErrorCode, UObjectHandle};
6
7const MAX_ELEM_BUF: usize = 4096;
8
9use crate::error::{RustealError, RustealResult, check_ffi, ffi_infallible};
10use crate::ffi_dispatch;
11use crate::object_ref::UObjectRef;
12use crate::struct_ref::UStructRef;
13use crate::traits::{UeClass, UeStruct};
14
15pub unsafe trait ContainerElement: Sized {
16 const BUF_SIZE: u32;
17
18 const RAW_COPYABLE: bool = false;
19
20 unsafe fn read_from_buf(buf: *const u8, written: u32) -> Self;
21
22 unsafe fn write_to_buf(&self, buf: *mut u8) -> u32;
23}
24
25macro_rules! impl_container_element_primitive {
26 ($ty:ty) => {
27 unsafe impl ContainerElement for $ty {
28 const BUF_SIZE: u32 = std::mem::size_of::<$ty>() as u32;
29 const RAW_COPYABLE: bool = true;
30
31 #[inline]
32 unsafe fn read_from_buf(buf: *const u8, _written: u32) -> Self {
33 unsafe { (buf as *const $ty).read_unaligned() }
34 }
35
36 #[inline]
37 unsafe fn write_to_buf(&self, buf: *mut u8) -> u32 {
38 unsafe {
39 (buf as *mut $ty).write_unaligned(*self);
40
41 std::mem::size_of::<$ty>() as u32
42 }
43 }
44 }
45 };
46}
47
48impl_container_element_primitive!(bool);
49impl_container_element_primitive!(i8);
50impl_container_element_primitive!(u8);
51impl_container_element_primitive!(i16);
52impl_container_element_primitive!(u16);
53impl_container_element_primitive!(i32);
54impl_container_element_primitive!(u32);
55impl_container_element_primitive!(i64);
56impl_container_element_primitive!(u64);
57impl_container_element_primitive!(f32);
58impl_container_element_primitive!(f64);
59
60unsafe impl ContainerElement for UObjectHandle {
61 const BUF_SIZE: u32 = std::mem::size_of::<UObjectHandle>() as u32;
62
63 #[inline]
64 unsafe fn read_from_buf(buf: *const u8, _written: u32) -> Self {
65 unsafe { (buf as *const UObjectHandle).read_unaligned() }
66 }
67
68 #[inline]
69 unsafe fn write_to_buf(&self, buf: *mut u8) -> u32 {
70 unsafe {
71 (buf as *mut UObjectHandle).write_unaligned(*self);
72
73 std::mem::size_of::<UObjectHandle>() as u32
74 }
75 }
76}
77
78unsafe impl ContainerElement for rusteal_ffi::FNameHandle {
79 const BUF_SIZE: u32 = 8;
80
81 #[inline]
82 unsafe fn read_from_buf(buf: *const u8, _written: u32) -> Self {
83 unsafe { (buf as *const rusteal_ffi::FNameHandle).read_unaligned() }
84 }
85
86 #[inline]
87 unsafe fn write_to_buf(&self, buf: *mut u8) -> u32 {
88 unsafe {
89 (buf as *mut rusteal_ffi::FNameHandle).write_unaligned(*self);
90
91 8
92 }
93 }
94}
95
96unsafe impl ContainerElement for crate::fname::FName {
97 const BUF_SIZE: u32 = 8;
98
99 #[inline]
100 unsafe fn read_from_buf(buf: *const u8, written: u32) -> Self {
101 crate::fname::FName(unsafe { rusteal_ffi::FNameHandle::read_from_buf(buf, written) })
102 }
103
104 #[inline]
105 unsafe fn write_to_buf(&self, buf: *mut u8) -> u32 {
106 unsafe { self.0.write_to_buf(buf) }
107 }
108}
109
110unsafe impl<T: UeClass> ContainerElement for UObjectRef<T> {
111 const BUF_SIZE: u32 = std::mem::size_of::<UObjectHandle>() as u32;
112
113 #[inline]
114 unsafe fn read_from_buf(buf: *const u8, _written: u32) -> Self {
115 unsafe {
116 let handle = (buf as *const UObjectHandle).read_unaligned();
117
118 UObjectRef::from_raw(handle)
119 }
120 }
121
122 #[inline]
123 unsafe fn write_to_buf(&self, buf: *mut u8) -> u32 {
124 unsafe {
125 (buf as *mut UObjectHandle).write_unaligned(self.raw());
126
127 std::mem::size_of::<UObjectHandle>() as u32
128 }
129 }
130}
131
132unsafe impl ContainerElement for String {
133 const BUF_SIZE: u32 = 4096;
134
135 unsafe fn read_from_buf(buf: *const u8, written: u32) -> Self {
136 unsafe {
137 if written < 4 {
138 return String::new();
139 }
140
141 let len = (buf as *const u32).read_unaligned() as usize;
142 let data_len = (written as usize).saturating_sub(4).min(len);
143 let slice = std::slice::from_raw_parts(buf.add(4), data_len);
144
145 String::from_utf8_lossy(slice).into_owned()
146 }
147 }
148
149 unsafe fn write_to_buf(&self, buf: *mut u8) -> u32 {
150 unsafe {
151 let bytes = self.as_bytes();
152 let len = bytes.len() as u32;
153 (buf as *mut u32).write_unaligned(len);
154 std::ptr::copy_nonoverlapping(bytes.as_ptr(), buf.add(4), bytes.len());
155
156 4 + len
157 }
158 }
159}
160
161#[derive(Clone, Copy)]
162pub struct UeArray<T: ContainerElement> {
163 owner: UObjectHandle,
164 prop: FPropertyHandle,
165 _marker: PhantomData<T>,
166}
167
168impl<T: ContainerElement> UeArray<T> {
169 #[inline]
170 pub fn new(owner: UObjectHandle, prop: FPropertyHandle) -> Self {
171 UeArray {
172 owner,
173 prop,
174 _marker: PhantomData,
175 }
176 }
177
178 #[track_caller]
179 pub fn len(&self) -> RustealResult<usize> {
180 let n = unsafe { ffi_dispatch::container_array_len(self.owner, self.prop) };
181
182 if n < 0 {
183 return Err(RustealError::object_destroyed());
184 }
185
186 Ok(n as usize)
187 }
188
189 #[track_caller]
190 pub fn is_empty(&self) -> RustealResult<bool> {
191 Ok(self.len()? == 0)
192 }
193
194 #[track_caller]
195 pub fn get(&self, index: usize) -> RustealResult<T> {
196 let mut buf = [0u8; MAX_ELEM_BUF];
197 let mut written: u32 = 0;
198
199 check_ffi(unsafe {
200 ffi_dispatch::container_array_get(
201 self.owner,
202 self.prop,
203 index as i32,
204 buf.as_mut_ptr(),
205 T::BUF_SIZE,
206 &mut written,
207 )
208 })?;
209
210 Ok(unsafe { T::read_from_buf(buf.as_ptr(), written) })
211 }
212
213 #[track_caller]
214 pub fn set(&self, index: usize, val: &T) -> RustealResult<()> {
215 let mut buf = [0u8; MAX_ELEM_BUF];
216
217 let written = unsafe { val.write_to_buf(buf.as_mut_ptr()) };
218
219 check_ffi(unsafe {
220 ffi_dispatch::container_array_set(
221 self.owner,
222 self.prop,
223 index as i32,
224 buf.as_ptr(),
225 written,
226 )
227 })
228 }
229
230 #[track_caller]
231 pub fn push(&self, val: &T) -> RustealResult<()> {
232 let mut buf = [0u8; MAX_ELEM_BUF];
233
234 let written = unsafe { val.write_to_buf(buf.as_mut_ptr()) };
235
236 check_ffi(unsafe {
237 ffi_dispatch::container_array_add(self.owner, self.prop, buf.as_ptr(), written)
238 })
239 }
240
241 #[track_caller]
242 pub fn remove(&self, index: usize) -> RustealResult<()> {
243 check_ffi(unsafe {
244 ffi_dispatch::container_array_remove(self.owner, self.prop, index as i32)
245 })
246 }
247
248 #[track_caller]
249 pub fn clear(&self) -> RustealResult<()> {
250 check_ffi(unsafe { ffi_dispatch::container_array_clear(self.owner, self.prop) })
251 }
252
253 pub fn iter(&self) -> UeArrayIter<'_, T> {
254 let len = self.len().unwrap_or(0);
255
256 UeArrayIter {
257 array: self,
258 index: 0,
259 len,
260 }
261 }
262}
263
264impl<'a, T: ContainerElement> IntoIterator for &'a UeArray<T> {
265 type Item = RustealResult<T>;
266 type IntoIter = UeArrayIter<'a, T>;
267
268 fn into_iter(self) -> Self::IntoIter {
269 self.iter()
270 }
271}
272
273pub struct UeArrayIter<'a, T: ContainerElement> {
274 array: &'a UeArray<T>,
275 index: usize,
276 len: usize,
277}
278
279impl<T: ContainerElement> Iterator for UeArrayIter<'_, T> {
280 type Item = RustealResult<T>;
281
282 fn next(&mut self) -> Option<Self::Item> {
283 if self.index >= self.len {
284 return None;
285 }
286
287 let result = self.array.get(self.index);
288 self.index += 1;
289
290 Some(result)
291 }
292
293 fn size_hint(&self) -> (usize, Option<usize>) {
294 let remaining = self.len.saturating_sub(self.index);
295
296 (remaining, Some(remaining))
297 }
298}
299
300impl<T: ContainerElement> ExactSizeIterator for UeArrayIter<'_, T> {}
301
302fn bulk_copy_with_retry(
303 estimate: usize,
304 call: impl Fn(*mut u8, u32, *mut u32, *mut i32) -> RustealErrorCode,
305) -> RustealResult<(Vec<u8>, i32)> {
306 let mut buf = vec![0u8; estimate.max(64)];
307 let mut written: u32 = 0;
308 let mut count: i32 = 0;
309 let code = call(buf.as_mut_ptr(), buf.len() as u32, &mut written, &mut count);
310
311 if code == RustealErrorCode::BufferTooSmall {
312 let needed = (written as usize).max(buf.len() * 2);
313 buf.resize(needed, 0);
314
315 check_ffi(call(
316 buf.as_mut_ptr(),
317 buf.len() as u32,
318 &mut written,
319 &mut count,
320 ))?;
321 } else {
322 check_ffi(code)?;
323 }
324
325 buf.truncate(written as usize);
326 Ok((buf, count))
327}
328
329pub struct BulkArrayIter<T: ContainerElement> {
330 buf: Vec<u8>,
331 count: usize,
332 index: usize,
333 offset: usize,
334 raw_elem_size: usize,
335 _marker: PhantomData<T>,
336}
337
338impl<T: ContainerElement> Iterator for BulkArrayIter<T> {
339 type Item = T;
340
341 fn next(&mut self) -> Option<T> {
342 if self.index >= self.count {
343 return None;
344 }
345
346 if self.raw_elem_size > 0 {
347 let elem = unsafe {
348 T::read_from_buf(
349 self.buf.as_ptr().add(self.offset),
350 self.raw_elem_size as u32,
351 )
352 };
353
354 self.offset += self.raw_elem_size;
355 self.index += 1;
356
357 Some(elem)
358 } else {
359 if self.offset + 4 > self.buf.len() {
360 return None;
361 }
362
363 let written =
364 u32::from_ne_bytes(self.buf[self.offset..self.offset + 4].try_into().unwrap());
365
366 self.offset += 4;
367
368 let elem = unsafe { T::read_from_buf(self.buf.as_ptr().add(self.offset), written) };
369
370 self.offset += written as usize;
371 self.index += 1;
372
373 Some(elem)
374 }
375 }
376
377 fn size_hint(&self) -> (usize, Option<usize>) {
378 let r = self.count - self.index;
379
380 (r, Some(r))
381 }
382}
383
384impl<T: ContainerElement> ExactSizeIterator for BulkArrayIter<T> {}
385
386pub struct BulkMapIter<K: ContainerElement, V: ContainerElement> {
387 buf: Vec<u8>,
388 count: usize,
389 index: usize,
390 offset: usize,
391 _marker: PhantomData<(K, V)>,
392}
393
394impl<K: ContainerElement, V: ContainerElement> Iterator for BulkMapIter<K, V> {
395 type Item = (K, V);
396
397 fn next(&mut self) -> Option<(K, V)> {
398 if self.index >= self.count {
399 return None;
400 }
401
402 if self.offset + 4 > self.buf.len() {
403 return None;
404 }
405
406 let key_written =
407 u32::from_ne_bytes(self.buf[self.offset..self.offset + 4].try_into().unwrap());
408
409 self.offset += 4;
410
411 let key = unsafe { K::read_from_buf(self.buf.as_ptr().add(self.offset), key_written) };
412
413 self.offset += key_written as usize;
414
415 if self.offset + 4 > self.buf.len() {
416 return None;
417 }
418
419 let val_written =
420 u32::from_ne_bytes(self.buf[self.offset..self.offset + 4].try_into().unwrap());
421
422 self.offset += 4;
423
424 let val = unsafe { V::read_from_buf(self.buf.as_ptr().add(self.offset), val_written) };
425
426 self.offset += val_written as usize;
427
428 self.index += 1;
429
430 Some((key, val))
431 }
432
433 fn size_hint(&self) -> (usize, Option<usize>) {
434 let r = self.count - self.index;
435
436 (r, Some(r))
437 }
438}
439
440impl<K: ContainerElement, V: ContainerElement> ExactSizeIterator for BulkMapIter<K, V> {}
441
442pub struct BulkSetIter<T: ContainerElement> {
443 buf: Vec<u8>,
444 count: usize,
445 index: usize,
446 offset: usize,
447 _marker: PhantomData<T>,
448}
449
450impl<T: ContainerElement> Iterator for BulkSetIter<T> {
451 type Item = T;
452
453 fn next(&mut self) -> Option<T> {
454 if self.index >= self.count {
455 return None;
456 }
457
458 if self.offset + 4 > self.buf.len() {
459 return None;
460 }
461
462 let written =
463 u32::from_ne_bytes(self.buf[self.offset..self.offset + 4].try_into().unwrap());
464
465 self.offset += 4;
466 let elem = unsafe { T::read_from_buf(self.buf.as_ptr().add(self.offset), written) };
467 self.offset += written as usize;
468 self.index += 1;
469
470 Some(elem)
471 }
472
473 fn size_hint(&self) -> (usize, Option<usize>) {
474 let r = self.count - self.index;
475
476 (r, Some(r))
477 }
478}
479
480impl<T: ContainerElement> ExactSizeIterator for BulkSetIter<T> {}
481
482impl<T: ContainerElement> UeArray<T> {
483 #[track_caller]
484 pub fn to_vec(&self) -> RustealResult<Vec<T>> {
485 let len = self.len()?;
486
487 if len == 0 {
488 return Ok(Vec::new());
489 }
490
491 let owner = self.owner;
492 let prop = self.prop;
493
494 let estimate = if T::RAW_COPYABLE {
495 len * T::BUF_SIZE as usize
496 } else {
497 len * (T::BUF_SIZE as usize + 4)
498 };
499
500 let (buf, count) = bulk_copy_with_retry(estimate, |out, size, written, cnt| unsafe {
501 ffi_dispatch::container_array_copy_all(owner, prop, out, size, written, cnt)
502 })?;
503
504 let (actual_count, raw_elem_size) = if count < 0 {
505 ((-count) as usize, T::BUF_SIZE as usize)
506 } else {
507 (count as usize, 0)
508 };
509
510 Ok(BulkArrayIter::<T> {
511 buf,
512 count: actual_count,
513 index: 0,
514 offset: 0,
515 raw_elem_size,
516 _marker: PhantomData,
517 }
518 .collect())
519 }
520
521 #[track_caller]
522 pub fn bulk_iter(&self) -> RustealResult<BulkArrayIter<T>> {
523 let len = self.len()?;
524
525 if len == 0 {
526 return Ok(BulkArrayIter {
527 buf: Vec::new(),
528 count: 0,
529 index: 0,
530 offset: 0,
531 raw_elem_size: 0,
532 _marker: PhantomData,
533 });
534 }
535
536 let owner = self.owner;
537 let prop = self.prop;
538
539 let estimate = if T::RAW_COPYABLE {
540 len * T::BUF_SIZE as usize
541 } else {
542 len * (T::BUF_SIZE as usize + 4)
543 };
544
545 let (buf, count) = bulk_copy_with_retry(estimate, |out, size, written, cnt| unsafe {
546 ffi_dispatch::container_array_copy_all(owner, prop, out, size, written, cnt)
547 })?;
548
549 let (actual_count, raw_elem_size) = if count < 0 {
550 ((-count) as usize, T::BUF_SIZE as usize)
551 } else {
552 (count as usize, 0)
553 };
554
555 Ok(BulkArrayIter {
556 buf,
557 count: actual_count,
558 index: 0,
559 offset: 0,
560 raw_elem_size,
561 _marker: PhantomData,
562 })
563 }
564
565 #[track_caller]
566 pub fn set_all(&self, items: &[T]) -> RustealResult<()> {
567 if items.is_empty() {
568 return self.clear();
569 }
570
571 if T::RAW_COPYABLE {
572 let elem_size = T::BUF_SIZE as usize;
573 let mut buf = vec![0u8; items.len() * elem_size];
574
575 for (i, item) in items.iter().enumerate() {
576 unsafe {
577 item.write_to_buf(buf.as_mut_ptr().add(i * elem_size));
578 }
579 }
580
581 check_ffi(unsafe {
582 ffi_dispatch::container_array_set_all(
583 self.owner,
584 self.prop,
585 buf.as_ptr(),
586 buf.len() as u32,
587 -(items.len() as i32),
588 )
589 })
590 } else {
591 let mut buf = Vec::with_capacity(items.len() * (T::BUF_SIZE as usize + 4));
592 let mut elem_buf = [0u8; MAX_ELEM_BUF];
593
594 for item in items {
595 let written = unsafe { item.write_to_buf(elem_buf.as_mut_ptr()) };
596 buf.extend_from_slice(&written.to_ne_bytes());
597 buf.extend_from_slice(&elem_buf[..written as usize]);
598 }
599
600 check_ffi(unsafe {
601 ffi_dispatch::container_array_set_all(
602 self.owner,
603 self.prop,
604 buf.as_ptr(),
605 buf.len() as u32,
606 items.len() as i32,
607 )
608 })
609 }
610 }
611}
612
613#[derive(Clone, Copy)]
614pub struct UeMap<K: ContainerElement, V: ContainerElement> {
615 owner: UObjectHandle,
616 prop: FPropertyHandle,
617 _marker: PhantomData<(K, V)>,
618}
619
620impl<K: ContainerElement, V: ContainerElement> UeMap<K, V> {
621 #[inline]
622 pub fn new(owner: UObjectHandle, prop: FPropertyHandle) -> Self {
623 UeMap {
624 owner,
625 prop,
626 _marker: PhantomData,
627 }
628 }
629
630 #[track_caller]
631 pub fn len(&self) -> RustealResult<usize> {
632 let n = unsafe { ffi_dispatch::container_map_len(self.owner, self.prop) };
633
634 if n < 0 {
635 return Err(RustealError::object_destroyed());
636 }
637
638 Ok(n as usize)
639 }
640
641 #[track_caller]
642 pub fn is_empty(&self) -> RustealResult<bool> {
643 Ok(self.len()? == 0)
644 }
645
646 #[track_caller]
647 pub fn find(&self, key: &K) -> RustealResult<V> {
648 let mut key_buf = [0u8; MAX_ELEM_BUF];
649 let key_written = unsafe { key.write_to_buf(key_buf.as_mut_ptr()) };
650 let mut val_buf = [0u8; MAX_ELEM_BUF];
651 let mut val_written: u32 = 0;
652
653 check_ffi(unsafe {
654 ffi_dispatch::container_map_find(
655 self.owner,
656 self.prop,
657 key_buf.as_ptr(),
658 key_written,
659 val_buf.as_mut_ptr(),
660 V::BUF_SIZE,
661 &mut val_written,
662 )
663 })?;
664
665 Ok(unsafe { V::read_from_buf(val_buf.as_ptr(), val_written) })
666 }
667
668 #[track_caller]
669 pub fn add(&self, key: &K, val: &V) -> RustealResult<()> {
670 let mut key_buf = [0u8; MAX_ELEM_BUF];
671 let key_written = unsafe { key.write_to_buf(key_buf.as_mut_ptr()) };
672 let mut val_buf = [0u8; MAX_ELEM_BUF];
673 let val_written = unsafe { val.write_to_buf(val_buf.as_mut_ptr()) };
674
675 check_ffi(unsafe {
676 ffi_dispatch::container_map_add(
677 self.owner,
678 self.prop,
679 key_buf.as_ptr(),
680 key_written,
681 val_buf.as_ptr(),
682 val_written,
683 )
684 })
685 }
686
687 #[track_caller]
688 pub fn remove(&self, key: &K) -> RustealResult<()> {
689 let mut key_buf = [0u8; MAX_ELEM_BUF];
690 let key_written = unsafe { key.write_to_buf(key_buf.as_mut_ptr()) };
691
692 check_ffi(unsafe {
693 ffi_dispatch::container_map_remove(self.owner, self.prop, key_buf.as_ptr(), key_written)
694 })
695 }
696
697 #[track_caller]
698 pub fn clear(&self) -> RustealResult<()> {
699 check_ffi(unsafe { ffi_dispatch::container_map_clear(self.owner, self.prop) })
700 }
701
702 #[track_caller]
703 pub fn get_pair(&self, logical_index: usize) -> RustealResult<(K, V)> {
704 let mut key_buf = [0u8; MAX_ELEM_BUF];
705 let mut key_written: u32 = 0;
706 let mut val_buf = [0u8; MAX_ELEM_BUF];
707 let mut val_written: u32 = 0;
708
709 check_ffi(unsafe {
710 ffi_dispatch::container_map_get_pair(
711 self.owner,
712 self.prop,
713 logical_index as i32,
714 key_buf.as_mut_ptr(),
715 K::BUF_SIZE,
716 &mut key_written,
717 val_buf.as_mut_ptr(),
718 V::BUF_SIZE,
719 &mut val_written,
720 )
721 })?;
722
723 Ok(unsafe {
724 (
725 K::read_from_buf(key_buf.as_ptr(), key_written),
726 V::read_from_buf(val_buf.as_ptr(), val_written),
727 )
728 })
729 }
730
731 pub fn iter(&self) -> UeMapIter<'_, K, V> {
732 let len = self.len().unwrap_or(0);
733
734 UeMapIter {
735 map: self,
736 index: 0,
737 len,
738 }
739 }
740}
741
742impl<'a, K: ContainerElement, V: ContainerElement> IntoIterator for &'a UeMap<K, V> {
743 type Item = RustealResult<(K, V)>;
744 type IntoIter = UeMapIter<'a, K, V>;
745
746 fn into_iter(self) -> Self::IntoIter {
747 self.iter()
748 }
749}
750
751pub struct UeMapIter<'a, K: ContainerElement, V: ContainerElement> {
752 map: &'a UeMap<K, V>,
753 index: usize,
754 len: usize,
755}
756
757impl<K: ContainerElement, V: ContainerElement> Iterator for UeMapIter<'_, K, V> {
758 type Item = RustealResult<(K, V)>;
759
760 fn next(&mut self) -> Option<Self::Item> {
761 if self.index >= self.len {
762 return None;
763 }
764
765 let result = self.map.get_pair(self.index);
766 self.index += 1;
767
768 Some(result)
769 }
770
771 fn size_hint(&self) -> (usize, Option<usize>) {
772 let remaining = self.len.saturating_sub(self.index);
773
774 (remaining, Some(remaining))
775 }
776}
777
778impl<K: ContainerElement, V: ContainerElement> ExactSizeIterator for UeMapIter<'_, K, V> {}
779
780impl<K: ContainerElement, V: ContainerElement> UeMap<K, V> {
781 #[track_caller]
782 pub fn bulk_iter(&self) -> RustealResult<BulkMapIter<K, V>> {
783 let len = self.len()?;
784
785 if len == 0 {
786 return Ok(BulkMapIter {
787 buf: Vec::new(),
788 count: 0,
789 index: 0,
790 offset: 0,
791 _marker: PhantomData,
792 });
793 }
794
795 let owner = self.owner;
796 let prop = self.prop;
797 let estimate = len * (K::BUF_SIZE as usize + V::BUF_SIZE as usize + 8);
798
799 let (buf, count) = bulk_copy_with_retry(estimate, |out, size, written, cnt| unsafe {
800 ffi_dispatch::container_map_copy_all(owner, prop, out, size, written, cnt)
801 })?;
802
803 Ok(BulkMapIter {
804 buf,
805 count: count as usize,
806 index: 0,
807 offset: 0,
808 _marker: PhantomData,
809 })
810 }
811}
812
813impl<K: ContainerElement + Hash + Eq, V: ContainerElement> UeMap<K, V> {
814 #[track_caller]
815 pub fn to_hash_map(&self) -> RustealResult<HashMap<K, V>> {
816 let iter = self.bulk_iter()?;
817 let count = iter.count;
818 let mut map = HashMap::with_capacity(count);
819
820 for (k, v) in iter {
821 map.insert(k, v);
822 }
823
824 Ok(map)
825 }
826}
827
828#[derive(Clone, Copy)]
829pub struct UeSet<T: ContainerElement> {
830 owner: UObjectHandle,
831 prop: FPropertyHandle,
832 _marker: PhantomData<T>,
833}
834
835impl<T: ContainerElement> UeSet<T> {
836 #[inline]
837 pub fn new(owner: UObjectHandle, prop: FPropertyHandle) -> Self {
838 UeSet {
839 owner,
840 prop,
841 _marker: PhantomData,
842 }
843 }
844
845 #[track_caller]
846 pub fn len(&self) -> RustealResult<usize> {
847 let n = unsafe { ffi_dispatch::container_set_len(self.owner, self.prop) };
848
849 if n < 0 {
850 return Err(RustealError::object_destroyed());
851 }
852
853 Ok(n as usize)
854 }
855
856 #[track_caller]
857 pub fn is_empty(&self) -> RustealResult<bool> {
858 Ok(self.len()? == 0)
859 }
860
861 #[track_caller]
862 pub fn contains(&self, val: &T) -> RustealResult<bool> {
863 let mut buf = [0u8; MAX_ELEM_BUF];
864 let written = unsafe { val.write_to_buf(buf.as_mut_ptr()) };
865
866 Ok(unsafe {
867 ffi_dispatch::container_set_contains(self.owner, self.prop, buf.as_ptr(), written)
868 })
869 }
870
871 #[track_caller]
872 pub fn add(&self, val: &T) -> RustealResult<()> {
873 let mut buf = [0u8; MAX_ELEM_BUF];
874 let written = unsafe { val.write_to_buf(buf.as_mut_ptr()) };
875
876 check_ffi(unsafe {
877 ffi_dispatch::container_set_add(self.owner, self.prop, buf.as_ptr(), written)
878 })
879 }
880
881 #[track_caller]
882 pub fn remove(&self, val: &T) -> RustealResult<()> {
883 let mut buf = [0u8; MAX_ELEM_BUF];
884 let written = unsafe { val.write_to_buf(buf.as_mut_ptr()) };
885
886 check_ffi(unsafe {
887 ffi_dispatch::container_set_remove(self.owner, self.prop, buf.as_ptr(), written)
888 })
889 }
890
891 #[track_caller]
892 pub fn clear(&self) -> RustealResult<()> {
893 check_ffi(unsafe { ffi_dispatch::container_set_clear(self.owner, self.prop) })
894 }
895
896 #[track_caller]
897 pub fn get_element(&self, logical_index: usize) -> RustealResult<T> {
898 let mut buf = [0u8; MAX_ELEM_BUF];
899 let mut written: u32 = 0;
900
901 check_ffi(unsafe {
902 ffi_dispatch::container_set_get_element(
903 self.owner,
904 self.prop,
905 logical_index as i32,
906 buf.as_mut_ptr(),
907 T::BUF_SIZE,
908 &mut written,
909 )
910 })?;
911
912 Ok(unsafe { T::read_from_buf(buf.as_ptr(), written) })
913 }
914
915 pub fn iter(&self) -> UeSetIter<'_, T> {
916 let len = self.len().unwrap_or(0);
917
918 UeSetIter {
919 set: self,
920 index: 0,
921 len,
922 }
923 }
924}
925
926impl<'a, T: ContainerElement> IntoIterator for &'a UeSet<T> {
927 type Item = RustealResult<T>;
928 type IntoIter = UeSetIter<'a, T>;
929
930 fn into_iter(self) -> Self::IntoIter {
931 self.iter()
932 }
933}
934
935pub struct UeSetIter<'a, T: ContainerElement> {
936 set: &'a UeSet<T>,
937 index: usize,
938 len: usize,
939}
940
941impl<T: ContainerElement> Iterator for UeSetIter<'_, T> {
942 type Item = RustealResult<T>;
943
944 fn next(&mut self) -> Option<Self::Item> {
945 if self.index >= self.len {
946 return None;
947 }
948
949 let result = self.set.get_element(self.index);
950 self.index += 1;
951
952 Some(result)
953 }
954
955 fn size_hint(&self) -> (usize, Option<usize>) {
956 let remaining = self.len.saturating_sub(self.index);
957
958 (remaining, Some(remaining))
959 }
960}
961
962impl<T: ContainerElement> ExactSizeIterator for UeSetIter<'_, T> {}
963
964impl<T: ContainerElement> UeSet<T> {
965 #[track_caller]
966 pub fn bulk_iter(&self) -> RustealResult<BulkSetIter<T>> {
967 let len = self.len()?;
968
969 if len == 0 {
970 return Ok(BulkSetIter {
971 buf: Vec::new(),
972 count: 0,
973 index: 0,
974 offset: 0,
975 _marker: PhantomData,
976 });
977 }
978
979 let owner = self.owner;
980 let prop = self.prop;
981 let estimate = len * (T::BUF_SIZE as usize + 4);
982
983 let (buf, count) = bulk_copy_with_retry(estimate, |out, size, written, cnt| unsafe {
984 ffi_dispatch::container_set_copy_all(owner, prop, out, size, written, cnt)
985 })?;
986
987 Ok(BulkSetIter {
988 buf,
989 count: count as usize,
990 index: 0,
991 offset: 0,
992 _marker: PhantomData,
993 })
994 }
995}
996
997impl<T: ContainerElement + Hash + Eq> UeSet<T> {
998 #[track_caller]
999 pub fn to_hash_set(&self) -> RustealResult<HashSet<T>> {
1000 let iter = self.bulk_iter()?;
1001 let count = iter.count;
1002 let mut set = HashSet::with_capacity(count);
1003
1004 for elem in iter {
1005 set.insert(elem);
1006 }
1007
1008 Ok(set)
1009 }
1010}
1011
1012pub struct OwnedStruct<T: UeStruct> {
1013 data: Vec<u8>,
1014 needs_destroy: bool,
1015 _marker: PhantomData<T>,
1016}
1017
1018impl<T: UeStruct> Default for OwnedStruct<T> {
1019 fn default() -> Self {
1020 Self::new()
1021 }
1022}
1023
1024impl<T: UeStruct> OwnedStruct<T> {
1025 pub fn new() -> Self {
1026 let ustruct = T::static_struct();
1027 let size = unsafe { ffi_dispatch::reflection_get_struct_size(ustruct) };
1028
1029 debug_assert!(
1030 size > 0,
1031 "get_struct_size returned 0 for {}",
1032 std::any::type_name::<T>()
1033 );
1034
1035 let mut data = vec![0u8; size as usize];
1036
1037 ffi_infallible(unsafe {
1038 ffi_dispatch::reflection_initialize_struct(ustruct, data.as_mut_ptr())
1039 });
1040
1041 OwnedStruct {
1042 data,
1043 needs_destroy: true,
1044 _marker: PhantomData,
1045 }
1046 }
1047
1048 pub fn from_bytes(data: Vec<u8>) -> Self {
1049 OwnedStruct {
1050 data,
1051 needs_destroy: false,
1052 _marker: PhantomData,
1053 }
1054 }
1055
1056 pub fn copy_from(src: &UStructRef<T>) -> Self {
1057 let mut owned = Self::new();
1058
1059 ffi_infallible(unsafe {
1060 ffi_dispatch::reflection_copy_struct(
1061 T::static_struct(),
1062 owned.data.as_mut_ptr(),
1063 src.as_ptr().0 as *const u8,
1064 )
1065 });
1066
1067 owned
1068 }
1069
1070 pub fn as_ref(&self) -> UStructRef<T> {
1071 unsafe { UStructRef::from_raw(self.data.as_ptr() as *mut u8) }
1072 }
1073
1074 pub fn as_bytes(&self) -> &[u8] {
1075 &self.data
1076 }
1077
1078 pub fn to_bytes(&self) -> Vec<u8> {
1079 self.data.clone()
1080 }
1081}
1082
1083impl<T: UeStruct> Clone for OwnedStruct<T> {
1084 fn clone(&self) -> Self {
1085 OwnedStruct {
1086 data: self.data.clone(),
1087 needs_destroy: false,
1088 _marker: PhantomData,
1089 }
1090 }
1091}
1092
1093impl<T: UeStruct> Drop for OwnedStruct<T> {
1094 fn drop(&mut self) {
1095 if self.needs_destroy {
1096 unsafe {
1097 ffi_dispatch::reflection_destroy_struct(T::static_struct(), self.data.as_mut_ptr());
1098 }
1099 }
1100 }
1101}
1102
1103impl<T: UeStruct> std::fmt::Debug for OwnedStruct<T> {
1104 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1105 f.debug_struct("OwnedStruct")
1106 .field("size", &self.data.len())
1107 .finish()
1108 }
1109}
1110
1111unsafe impl<T: UeStruct> ContainerElement for OwnedStruct<T> {
1112 const BUF_SIZE: u32 = 4096;
1113
1114 unsafe fn read_from_buf(buf: *const u8, written: u32) -> Self {
1115 unsafe {
1116 let data = vec![0u8; written as usize];
1117 std::ptr::copy_nonoverlapping(buf, data.as_ptr() as *mut u8, written as usize);
1118
1119 OwnedStruct::from_bytes(data)
1120 }
1121 }
1122
1123 unsafe fn write_to_buf(&self, buf: *mut u8) -> u32 {
1124 unsafe {
1125 let bytes = self.to_bytes();
1126 let len = bytes.len();
1127 std::ptr::copy_nonoverlapping(bytes.as_ptr(), buf, len);
1128
1129 len as u32
1130 }
1131 }
1132}