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    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}