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