#pin #macro #declarative-macro

pin-projections

Declarative macro for creating projection functions for pinned objects

6 releases (3 breaking)

0.4.0 Jul 16, 2022
0.3.1 Jul 9, 2022
0.2.0 Jul 8, 2022
0.1.1 Jun 14, 2022

#2142 in Rust patterns

MIT/Apache

11KB
150 lines

Yet another pin projection helper macro

Creates zero-cost projection functions for pinned objects.

Example usage:

use pin_projections::project;
use std::pin::Pin;

// Just a placeholder for illustration
#[derive(Clone)]
struct Entry(u64);

// The structure to be projected
struct Example {
    structural_pinned: Entry,
    not_structural_pinned: Entry,
}

impl Example {
    // The projections are defined within impl

    // defining a projection for structural_pinned
    // 1. for a pinned shared reference
    project!(pub structural_pinned as first_entry() -> Pin<&Entry>);

    // 2. and one for a pinned mutable reference.
    project!(structural_pinned as first_entry_mut() -> Pin<&mut Entry>);

    // 3. without the 'as function()' part the projection is named the same as the member
    project!(pub structural_pinned -> Pin<&Entry>);

    // When no projection name is given then mutable and immutable projections are
    // mutually exclusive. The following would then collide with the definition #3 above.
    // project!(structural_pinned -> Pin<&mut Entry>);

    // 4. non structural pinned members are similar, just without the Pin<>
    project!(not_structural_pinned as second_entry() -> &Entry);

    // 5. one for a mutable reference.
    project!(not_structural_pinned as second_entry_mut() -> &mut Entry);

    // 6. all projections can be defined unsafe if necessary.
    project!(pub(crate) unsafe structural_pinned as unsafe_projection() -> &mut Entry);

    // 7. Types that are Clone can use a (cloning) getter.
    project!(structural_pinned as get_first() -> Entry);

    // 8. Types that are Clone you can use a borrowing setter.
    project!(structural_pinned as set_first_from(&Entry));

    // 9. Types that are not Clone can be set by a owning setter.
    project!(structural_pinned as set_first_to(Entry));
}

fn main() {
    let mut example = Box::pin(
        Example{
             structural_pinned: Entry(42),
             not_structural_pinned: Entry(99),
        }
    );

    // This is Pin<&Example>
    let example_ref = example.as_ref();

    // for 1.
    assert_eq!(example_ref.first_entry().0, 42);

    // for 3.
    assert_eq!(example_ref.structural_pinned().0, 42);

    // for 4.
    assert_eq!(example_ref.second_entry().0, 99);
}

No runtime deps