Skip to content

Commit

Permalink
Release 0.3
Browse files Browse the repository at this point in the history
  • Loading branch information
djkoloski committed Aug 10, 2022
1 parent 3ab52ff commit 8fa8631
Show file tree
Hide file tree
Showing 14 changed files with 407 additions and 676 deletions.
26 changes: 5 additions & 21 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,21 +1,5 @@
[package]
name = "munge"
version = "0.2.0"
authors = ["David Koloski <[email protected]>"]
edition = "2021"
description = "Macro for easily initializing `MaybeUninit`s"
license = "MIT"
documentation = "https://docs.rs/munge"
repository = "https://github.com/djkoloski/munge"
keywords = ["munge", "macro", "initialize"]
categories = ["no-std", "rust-patterns"]
readme = "crates-io.md"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dev-dependencies]
compiletest_rs = "0.7"

[features]
default = []
offset_of = []
[workspace]
members = [
"munge",
"munge_macro",
]
37 changes: 1 addition & 36 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# `munge`

`munge` makes it easy and safe to destructure raw pointers, `MaybeUninit`s, `Cell`s, and `Pin`s.
`munge` makes it easy and safe to destructure `MaybeUninit`s, `Cell`s, `ManuallyDrop`s, and more.

Just use the `munge!` macro to destructure opaque types the same way you'd destructure a value.

Expand Down Expand Up @@ -70,40 +70,5 @@ assert_eq!(value.b.0, '!');
assert_eq!(value.b.1, 1.41);
```

And `Pin`s as long as all fields are structurally pinned:

```rust
use {
::core::{marker::PhantomPinned, pin::Pin},
::munge::{munge, StructuralPinning},
};

struct Example {
pub a: u32,
pub b: char,
pub _phantom: PhantomPinned,
}

// SAFETY: `Example` obeys structural pinning.
unsafe impl StructuralPinning for Example {}

let mut value = Example {
a: 0,
b: ' ',
_phantom: PhantomPinned,
};
// SAFETY: `value` will not be moved before being dropped.
let mut pin = unsafe { Pin::new_unchecked(&mut value) };

munge!(let Example { a, b, .. } = pin.as_mut());
*a.get_mut() = 1;
*b.get_mut() = 'a';

assert_eq!(pin.as_mut().into_ref().a, 1);
assert_eq!(pin.as_mut().into_ref().b, 'a');
assert_eq!(value.a, 1);
assert_eq!(value.b, 'a');
```

You can even extend `munge` to work with your own types by implementing its `Destructure` and
`Restructure` traits.
20 changes: 20 additions & 0 deletions munge/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
[package]
name = "munge"
version = "0.3.0"
authors = ["David Koloski <[email protected]>"]
edition = "2021"
description = "Macro for custom destructuring"
license = "MIT"
documentation = "https://docs.rs/munge"
repository = "https://github.com/djkoloski/munge"
keywords = ["munge", "macro", "destructure"]
categories = ["no-std", "rust-patterns"]
readme = "crates-io.md"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
munge_macro = { version = "0.3", path = "../munge_macro" }

[dev-dependencies]
compiletest_rs = "0.7"
38 changes: 2 additions & 36 deletions crates-io.md → munge/crates-io.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
`munge` makes it easy and safe to destructure raw pointers, `MaybeUninit`s, `Cell`s, and `Pin`s.

`munge` makes it easy and safe to destructure `MaybeUninit`s, `Cell`s, `ManuallyDrop`s, and more.

Just use the `munge!` macro to destructure opaque types the same way you'd destructure a value.

Expand Down Expand Up @@ -68,40 +69,5 @@ assert_eq!(value.b.0, '!');
assert_eq!(value.b.1, 1.41);
```

And `Pin`s as long as all fields are structurally pinned:

```rust
use {
::core::{marker::PhantomPinned, pin::Pin},
::munge::{munge, StructuralPinning},
};

struct Example {
pub a: u32,
pub b: char,
pub _phantom: PhantomPinned,
}

// SAFETY: `Example` obeys structural pinning.
unsafe impl StructuralPinning for Example {}

let mut value = Example {
a: 0,
b: ' ',
_phantom: PhantomPinned,
};
// SAFETY: `value` will not be moved before being dropped.
let mut pin = unsafe { Pin::new_unchecked(&mut value) };

munge!(let Example { a, b, .. } = pin.as_mut());
*a.get_mut() = 1;
*b.get_mut() = 'a';

assert_eq!(pin.as_mut().into_ref().a, 1);
assert_eq!(pin.as_mut().into_ref().b, 'a');
assert_eq!(value.a, 1);
assert_eq!(value.b, 'a');
```

You can even extend `munge` to work with your own types by implementing its `Destructure` and
`Restructure` traits.
133 changes: 133 additions & 0 deletions munge/src/impls.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
use {
crate::{Destructure, Restructure},
::core::{
cell::{Cell, UnsafeCell},
mem::{ManuallyDrop, MaybeUninit},
},
};

// &MaybeUninit<T>

// SAFETY: Destructuring `&'a MaybeUninit<T>` is safe if and only if destructuring `&'a T` with the
// same pattern is also safe.
unsafe impl<'a, T> Destructure for &'a MaybeUninit<T> {
type Underlying = T;
type Test = &'a T;

fn as_mut_ptr(&mut self) -> *mut Self::Underlying {
self.as_ptr() as *mut Self::Underlying
}
}

// SAFETY: `restructure` returns a valid `MaybeUninit` reference that upholds the same invariants as
// a mutably borrowed subfield of some `T`.
unsafe impl<'a: 'b, 'b, T, U: 'b> Restructure<U> for &'b &'a MaybeUninit<T> {
type Restructured = &'b MaybeUninit<U>;

unsafe fn restructure(ptr: *mut U) -> Self::Restructured {
// SAFETY: The caller has guaranteed that `ptr` points to a subfield of some
// `&'b &'a MaybeUninit<T>`, so it's safe to dereference for the `'b` lifetime.
unsafe { &*ptr.cast() }
}
}

// &mut MaybeUninit<T>

// SAFETY: Destructuring `&'a mut MaybeUninit<T>` is safe if and only if destructuring `&'a mut T`
// with the same pattern is also safe.
unsafe impl<'a, T> Destructure for &'a mut MaybeUninit<T> {
type Underlying = T;
type Test = &'a T;

fn as_mut_ptr(&mut self) -> *mut Self::Underlying {
MaybeUninit::as_mut_ptr(self)
}
}

// SAFETY: `restructure` returns a valid `MaybeUninit` reference that upholds the same invariants as
// a mutably borrowed subfield of some `T`.
unsafe impl<'a: 'b, 'b, T, U: 'b> Restructure<U> for &'b &'a mut MaybeUninit<T> {
type Restructured = &'b mut MaybeUninit<U>;

unsafe fn restructure(ptr: *mut U) -> Self::Restructured {
// SAFETY: The caller has guaranteed that `ptr` points to a subfield of some
// `&'b &'a mut MaybeUninit<T>`, so it's safe to mutably dereference for the `'b` lifetime.
unsafe { &mut *ptr.cast() }
}
}

// &Cell<T>

// SAFETY: Destructuring `&'a Cell<T>` is safe if and only if destructuring `&'a T` with the same
// pattern is also safe.
unsafe impl<'a, T: ?Sized> Destructure for &'a Cell<T> {
type Underlying = T;
type Test = &'a T;

fn as_mut_ptr(&mut self) -> *mut Self::Underlying {
self.as_ptr()
}
}

// SAFETY: `restructure` returns a valid `Cell` reference that upholds the same invariants as a
// mutably borrowed subfield of some `T`.
unsafe impl<'a: 'b, 'b, T: ?Sized, U: 'b + ?Sized> Restructure<U> for &'b &'a Cell<T> {
type Restructured = &'b Cell<U>;

unsafe fn restructure(ptr: *mut U) -> Self::Restructured {
// SAFETY: The caller has guaranteed that `ptr` points to a subfield of some
// `&'b &'a Cell<T>`, so it's safe to dereference for the `'b` lifetime. Additionally, `ptr`
// is guaranteed to have the same pointer metadata as a pointer to `Cell<U>`.
unsafe { &*::core::mem::transmute::<*mut U, *const Cell<U>>(ptr) }
}
}

// &UnsafeCell<T>

// SAFETY: Destructuring `&'a UnsafeCell<T>` is safe if and only if destructuring `&'a T` with the
// same pattern is also safe.
unsafe impl<'a, T: ?Sized> Destructure for &'a UnsafeCell<T> {
type Underlying = T;
type Test = &'a T;

fn as_mut_ptr(&mut self) -> *mut Self::Underlying {
self.get()
}
}

// SAFETY: `restructure` returns a valid `UnsafeCell` reference that upholds the same invariants as
// a mutably borrowed subfield of some `T`.
unsafe impl<'a: 'b, 'b, T: ?Sized, U: 'b + ?Sized> Restructure<U> for &'b &'a UnsafeCell<T> {
type Restructured = &'b UnsafeCell<U>;

unsafe fn restructure(ptr: *mut U) -> Self::Restructured {
// SAFETY: The caller has guaranteed that `ptr` points to a subfield of some
// `&'b &'a UnsafeCell<T>`, so it's safe to dereference for the `'b` lifetime. Additionally,
// `ptr` is guaranteed to have the same pointer metadata as a pointer to `UnsafeCell<U>`.
unsafe { &*::core::mem::transmute::<*mut U, *const UnsafeCell<U>>(ptr) }
}
}

// ManuallyDrop<T>

// SAFETY: Destructuring `ManuallyDrop<T>` is safe if and only if destructuring `T` with the same
// pattern is also safe.
unsafe impl<T> Destructure for ManuallyDrop<T> {
type Underlying = T;
type Test = T;

fn as_mut_ptr(&mut self) -> *mut Self::Underlying {
&mut **self as *mut Self::Underlying
}
}

// SAFETY: `restructure` returns a valid `ManuallyDrop<T>` that upholds the same invariants as a
// mutably borrowed subfield of some `T`.
unsafe impl<T, U> Restructure<U> for &ManuallyDrop<T> {
type Restructured = ManuallyDrop<U>;

unsafe fn restructure(ptr: *mut U) -> Self::Restructured {
// SAFETY: `ptr` is a pointer to a subfield of some `&ManuallyDrop<T>`.
unsafe { ::core::ptr::read(ptr.cast()) }
}
}
Loading

0 comments on commit 8fa8631

Please sign in to comment.