swiftui_native/
existential.rs1use core::ffi::c_void;
10use swift_runtime_sys::SwiftABI::get_value_witness_table;
11
12pub struct ViewExistential {
17 buf: *mut u8,
19}
20
21const CONTAINER_SIZE: usize = 40;
22const INLINE_SIZE: usize = 24;
23
24impl ViewExistential {
25 pub unsafe fn new(
32 value: *const c_void,
33 value_size: usize,
34 metadata: *const c_void,
35 view_wt: *const c_void,
36 ) -> Self {
37 unsafe {
38 let buf = libc::malloc(CONTAINER_SIZE) as *mut u8;
39 assert!(!buf.is_null(), "Failed to allocate existential container");
40 core::ptr::write_bytes(buf, 0, CONTAINER_SIZE);
41
42 if value_size <= INLINE_SIZE {
43 core::ptr::copy_nonoverlapping(value as *const u8, buf, value_size);
45 } else {
46 let vwt = &*get_value_witness_table(metadata);
48 let heap_buf = libc::malloc(value_size);
49 assert!(!heap_buf.is_null());
50 (vwt.initialize_with_copy)(heap_buf, value as *mut c_void, metadata);
52 *(buf as *mut *mut c_void) = heap_buf;
53 }
54
55 *((buf.add(24)) as *mut *const c_void) = metadata;
57 *((buf.add(32)) as *mut *const c_void) = view_wt;
59
60 Self { buf }
61 }
62 }
63
64 pub unsafe fn from_zero_size(metadata: *const c_void, view_wt: *const c_void) -> Self {
70 unsafe {
71 Self::new(core::ptr::null(), 0, metadata, view_wt)
72 }
73 }
74
75 pub fn metadata(&self) -> *const c_void {
77 unsafe { *((self.buf.add(24)) as *const *const c_void) }
78 }
79
80 pub fn witness_table(&self) -> *const c_void {
82 unsafe { *((self.buf.add(32)) as *const *const c_void) }
83 }
84
85 pub fn value_ptr(&self) -> *const c_void {
87 let vwt = unsafe { &*get_value_witness_table(self.metadata()) };
88 if vwt.size <= INLINE_SIZE {
89 self.buf as *const c_void
90 } else {
91 unsafe { *(self.buf as *const *const c_void) }
92 }
93 }
94
95 pub fn as_raw(&self) -> *const c_void {
97 self.buf as *const c_void
98 }
99}
100
101impl Drop for ViewExistential {
102 fn drop(&mut self) {
103 if !self.buf.is_null() {
104 let metadata = self.metadata();
105 if !metadata.is_null() {
106 let vwt = unsafe { &*get_value_witness_table(metadata) };
107 if vwt.size <= INLINE_SIZE {
108 unsafe { (vwt.destroy)(self.buf as *mut c_void, metadata) };
110 } else {
111 let box_ptr = unsafe { *(self.buf as *mut *mut c_void) };
113 if !box_ptr.is_null() {
114 unsafe { (vwt.destroy)(box_ptr, metadata) };
115 unsafe { libc::free(box_ptr) };
116 }
117 }
118 }
119 unsafe { libc::free(self.buf as *mut c_void) };
120 self.buf = core::ptr::null_mut();
121 }
122 }
123}
124
125impl Clone for ViewExistential {
126 fn clone(&self) -> Self {
127 let metadata = self.metadata();
128 let view_wt = self.witness_table();
129 let vwt = unsafe { &*get_value_witness_table(metadata) };
130
131 let new_buf = unsafe { libc::malloc(CONTAINER_SIZE) as *mut u8 };
132 assert!(!new_buf.is_null());
133 unsafe { core::ptr::write_bytes(new_buf, 0, CONTAINER_SIZE) };
134
135 if vwt.size <= INLINE_SIZE {
136 unsafe {
138 (vwt.initialize_with_copy)(
139 new_buf as *mut c_void,
140 self.buf as *mut c_void,
141 metadata,
142 );
143 }
144 } else {
145 let new_box = unsafe { libc::malloc(vwt.size) };
147 assert!(!new_box.is_null());
148 let old_box = unsafe { *(self.buf as *const *mut c_void) };
149 unsafe { (vwt.initialize_with_copy)(new_box, old_box, metadata) };
150 unsafe { *(new_buf as *mut *mut c_void) = new_box };
151 }
152
153 unsafe {
155 *((new_buf.add(24)) as *mut *const c_void) = metadata;
156 *((new_buf.add(32)) as *mut *const c_void) = view_wt;
157 }
158
159 Self { buf: new_buf }
160 }
161}
162
163unsafe impl Send for ViewExistential {}