Skip to content

Instantly share code, notes, and snippets.

@yytyd
Last active October 13, 2019 16:23
Show Gist options
  • Save yytyd/b235cdb1419241274979f1e4176f7850 to your computer and use it in GitHub Desktop.
Save yytyd/b235cdb1419241274979f1e4176f7850 to your computer and use it in GitHub Desktop.
普通の macro でちょっとボイラープレートをなくす
use crate::domain::repository::task::{MixInTaskRepository, TaskRepository};
use crate::infra::mysql::mysqlcon::{
MixInMySqlConnection, MySqlConnection, MySqlConnectionDependencies,
};
use crate::infra::redis::pool_ctxt::{MixInRedisContext, RedisContext, RedisContextDependencies};
use crate::infra::repository::task::TaskRepositoryDependencies;
use crate::{add_deps, add_mixin_impl};
pub struct TaskBootstrap {}
impl TaskBootstrap {
pub fn call(&self) {
let a = self.task_repository().find_task_by_id("aaa".to_string());
a;
}
}
add_deps!(
TaskBootstrap,
TaskRepositoryDependencies,
RedisContextDependencies,
MySqlConnectionDependencies
);
add_mixin_impl!(
TaskBootstrap,
TaskRepository,
MixInTaskRepository,
task_repository
);
add_mixin_impl!(
TaskBootstrap,
MySqlConnection,
MixInMySqlConnection,
mysql_con
);
add_mixin_impl!(
TaskBootstrap,
RedisContext,
MixInRedisContext,
redis_pool_ctxt
);
extern crate macros;
pub mod app;
pub mod domain;
pub mod infra;
/// Add XXXDependencies trait for the struct you want to inject in.
#[macro_export]
macro_rules! add_deps {
($struct_:ident, $($dep_trait_:ident),*) => {
$(
impl $dep_trait_ for $struct_ {}
)*
}
}
/// Add MixInXXX trait.
#[macro_export]
macro_rules! add_mixin {
($trait_:ident, $mixin_trait_:ident, $func_name_:tt) => {
pub trait $mixin_trait_ {
type $trait_: $trait_;
fn $func_name_(&self) -> &Self::$trait_;
}
};
}
/// Add concrete implementation to MixInXXX trait.
#[macro_export]
macro_rules! add_mixin_impl {
($struct_:ident, $trait_:ident, $mixin_trait_: ident, $func_name_:tt) => {
impl $mixin_trait_ for $struct_ {
type $trait_ = Self;
fn $func_name_(&self) -> &Self::$trait_ {
&self
}
}
};
}
/// At last, no need to use below.
extern crate proc_macro;
use crate::proc_macro::TokenStream;
use quote::quote;
#[proc_macro_derive(TaskRepository)]
pub fn mixin_task_repository(input: TokenStream) -> TokenStream {
let input = syn::parse_macro_input!(input as syn::DeriveInput);
let name = &input.ident;
let expanded = quote! {
impl MixInTaskRepository for #name {
type TaskRepository = Self;
fn task_repository(&self) -> &Self::TaskRepository {
&self
}
}
};
TokenStream::from(expanded)
}
#[proc_macro_derive(MySqlConnection)]
pub fn mixin_mysql_connection(input: TokenStream) -> TokenStream {
let input = syn::parse_macro_input!(input as syn::DeriveInput);
let name = &input.ident;
let expanded = quote! {
impl MixInMySqlConnection for #name {
type MySqlConnection = Self;
fn mysql_con(&self) -> &Self::MySqlConnection {
&self
}
}
};
TokenStream::from(expanded)
}
#[proc_macro_derive(RedisContext)]
pub fn mixin_redis_context(input: TokenStream) -> TokenStream {
let input = syn::parse_macro_input!(input as syn::DeriveInput);
let name = &input.ident;
let expanded = quote! {
impl MixInRedisContext for #name {
type RedisContext = Self;
fn redis_pool_ctxt(&self) -> &Self::RedisContext {
&self
}
}
};
TokenStream::from(expanded)
}
use crate::add_mixin;
use crate::domain::entity::task::Task;
pub trait TaskRepository {
fn find_task_by_id(&self, id: String) -> Option<Task>;
}
add_mixin!(TaskRepository, MixInTaskRepository, task_repository);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment