pub trait Block: Clone + Default {
type CreationInstructions: Clone + Default;
fn create(instructions: &Self::CreationInstructions) -> Self;
fn void() -> Self;
fn is_void(&self) -> bool;
fn to_void(&mut self) {
*self = Self::void()
}
fn overwrite(&mut self, other: Self) {
*self = other
}
fn swap(&mut self, other: &mut Self) {
let shelf = other.clone();
other.overwrite(self.clone());
self.overwrite(shelf);
}
fn shift(&mut self, other: &mut Self) -> Option<()> {
match other.is_void() {
true => { Some(self.swap(other)) },
false => None
}
}
fn map<C: Block, T: Fn(&Self) -> C>(&self, t: T) -> C {
t(self)
}
}
#[cfg(test)] pub(crate) mod test {
use super::*;
#[derive(
Default, Clone, // Necessary for Block impl
Debug, Eq, PartialEq // Nice to have for testing
)]
pub(crate) struct TestBlock {
pub(crate) id: String,
pub(crate) connections: Vec<String> }
impl Block for TestBlock {
type CreationInstructions = String;
fn create(id: &Self::CreationInstructions) -> Self {
TestBlock {
id: id.to_owned(),
connections: Vec::new()
}
}
fn void() -> Self {
TestBlock::default()
}
fn is_void(&self) -> bool {
self.id.is_empty()
}
}
#[test] fn new_block_test() {
let block = TestBlock::create(&"test".to_string());
assert_eq!(&block.id, "test");
assert!(!block.is_void());
}
#[test] fn void_block_test() {
let void = TestBlock::void();
assert!(void.is_void());
let mut block = TestBlock::create(&"not_void".to_string());
assert!(!block.is_void());
block.to_void();
assert!(block.is_void());
assert_eq!(block, void);
}
#[test] fn swap_block_test() {
let mut block = TestBlock::create(&"block".to_string());
let mut void = TestBlock::void();
block.swap(&mut void);
assert!(block.is_void());
assert!(!void.is_void());
}
#[test] fn shift_block_test() {
let mut block = TestBlock::create(&"block".to_string());
let mut void = TestBlock::void();
block.shift(&mut void)
.expect("Shift block into void position");
assert!(block.is_void());
assert!(!void.is_void());
let mut other_block = TestBlock::create(&"other".to_string());
assert!(void.shift(&mut other_block).is_none(), "Cannot shift into non-void block");
other_block.shift(&mut block)
.expect("Shift block into void (block) position");
void.shift(&mut other_block)
.expect("Shift block into void (other_block) position");
assert!(void.is_void());
assert_eq!(&other_block.id, "block", "Other block is 'block'");
assert_eq!(&block.id, "other", "Original block is 'other'");
}
#[test] fn overwrite_block_test() {
let mut block = TestBlock::create(&"block".to_string());
block.overwrite(TestBlock::create(&"overwrite".to_string()));
assert_eq!(&block.id, "overwrite", "Original block is overwritten");
}
}