Skip to content

Instantly share code, notes, and snippets.

@rgdmarshall
Created July 3, 2015 12:24
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rgdmarshall/efe4e36d4ed8a6a5b544 to your computer and use it in GitHub Desktop.
Save rgdmarshall/efe4e36d4ed8a6a5b544 to your computer and use it in GitHub Desktop.
// Mutability exercise.
#[cfg(not(second))]
fn do_frob() {
let mut aa = MySource::new();
{
let mut aaw = aa.get_sink();
let ff = first::Outer::new();
ff.frob(&mut *aaw);
aaw.flush();
}
println!("aa: {:?}", aa.all());
}
#[cfg(second)]
fn do_frob() {
let mut bb = MySource::new();
{
second::Outer::new(bb.get_sink()).frob();
}
println!("bb: {:?}", bb.all());
}
fn main() {
do_frob();
}
// A source is initially opened, the type being determined by what is actually
// found on the device.
pub trait Source {
fn get_sink<'a>(&'a mut self) -> Box<Sink + 'a>;
fn all(&self) -> Vec<u32>;
}
// To update, request a sink, `add` with it, and then flush.
pub trait Sink {
fn add(&mut self, item: u32);
fn flush(self: Box<Self>);
}
// A very simple implementation of this.
struct MySource {
items: Vec<u32>,
}
impl MySource {
fn new() -> MySource {
MySource {
items: Vec::new(),
}
}
}
impl Source for MySource {
fn all(&self) -> Vec<u32> {
self.items.iter().cloned().collect()
}
fn get_sink<'a>(&'a mut self) -> Box<Sink + 'a> {
Box::new(MySink {
parent: self,
})
}
}
pub struct MySink<'a> {
parent: &'a mut MySource,
}
impl<'a> Sink for MySink<'a> {
fn add(&mut self, item: u32) {
self.parent.items.push(item);
}
fn flush(self: Box<Self>) {
// Nothing to do in the example.
}
}
//----------------------------------------------------------------------
// For example.
// In this first instance, the two structs don't contain the Sink and it gets
// passed around as needed. This works, but the Sink has to be passed all
// around to make things work.
#[cfg(not(second))]
mod first {
use super::*;
pub struct Outer {
other: u32,
}
impl Outer {
pub fn new() -> Outer {
Outer {
other: 1,
}
}
pub fn frob(&self, sink: &mut Sink) {
let inside = Inner::new();
sink.add(self.other);
inside.frob(sink, self.other + 1);
sink.add(self.other + 2);
}
}
struct Inner {
other: u32,
}
impl Inner {
fn new() -> Inner {
Inner {
other: 100,
}
}
fn frob(&self, sink: &mut Sink, extra: u32) {
sink.add(self.other + extra);
}
}
}
// For this second instance, we wrap up the Sink with inner mutability so that
// it can just be stored directly in the instances.
#[cfg(second)]
mod second {
use super::*;
use std::cell::RefCell;
pub struct Outer<'a> {
other: u32,
sink: RefCell<Box<Sink + 'a>>,
}
impl<'a> Outer<'a> {
pub fn new(sink: Box<Sink + 'a>) -> Outer<'a> {
Outer {
other: 1,
sink: RefCell::new(sink),
}
}
pub fn frob(&self) {
let inside = Inner::new();
self.use_sink(|| { self.other });
inside.frob(self, self.other + 1);
self.use_sink(|| { self.other + 2 });
}
pub fn use_sink<F>(&self, f: F) where F: Fn() -> u32 {
let mut sink = self.sink.borrow_mut();
sink.add(f());
}
}
struct Inner {
other: u32,
}
impl Inner {
fn new() -> Inner {
Inner {
other: 100,
}
}
fn frob(&self, outer: &Outer, extra: u32) {
outer.use_sink(|| { self.other + extra });
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment