#cell #project #no-std

no-std cell-project

Safe interface for cell projection

1 unstable release

0.1.4 Aug 8, 2022
0.1.3 Dec 21, 2020
0.1.2 May 3, 2020
0.1.1 Apr 30, 2020
0.1.0 Apr 30, 2020

#1831 in Rust patterns

Download history 3/week @ 2024-02-20 51/week @ 2024-02-27

54 downloads per month

MIT license

8KB

cell-project

A safe interface to project through shared references to core::cell::Cell.

Documentation: https://docs.rs/cell-project

use std::cell::Cell;
use cell_project::cell_project as cp; // renamed for ergonomics

struct Point {
    x: f32,
    y: f32,
}

fn get_x_cell(point: &Cell<Point>) -> &Cell<f32> {
    cp!(Point, point.x)
}

The syntax for the macro is as follows

let projection = cp!($TypeOfValue, $value_identifier.$field_identifier);

You may not pass an expression for $value_identifier, if you need to then you should do.

let value = Cell::new(get_point());
let projection = cp!(Point, value.y);

If you need to project through multiple fields then you need to call cp! multiple times, once per projection

struct Pair<T>(T, T);

// let some_pair: &Cell<Pair<Point>>;
let point = cp!(Pair<Point>, some_pair.0);
let x = cp!(Point, point.x);

note: for generic types, you can use _ to infer the generic parameters

fn get_x_cell<T>(point: &Cell<Pair<T>>) -> &Cell<T> {
    cp!(Pair<_>, point.0)
}

Some limitations, you cannot project an enum variant because that is potentially unsound.

let x = Cell::new(Some(0));

// let's imagine a macro like `try_cell_project`, which takes a varaint as well as a type
let proj = cell_project::try_cell_project!(Option<_>, Some, x.0).unwrap();

x.set(None); // we can still write to the `Cell` directly

// this will read uninitialized memory (because that's what `None` wrote in)
// and there is no way to fix this. Enums cannot allow safe projection through
// a shared mutable reference (like `&Cell<_>`)
let _ = proj.get();

so you cannot project through enums

Another limitation of stable, you can only project to Sized types. For example, if I have a type

struct Unsized(i32, [u8]);

Then I can only project to the first field, because the second field is !Sized

features

nightly - unlocks cell_project::nightly_cell_project, which uses the unstable #![feature(raw_ref_op)] to allow projections to !Sized fields.

License: MIT

No runtime deps