Skip to main content

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}