Expand description
§Create structural pin projections without unsafe or macros.
This like pin-project-lite but more lite.
§Why Another Pin Projection Crate?
Because you want to create structural pin projections without macros or
unsafe for some reason (perhaps for fun?). If you need functionality not
supported by this crate, it’s worth considering using pin-project-lite or
pin-project instead.
§Differences To pin-project-lite
pin-project-lite only supports structs with named fields; projections
only supports wrapped tuple structs (up to an arity of 7).
pin-project-lite only projects fields annotated with #[pin];
projections always projects all fields.
pin-project-lite might not have the best error messages; projections
error messages should be relatively good.
§Getting Started
Structurally pin a tuple inside of an Sp:
use std::pin::{pin, Pin};
use projections::Sp;
// Create structurally-pinned type
let mut sp: Pin<&mut Sp<(u32, String)>> = pin!(
Sp::new((12u32, "Hi".to_string())),
);
// Project entire inner tuple
let _inner: Pin<&(u32, String)> = Sp::get(sp.as_ref());
let _inner: Pin<&mut (u32, String)> = Sp::get_mut(sp.as_mut());
// Immutable projection of tuple elements
let (int, string): (Pin<&u32>, Pin<&String>) = Sp::project(sp.as_ref());
assert_eq!(*int.get_ref(), 12);
assert_eq!(*string.get_ref(), "Hi");
// Mutable projection of tuple elements
let (int, string): (Pin<&mut u32>, Pin<&mut String>) = Sp::project_mut(sp);
assert_eq!(*int.get_mut(), 12);
assert_eq!(string.get_mut(), "Hi");§Orphan Rule: Alloc
Due to the orphan rule, either alloc, unsafe, or macros are required to
implement Future or other traits usually requiring pinned references
into a structurally-pinned type on a newtype.
use std::{pin::Pin, task::{Context, Poll}};
use projections::Sp;
pub struct MyFuture<F>(Pin<Box<Sp<(F,)>>>);
impl<F> Future for MyFuture<F>
where
F: Future
{
type Output = F::Output;
fn poll(
mut self: Pin<&mut Self>,
cx: &mut Context<'_>,
) -> Poll<F::Output> {
Sp::project_mut(self.0.as_mut()).0.poll(cx)
}
}
let output = MyFuture(Box::pin(Sp::new((async { "uwu" },)))).await;
assert_eq!(output, "uwu");§Orphan Rule: Unsafe
Using unsafe to get around the orphan rule (with the as_repr crate):
use std::{pin::Pin, task::{Context, Poll}};
use as_repr::AsRepr;
use projections::Sp;
// Marker to prevent consumers from invalidating invariants
struct PrivateMarker;
#[repr(transparent)]
pub struct MyFuture<F>(Sp<(F, PrivateMarker)>);
// SAFETY: `MyFuture` is `repr(transparent)`
unsafe impl<F> AsRepr<Pin<&mut Sp<(F, PrivateMarker)>>>
for Pin<&mut MyFuture<F>>
{}
impl<F> Future for MyFuture<F>
where
F: Future
{
type Output = F::Output;
fn poll(
mut self: Pin<&mut Self>,
cx: &mut Context<'_>,
) -> Poll<F::Output> {
let mut sp: Pin<&mut Sp<(F, PrivateMarker)>>
= as_repr::as_repr(self);
Sp::project_mut(sp.as_mut()).0.poll(cx)
}
}
let output = MyFuture(Sp::new((async { "uwu" }, PrivateMarker))).await;
assert_eq!(output, "uwu");§Orphan Rule: Macros
Using macros to get around the orphan rule (with the as_repr crate):
use std::{pin::Pin, task::{Context, Poll}};
use as_repr::AsRepr;
use projections::Sp;
// Marker to prevent consumers from invalidating invariants
struct PrivateMarker;
as_repr::transparent_newtype! {
pub struct MyFuture<F>(Sp<(F, PrivateMarker)>);
}
impl<F> Future for MyFuture<F>
where
F: Future
{
type Output = F::Output;
fn poll(
mut self: Pin<&mut Self>,
cx: &mut Context<'_>,
) -> Poll<F::Output> {
let mut sp: Pin<&mut Sp<(F, PrivateMarker)>>
= as_repr::as_repr(self);
Sp::project_mut(sp.as_mut()).0.poll(cx)
}
}
let output = MyFuture(Sp::new((async { "uwu" }, PrivateMarker))).await;
assert_eq!(output, "uwu");Structs§
- Sp
Spstands for “Structurally Pinned”
Traits§
- Project
- Trait indicating the inner elements or fields can be projected.