Created
February 10, 2019 19:37
-
-
Save wdevore/db1e6a605d182d34491f972aa94daa93 to your computer and use it in GitHub Desktop.
An example of using RefCells to handle interior mutability
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::cell::RefCell; | |
use std::rc::Rc; | |
type RefNode = Rc<RefCell<NodeTrait>>; | |
type RefTransform = Rc<RefCell<TransformProperty>>; | |
trait NodeTrait { | |
fn id(&self) -> usize { | |
0 | |
} | |
fn set_id(&mut self, id: usize); | |
fn name(&self) -> &String; | |
fn set_name(&mut self, name: String); | |
fn to_string(&self) -> String; | |
fn node(&self) -> &Node; | |
// -------------------------------------------------------- | |
// Transformations | |
// -------------------------------------------------------- | |
fn transform_p(&mut self) -> &Option<RefTransform> { | |
&None | |
} | |
fn set_position(&mut self, x: f32, y: f32); | |
} | |
struct TransformProperty { | |
x: f32, | |
y: f32, | |
} | |
impl TransformProperty { | |
fn new() -> Self { | |
Self { x: 0.0, y: 0.0 } | |
} | |
fn set_position(&mut self, x: f32, y: f32) { | |
self.x = x; | |
self.y = y; | |
} | |
} | |
struct Node { | |
id: usize, | |
name: String, | |
transform: Option<RefTransform>, | |
} | |
impl Node { | |
fn new() -> Self { | |
Self { | |
id: 0, | |
name: String::from("NoName"), | |
transform: None, | |
} | |
} | |
} | |
// ====================================================== | |
struct BootScene { | |
node: Node, | |
} | |
impl BootScene { | |
fn new() -> RefNode { | |
let mut n = Node::new(); | |
n.transform = Some(Rc::new(RefCell::new(TransformProperty::new()))); | |
Rc::new(RefCell::new(Self { node: n })) | |
} | |
} | |
impl NodeTrait for BootScene { | |
fn id(&self) -> usize { | |
self.node.id | |
} | |
fn set_id(&mut self, id: usize) { | |
self.node.id = id; | |
} | |
fn to_string(&self) -> String { | |
self.node.name.to_string() | |
} | |
fn name(&self) -> &String { | |
&self.node.name | |
} | |
fn set_name(&mut self, name: String) { | |
self.node.name = name.to_string(); | |
} | |
fn transform_p(&mut self) -> &Option<RefTransform> { | |
&self.node.transform | |
} | |
fn node(&self) -> &Node { | |
&self.node | |
} | |
fn set_position(&mut self, x: f32, y: f32) { | |
if let Some(t) = &self.node.transform { | |
t.borrow_mut().set_position(x, y); | |
} | |
} | |
} | |
// impl TimingTarget for BootScene { | |
// fn update(&mut self, dt: f32) { | |
// println!("bs.update: {}", dt); | |
// } | |
// } | |
// ====================================================== | |
struct SplashScene { | |
node: Node, | |
} | |
impl SplashScene { | |
fn new() -> RefNode { | |
Rc::new(RefCell::new(Self { node: Node::new() })) | |
} | |
} | |
impl NodeTrait for SplashScene { | |
fn id(&self) -> usize { | |
self.node.id | |
} | |
fn set_id(&mut self, id: usize) { | |
self.node.id = id; | |
} | |
fn to_string(&self) -> String { | |
self.node.name.to_string() | |
} | |
fn name(&self) -> &String { | |
&self.node.name | |
} | |
fn set_name(&mut self, name: String) { | |
self.node.name = name.to_string(); | |
} | |
fn node(&self) -> &Node { | |
&self.node | |
} | |
fn set_position(&mut self, x: f32, y: f32) { | |
if let Some(t) = &self.node.transform { | |
t.borrow_mut().set_position(x, y); | |
} | |
} | |
} | |
// ====================================================== | |
struct SceneManager { | |
scenes: Vec<RefNode>, | |
} | |
impl SceneManager { | |
fn new() -> Self { | |
Self { scenes: Vec::new() } | |
} | |
fn push_scene(&mut self, scene: RefNode) { | |
self.scenes.push(scene); | |
} | |
fn to_string(&self) { | |
for sc in self.scenes.iter() { | |
print!("({}) '{}'", sc.borrow().id(), sc.borrow().to_string()); | |
let mut scb = sc.borrow_mut(); | |
match scb.transform_p() { | |
Some(tp) => println!(" : {},{}", tp.borrow().x, tp.borrow().y), | |
None => println!(""), | |
} | |
} | |
} | |
fn scene(&self, id: usize) -> Option<&RefNode> { | |
// self.scenes.get(id) // By index | |
// Or by Id | |
let mut s = None; | |
for sc in self.scenes.iter() { | |
if sc.borrow().id() == id { | |
s = Some(sc); | |
break; | |
} | |
} | |
s | |
} | |
} | |
type BuildCallback = fn(&mut Engine); | |
struct Engine { | |
id: usize, | |
scm: SceneManager, | |
} | |
impl<'a> Engine { | |
fn new() -> Self { | |
Self { | |
id: 0, | |
scm: SceneManager::new(), | |
} | |
} | |
fn launch(&mut self, build: BuildCallback) { | |
build(self); | |
} | |
fn scene_manager(&'a mut self) -> &'a SceneManager { | |
&self.scm | |
} | |
// fn scene_manager_mut(&'a mut self) -> &'a mut SceneManager { | |
// &mut self.scm | |
// } | |
fn push_scene(&mut self, scene: RefNode) { | |
self.id += 1; | |
scene.borrow_mut().set_id(self.id); | |
self.scm.push_scene(scene); | |
} | |
} | |
fn main() { | |
let mut eng = Engine::new(); | |
eng.launch(build); | |
} | |
fn build(eng: &mut Engine) { | |
let bs = BootScene::new(); | |
// { | |
// let mut node = bs.borrow_mut(); | |
// node.set_name(String::from("Boot")); | |
// node.set_position(2.2, 5.5); | |
// } | |
// Or better style | |
match bs.borrow_mut() { | |
mut node => { | |
node.set_name(String::from("Boot")); | |
node.set_position(2.2, 5.5); | |
} | |
} | |
// Or cumbersome | |
// bs.borrow_mut().set_name(String::from("Boot")); | |
// bs.borrow_mut().set_position(2.2, 5.5); | |
// if let Some(stp) = bs.borrow_mut().transform_p() { | |
// stp.borrow_mut().set_position(1.0, 3.3); | |
// } | |
// match bs.borrow_mut().transform_p() { | |
// Some(stp) => { | |
// stp.borrow_mut().set_position(1.0, 3.3); | |
// }, | |
// _ => (), | |
// } | |
let sp = SplashScene::new(); | |
sp.borrow_mut().set_name(String::from("Splash")); | |
sp.borrow_mut().set_position(1.0, 4.4); // doesn't change anything | |
eng.push_scene(bs); | |
eng.push_scene(sp); | |
let scm = eng.scene_manager(); | |
if let Some(se) = scm.scene(1) { | |
se.borrow_mut().set_name(String::from("Boot2")); | |
} | |
// Or | |
// match scm.scene(1) { | |
// Some(se) => { | |
// se.borrow_mut().set_name(String::from("Boot2")); | |
// // println!("sn: {}", se.borrow().to_string()); | |
// } | |
// None => println!("2 not found"), | |
// } | |
println!("----------------------"); | |
scm.to_string(); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment