// 1st day: Let's create door.
// I think Door can be represented simply:
struct Door { opened: bool, knob_turned: bool }
// Logic of Door.
impl Door {
fn new() -> Self { Door { opened: false, knob_turned: false } }
fn is_open(&self) -> bool { self.opened }
#[allow(unused)]
fn is_close(&mut self) -> bool { !self.opened }
fn knob_turn(&mut self) { self.knob_turned = true; }
fn knob_unturn(&mut self) { self.knob_turned = false; }
fn push(&mut self) {
if self.knob_turned { self.opened = true; }
}
fn pull(&mut self) { self.opened = false; self.knob_turned = false; }
fn can_be_opened(&self) -> bool { self.knob_turned && !self.opened }
}
// Day 2. We need another door.
// Let's define common methods of Door.
trait TDoor {
fn is_open(&self) -> bool;
fn knob_turn(&mut self);
fn knob_unturn(&mut self);
fn push(&mut self);
fn pull(&mut self);
fn can_be_opened(&self) -> bool;
fn is_close(&self) -> bool { !self.is_open() }
}
// .. and Door is a type of TDoor.
impl TDoor for Door {
fn is_open(&self) -> bool { Door::is_open(self) }
fn knob_turn(&mut self) { Door::knob_turn(self) }
fn knob_unturn(&mut self) { Door::knob_unturn(self) }
fn push(&mut self) { Door::push(self) }
fn pull(&mut self) { Door::pull(self) }
fn can_be_opened(&self) -> bool { Door::can_be_opened(self) }
}
// Now we can manipulate any doors through TDoor.
// Next we define DoorWithCloser which will be closed automatically after 4 seconds.
use std::sync::{Arc, Mutex};
struct DoorWithCloser<T: TDoor> {
// Because door is modified by main thread and closer thread,
// we need Atomic Reference Counting (Arc) and exclusive mutation (Mutex)
door: Arc<Mutex<T>>,
closer_sec: u64,
}
// Constructor and basic operations.
impl<T: TDoor> DoorWithCloser<T> {
fn from_door(door: T) -> Self {
DoorWithCloser { door: Arc::new(Mutex::new(door)), closer_sec: 4 }
}
#[allow(unused)]
fn set_closer_timer(&mut self, sec: u64) { self.closer_sec = sec; }
}
// For convenience, `new` can create previous `Door` with closer.
impl DoorWithCloser<Door> {
fn new() -> DoorWithCloser<Door> { DoorWithCloser::from_door(Door::new()) }
}
// Logic of DoorWithCloser.
// Rust is very strict about multithreading,
// so you doesn't need to understand all notation below.
impl<T: TDoor + Send + 'static> TDoor for DoorWithCloser<T> {
fn is_open(&self) -> bool { self.door.lock().unwrap().is_open() }
fn knob_turn(&mut self) { self.door.lock().unwrap().knob_turn() }
fn knob_unturn(&mut self) { self.door.lock().unwrap().knob_unturn() }
fn pull(&mut self) { self.door.lock().unwrap().pull() }
fn can_be_opened(&self) -> bool { self.door.lock().unwrap().can_be_opened() }
// When door is opened, closer thread start.
fn push(&mut self) {
self.door.lock().unwrap().push();
if self.door.lock().unwrap().is_open() {
let door = Arc::downgrade(&self.door);
let sec = self.closer_sec;
std::thread::spawn(move || {
std::thread::sleep(Duration::new(sec, 0));
let door_rwlock = door.upgrade().unwrap();
let mut door = door_rwlock.lock().unwrap();
door.pull();
});
}
}
}
// Let's add another item to `Door`: stopper which prevents closing
struct DoorWithStopper<T: TDoor> { door: T, stoppered: bool }
// Constructor and basic operations.
impl<T: TDoor> DoorWithStopper<T> {
fn from_door(door: T) -> Self { DoorWithStopper { door: door, stoppered: false } }
fn be_stoppered_on(&mut self) { self.stoppered = true; }
fn be_stoppered_off(&mut self) { self.stoppered = false; }
}
// For convenience, `new` creates previous `Door` with stopper.
impl DoorWithStopper<Door> { fn new() -> Self { DoorWithStopper::from_door(Door::new()) } }
// Logic of DoorWithStopper, which is simpler than DoorWithCloser...
impl<T: TDoor> TDoor for DoorWithStopper<T> {
fn is_open(&self) -> bool { self.door.is_open() }
fn knob_turn(&mut self) { self.door.knob_turn() }
fn knob_unturn(&mut self) { self.door.knob_unturn() }
fn can_be_opened(&self) -> bool { self.door.can_be_opened() }
fn push(&mut self) {
self.door.push();
if self.door.is_open() { self.be_stoppered_off() }
}
fn pull(&mut self) {
if !self.stoppered { self.door.pull() }
}
}
// 3rd day: Let's Combine stopper and closer.
// But it seems that stopper always precedes over closer,
// So just define DoorWithStopperCloser like this:
struct DoorWithStopperCloser { door: DoorWithStopper<DoorWithCloser<Door>> }
// Constructors and basic operations
impl DoorWithStopperCloser {
fn new() -> Self {
DoorWithStopperCloser {
door: DoorWithStopper {
door: DoorWithCloser::new(),
stoppered: false,
}
}
}
fn be_stoppered_on(&mut self) { self.door.be_stoppered_on() }
fn be_stoppered_off(&mut self) { self.door.be_stoppered_off() }
}
// Logic of DoorWithStopperCloser
impl TDoor for DoorWithStopperCloser {
fn is_open(&self) -> bool { self.door.is_open() }
fn knob_turn(&mut self) { self.door.knob_turn() }
fn knob_unturn(&mut self) { self.door.knob_unturn() }
fn push(&mut self) { self.door.push() }
fn pull(&mut self) { self.door.pull() }
fn can_be_opened(&self) -> bool { self.door.can_be_opened() }
}
fn main() {
let mut door = Door::new();
println!("door is a door...");
door.knob_turn();
println!("door.knob_turn(); door.can_be_opened(); => {}", door.can_be_opened());
door.knob_unturn();
println!("door.knob_unturn(); door.can_be_opened(); => {}", door.can_be_opened());
door.push();
println!("door.push(); door.is_open(); => {}", door.is_open());
door.knob_turn(); door.push();
println!("door.knob_turn(); door.push(); door.is_open(); => {}", door.is_open());
door.pull();
println!("door.pull; door.is_open(); => {}", door.is_open());
println!("door.can_be_opened(); => {}\n", door.can_be_opened());
let mut door = DoorWithCloser::new();
println!("door is doorWithCloser...");
door.knob_turn(); door.push();
println!("door.knob_turn(); door.push(); door.is_open(); => {}", door.is_open());
std::thread::sleep(Duration::new(1, 0));
println!("1 second after, door.is_open(); => {}", door.is_open());
std::thread::sleep(Duration::new(4, 0));
println!("4 seconds after, door.is_open(); => {}\n", door.is_open());
let mut door = DoorWithStopper::new();
println!("door is DoorWithStopper...");
door.knob_turn(); door.push();
println!("door.knob_turn(); door.push(); door.is_open(); => {}", door.is_open());
door.be_stoppered_on(); door.pull();
println!("door.be_stoppered_on(); door.pull(); door.is_close(); => {}", door.is_close()); // => false
door.be_stoppered_off(); door.pull();
println!("door.be_stoppered_off(); door.pull(); door.is_close(); => {}", door.is_close()); // => true
door.knob_turn(); door.push();
println!("door.knob_turn(); door.push(); door.is_open(); => {}", door.is_open()); // => true
door.be_stoppered_on(); door.pull();
println!("door.be_stoppered_on(); door.pull(); door.is_close() => {}", door.is_close());
door.push(); door.pull();
println!("door.push(); door.pull(); door.is_close(); => {}\n", door.is_close());
let mut door = DoorWithStopperCloser::new();
println!("door is a DoorWithStopperCloser...");
door.knob_turn(); door.push();
println!("door.knob_turn(); door.push(); door.is_open(); => {}", door.is_open()); // => true
door.be_stoppered_on(); std::thread::sleep(Duration::new(4, 0));
println!("door.be_stoppered_on(); then 4 seconds after, door.is_close(); => {}", door.is_close()); // => false
door.be_stoppered_off(); std::thread::sleep(Duration::new(4, 0));
println!("door.be_stoppered_off(); then 4 seconds after, door.is_close(); => {}", door.is_close()); // => true
door.knob_turn(); door.push();
println!("door.knob_turn(); door.push(); door.is_open(); => {}", door.is_open()); // => true
door.be_stoppered_on(); std::thread::sleep(Duration::new(4, 0));
println!("door.be_stoppered_on(); then 4 seconds after, door.is_close(); => {}", door.is_close()); // => false
door.push(); std::thread::sleep(Duration::new(4, 0));
println!("door.push(); then 4 seconds after, door.is_close(); => {}", door.is_close()); // => true
}