Created
November 12, 2016 19:26
-
-
Save anonymous/80ec6747d5df6235aa36abe16ef6cb84 to your computer and use it in GitHub Desktop.
Shared via Rust Playground
This file contains hidden or 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