-
-
Save Kimundi/2079d773d7551be4e8b0d55608786955 to your computer and use it in GitHub Desktop.
Shared via Rust Playground
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use std::mem; | |
use std::cell::Cell; | |
fn ref_as_cell<T: Copy>(t: &mut T) -> &Cell<T> { | |
unsafe { mem::transmute(t) } | |
} | |
fn slice_as_cell<T: Copy>(t: &mut [T]) -> &[Cell<T>] { | |
unsafe { mem::transmute(t) } | |
} | |
trait AsCell { | |
type Cell; | |
fn as_cell(self) -> Self::Cell; | |
} | |
impl<'a, T: Copy> AsCell for &'a mut T { | |
type Cell = &'a Cell<T>; | |
fn as_cell(self) -> Self::Cell { ref_as_cell(self) } | |
} | |
impl<'a, T: Copy> AsCell for &'a mut [T] { | |
type Cell = &'a [Cell<T>]; | |
fn as_cell(self) -> Self::Cell { slice_as_cell(self) } | |
} | |
fn use_case_1() { | |
// Accessing all values for each value in a slice. | |
let mut v = vec![1, 2, 3, 4]; | |
{ | |
let cell_slice = v.as_cell(); | |
for a in cell_slice { | |
let mut tmp = 0; | |
for b in cell_slice { | |
tmp += b.get() | |
} | |
a.set(tmp); | |
} | |
} | |
println!("uc 1: {:?}\n", v); | |
} | |
fn use_case_2() { | |
// Offset iteration and mutation | |
let mut v = vec![1, 2, 3, 4]; | |
{ | |
let cell_slice = v.as_cell(); | |
for (a, b) in cell_slice.iter().zip(cell_slice[1..].iter()) { | |
a.set(a.get() + b.get()); | |
} | |
} | |
println!("uc 2: {:?}\n", v); | |
} | |
fn method_resolve_ergonomics() { | |
let mut a = 4; | |
let ac = a.as_cell(); // &mut i32 -> &Cell<i32> | |
ac.set(5); | |
let mut b = [1, 2, 3]; | |
let bc = b.as_cell(); // &mut [i32; 3] -> &Cell<[i32; 3]> | |
bc.set([7, 8, 9]); | |
let mut c = [1, 2, 3]; | |
let cc = c[..].as_cell(); // &mut [i32] -> &[Cell<i32>] | |
cc[0].set(5); | |
let mut d = vec![1, 2, 3]; | |
let dc = d.as_cell(); // &mut [i32] -> &[Cell<i32>] | |
dc[0].set(5); | |
} | |
fn use_case_3() { | |
// Very simplified contrain solver. | |
// see eddyb's code @ https://github.com/eddyb/r3/blob/master/src/ui/layout.rs#L297 | |
// for a real use case. | |
// Idea: initial list of objects with (left, right) coordinates of their bounding boxes | |
let mut objects = vec![(0.0, 1.0), (0.0, 0.0), (0.0, 0.0), (0.0, 3.0)]; | |
println!("uc 3, initial state:"); | |
println!("{:?}", objects); | |
// Solver goals: | |
// - objects may not overlap | |
// - objects may not have negative width | |
{ | |
// Define a constraint. It contains: | |
// - a reference `x` to the element that may be changed | |
// to fulfill the constraint. | |
// - a reference to an element that gives the contraint, | |
// in this case the minimum value needed for `x`. | |
#[derive(Debug)] | |
struct Constr<'a> { | |
x: &'a Cell<f32>, | |
minimum_x_needed: &'a Cell<f32> | |
} | |
// helper code to convert the mutable references to the elements | |
// of the `objects` vector to &Cell references to both | |
// x coordinates in each object. | |
let refs: Vec<(&Cell<f32>, &Cell<f32>)> = objects | |
.iter_mut() | |
.map(|&mut (ref mut x, ref mut y)| { | |
(x.as_cell(), y.as_cell()) | |
}).collect(); | |
// Gather all constraints. | |
// Done manually for simplicity, but could trivially be generated by an algorithms | |
let constrs = vec![ | |
// objects next to each other may not overlap | |
Constr { x: &refs[1].0, minimum_x_needed: &refs[0].1 }, | |
Constr { x: &refs[2].0, minimum_x_needed: &refs[1].1 }, | |
Constr { x: &refs[3].0, minimum_x_needed: &refs[2].1 }, | |
// objects may not have negative width | |
Constr { x: &refs[0].1, minimum_x_needed: &refs[0].0 }, | |
Constr { x: &refs[1].1, minimum_x_needed: &refs[1].0 }, | |
Constr { x: &refs[2].1, minimum_x_needed: &refs[2].0 }, | |
Constr { x: &refs[3].1, minimum_x_needed: &refs[3].0 }, | |
]; | |
println!(" {:?}", refs); | |
// fixpoint calculation - loop as long as a constraint is | |
// broken and needs to be adjusted | |
'outer: loop { | |
for constr in &constrs { | |
if constr.x.get() < constr.minimum_x_needed.get() { | |
constr.x.set(constr.minimum_x_needed.get()); | |
println!(" > {:?}", refs); | |
continue 'outer; | |
} | |
} | |
break; | |
} | |
} | |
println!("{:?}\n", objects); | |
} | |
fn main() { | |
use_case_1(); | |
use_case_2(); | |
use_case_3(); | |
method_resolve_ergonomics(); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment