facet_reflect/wip/put_shape.rs
1use facet_core::{Def, PtrConst, PtrMut, SequenceType, Shape, Type, UserType};
2#[allow(unused_imports)]
3use owo_colors::OwoColorize;
4
5use crate::{ISet, ReflectError};
6use crate::{debug, trace};
7
8use super::Wip;
9
10impl<'facet, 'shape> Wip<'facet, 'shape> {
11 /// Puts a value from a `PtrConst` with the given shape into the current frame.
12 pub fn put_shape(
13 mut self,
14 src: PtrConst<'_>,
15 src_shape: &'shape Shape<'shape>,
16 ) -> Result<Wip<'facet, 'shape>, ReflectError<'shape>> {
17 let Some(frame) = self.frames.last_mut() else {
18 return Err(ReflectError::OperationFailed {
19 shape: src_shape,
20 operation: "tried to put a value but there was no frame to put into",
21 });
22 };
23
24 // Check that the type matches
25 if frame.shape != src_shape {
26 trace!(
27 "Trying to put a {} into a {}",
28 src_shape.yellow(),
29 frame.shape.magenta()
30 );
31
32 // Check if the frame's shape has an inner type (is a transparent wrapper)
33 if let Some(inner_fn) = frame.shape.inner {
34 // Get the inner shape
35 let inner_shape = inner_fn();
36
37 // If the source shape matches the inner shape, we need to build the outer (transparent) wrapper
38 if src_shape == inner_shape {
39 // Look for a try_from_inner function in the vtable
40 if let Some(try_from_fn) = frame.shape.vtable.try_from {
41 match unsafe { (try_from_fn)(src, src_shape, frame.data) } {
42 Ok(_) => {
43 unsafe {
44 frame.mark_fully_initialized();
45 }
46
47 let shape = frame.shape;
48 let index = frame.field_index_in_parent;
49
50 // mark the field as initialized
51 self.mark_field_as_initialized(shape, index)?;
52
53 debug!(
54 "[{}] Just put a {} value into transparent type {}",
55 self.frames.len(),
56 src_shape.green(),
57 shape.blue()
58 );
59
60 return Ok(self);
61 }
62 Err(e) => {
63 return Err(ReflectError::TryFromError {
64 inner: e,
65 src_shape,
66 dst_shape: frame.shape,
67 });
68 }
69 }
70 } else {
71 // No try_from_inner function, try normal TryFrom
72 debug!(
73 "No try_from_inner function for transparent type, falling back to TryFrom"
74 );
75 }
76 }
77 }
78
79 // Maybe there's a `TryFrom` impl?
80 if let Some(try_from) = frame.shape.vtable.try_from {
81 match unsafe { try_from(src, src_shape, frame.data) } {
82 Ok(_) => {
83 unsafe {
84 frame.mark_fully_initialized();
85 }
86
87 let shape = frame.shape;
88 let index = frame.field_index_in_parent;
89
90 // mark the field as initialized
91 self.mark_field_as_initialized(shape, index)?;
92
93 debug!("[{}] Just put a {} value", self.frames.len(), shape.green());
94
95 return Ok(self);
96 }
97 Err(e) => {
98 return Err(ReflectError::TryFromError {
99 inner: e,
100 src_shape,
101 dst_shape: frame.shape,
102 });
103 }
104 }
105 }
106
107 // Maybe we're putting into an Option<T>?
108 // Handle Option<Inner>
109 if let Def::Option(od) = frame.shape.def {
110 // Check if inner type matches
111 if od.t() == src_shape {
112 debug!("Putting into an Option<T>!");
113 if frame.istate.fields.is_any_set() {
114 let data = unsafe { frame.data.assume_init() };
115 unsafe { (od.vtable.replace_with_fn)(data, Some(src)) };
116 } else {
117 let data = frame.data;
118 unsafe { (od.vtable.init_some_fn)(data, src) };
119 }
120 unsafe {
121 frame.mark_fully_initialized();
122 }
123
124 let shape = frame.shape;
125 let index = frame.field_index_in_parent;
126
127 // mark the field as initialized
128 self.mark_field_as_initialized(shape, index)?;
129
130 debug!("[{}] Just put a {} value", self.frames.len(), shape.green());
131
132 return Ok(self);
133 }
134 }
135
136 // Maybe we're putting into a tuple struct, or a tuple, and it just so happens that the
137 // first non-initialized field has the right type?
138 {
139 let fields = match &frame.shape.ty {
140 Type::User(UserType::Struct(sd)) => Some(sd.fields),
141 Type::Sequence(SequenceType::Tuple(tt)) => Some(tt.fields),
142 _ => None,
143 };
144
145 if let Some(fields) = fields {
146 // Look for the first uninitialized field
147 for (i, field) in fields.iter().enumerate() {
148 if !frame.istate.fields.has(i) {
149 // First, check for exact type match
150 if field.shape() == src_shape {
151 debug!(
152 "Found uninitialized field {} with matching type {}",
153 i.blue(),
154 src_shape.green()
155 );
156
157 // Copy the value to the field
158 unsafe {
159 let field_data = frame.data.field_uninit_at(field.offset);
160 field_data.copy_from(src, field.shape()).map_err(|_| {
161 ReflectError::Unsized {
162 shape: field.shape(),
163 }
164 })?;
165 frame.istate.fields.set(i);
166 }
167
168 let shape = frame.shape;
169 let index = frame.field_index_in_parent;
170
171 // If all fields are now initialized, mark the struct itself as initialized
172 if frame.is_fully_initialized() {
173 self.mark_field_as_initialized(shape, index)?;
174 }
175
176 debug!(
177 "[{}] Put a {} value into field {} of {}",
178 self.frames.len(),
179 src_shape.green(),
180 i.blue(),
181 shape.green()
182 );
183
184 return Ok(self);
185 }
186
187 // Then check if field's type has a try_from impl that can convert from src_shape
188 if let Some(try_from) = field.shape().vtable.try_from {
189 debug!(
190 "Found uninitialized field {} with try_from for type {}",
191 i.blue(),
192 src_shape.green()
193 );
194
195 // Try to convert the value and store it in the field
196 let field_data =
197 unsafe { frame.data.field_uninit_at(field.offset) };
198 match unsafe { try_from(src, src_shape, field_data) } {
199 Ok(_) => {
200 frame.istate.fields.set(i);
201
202 let shape = frame.shape;
203 let index = frame.field_index_in_parent;
204
205 // If all fields are now initialized, mark the struct itself as initialized
206 if frame.is_fully_initialized() {
207 self.mark_field_as_initialized(shape, index)?;
208 }
209
210 debug!(
211 "[{}] Put a {} value (converted) into field {} of {}",
212 self.frames.len(),
213 src_shape.green(),
214 i.blue(),
215 shape.green()
216 );
217
218 return Ok(self);
219 }
220 Err(_) => {
221 // Conversion failed, try the next field
222 continue;
223 }
224 }
225 }
226 }
227 }
228 }
229 }
230
231 // Maybe we're putting into an enum, which has a variant selected, which has tuple-like fields,
232 // and the first field that is uninitialized just so happens to be the right type?
233 if let Type::User(UserType::Enum(_)) = frame.shape.ty {
234 // Check if we're putting into an enum with a selected variant
235 if let Some(variant) = &frame.istate.variant {
236 // Look for the first uninitialized field in the variant
237 for (i, field) in variant.data.fields.iter().enumerate() {
238 if !frame.istate.fields.has(i) {
239 // First, check for exact type match
240 if field.shape() == src_shape {
241 debug!(
242 "Found uninitialized field {} in enum variant '{}' with matching type {}",
243 i.blue(),
244 variant.name.bright_yellow(),
245 src_shape.green()
246 );
247
248 // Copy the value to the field
249 unsafe {
250 let field_data = frame.data.field_uninit_at(field.offset);
251 field_data.copy_from(src, field.shape()).map_err(|_| {
252 ReflectError::Unsized {
253 shape: field.shape(),
254 }
255 })?;
256 frame.istate.fields.set(i);
257 }
258
259 let shape = frame.shape;
260 let index = frame.field_index_in_parent;
261
262 #[allow(unused)]
263 let variant_name = variant.name;
264
265 // If all fields are now initialized, mark the enum itself as initialized
266 if frame.is_fully_initialized() {
267 self.mark_field_as_initialized(shape, index)?;
268 }
269
270 debug!(
271 "[{}] Put a {} value into field {} of variant '{}' in enum {}",
272 self.frames.len(),
273 src_shape.green(),
274 i.blue(),
275 variant_name.bright_yellow(),
276 shape.green()
277 );
278
279 return Ok(self);
280 }
281
282 // Then check if field's type has a try_from impl that can convert from src_shape
283 if let Some(try_from) = field.shape().vtable.try_from {
284 debug!(
285 "Found uninitialized field {} in enum variant '{}' with try_from for type {}",
286 i.blue(),
287 variant.name.bright_yellow(),
288 src_shape.green()
289 );
290
291 // Try to convert the value and store it in the field
292 let field_data =
293 unsafe { frame.data.field_uninit_at(field.offset) };
294 match unsafe { try_from(src, src_shape, field_data) } {
295 Ok(_) => {
296 frame.istate.fields.set(i);
297
298 let shape = frame.shape;
299 let index = frame.field_index_in_parent;
300
301 #[allow(unused_variables)]
302 let variant_name = variant.name;
303
304 // If all fields are now initialized, mark the enum itself as initialized
305 if frame.is_fully_initialized() {
306 self.mark_field_as_initialized(shape, index)?;
307 }
308
309 debug!(
310 "[{}] Put a {} value (converted) into field {} of variant '{}' in enum {}",
311 self.frames.len(),
312 src_shape.green(),
313 i.blue(),
314 variant_name.bright_yellow(),
315 shape.green()
316 );
317
318 return Ok(self);
319 }
320 Err(_) => {
321 // Conversion failed, try the next field
322 continue;
323 }
324 }
325 }
326 }
327 }
328 }
329 }
330
331 return Err(ReflectError::WrongShape {
332 expected: frame.shape,
333 actual: src_shape,
334 });
335 }
336
337 // de-initialize partially initialized fields, if any
338 if frame.istate.variant.is_some() || frame.istate.fields.is_any_set() {
339 debug!("De-initializing partially initialized {:?}", frame.yellow());
340
341 match frame.shape.ty {
342 Type::User(UserType::Struct(sd)) => {
343 for (i, field) in sd.fields.iter().enumerate() {
344 if frame.istate.fields.has(i) {
345 if let Some(drop_fn) = field.shape().vtable.drop_in_place {
346 unsafe {
347 let field_ptr = frame.data.as_mut_byte_ptr().add(field.offset);
348 drop_fn(PtrMut::new(field_ptr));
349 }
350 }
351 }
352 }
353 }
354 Type::User(UserType::Enum(_)) => {
355 if let Some(variant) = &frame.istate.variant {
356 for (i, field) in variant.data.fields.iter().enumerate() {
357 if frame.istate.fields.has(i) {
358 if let Some(drop_fn) = field.shape().vtable.drop_in_place {
359 unsafe {
360 let field_ptr =
361 frame.data.as_mut_byte_ptr().add(field.offset);
362 drop_fn(PtrMut::new(field_ptr));
363 }
364 }
365 }
366 }
367 }
368 }
369 _ => {
370 // For scalar types and other non-struct/enum, attempt to drop the field in place if initialized
371 if frame.istate.fields.is_any_set() {
372 debug!("Scalar type was set...");
373 if let Some(drop_fn) = frame.shape.vtable.drop_in_place {
374 debug!("And it has a drop fn, dropping now!");
375 unsafe {
376 drop_fn(frame.data.assume_init());
377 }
378 }
379 }
380 }
381 }
382
383 // Reset initialization state
384 frame.istate.variant = None;
385 ISet::clear(&mut frame.istate.fields);
386 }
387
388 unsafe {
389 // Copy the contents from src to destination
390 frame
391 .data
392 .copy_from(src, frame.shape)
393 .map_err(|_| ReflectError::Unsized { shape: frame.shape })?;
394 frame.mark_fully_initialized();
395 }
396
397 let shape = frame.shape;
398 let index = frame.field_index_in_parent;
399
400 // mark the field as initialized
401 self.mark_field_as_initialized(shape, index)?;
402
403 debug!("[{}] Just put a {} value", self.frames.len(), shape.green());
404
405 Ok(self)
406 }
407}