facet_maybe_mut/maybe_mut.rs
1//! This asserts that you cannot move out of the Guard
2//!
3//! ```compile_fail
4//! use std::sync::{Arc, RwLock};
5//!
6//! use facet::Facet;
7//! use facet_maybe_mut::MaybeMut;
8//! use facet_reflect::Peek;
9//!
10//! #[derive(Debug, Facet, Default)]
11//! struct User {
12//! id: u32,
13//! name: String,
14//! }
15//!
16//! fn main() {
17//! let strong = Arc::new(RwLock::new(User {
18//! id: 123,
19//! name: String::new(),
20//! }));
21//! let w = Arc::downgrade(&strong);
22//! let dummy = User {
23//! id: 787,
24//! name: String::new(),
25//! };
26//!
27//! let mut guard: facet_maybe_mut::Guard<'_, '_> = MaybeMut::Not(Peek::new(&w)).read().unwrap();
28//! let bad: MaybeMut<'_, '_> =
29//! std::mem::replace(&mut guard.as_maybe(), MaybeMut::Not(Peek::new(&dummy)));
30//!
31//! drop(strong);
32//! //drop(guard);
33//!
34//! assert_eq!(w.strong_count(), 1);
35//!
36//! let user = bad.as_peek().get::<User>().unwrap();
37//! assert_eq!(user.id, 123);
38//! drop(guard);
39//! // this wont work which is correct, otherwise it would be UB
40//! let user = bad.as_peek().get::<User>().unwrap();
41//! assert_eq!(w.strong_count(), 0);
42//! }
43//! ```
44
45use std::{mem::ManuallyDrop, ops::DerefMut};
46
47use derive_more::From;
48use facet::{Def, PointerFlags, PtrConst, PtrMut, ReadLockResult, Shape, WriteLockResult};
49use facet_reflect::{Peek, Poke};
50
51/// Some reference to a type that implements [`Facet`](facet::Facet) that may be
52/// `mut` or not.
53#[derive(From)]
54#[repr(C)]
55pub enum MaybeMut<'mem, 'facet> {
56 Not(Peek<'mem, 'facet>),
57 Mut(Poke<'mem, 'facet>),
58}
59
60impl<'mem, 'facet> MaybeMut<'mem, 'facet> {
61 /// Returns a readonly/immutable version of the inner type
62 pub fn as_peek(&'mem self) -> Peek<'mem, 'facet> {
63 match self {
64 Self::Not(peek) => *peek,
65 Self::Mut(poke) => poke.as_peek(),
66 }
67 }
68
69 pub fn into_peek(self) -> Peek<'mem, 'facet> {
70 match self {
71 MaybeMut::Not(n) => n,
72 MaybeMut::Mut(m) => m.into_peek(),
73 }
74 }
75
76 /// Returns the [`Shape`] of the underlying type
77 ///
78 /// The [`Shape`] is the same for [`Mut`](Self::Mut) and [`Not`](Self::Not)
79 pub fn shape(&self) -> &'static Shape {
80 self.as_peek().shape()
81 }
82}
83
84#[derive(Debug, thiserror::Error)]
85#[error("{kind}")]
86pub struct MakeLockError<'mem, 'facet> {
87 pub unchanged: Peek<'mem, 'facet>,
88 pub kind: MakeLockErrorKind,
89}
90
91#[derive(Debug, thiserror::Error)]
92pub enum MakeLockErrorKind {
93 /// The underlying type is not a type that we can lock from a `&T` to `&mut T` (but it is more complicated...)
94 #[error("type cannot be locked")]
95 NotLockable,
96 /// The underlying type could be locked but the provided lock method in the
97 /// vtable returned an error.
98 #[error("locking of type failed")]
99 LockFailure,
100 /// A weak pointer where the upgrade function returned None.
101 ///
102 /// There exist no strong references (no instances of an `Arc`)
103 #[error("could not upgrade weak pointer, no strong references exist")]
104 NotUpgradable,
105}
106
107/// Depending on whether this is a read or write lock, `P` will be either
108/// [`PtrConst`] or [`PtrMut`](facet::PtrMut). This enum makes `P` dynamic
109#[derive(From)]
110pub(crate) enum LockGuardType {
111 Write(WriteLockResult),
112 Read(ReadLockResult),
113 /// A Weak that has been upgraded to an Arc or Rc
114 /// The downgrade is handled directly in the [`Drop`] implementation of this
115 /// [`LockGuardType`]
116 Upgrade {
117 /// The [`Shape`] of the strong pointer that can be used later to
118 /// downgrade again
119 strong_shape: &'static Shape,
120 /// The pointer to the allocated Arc or Rc
121 allocation: PtrMut,
122 },
123}
124
125impl LockGuardType {
126 /// Safety
127 ///
128 /// For an Weak guard, this calls the `BorrowFn` of the (currently existing)
129 /// strong shape to obtain the data pointer.
130 /// This is the raw pointer returned from the lock which is already
131 /// available via [`Guard`]. Creating a new [`Peek`] or [`Poke`] from this
132 /// [`PtrConst`] is UB.
133 pub fn data_const(&self) -> PtrConst {
134 match self {
135 Self::Write(w) => w.data_const(),
136 Self::Read(r) => *r.data(),
137 Self::Upgrade {
138 strong_shape,
139 allocation,
140 } => {
141 let borrow_fn = strong_shape
142 .def
143 .into_pointer()
144 .expect("only pointer types get this lock type")
145 .vtable
146 .borrow_fn
147 .expect("all strong pointers have a borrow function");
148 // SAFETY: allocation is the pointer of the strong type (Arc or Rc)
149 unsafe { borrow_fn(allocation.as_const()) }
150 }
151 }
152 }
153}
154
155impl Drop for LockGuardType {
156 fn drop(&mut self) {
157 if let Self::Upgrade {
158 strong_shape,
159 allocation,
160 } = self
161 {
162 // dropping the strong pointer automatically decreases reference
163 // count
164 // SAFETY: we cant just deallocate but need to run the actual drop
165 // implementation as well since the drop impl of the strong pointer decreases strong pointer count
166 unsafe {
167 strong_shape.call_drop_in_place(*allocation);
168 }
169 // SAFETY: the allocation was created using Shape::alloc
170 unsafe {
171 strong_shape
172 .deallocate_mut(*allocation)
173 .expect("strong pointer is sized");
174 }
175 }
176 }
177}
178
179/// Contains the guard, the data ptr, and drop vtable to free the lock
180///
181/// # Note
182///
183/// The contained [`MaybeMut`] is NOT guaranteed to be [`Mut`](MaybeMut::Mut)
184///
185/// For example, RwLock also needs a lock and guard for a read.
186pub struct Guard<'lock_mem, 'facet> {
187 /// This [`MaybeMut`] contains the [`Peek`] or [`Poke`] of the most inner,
188 /// non lockable type.
189 // declaration order matters: data must be dropped first before any guards
190 data: ManuallyDrop<MaybeMut<'lock_mem, 'facet>>,
191 /// Dropping the guard handles freeing the lock
192 ///
193 /// If this is empty, the `data` can be accessed directly and there is no
194 /// lock that must be freeed
195 ///
196 /// SAFETY: The pointer inside the [`LockGuardType`] MUST NOT be used
197 /// since the data is already (mutable) available via `data`
198 ///
199 /// The drop order must be the reverse of this [`Vec`] (pop until empty)
200 /// in order to guarantee the locks are released in the correct order.
201 guards: Vec<LockGuardType>,
202}
203
204impl Drop for Guard<'_, '_> {
205 fn drop(&mut self) {
206 unsafe {
207 ManuallyDrop::drop(&mut self.data);
208 }
209 while let Some(pop) = self.guards.pop() {
210 drop(pop);
211 }
212 }
213}
214
215impl<'lock, 'facet> Guard<'lock, 'facet> {
216 /// Returns the Shape of the underlying [`MaybeMut`]
217 pub fn shape(&self) -> &'static Shape {
218 self.data.shape()
219 }
220 /// It is always possible to get a [`Peek`] from a [`Guard`]
221 pub fn as_peek<'s>(&'s self) -> Peek<'s, 'facet> {
222 match &*self.data {
223 MaybeMut::Mut(m) => m.as_peek(),
224 MaybeMut::Not(n) => *n,
225 }
226 }
227
228 /// If the [`Guard`] contains a [`Poke`], this will return
229 /// `Some(Poke)` assuming [`Poke`] can be reborrowed.
230 pub fn as_poke<'s>(&'s mut self) -> Option<Poke<'s, 'facet>> {
231 if let MaybeMut::Mut(m) = self.data.deref_mut() {
232 m.try_reborrow()
233 } else {
234 None
235 }
236 }
237 /// Returns either a [`Poke`] or a [`Peek`] depending on whats available
238 /// via the guard (read lock or write lock)
239 pub fn as_maybe<'s>(&'s mut self) -> MaybeMut<'s, 'facet> {
240 match self.data.deref_mut() {
241 MaybeMut::Mut(m) => {
242 let data = m.data();
243 let shape: &'static Shape = m.shape();
244 if let Some(poke) = m.try_reborrow() {
245 MaybeMut::Mut(poke)
246 } else {
247 // SAFETY: "downgrading" a single Poke into a single Peek (which is guaranteed via borrow of &mut self) is always safe since Poke has a superset of capabilities of Peek (&mut T can do everything &T)
248 let peek = unsafe { Peek::unchecked_new(data, shape) };
249 MaybeMut::Not(peek)
250 }
251 }
252 MaybeMut::Not(peek) => MaybeMut::Not(*peek),
253 }
254 }
255
256 /// Takes out all [`LockGuardType`]s out of this [`Guard`] as well as the
257 /// [`MaybeMut`] data.
258 /// The [`Guard`] is effectively empty.
259 unsafe fn take(mut self) -> (Vec<LockGuardType>, MaybeMut<'lock, 'facet>) {
260 //let data = ManuallyDrop::into_inner(self.data);
261 //let guards = ManuallyDrop::into_inner(self.guards);
262 // SAFETY: data is moved out of Guard
263 // all LockGuardTypes are also "moved" out of the Vec, but the Vec
264 // itself is retained (as it is replaced)
265 let v = (core::mem::take(&mut self.guards), unsafe {
266 ManuallyDrop::take(&mut self.data)
267 });
268 // SAFETY:
269 // do not run Guards Drop impl which would lead to a double free later, because it manually drops `data` but data is moved out of
270 core::mem::forget(self);
271 v
272 }
273}
274
275impl<'mem, 'facet> MaybeMut<'mem, 'facet> {
276 /// Try to turn [`MaybeMut::Not`] into [`MaybeMut::Mut`]
277 ///
278 /// The returned [`MaybeMut`] may contain a different [`Shape`].
279 /// Which exact [`Shape`] it is, depends on what the input type was.
280 ///
281 /// One edge case is if you pass a `&mut Arc<RwLock<String>` the type will
282 /// not be changed to `&mut String`. But if you pass a `&Arc<RwLock<String>`
283 /// due to locking etc, it will be a `&mut String`.
284 ///
285 /// If the underlying type is something that can be write locked,
286 /// for example an `RwLock` or `Mutex`, this method creates a lock on it.
287 ///
288 /// If we already have [`MaybeMut::Mut`] this is a no-op.
289 ///
290 /// If we have [`MaybeMut::Not`] and the [`Shape`] of
291 /// `T` does not contain a [`PointerDef`](facet::PointerDef) which
292 /// has a vtable with a `write_fn` we can call with `&T`, this method
293 /// returns [`Err(MaybeMut::Not)`](Err). In this case, besides the lookup,
294 /// it is also a no-op.
295 ///
296 /// # Note
297 ///
298 /// It is very important that you drop the [`Guard`] as soon as possible
299 /// to free the lock
300 ///
301 /// [`Shape`]: facet::Shape
302 pub fn write<'lock>(self) -> Result<Guard<'lock, 'facet>, MakeLockError<'mem, 'facet>>
303 where
304 'mem: 'lock,
305 'facet: 'lock,
306 {
307 match self {
308 // if we already have a mut this is a no op
309 MaybeMut::Mut(v) => {
310 // but only if this is a type that is not a smart pointer that can be locked
311 if let Def::Pointer(p) = v.as_peek().innermost_peek().shape().def
312 // restrict downgrading to Peek only if there is a a lock _somewhere_
313 && (p.flags.contains(PointerFlags::LOCK) || p.flags.contains(PointerFlags::WEAK))
314 {
315 Self::Not(v.into_peek()).write()
316 } else {
317 Ok(Guard {
318 guards: Vec::new(),
319 data: ManuallyDrop::new(v.into()),
320 })
321 }
322 }
323 // this is where it gets interesting
324 MaybeMut::Not(v) => {
325 // SAFETY: v.innermost_peek() unwraps all transparent wrappers like Arc or Rc until something that needs
326 // locking is reached which is all we care about
327 // FIXME: naively using innermost_peek is a bad idea i think.
328 // for example, in the UI if there is a NonZero<u32> this will peek
329 // up tu u32. Then, we will perhaps display an editable u32 which
330 // can be set to zero. Now what? We broke it boys
331 let v = v.innermost_peek();
332 // the shape of the pointer type (if it is one) but derefence smart pointers that can so without locking
333 // e.g. Arc<T> AND also &T
334 let shape = v.shape();
335 let def = shape.def;
336
337 // short cirucit if it is not a pointer. in these
338 // cases we wont be able to reach something like
339 // RwLock or Mutex
340 let Def::Pointer(pointer) = def else {
341 return Err(MakeLockError {
342 unchanged: v,
343 kind: MakeLockErrorKind::NotLockable,
344 });
345 };
346
347 // we dont care if we lock it (Mutex) or write lock it (RwLock)
348 let lock_fn =
349 pointer
350 .vtable
351 .write_fn
352 .or(pointer.vtable.lock_fn)
353 .ok_or(MakeLockError {
354 unchanged: v,
355 kind: MakeLockErrorKind::NotLockable,
356 });
357
358 // SAFETY: v.innermost_peek() unwraps all transparent wrappers like Arc or Rc until something that needs
359 // locking is reached which is also the same type we get the lock_fn from
360 let (mut guards, mut value): (Vec<LockGuardType>, MaybeMut<'lock, 'facet>) =
361 match lock_fn {
362 Ok(lock_fn) => {
363 let res = unsafe { lock_fn(v.data()) };
364 let Ok(lock) = res else {
365 return Err(MakeLockError {
366 unchanged: v,
367 kind: MakeLockErrorKind::LockFailure,
368 });
369 };
370 // SAFETY: creates access via the PtrMut returned from locking
371 // the smart pointer. 'mem outlives 'lock this means
372 // the returned SmartPointer<'mem> also outlives the mutable Poke<'lock>
373 let poke: Poke<'lock, 'facet> = unsafe {
374 Poke::from_raw_parts(
375 // if the input type was Arc<RwLock<String>> this willbe
376 // a pointer to a String
377 *lock.data(),
378 shape
379 .inner
380 .expect("a smart pointer always has an inner shape"),
381 )
382 };
383
384 (vec![lock.into()], MaybeMut::Mut(poke))
385 }
386 // TODO: write upgrade Weak<RwLock>??
387 // try it as an upgrade instead
388 Err(MakeLockError {
389 unchanged,
390 kind: MakeLockErrorKind::NotLockable,
391 }) if let Def::Pointer(pointer) = unchanged.shape().def
392 && let Some(upgrade_fn) = pointer.vtable.upgrade_into_fn
393 && let Some(strong_shape) =
394 def.into_pointer().ok().and_then(|x| x.strong()) =>
395 {
396 // if the strong shape is unsized, the Facet implementation of the type is wrong.
397 let strong = strong_shape
398 .allocate()
399 .expect("strong pointer is always sized");
400
401 // SAFETY: turning this peek into a PtrMut is okay,. because
402 // the upgrade function only needs &self
403 // in theory, the upgrade_fn signature could take a PtrConst as well.
404 let ptr = unsafe { v.data().into_mut() };
405 // SAFETY: Facet implementation of Weak garantees strong is the correct
406 // shape of the strong part for this Weak
407 let guard = unsafe { upgrade_fn(ptr, strong) }
408 .map(|strong_instance| LockGuardType::Upgrade {
409 strong_shape,
410 allocation: strong_instance,
411 })
412 .ok_or(MakeLockError {
413 kind: MakeLockErrorKind::NotUpgradable,
414 unchanged: v,
415 })?;
416 // SAFETY: creates access via the PtrMut returned from locking
417 // the smart pointer. 'mem outlives 'lock this means
418 // the returned mutable Poke<'lock> lives shorter than 'mem
419 let peek: Peek<'lock, 'facet> = unsafe {
420 Peek::unchecked_new(
421 guard.data_const(),
422 shape
423 .inner
424 .expect("a smart pointer always has an inner shape"),
425 )
426 };
427
428 (vec![guard], MaybeMut::Not(peek.innermost_peek()))
429 }
430 Err(e) => {
431 return Err(e);
432 }
433 };
434
435 // unwrap remaining inner pointer types
436 // -> all types that have an inner type and are a pointer
437 while let Some(_inner) = value.as_peek().shape().inner
438 && let Def::Pointer(def) = value.as_peek().shape().def
439 // lock gets locked in the next write call
440 && (def.flags.contains(PointerFlags::LOCK) ||
441 // weak gets upgraded at the next write call
442 def.flags.contains(PointerFlags::WEAK) ||
443 // atomics just get unwrapped in the next write call
444 def.flags.contains(PointerFlags::ATOMIC))
445 {
446 // SAFETY: we synthesize a Peek with the outer 'mem lifetime so we
447 // can re-enter `write`. The fabricated lifetime never escapes:
448 //
449 // * On success, the recursive call returns `Guard<'lock>`. Its
450 // `data` is bounded by 'lock and its guards are moved into our
451 // `guards` Vec, so the parent lock keeps the pointer live for
452 // as long as the returned `Guard` exists.
453 // * On failure, we MUST NOT propagate the inner
454 // `MakeLockError::unchanged` since that Peek carries the
455 // fabricated 'mem lifetime while actually pointing into
456 // lock-protected memory that we are about to release as our
457 // `guards` Vec drops on early return. Instead we substitute
458 // the original outer Peek `v`, which is genuinely valid for
459 // 'mem because it comes straight from the function input.
460 let shorter_peek: Peek<'mem, 'facet> =
461 unsafe { Peek::unchecked_new(value.as_peek().data(), value.shape()) };
462 let shorter_maybe: MaybeMut<'mem, 'facet> = MaybeMut::Not(shorter_peek);
463 let guard: Guard<'lock, 'facet> = match shorter_maybe.write() {
464 Ok(g) => g,
465 Err(e) => {
466 // Peek v needs no Guards, drop them explicitly to free
467 // locks (they would be dropped by the return anyways)
468 drop(guards);
469 // Discard `e.unchanged` (would dangle once `guards`
470 // drops on return); substitute the original outer Peek
471 // which is actually valid for 'mem.
472 return Err(MakeLockError {
473 unchanged: v,
474 kind: e.kind,
475 });
476 }
477 };
478 // SAFETY: this moves out all values from guard. Guard is no longer used afterwards
479 let (inner_guards, data) = unsafe { guard.take() };
480 // SAFETY: the values must be moved to the new vec not cloned and NOT dropped.
481 // this would lead to a double unlock later
482 guards.extend(inner_guards);
483 // SAFETY: set the new value to the inner most available value
484 value = data;
485 }
486 Ok(Guard {
487 data: ManuallyDrop::new(value),
488 guards,
489 })
490 }
491 }
492 }
493
494 /// Returns a [`Guard`] with a lock that is sufficent for reading.
495 ///
496 /// In case of `RwLock` it is locked to read. If it is a `Mutex`, it must
497 /// be exclusively locked to write but we only consider it being read which
498 /// is safe
499 pub fn read<'lock>(self) -> Result<Guard<'lock, 'facet>, MakeLockError<'mem, 'facet>>
500 where
501 'mem: 'lock,
502 {
503 let peek = self.into_peek();
504 // unwrap smart pointers
505 // this will deref Arcs but not Weaks, Weaks are handled special as a guard that automatically downgrades them on Drop
506 let v = peek.innermost_peek();
507 // the shape of the pointer type (if it is one) but derefence smart pointers that can so without locking
508 // e.g. Arc<T>
509 let shape = v.shape();
510 let def = shape.def;
511
512 // short cirucit if it is not a pointer. in these
513 // cases we wont be able to reach something like
514 // RwLock or Mutex
515 // In this case, we just return the reference to the underlying type
516 let Def::Pointer(pointer) = def else {
517 return Ok(Guard {
518 guards: Vec::new(),
519 data: ManuallyDrop::new(MaybeMut::Not(v)),
520 });
521 };
522
523 // we dont care if we lock it (Mutex) or read lock it (RwLock) or just upgrade it so it can be dereferenced
524 let res: Result<LockGuardType, _> = if let Some(read_fn) = pointer.vtable.read_fn {
525 unsafe { read_fn(v.data()) }.map(Into::into)
526 } else if let Some(lock_fn) = pointer.vtable.lock_fn {
527 unsafe { lock_fn(v.data()) }.map(Into::into)
528 // handle weak pointers and try to upgrade them
529 } else if let Some(upgrade_fn) = pointer.vtable.upgrade_into_fn
530 && let Some(strong_shape) = def.into_pointer().ok().and_then(|x| x.strong())
531 {
532 // if the strong shape is unsized, the Facet implementation of the type is wrong.
533 let strong = strong_shape
534 .allocate()
535 .expect("strong pointer is always sized");
536
537 // SAFETY: turning this peek into a PtrMut is okay, because
538 // the upgrade function only needs &self
539 // in theory, the upgrade_fn signature could take a PtrConst as well.
540 let ptr = unsafe { v.data().into_mut() };
541 // SAFETY: Facet implementation of Weak garantees strong is the correct
542 // shape of the strong part for this Weak
543 Ok(unsafe { upgrade_fn(ptr, strong) }
544 .map(|strong_instance| LockGuardType::Upgrade {
545 strong_shape,
546 allocation: strong_instance,
547 })
548 .ok_or(MakeLockError {
549 kind: MakeLockErrorKind::NotUpgradable,
550 unchanged: v,
551 })?)
552 } else {
553 return Err(MakeLockError {
554 unchanged: v,
555 kind: MakeLockErrorKind::NotLockable,
556 });
557 };
558
559 let Ok(lock) = res else {
560 return Err(MakeLockError {
561 unchanged: v,
562 kind: MakeLockErrorKind::LockFailure,
563 });
564 };
565 // SAFETY: creates access via the PtrMut returned from locking
566 // the smart pointer. 'mem outlives 'lock this means
567 // the returned mutable Poke<'lock> lives shorter than 'mem
568 let peek: Peek<'lock, 'facet> = unsafe {
569 Peek::unchecked_new(
570 lock.data_const(),
571 shape
572 .inner
573 .expect("a smart pointer always has an inner shape"),
574 )
575 };
576 let (mut guards, mut value): (Vec<LockGuardType>, MaybeMut<'lock, 'facet>) =
577 (vec![lock], MaybeMut::Not(peek.innermost_peek()));
578
579 // unwrap remaining inner pointer types
580 // -> all types that have an inner type and are a pointer
581 while let Some(_inner) = value.as_peek().shape().inner
582 && let Def::Pointer(def) = value.as_peek().shape().def
583 // lock gets read-locked in the next read call
584 && (def.flags.contains(PointerFlags::LOCK) ||
585 // weak gets upgraded at the next read call
586 def.flags.contains(PointerFlags::WEAK) ||
587 // atomics just get unwrapped in the next read call
588 def.flags.contains(PointerFlags::ATOMIC))
589 {
590 // SAFETY: we synthesize a Peek with the outer 'mem lifetime so we
591 // can re-enter `read`. The fabricated lifetime never escapes:
592 //
593 // * On success, the recursive call returns `Guard<'lock>`. Its
594 // `data` is bounded by 'lock and its guards are moved into our
595 // `guards` Vec, so the parent lock keeps the pointer live for
596 // as long as the returned `Guard` exists.
597 // * On failure, we MUST NOT propagate the inner
598 // `MakeLockError::unchanged` since that Peek carries the
599 // fabricated 'mem lifetime while actually pointing into
600 // lock-protected memory that we are about to release as our
601 // `guards` Vec drops on early return. Instead we substitute
602 // the original outer Peek `v`, which is genuinely valid for
603 // 'mem because it comes straight from the function input.
604 let shorter_peek: Peek<'mem, 'facet> =
605 unsafe { Peek::unchecked_new(value.as_peek().data(), value.shape()) };
606 let shorter_maybe: MaybeMut<'mem, 'facet> = MaybeMut::Not(shorter_peek);
607 let guard: Guard<'lock, 'facet> = match shorter_maybe.read() {
608 Ok(g) => g,
609 Err(e) => {
610 // Peek v needs no Guards, drop them explicitly to free
611 // locks (they would be dropped by the return anyways)
612 drop(guards);
613 // Discard `e.unchanged` (would dangle once `guards`
614 // drops on return); substitute the original outer Peek
615 // which is actually valid for 'mem.
616 return Err(MakeLockError {
617 unchanged: v,
618 kind: e.kind,
619 });
620 }
621 };
622
623 // SAFETY: moves out all values from guard, Guard is no longer used afterwards
624 let (inner_guards, data) = unsafe { guard.take() };
625 // SAFETY: the values must be moved to the new vec not cloned and NOT dropped.
626 // this would lead to a double unlock later
627 guards.extend(inner_guards);
628 // SAFETY: set the new value to the inner most available value
629 value = data;
630 }
631 Ok(Guard {
632 data: ManuallyDrop::new(value),
633 guards,
634 })
635 }
636}
637
638#[cfg(test)]
639mod tests {
640 use facet::{Def, Facet, KnownPointer};
641 use facet_reflect::Peek;
642
643 #[derive(Debug, Facet)]
644 struct Foo {
645 value: String,
646 }
647
648 #[facet_testhelpers::test]
649 fn shared_reference() {
650 let a = Foo {
651 value: "aaaa".to_string(),
652 };
653 println!("{:#?}", <&Foo as Facet<'_>>::SHAPE.def);
654 assert!(
655 matches!(<&Foo as Facet<'_>>::SHAPE.def, Def::Pointer(p) if p.known == Some(KnownPointer::SharedReference))
656 );
657 let ref_a: &Foo = &a;
658 let ref_ref_a: &&Foo = &ref_a;
659 let peek = Peek::new(ref_ref_a);
660 println!("{:#?}", peek.shape().def); // `Undefined`
661 assert!(
662 matches!(peek.shape().def, Def::Pointer(p) if p.known == Some(KnownPointer::SharedReference))
663 );
664 }
665}