'How to destructure/move out of Drop implementing type?

I have a managed pointer type Uniq, implementing Drop, that has a method that is supposed to consume it without running drop and return a Box of its allocation.

struct Uniq<T> { data: ManuallyDropped<Box<T>>, metadata: Metadata }

impl Uniq<T> {
   fn into_parts(/* mut */ self) -> (Box<T>, Metadata) {
     (ManuallyDrop::into_inner(self.data), self.metadata) // doesn't work

     // let Self { data, metadata } = self; // doesn't work either
   }
}

impl<T> Drop for Uniq<T> {
  fn drop(&mut self) {
    // fancy_management_ledgerwork(self.metadata)
  }
}

#[derive(Clone, Copy)]
struct Metadata(usize);

How do I accomplish this kind of "destructuring move" for my type which implements Drop?

Note: Literally every search engine result is about people not understanding move semantics. I do understand move semantics and I am trying to exploit them to ensure memory safety and I cannot figure out how. I'd rather not convert the ManuallyDrop<Box<T>> to something less-safe-but-Copy like NonNull<T>.



Solution 1:[1]

Use ManuallyDrop::take():

fn into_parts(mut self) -> (Box<T>, Metadata) {
    (unsafe { ManuallyDrop::take(&mut self.data) }, self.metadata)
}

Edit: As correctly mentioned by @FilipeRodrigues, if your Drop implementation tries to do cleanup you also need to prevent it from running, either by std::mem::forget() or by wrapping self in ManuallyDrop.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1