Skip to main content

rusteal_core/
containers.rs

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}