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