Derive TypeTagged correctly
This commit is contained in:
parent
ba67c8251d
commit
6d8dd039b3
@ -1,12 +1,13 @@
|
||||
#![recursion_limit="128"]
|
||||
#![recursion_limit = "128"]
|
||||
|
||||
extern crate proc_macro;
|
||||
|
||||
use proc_macro::TokenStream;
|
||||
use syn::{LitStr, Result, parenthesized};
|
||||
use syn::{DeriveInput, punctuated::Punctuated, token::Comma};
|
||||
use syn::parse::{Parse, ParseStream};
|
||||
use quote::quote;
|
||||
use std::fmt::Write;
|
||||
use syn::parse::{Parse, ParseStream};
|
||||
use syn::{parenthesized, LitStr, Result};
|
||||
use syn::{punctuated::Punctuated, token::Comma, DeriveInput};
|
||||
|
||||
fn shared_part(_ast: &syn::DeriveInput, has_shared: bool) -> proc_macro2::TokenStream {
|
||||
if has_shared {
|
||||
@ -38,7 +39,7 @@ fn clone_part(ast: &syn::DeriveInput, has_clone: bool) -> proc_macro2::TokenStre
|
||||
} else {
|
||||
return false;
|
||||
};
|
||||
|
||||
|
||||
into.replace(core::clone::Clone::clone(self));
|
||||
true
|
||||
}
|
||||
@ -55,35 +56,74 @@ fn clone_part(ast: &syn::DeriveInput, has_clone: bool) -> proc_macro2::TokenStre
|
||||
}
|
||||
|
||||
fn type_tag_part(ast: &syn::DeriveInput, type_tag: Option<LitStr>) -> proc_macro2::TokenStream {
|
||||
let name = &ast.ident;
|
||||
let class_name = &ast.ident;
|
||||
let name = if let Some(tt) = type_tag {
|
||||
tt.value()
|
||||
} else {
|
||||
class_name.to_string()
|
||||
};
|
||||
|
||||
let (_, ty_generics, where_clause) = ast.generics.split_for_impl();
|
||||
let mut impl_generics = ast.generics.clone();
|
||||
|
||||
for mut param in impl_generics.params.pairs_mut() {
|
||||
let mut type_name = String::new();
|
||||
let mut type_values = String::from("(");
|
||||
let mut need_close = false;
|
||||
|
||||
write!(&mut type_name, "{}", name).unwrap();
|
||||
for mut param in impl_generics.params.pairs_mut() {
|
||||
match &mut param.value_mut() {
|
||||
syn::GenericParam::Lifetime(_) => continue,
|
||||
syn::GenericParam::Type(param) => {
|
||||
if !need_close {
|
||||
type_name.push('<');
|
||||
need_close = true;
|
||||
} else {
|
||||
type_name.push(',');
|
||||
type_values.push(',');
|
||||
}
|
||||
|
||||
type_name.push_str("{}");
|
||||
|
||||
write!(
|
||||
&mut type_values,
|
||||
"<{} as messagebus::TypeTagged>::type_tag_()",
|
||||
param.ident
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let bound: syn::TypeParamBound = syn::parse_str("messagebus::TypeTagged").unwrap();
|
||||
param.bounds.push(bound);
|
||||
}
|
||||
syn::GenericParam::Const(_) => {}
|
||||
syn::GenericParam::Const(_param) => {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(type_tag) = type_tag {
|
||||
if need_close {
|
||||
type_name.push('>');
|
||||
}
|
||||
|
||||
if type_values.len() > 1 {
|
||||
type_values.push_str(",)");
|
||||
|
||||
let type_values: syn::ExprTuple = syn::parse_str(&type_values).unwrap();
|
||||
let type_values = type_values.elems;
|
||||
|
||||
quote! {
|
||||
impl #impl_generics messagebus::TypeTagged for #name #ty_generics #where_clause {
|
||||
fn type_tag_() -> messagebus::TypeTag { #type_tag.into() }
|
||||
fn type_tag(&self) -> messagebus::TypeTag { #type_tag.into() }
|
||||
fn type_name(&self) -> std::borrow::Cow<str> { #type_tag.into() }
|
||||
impl #impl_generics messagebus::TypeTagged for #class_name #ty_generics #where_clause {
|
||||
fn type_tag_() -> messagebus::TypeTag { format!(#type_name, #type_values).into() }
|
||||
fn type_tag(&self) -> messagebus::TypeTag { Self::type_tag_() }
|
||||
fn type_name(&self) -> std::borrow::Cow<str> { Self::type_tag_() }
|
||||
}
|
||||
}
|
||||
} else {
|
||||
quote! {
|
||||
impl #impl_generics messagebus::TypeTagged for #name #ty_generics #where_clause {
|
||||
fn type_tag_() -> messagebus::TypeTag { std::any::type_name::<Self>().into() }
|
||||
fn type_tag(&self) -> messagebus::TypeTag { std::any::type_name::<Self>().into() }
|
||||
fn type_name(&self) -> std::borrow::Cow<str> { std::any::type_name::<Self>().into() }
|
||||
impl #impl_generics messagebus::TypeTagged for #class_name #ty_generics #where_clause {
|
||||
fn type_tag_() -> messagebus::TypeTag { #type_name.into() }
|
||||
fn type_tag(&self) -> messagebus::TypeTag { Self::type_tag_() }
|
||||
fn type_name(&self) -> std::borrow::Cow<str> { Self::type_tag_() }
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -103,9 +143,11 @@ impl Parse for TypeTag {
|
||||
for pair in punctuated.pairs() {
|
||||
inner = Some(pair.into_value());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(TypeTag { inner: inner.unwrap().to_owned() })
|
||||
Ok(TypeTag {
|
||||
inner: inner.unwrap().to_owned(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@ -126,7 +168,7 @@ impl Parse for Tags {
|
||||
fn parse(input: ParseStream) -> Result<Self> {
|
||||
let mut has_shared = false;
|
||||
let mut has_clone = false;
|
||||
|
||||
|
||||
let content;
|
||||
parenthesized!(content in input);
|
||||
let punctuated = Punctuated::<syn::Ident, Comma>::parse_terminated(&content)?;
|
||||
@ -136,9 +178,9 @@ impl Parse for Tags {
|
||||
match val.as_str() {
|
||||
"shared" => has_shared = true,
|
||||
"clone" => has_clone = true,
|
||||
_ => ()
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(Tags {
|
||||
has_clone,
|
||||
@ -168,7 +210,7 @@ pub fn derive_message(input: TokenStream) -> TokenStream {
|
||||
type_tag = Some(tt.inner);
|
||||
}
|
||||
|
||||
_ => ()
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -206,7 +248,7 @@ pub fn derive_error(input: TokenStream) -> TokenStream {
|
||||
type_tag = Some(tt.inner);
|
||||
}
|
||||
|
||||
_ => ()
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -217,4 +259,4 @@ pub fn derive_error(input: TokenStream) -> TokenStream {
|
||||
};
|
||||
|
||||
tokens.into()
|
||||
}
|
||||
}
|
||||
|
36
tests/test_derive.rs
Normal file
36
tests/test_derive.rs
Normal file
@ -0,0 +1,36 @@
|
||||
use messagebus::{
|
||||
derive::{Error as MbError, Message},
|
||||
error, Message, MessageBounds, TypeTagged,
|
||||
};
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Debug, Error, MbError)]
|
||||
enum Error {
|
||||
#[error("Error({0})")]
|
||||
Error(anyhow::Error),
|
||||
}
|
||||
|
||||
impl<M: Message> From<error::Error<M>> for Error {
|
||||
fn from(err: error::Error<M>) -> Self {
|
||||
Self::Error(err.into())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Message)]
|
||||
#[type_tag("api::Msg")]
|
||||
pub struct Msg<F: MessageBounds + Clone>(pub F);
|
||||
|
||||
#[derive(Debug, Clone, Message)]
|
||||
#[type_tag("api::Query")]
|
||||
pub struct Qqq<F: MessageBounds + Clone, G: MessageBounds + Clone, H: MessageBounds + Clone>(
|
||||
pub F,
|
||||
pub G,
|
||||
pub H,
|
||||
);
|
||||
|
||||
fn main() {
|
||||
assert_eq!(
|
||||
Qqq::<Msg<i32>, Msg<()>, u64>::type_tag_(),
|
||||
"api::Query<api::Msg<i32>,api::Msg<()>,u64>"
|
||||
);
|
||||
}
|
@ -11,144 +11,6 @@ use parking_lot::Mutex;
|
||||
use thiserror::Error;
|
||||
use tokio::sync::mpsc;
|
||||
|
||||
// macro_rules! type_map {
|
||||
// (inbound : $($tt:tt)*) => {{
|
||||
// let mut type_map = TypeMap::new();
|
||||
// type_map!(@inbound type_map, $($tt)*);
|
||||
// type_map
|
||||
// }};
|
||||
|
||||
// (outbound : $($tt:tt)*) => {
|
||||
// let mut type_map = TypeMap::new();
|
||||
// type_map!(@outbound type_map, $($tt)*);
|
||||
// type_map
|
||||
// };
|
||||
|
||||
// (@inbound $tm: ident, $msg:ty => $resp: ty, $($tt:tt)*) => {
|
||||
// $tm.add_inbound(<$msg as TypeTagged>::type_tag_(), <$resp as TypeTagged>::type_tag_(), None);
|
||||
// type_map!(@inbound $tm, $($tt)*)
|
||||
// };
|
||||
|
||||
// (@inbound $tm: ident, $msg:ty => ($resp:ty) throws $err: ty, $($tt:tt)*) => {
|
||||
// $tm.add_inbound(<$msg as messagebus::TypeTagged>::type_tag_(), <$resp as messagebus:TypeTagged>::type_tag_(), Some(<$err as messagebus::TypeTagged>::type_tag_()));
|
||||
// type_map!(@inbound $tm, $($tt)*)
|
||||
// };
|
||||
|
||||
// (@inbound $tm: ident, $msg:ty => $resp: ty) => {
|
||||
// $tm.add_inbound(<$msg as TypeTagged>::type_tag_(), <$resp as TypeTagged>::type_tag_(), None);
|
||||
// };
|
||||
|
||||
// (@inbound $tm: ident, outbound : $($tt:tt)*) => {
|
||||
// type_map!(@outbound $tm, $($tt)*)
|
||||
// };
|
||||
|
||||
// (@inbound $tm: ident,) => {};
|
||||
|
||||
// (@outbound $tm: ident, $msg:ty => ($resp:ty) throws $err: ty, $($tt:tt)*) => {
|
||||
// $tm.add_outbound(<$msg as TypeTagged>::type_tag_(), <$resp as TypeTagged>::type_tag_(), Some(<$err as TypeTagged>::type_tag_()));
|
||||
// type_map!(@outbound $tm, $($tt)*)
|
||||
// };
|
||||
|
||||
// (@outbound $tm: ident, $msg:ty => $resp: ty, $($tt:tt)*) => {
|
||||
// $tm.add_outbound(<$msg as TypeTagged>::type_tag_(), <$resp as TypeTagged>::type_tag_(), None);
|
||||
// type_map!(@outbound $tm, $($tt)*)
|
||||
// };
|
||||
|
||||
// (@outbound $tm: ident, $msg:ty => $resp: ty) => {
|
||||
// $tm.add_outbound(<$msg as TypeTagged>::type_tag_(), <$resp as TypeTagged>::type_tag_(), None);
|
||||
// };
|
||||
|
||||
// (@outbound $tm: ident, inbound : $($tt:tt)*) => {
|
||||
// type_map!(@inbound $tm, $($tt)*)
|
||||
// };
|
||||
|
||||
// (@outbound $tm: ident,) => {};
|
||||
// }
|
||||
|
||||
// #[derive(Debug, Clone)]
|
||||
// pub struct TypeMap {
|
||||
// inbound: HashMap<TypeTag, Vec<(TypeTag, Option<TypeTag>)>>,
|
||||
// outbound: HashMap<TypeTag, Vec<(TypeTag, Option<TypeTag>)>>,
|
||||
// }
|
||||
|
||||
// impl TypeMap {
|
||||
// pub fn new() -> Self {
|
||||
// Self {
|
||||
// inbound: Default::default(),
|
||||
// outbound: Default::default(),
|
||||
// }
|
||||
// }
|
||||
|
||||
// pub fn add_inbound(&mut self, msg: TypeTag, resp: TypeTag, err: Option<TypeTag>) -> &mut Self {
|
||||
// let vec = self.inbound.entry(msg)
|
||||
// .or_insert_with(Vec::new);
|
||||
|
||||
// vec.push((resp, err));
|
||||
// self
|
||||
// }
|
||||
|
||||
// pub fn add_outbound(&mut self, msg: TypeTag, resp: TypeTag, err: Option<TypeTag>) -> &mut Self {
|
||||
// let vec = self.outbound.entry(msg)
|
||||
// .or_insert_with(Vec::new);
|
||||
|
||||
// vec.push((resp, err));
|
||||
// self
|
||||
// }
|
||||
|
||||
// pub fn accept_inbound(&self, msg: &TypeTag, resp: Option<&TypeTag>, err: Option<&TypeTag>) -> bool {
|
||||
// if let Some(vec) = self.inbound.get(msg) {
|
||||
// if let Some(rr) = resp {
|
||||
// vec.iter().find(|(r, e)| {
|
||||
// let ee = if let Some(e) = e {
|
||||
// if let Some(te) = err {
|
||||
// te.as_ref() == e.as_ref()
|
||||
// } else {
|
||||
// true
|
||||
// }
|
||||
// } else {
|
||||
// err.is_none()
|
||||
// };
|
||||
|
||||
// r.as_ref() == rr.as_ref() && ee
|
||||
// }).is_some()
|
||||
// } else {
|
||||
// true
|
||||
// }
|
||||
// } else {
|
||||
// false
|
||||
// }
|
||||
// }
|
||||
|
||||
// pub fn accept_outbound(&self, msg: &TypeTag, resp: Option<&TypeTag>, err: Option<&TypeTag>) -> bool {
|
||||
// if let Some(vec) = self.outbound.get(msg) {
|
||||
// if let Some(rr) = resp {
|
||||
// vec.iter().find(|(r, e)| {
|
||||
// let ee = if let Some(e) = e {
|
||||
// if let Some(te) = err {
|
||||
// te.as_ref() == e.as_ref()
|
||||
// } else {
|
||||
// true
|
||||
// }
|
||||
// } else {
|
||||
// err.is_none()
|
||||
// };
|
||||
|
||||
// r.as_ref() == rr.as_ref() && ee
|
||||
// }).is_some()
|
||||
// } else {
|
||||
// true
|
||||
// }
|
||||
// } else {
|
||||
// false
|
||||
// }
|
||||
// }
|
||||
|
||||
// #[inline]
|
||||
// pub fn inbound_iter(&self) -> impl Iterator<Item = (&TypeTag, &TypeTag, Option<&TypeTag>)> {
|
||||
// self.inbound.iter().map(|(k, v)| v.into_iter().map(move |(r, e)|(k, r, e.as_ref()))).flatten()
|
||||
// }
|
||||
// }
|
||||
|
||||
#[derive(Debug, Error, MbError)]
|
||||
enum Error {
|
||||
#[error("Error({0})")]
|
||||
|
Loading…
Reference in New Issue
Block a user