-
Notifications
You must be signed in to change notification settings - Fork 76
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Mediator: Add
Rc<RefCell<..>>
approach (#11)
I found that `Rc<RefCell<..>>` may actually be useful in some cases. I decided to move this case into the repo for a quick reference. * Use Rust 1.53 for GitHub Workflows * Fix clippy errors * Update behavioral/mediator/README.md
- Loading branch information
Showing
22 changed files
with
387 additions
and
21 deletions.
There are no files selected for viewing
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
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
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
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
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 2 additions & 2 deletions
4
behavioral/mediator/Cargo.toml → ...l/mediator/mediator-rc-refcell/Cargo.toml
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,8 +1,8 @@ | ||
[package] | ||
edition = "2021" | ||
name = "mediator" | ||
name = "mediator-rc-refcell" | ||
version = "0.1.0" | ||
|
||
[[bin]] | ||
name = "mediator" | ||
name = "mediator-rc-refcell" | ||
path = "main.rs" |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
# Mediator with `Rc<RefCell<..>>` | ||
|
||
## How To Run | ||
|
||
```bash | ||
cargo run --bin mediator-rc-refcell | ||
``` | ||
|
||
## Mimicking a Typical OOP | ||
|
||
`Rc<RefCell<..>>` hides objects from compiler eyes inside of an opaque smart pointer. | ||
In this case, borrow checks move into the runtime that means panicking in case of | ||
borrow rules violation. | ||
|
||
There is an example of a [Station Manager example in Go][4]. Trying to make it | ||
with Rust leads to mimicking a typical OOP through reference counting and | ||
borrow checking with mutability in runtime (which has quite unpredictable | ||
behavior in runtime with panics here and there). | ||
|
||
Key points: | ||
|
||
1. All methods are read-only: immutable `self` and parameters. | ||
2. `Rc`, `RefCell` are extensively used under the hood to take responsibility for the mutable borrowing from compilation time to runtime. Invalid implementation will lead to panic in runtime. | ||
|
||
See the full article: [README.md](../README.md). | ||
|
||
[4]: https://refactoring.guru/design-patterns/mediator/go/example |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
mod train_station; | ||
mod trains; | ||
|
||
use std::{cell::RefCell, rc::Rc}; | ||
|
||
use train_station::StationManager; | ||
use trains::{FreightTrain, PassengerTrain, Train}; | ||
|
||
fn main() { | ||
let station = Rc::new(RefCell::new(StationManager::default())); | ||
|
||
let train1 = Rc::new(PassengerTrain::new("Train 1".into(), station.clone())); | ||
let train2 = Rc::new(FreightTrain::new("Train 2".into(), station.clone())); | ||
|
||
{ | ||
let mut station = station.borrow_mut(); | ||
station.register(train1.clone()); | ||
station.register(train2.clone()); | ||
} | ||
|
||
train1.arrive(); | ||
train2.arrive(); | ||
train1.depart(); | ||
train2.depart(); | ||
} |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
use std::{ | ||
cell::RefCell, | ||
collections::{HashMap, VecDeque}, | ||
rc::Rc, | ||
}; | ||
|
||
use crate::trains::Train; | ||
|
||
pub trait Mediator { | ||
fn notify_about_arrival(&self, train: &dyn Train) -> bool; | ||
fn notify_about_departure(&self, train: &dyn Train); | ||
} | ||
|
||
#[derive(Default)] | ||
pub struct StationManager { | ||
trains: HashMap<String, Rc<dyn Train>>, | ||
train_queue: RefCell<VecDeque<String>>, | ||
train_on_platform: RefCell<Option<String>>, | ||
} | ||
|
||
impl StationManager { | ||
pub fn register(&mut self, train: Rc<dyn Train>) { | ||
self.trains.insert(train.name().clone(), train); | ||
} | ||
} | ||
|
||
impl Mediator for StationManager { | ||
fn notify_about_arrival(&self, train: &dyn Train) -> bool { | ||
let train_name = train.name().clone(); | ||
|
||
self.trains.get(&train_name).expect("A train should exist"); | ||
|
||
if self.train_on_platform.borrow().is_some() { | ||
self.train_queue.borrow_mut().push_back(train_name); | ||
return false; | ||
} | ||
|
||
self.train_on_platform.replace(Some(train_name)); | ||
true | ||
} | ||
|
||
fn notify_about_departure(&self, train: &dyn Train) { | ||
if Some(train.name().clone()) != self.train_on_platform.replace(None) { | ||
return; | ||
} | ||
|
||
let next_train = self.train_queue.borrow_mut().pop_front(); | ||
|
||
if let Some(next_train_name) = next_train { | ||
let next_train = self.trains.get(&next_train_name).unwrap(); | ||
next_train.arrive(); | ||
} | ||
} | ||
} |
35 changes: 35 additions & 0 deletions
35
behavioral/mediator/mediator-rc-refcell/trains/freight_train.rs
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
use std::{cell::RefCell, rc::Rc}; | ||
|
||
use super::Train; | ||
use crate::train_station::Mediator; | ||
|
||
pub struct FreightTrain { | ||
name: String, | ||
mediator: Rc<RefCell<dyn Mediator>>, | ||
} | ||
|
||
impl FreightTrain { | ||
pub fn new(name: String, mediator: Rc<RefCell<dyn Mediator>>) -> Self { | ||
Self { name, mediator } | ||
} | ||
} | ||
|
||
impl Train for FreightTrain { | ||
fn name(&self) -> &String { | ||
&self.name | ||
} | ||
|
||
fn arrive(&self) { | ||
if !self.mediator.borrow().notify_about_arrival(self) { | ||
println!("Freight train {}: Arrival blocked, waiting", self.name); | ||
return; | ||
} | ||
|
||
println!("Freight train {}: Arrived", self.name); | ||
} | ||
|
||
fn depart(&self) { | ||
println!("Freight train {}: Leaving", self.name); | ||
self.mediator.borrow().notify_about_departure(self); | ||
} | ||
} |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
mod freight_train; | ||
mod passenger_train; | ||
|
||
pub use freight_train::FreightTrain; | ||
pub use passenger_train::PassengerTrain; | ||
|
||
pub trait Train { | ||
fn name(&self) -> &String; | ||
fn arrive(&self); | ||
fn depart(&self); | ||
} |
Oops, something went wrong.