diff --git a/macros/src/lib.rs b/macros/src/lib.rs index bbd2923..1da5d58 100644 --- a/macros/src/lib.rs +++ b/macros/src/lib.rs @@ -3,13 +3,93 @@ extern crate proc_macro; use proc_macro2::{Ident, Literal, Span, TokenTree}; use proc_macro::TokenStream; use std::iter::FromIterator; -use syn::{parse_macro_input, DeriveInput, Data, PathSegment, TraitItem, FieldsNamed, Fields, Visibility, Type, TypePath, Path, ImplItem, ImplItemConst, Expr, ExprLit, Lit}; +use std::mem; +use syn::{parse_macro_input, DeriveInput, Data, PathSegment, TraitItem, FieldsNamed, Fields, Visibility, Type, TypePath, Path, ImplItem, ImplItemConst, Expr, ExprLit, Lit, TypeParamBound, TraitBound, TraitBoundModifier, LitInt, Token, FnArg, Receiver, PatType, Pat, TypeInfer, TypeReference, TraitItemFn, Signature, Block, Stmt, Local, LocalInit, LitStr, PathArguments}; use quote::{quote, ToTokens, TokenStreamExt}; -use syn::parse::ParseStream; +use syn::buffer::TokenBuffer; +use syn::parse::{Parse, ParseBuffer, ParseStream}; use syn::punctuated::Punctuated; use syn::spanned::Spanned; +use syn::token::Comma; use syn::Visibility::Public; +fn self_referece_type() -> Type { + Type::Reference( + TypeReference { + and_token: Default::default(), + lifetime: None, + mutability: None, + elem: Box::new(Type::Path( + TypePath { + qself: None, + path: Path { + leading_colon: None, + segments: { + let mut punct = Punctuated::new(); + + punct.push_value(PathSegment{ + ident: Ident::new("Self", Span::call_site()), + arguments: PathArguments::None + }); + + punct + } + } + } + )) + } + ) +} + +struct ProtoInputParams{ + proto_num: LitInt, + properties: Option<(Token![,], Punctuated)> +} + +impl Parse for ProtoInputParams{ + fn parse(input: ParseStream) -> syn::Result { + let proto_num = input.parse()?; + + if let Some(seperator) = input.parse()?{ + let mut punctuated = Punctuated::new(); + loop { + punctuated.push_value( + input.parse()? + ); + if let Some(punct) = input.parse()? { + punctuated.push_punct(punct); + } else { + return Ok( + Self{ + proto_num, + properties: Some((seperator, punctuated)) + } + ) + } + } + } else { + Ok( + Self{ + proto_num, + properties: None + } + ) + } + } +} + +fn single_ident_path(ident: Ident) -> Path{ + Path{ + segments: { + let mut punc = Punctuated::new(); + punc.push(PathSegment::from(ident)); + punc + }, + leading_colon: None, + } +} + + /// Example of user-defined [derive mode macro][1] /// /// [1]: https://doc.rust-lang.org/reference/procedural-macros.html#derive-mode-macros @@ -167,7 +247,26 @@ pub fn rmc_serialize(input: TokenStream) -> TokenStream { #[proc_macro_attribute] pub fn rmc_proto(attr: TokenStream, input: TokenStream) -> TokenStream{ - let mut proto_num = parse_macro_input!(attr as syn::LitInt); + + let mut params = parse_macro_input!(attr as ProtoInputParams); + + let ProtoInputParams{ + proto_num, + properties + } = params; + + let no_return_data = properties.is_some_and(|p| p.1.iter().any(|i|{ + i.to_string() == "NoReturn" + })); + + let param_err_return = match no_return_data{ + true => quote!{ + return; + }, + false => quote!{ + return Err(ErrorCode::Core_InvalidArgument); + } + }; let mut input = parse_macro_input!(input as syn::ItemTrait); @@ -175,7 +274,7 @@ pub fn rmc_proto(attr: TokenStream, input: TokenStream) -> TokenStream{ let info_struct_ident = Ident::new(&info_struct_ident, input.ident.span()); let raw_details_struct = syn::ItemStruct{ - vis: Visibility::Public(Default::default()), + vis: Public(Default::default()), struct_token: Default::default(), fields: Fields::Unit, semi_token: Some(Default::default()), @@ -235,9 +334,27 @@ pub fn rmc_proto(attr: TokenStream, input: TokenStream) -> TokenStream{ ] }; - let funcs = input.items.iter().filter_map(|v| if let TraitItem::Fn(v) = v {Some(v)} else { None }); + let mut raw_trait = input.clone(); + + raw_trait.ident = Ident::new(&format!("Raw{}",raw_trait.ident.to_string()), raw_trait.ident.span()); + raw_trait.colon_token = Some(Default::default()); + raw_trait.supertraits = { + let mut punct = Punctuated::new(); + punct.push(TypeParamBound::Trait(TraitBound{ + path: single_ident_path(input.ident.clone()), + lifetimes: None, + modifier: TraitBoundModifier::None, + paren_token: None + })); + punct + }; + + let mut functions: Vec<(LitInt, Ident)> = Vec::new(); + + let funcs = raw_trait.items.iter_mut().filter_map(|v| if let TraitItem::Fn(v) = v {Some(v)} else { None }); for func in funcs{ + if matches!(func.default, Some(_)){ return syn::Error::new(func.default.span(), "rmc methods may not have bodies").to_compile_error().into(); } @@ -248,13 +365,152 @@ pub fn rmc_proto(attr: TokenStream, input: TokenStream) -> TokenStream{ return syn::Error::new(span, "every function inside of an rmc protocol must have a method id").to_compile_error().into(); }; - todo!("generate raw impl") + let Ok(func_id): Result = attr.parse_args() else { + return syn::Error::new(Span::call_site(), "todo: put a propper error message here").to_compile_error().into(); + }; + + + if !func.sig.inputs.first().is_some_and(|v| matches!(v, FnArg::Receiver(Receiver{ + colon_token: None, + mutability: None, + reference: Some(_), + .. + }))){ + return syn::Error::new(func.sig.inputs.span(), "every protocol function must have a ` & self ` as its first parameter.").to_compile_error().into(); + } + + let old_ident = func.sig.ident.clone(); + + func.sig.ident = Ident::new(&format!("raw_{}", func.sig.ident), func.sig.ident.span()); + + let mut new_params: Punctuated<_,_> = Punctuated::new(); + + new_params.push_value(FnArg::Receiver(Receiver{ + attrs: vec![], + mutability: None, + ty: Box::new(self_referece_type()), + colon_token: None, + self_token: Default::default(), + reference: Some((Default::default(), None)) + })); + + new_params.push_punct(Comma::default()); +/* + new_params.push_value(FnArg::Typed(PatType{ + attrs: vec![], + pat: Box::new(Pat::Verbatim(quote! { method_id })), + colon_token: Default::default(), + ty: Box::new(Type::Verbatim(quote!{u32})) + })); + + new_params.push_punct(Comma::default());*/ + + new_params.push_value(FnArg::Typed(PatType{ + attrs: vec![], + pat: Box::new(Pat::Verbatim(quote! {data})), + colon_token: Default::default(), + ty: Box::new(Type::Verbatim(quote!{::std::vec::Vec})) + })); + + mem::swap(&mut new_params, &mut func.sig.inputs); + let old_params = new_params; + + + let mut inner_raw_tokens = quote!{ + let mut cursor = ::std::io::Cursor::new(data); + }; + + let mut call_params = quote!{}; + + + for param in old_params.iter().skip(1).filter_map(|v| if let FnArg::Typed(t) = v { + Some(t) + } else { + None + }){ + let param_name = &*param.pat; + let ty = &*param.ty; + + inner_raw_tokens.append_all(quote!{ + let Ok(#param_name) = <#ty as crate::rmc::structures::RmcSerialize>::deserialize(&mut cursor) else { + #param_err_return + }; + }); + + call_params.append_all(quote!{#param_name ,}) + } + + inner_raw_tokens.append_all(quote!{ + let retval = self.#old_ident(#call_params).await; + }); + + if !no_return_data{ + //let + + //inner_raw_tokens.append_all() + } + + + let braced = quote! { + { + #inner_raw_tokens + } + }; + + let braced = braced.into(); + + func.default = Some( + parse_macro_input!(braced as Block) + ); + + functions.push((func_id, func.sig.ident.clone())); } + let mut inner_match = quote!{}; + + for toks in functions.iter().map(|(lit, ident)|{ + quote! { + #lit => self.#ident(data).await, + } + }){ + inner_match.append_all(toks); + } + + if no_return_data{ + inner_match.append_all(quote!{ + _ => return + }) + } else { + // + inner_match.append_all(quote!{ + _ => return + }) + } + + raw_trait.items.push( + TraitItem::Verbatim( + quote!{ + async fn rmc_call_proto(&self, method_id: u32, data: Vec){ + match method_id{ + #inner_match + } + } + } + ) + ); + + + + let regular_trait_name = &input.ident; + let raw_trait_name = &raw_trait.ident; + quote!{ #input #raw_details_struct #raw_details_impl_block + #raw_trait + + impl #raw_trait_name for T{} }.into() } @@ -293,4 +549,10 @@ pub fn rmc_struct(attr: TokenStream, input: TokenStream) -> TokenStream{ }; out.into() +} + +#[proc_macro_attribute] +pub fn connection(_attr: TokenStream, input: TokenStream) -> TokenStream{ + // this attribute doesnt do anything by itself, see `rmc_struct` + input } \ No newline at end of file diff --git a/src/prudp/socket.rs b/src/prudp/socket.rs index 9c4db03..a0429c8 100644 --- a/src/prudp/socket.rs +++ b/src/prudp/socket.rs @@ -514,9 +514,9 @@ pub struct NewEncryptionPair { pub struct CommonConnection { pub user_id: u32, - session_id: u8, pub socket_addr: PRUDPSockAddr, - pub server_port: VirtualPort + pub server_port: VirtualPort, + session_id: u8, } struct InternalConnection { @@ -670,6 +670,8 @@ impl InternalSocket { .write_to(&mut vec) .expect("somehow failed to convert backet to bytes"); + println!("{}", hex::encode(&vec)); + self.socket .send_to(&vec, dest.regular_socket_addr) .await diff --git a/src/rmc/protocols/mod.rs b/src/rmc/protocols/mod.rs index 5025cb4..2603f8c 100644 --- a/src/rmc/protocols/mod.rs +++ b/src/rmc/protocols/mod.rs @@ -11,10 +11,11 @@ use tokio::sync::{Mutex, Notify}; use tokio::time::{sleep_until, Instant}; use crate::prudp::socket::{ExternalConnection, SendingConnection}; use crate::rmc::structures::connection_data::ConnectionData; +use crate::rmc::structures::matchmake::AutoMatchmakeParam; -struct RmcConnection(SendingConnection, RmcResponseReceiver); +pub struct RmcConnection(pub SendingConnection, pub RmcResponseReceiver); -struct RmcResponseReceiver(Notify, Mutex>>); +pub struct RmcResponseReceiver(Notify, Mutex>>); impl RmcResponseReceiver{ // returns none if timed out @@ -48,17 +49,29 @@ impl RmcResponseReceiver{ } } +pub trait RemoteObject{ + fn new(conn: RmcConnection) -> Self; +} + +impl RemoteObject for (){ + fn new(_: RmcConnection) -> Self {} +} + pub trait RmcCallable{ + //type Remote: RemoteObject; + //fn new_callable(remote: Self::Remote); async fn rmc_call(&self, protocol_id: u16, method_id: u32, rest: Vec); } + + macro_rules! define_rmc_proto { (proto $name:ident{ $($protocol:path),* }) => { paste!{ - trait []: std::any::Any $( + [])* { + trait []: std::any::Any $( + [] + $protocol)* { async fn rmc_call(&self, protocol_id: u16, method_id: u32, rest: Vec){ match protocol_id{ $( @@ -77,16 +90,21 @@ trait RawNotif{ } } +trait Notif{ + +} struct RawNotifInfo; impl RawNotifInfo{ const PROTOCOL_ID: u16 = 10; } -#[rmc_proto(1)] +pub trait ImplementRemoteCalls{} + +#[rmc_proto(1, NoReturn)] pub trait Another{ #[method_id(1)] - async fn test(); + async fn test(&self, thing: AutoMatchmakeParam); } define_rmc_proto!{ @@ -100,6 +118,12 @@ define_rmc_proto!{ #[rmc_struct(TestProto)] struct TestProtoImplementor{ + +} + + + +impl Notif for TestProtoImplementor{ } @@ -107,3 +131,10 @@ impl RawNotif for TestProtoImplementor{ } +impl Another for TestProtoImplementor{ + async fn test(&self, thing: AutoMatchmakeParam) { + + } +} + +impl ImplementRemoteCalls for TestProtoImplementor{} \ No newline at end of file