facet_reflect/wip/
drop.rs1use alloc::{vec, vec::Vec};
2use facet_core::{Type, UserType};
3
4#[allow(unused_imports)]
5use owo_colors::OwoColorize;
6
7use super::Wip;
8use crate::{FrameFlags, FrameMode, Guard, ValueId, trace, wip::frame::Frame};
9
10impl<'facet, 'shape> Drop for Wip<'facet, 'shape> {
11 fn drop(&mut self) {
12 trace!("🧹🧹🧹 WIP is dropping");
13
14 while let Some(frame) = self.frames.pop() {
15 self.track(frame);
16 }
17
18 let Some((root_id, _)) = self.istates.iter().find(|(_k, istate)| istate.depth == 0) else {
19 trace!("No root found, we probably built already");
20 return;
21 };
22
23 let root_id = *root_id;
24 let root_istate = self.istates.remove(&root_id).unwrap();
25 let root = Frame::recompose(root_id, root_istate);
26 let mut to_clean = vec![root];
27
28 let mut _root_guard: Option<Guard> = None;
29
30 while let Some(mut frame) = to_clean.pop() {
31 trace!(
32 "Cleaning frame: shape={} at {:p}, flags={:?}, mode={:?}, fully_initialized={}",
33 frame.shape.blue(),
34 frame.data.as_byte_ptr(),
35 frame.istate.flags.bright_magenta(),
36 frame.istate.mode.yellow(),
37 if frame.is_fully_initialized() {
38 "✅"
39 } else {
40 "❌"
41 }
42 );
43
44 if frame.istate.flags.contains(FrameFlags::MOVED) {
45 trace!(
46 "{}",
47 "Frame was moved out of, nothing to dealloc/drop_in_place".yellow()
48 );
49 continue;
50 }
51
52 match frame.shape.ty {
53 Type::User(UserType::Struct(sd)) => {
54 if frame.is_fully_initialized() {
55 trace!(
56 "Dropping fully initialized struct: {} at {:p}",
57 frame.shape.green(),
58 frame.data.as_byte_ptr()
59 );
60 let frame = self.evict_tree(frame);
61 unsafe { frame.drop_and_dealloc_if_needed() };
62 } else {
63 let num_fields = sd.fields.len();
64 trace!(
65 "De-initializing struct {} at {:p} field-by-field ({} fields)",
66 frame.shape.yellow(),
67 frame.data.as_byte_ptr(),
68 num_fields.bright_cyan()
69 );
70 for i in 0..num_fields {
71 if frame.istate.fields.has(i) {
72 let field = sd.fields[i];
73 let field_shape = field.shape();
74 let field_ptr = unsafe { frame.data.field_init_at(field.offset) };
75 let field_id = ValueId::new(field_shape, field_ptr.as_byte_ptr());
76 trace!(
77 "Recursively cleaning field #{} '{}' of {}: field_shape={}, field_ptr={:p}",
78 i.bright_cyan(),
79 field.name.bright_blue(),
80 frame.shape.blue(),
81 field_shape.green(),
82 field_ptr.as_byte_ptr()
83 );
84 let istate = self.istates.remove(&field_id).unwrap();
85 let field_frame = Frame::recompose(field_id, istate);
86 to_clean.push(field_frame);
87 } else {
88 trace!(
89 "Field #{} '{}' of {} was NOT initialized, skipping",
90 i.bright_cyan(),
91 sd.fields[i].name.bright_red(),
92 frame.shape.red()
93 );
94 }
95 }
96
97 if frame.istate.mode == FrameMode::Root {
99 if let Ok(layout) = frame.shape.layout.sized_layout() {
100 _root_guard = Some(Guard {
101 ptr: frame.data.as_mut_byte_ptr(),
102 layout,
103 });
104 }
105 }
106 }
107 }
108 Type::User(UserType::Enum(_ed)) => {
109 trace!(
110 "Handling enum deallocation for {} at {:p}",
111 frame.shape.yellow(),
112 frame.data.as_byte_ptr()
113 );
114
115 if let Some(variant) = &frame.istate.variant {
117 trace!(
118 "Dropping enum variant {} of {} with {} fields",
119 variant.name.bright_yellow(),
120 frame.shape.yellow(),
121 variant.data.fields.len()
122 );
123
124 for (i, field) in variant.data.fields.iter().enumerate() {
126 if frame.istate.fields.has(i) {
127 let field_shape = field.shape();
128 let field_ptr = unsafe { frame.data.field_init_at(field.offset) };
129 let field_id = ValueId::new(field_shape, field_ptr.as_byte_ptr());
130 trace!(
131 "Recursively cleaning field #{} '{}' of variant {}: field_shape={}, field_ptr={:p}",
132 i.bright_cyan(),
133 field.name.bright_blue(),
134 variant.name.yellow(),
135 field_shape.green(),
136 field_ptr.as_byte_ptr()
137 );
138 if let Some(istate) = self.istates.remove(&field_id) {
139 let field_frame = Frame::recompose(field_id, istate);
140 to_clean.push(field_frame);
141 } else {
142 trace!(
143 "Field not found in istates: #{} '{}' of variant {}",
144 i.bright_cyan(),
145 field.name.bright_blue(),
146 variant.name.yellow()
147 );
148 unsafe {
150 if let Some(drop_in_place) =
151 field_shape.vtable.drop_in_place
152 {
153 drop_in_place(field_ptr);
154 }
155 }
156 }
157 } else {
158 trace!(
159 "Field #{} '{}' of variant {} was NOT initialized, skipping",
160 i.bright_cyan(),
161 field.name.bright_red(),
162 variant.name.yellow()
163 );
164 }
165 }
166 } else {
167 trace!(
168 "Enum {} has no variant selected, nothing to drop for fields",
169 frame.shape.yellow()
170 );
171 }
172
173 if frame.istate.mode == FrameMode::Root {
175 if let Ok(layout) = frame.shape.layout.sized_layout() {
176 _root_guard = Some(Guard {
177 ptr: frame.data.as_mut_byte_ptr(),
178 layout,
179 });
180 }
181 }
182 }
183 _ => {
184 trace!(
185 "Can drop all at once for shape {} (frame mode {:?}) at {:p}",
186 frame.shape.cyan(),
187 frame.istate.mode.yellow(),
188 frame.data.as_byte_ptr(),
189 );
190
191 if frame.is_fully_initialized() {
192 unsafe { frame.drop_and_dealloc_if_needed() }
193 } else {
194 frame.dealloc_if_needed();
195 }
196 }
197 }
198 }
199
200 let mut all_ids = self.istates.keys().copied().collect::<Vec<_>>();
202 for frame_id in all_ids.drain(..) {
203 let frame_istate = self.istates.remove(&frame_id).unwrap();
204
205 trace!(
206 "Checking leftover istate: id.shape={} id.ptr={:p} mode={:?}",
207 frame_id.shape.cyan(),
208 frame_id.ptr.red(),
209 frame_istate.mode.yellow()
210 );
211 let mut frame = Frame::recompose(frame_id, frame_istate);
212
213 if frame.is_fully_initialized() {
214 trace!("It's fully initialized, we can drop it");
215 unsafe { frame.drop_and_dealloc_if_needed() };
216 } else if frame.istate.flags.contains(FrameFlags::ALLOCATED) {
217 trace!("Not initialized but allocated, let's free it");
218 frame.dealloc_if_needed();
219 }
220 }
221 }
222}