1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
//! A safe interface to project through shared references to [`core::cell::Cell`](https://!doc.rust-lang.org/core/cell/struct.Cell.html).
//!
//! ```rust
//! 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
//!
//! ```rust compile_fail
//! 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.
//!
//! ```rust
//! # cell_project::docs_example!{point}
//! # fn get_point() -> Point { Point { x: 0.0, y: 0.0 } }
//! 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
//!
//! ```rust
//! # cell_project::docs_example!{point}
//! struct Pair<T>(T, T);
//!
//! # fn some_point(some_pair: &Cell<Pair<Point>>) {
//! // 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
//!
//! ```rust
//! # cell_project::docs_example!{pair}
//! 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.
//!
//! ```rust compile_fail
//! # cell_project::docs_example!{}
//! 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
//!
//! ```rust
//! 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`](nightly_cell_project), which uses the unstable `#![feature(raw_ref_op)]` to
//! allow projections to `!Sized` fields.
/// project through a shared mutable reference `&Cell`
///
/// see the crate docs for more information