Instantly share code, notes, and snippets.
Created
January 22, 2018 21:36
-
Save arcrose/206de0fee2655e47ddba29254a15adff to your computer and use it in GitHub Desktop.
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::marker::PhantomData; | |
pub trait Capability<Operation> { | |
type Data; | |
type Error; | |
fn perform(&self, Operation) -> Result<Self::Data, Self::Error>; | |
} | |
pub trait Authority<Request> { | |
type Operation; | |
type Data; | |
type Error; | |
fn request(&self, req: Request) -> Option<Box<Capability<Self::Operation, Data = Self::Data, Error = Self::Error>>>; | |
} | |
macro_rules! capability { | |
($name:ident for $type:ty, | |
composing $({$operations:ty, $d:ty, $e:ty}),+) => { | |
trait $name: $(Capability<$operations, Data = $d, Error = $e>+)+ {} | |
impl $name for $type {} | |
}; | |
} | |
#[derive(Clone)] | |
pub struct SQLite { | |
// Some connection. | |
} | |
struct SaveCap<Resource> { | |
_t: PhantomData<Resource>, | |
id: String, | |
} | |
struct UpdateCap<Resource> { | |
_t: PhantomData<Resource>, | |
id: String, | |
} | |
pub struct SaveCapRequest<Resource> { | |
_t: PhantomData<Resource>, | |
id: String, | |
} | |
pub struct Save<T>(pub T); | |
pub struct Update<T>(pub T); | |
pub struct Delete<T>(pub T); | |
pub struct Search<T>(pub T); | |
#[derive(Debug)] | |
pub struct User { | |
pub email_address: String, | |
pub name: String, | |
} | |
#[derive(Debug)] | |
pub struct Order { | |
pub item_name: String, | |
pub cost: u32, | |
} | |
pub struct FindByEmail { | |
pub email_address: String, | |
} | |
impl Authority<SaveCapRequest<User>> for SQLite { | |
type Operation = Save<User>; | |
type Data = User; | |
type Error = String; | |
fn request(&self, req: SaveCapRequest<User>) -> Option<Box<Capability<Save<User>, Data = User, Error = String>>> { | |
Some(Box::new(Save(User { | |
email_address: "testing@site.com".to_string(), | |
name: "test user".to_string(), | |
}))) | |
} | |
} | |
impl Capability<Save<User>> for Save<User> { | |
type Data = User; | |
type Error = String; | |
fn perform(&self, to_save: Save<User>) -> Result<User, String> { | |
println!("Saved user {:?}", to_save.0); | |
Ok(to_save.0) | |
} | |
} | |
impl Capability<Update<User>> for Update<User> { | |
type Data = User; | |
type Error = String; | |
fn perform(&self, to_update: Update<User>) -> Result<User, String> { | |
println!("Updating user {:?}", to_update.0); | |
Ok(to_update.0) | |
} | |
} | |
capability!(CreateAndUpdateUsers for SQLite, | |
composing { Save<User>, User, String }, | |
{ Update<User>, User, String }); | |
fn create_new_user<R: CreateAndUpdateUsers>(resource_manager: &R) -> Result<(), String> | |
//where R: Capability<Save<User>, Error = String> | |
{ | |
// Load user from, e.g., a request. | |
let user = User { | |
email_address: "test@site.com".to_string(), | |
name: "Test User".to_string(), | |
}; | |
let user = resource_manager.perform(Save(user)).unwrap(); | |
resource_manager.perform(Update(user)).map(|_| ()) | |
} | |
#[cfg(test)] | |
mod tests { | |
use super::*; | |
#[test] | |
fn can_create_users() { | |
/* | |
let db = SQLite{}; | |
let cap = db.request | |
let create_result = create_new_user(&resource_manager); | |
assert!(create_result.is_ok()); | |
*/ | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment