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