Skip to content

Instantly share code, notes, and snippets.

@arcrose
Created January 22, 2018 21:36
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 arcrose/206de0fee2655e47ddba29254a15adff to your computer and use it in GitHub Desktop.
Save arcrose/206de0fee2655e47ddba29254a15adff to your computer and use it in GitHub Desktop.
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