Building some more necessary structures out of the protocol definition
This commit is contained in:
parent
0125605468
commit
6c75996096
101
Cargo.lock
generated
101
Cargo.lock
generated
@ -2,6 +2,48 @@
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "addr2line"
|
||||
version = "0.22.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6e4503c46a5c0c7844e948c9a4d6acd9f50cccb4de1c48eb9e291ea17470c678"
|
||||
dependencies = [
|
||||
"gimli",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "adler"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
|
||||
|
||||
[[package]]
|
||||
name = "backtrace"
|
||||
version = "0.3.73"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5cc23269a4f8976d0a4d2e7109211a419fe30e8d88d677cd60b6bc79c5732e0a"
|
||||
dependencies = [
|
||||
"addr2line",
|
||||
"cc",
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"miniz_oxide",
|
||||
"object",
|
||||
"rustc-demangle",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.0.99"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "96c51067fd44124faa7f870b4b1c969379ad32b2ba805aa959430ceaa384f695"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "eagle"
|
||||
version = "0.1.0"
|
||||
@ -9,8 +51,51 @@ dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gimli"
|
||||
version = "0.29.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.155"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c"
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.7.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
|
||||
|
||||
[[package]]
|
||||
name = "miniz_oxide"
|
||||
version = "0.7.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08"
|
||||
dependencies = [
|
||||
"adler",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "object"
|
||||
version = "0.36.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "576dfe1fc8f9df304abb159d767a29d0476f7750fbf8aa7ad07816004a207434"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pin-project-lite"
|
||||
version = "0.2.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.85"
|
||||
@ -29,6 +114,12 @@ dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc-demangle"
|
||||
version = "0.1.24"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.66"
|
||||
@ -40,6 +131,16 @@ dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio"
|
||||
version = "1.38.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ba4f4a02a7a80d6f274636f0aa95c7e383b912d41fe721a31f29e29698585a4a"
|
||||
dependencies = [
|
||||
"backtrace",
|
||||
"pin-project-lite",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.12"
|
||||
|
@ -8,6 +8,11 @@ license = "AGPL-3.0"
|
||||
proc-macro2 = "1.0.85"
|
||||
quote = "1.0.36"
|
||||
syn = "2.0.66"
|
||||
tokio = { version = "1.38.0", features = ["sync"] }
|
||||
|
||||
[lib]
|
||||
proc-macro = true
|
||||
|
||||
[[test]]
|
||||
name = "tests"
|
||||
path = "tests/mod.rs"
|
@ -32,7 +32,7 @@
|
||||
inherit inputs pkgs;
|
||||
modules = [
|
||||
{
|
||||
packages = with pkgs; [pkg-config];
|
||||
packages = with pkgs; [pkg-config cargo-expand];
|
||||
|
||||
languages.rust.enable = true;
|
||||
languages.rust.channel = "nightly";
|
||||
|
63
src/lib.rs
63
src/lib.rs
@ -16,7 +16,7 @@ You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
use proc_macro::TokenStream;
|
||||
use quote::quote;
|
||||
use quote::{format_ident, quote};
|
||||
use syn::{parse_macro_input, spanned::Spanned, DeriveInput, Field, Ident};
|
||||
|
||||
#[proc_macro_derive(Protocol)]
|
||||
@ -35,7 +35,11 @@ pub fn derive_protocol(input: TokenStream) -> TokenStream {
|
||||
let vis = &input.vis;
|
||||
|
||||
let mut server_trait = Vec::new();
|
||||
let mut server_enum = Vec::new();
|
||||
let mut client_impl = Vec::new();
|
||||
let mut client_enum = Vec::new();
|
||||
|
||||
let mut query_enum = Vec::new();
|
||||
|
||||
for variant in &enum_.variants {
|
||||
// Every variant must have 2 fields
|
||||
@ -55,32 +59,81 @@ pub fn derive_protocol(input: TokenStream) -> TokenStream {
|
||||
let question_args = field_to_args(question_field);
|
||||
let answer_type = variant_fields.next().unwrap().ty.clone();
|
||||
|
||||
// The variants that either the server or the client will use
|
||||
// The "server" enum contains messages the server can send, the "client" enum contains messages the client can send
|
||||
server_enum.push(quote! {
|
||||
#var_name(#answer_type)
|
||||
});
|
||||
client_enum.push(quote! {
|
||||
#var_name(#question_field)
|
||||
});
|
||||
// The function that the server needs to implement
|
||||
server_trait.push(quote! {
|
||||
fn #var_name(&mut self, #question_args) -> #answer_type;
|
||||
});
|
||||
// The function that the client uses to communicate
|
||||
client_impl.push(quote! {
|
||||
pub fn #var_name(&mut self, #question_args) -> #answer_type {
|
||||
::std::unimplemented!()
|
||||
}
|
||||
})
|
||||
});
|
||||
// The query enum is the same as the source enum, but the second field is always wrapped in a Option<>
|
||||
query_enum.push(quote! {
|
||||
#var_name(#question_field, Option<#answer_type>)
|
||||
});
|
||||
}
|
||||
|
||||
// Create enums for the types of messages the server and client will use
|
||||
let server_enum_name = format_ident!("{}Answer", name);
|
||||
let server_enum = quote! {
|
||||
#vis enum #server_enum_name {
|
||||
#(#server_enum), *
|
||||
}
|
||||
};
|
||||
let client_enum_name = format_ident!("{}Question", name);
|
||||
let client_enum = quote! {
|
||||
#vis enum #client_enum_name {
|
||||
#(#client_enum), *
|
||||
}
|
||||
};
|
||||
// Create an enum to represent the queries the client has sent
|
||||
let query_enum_name = format_ident!("{}Query", name);
|
||||
let query_enum = quote! {
|
||||
#vis enum #query_enum_name {
|
||||
#(#query_enum), *
|
||||
}
|
||||
};
|
||||
// Create a trait which the server will have to implement
|
||||
let server_trait_name = Ident::new(&format!("{}Server", name), name.span());
|
||||
let server_trait_name = format_ident!("{}Server", name);
|
||||
let server_trait = quote! {
|
||||
#vis trait #server_trait_name {
|
||||
#(#server_trait)*
|
||||
}
|
||||
};
|
||||
let client_struct_name = Ident::new(&format!("{}Client", name), name.span());
|
||||
// Create a struct which the client will use to communicate
|
||||
let client_struct_name = format_ident!("{}Client", name);
|
||||
let client_struct = quote! {
|
||||
#vis struct #client_struct_name; // TODO: This struct will have some fields to handle the actual connection
|
||||
#vis struct #client_struct_name {
|
||||
queries: ::std::collections::HashMap<u64, #query_enum_name>,
|
||||
send_queue: tokio::sync::mpsc::Sender<#client_enum_name>,
|
||||
recv_queue: tokio::sync::mpsc::Receiver<#server_enum_name>,
|
||||
} // TODO: This struct will have some fields to handle the actual connection
|
||||
impl #client_struct_name {
|
||||
pub fn new(send_queue: tokio::sync::mpsc::Sender<#client_enum_name>, recv_queue: tokio::sync::mpsc::Receiver<#server_enum_name>) -> Self {
|
||||
Self {
|
||||
queries: ::std::collections::HashMap::new(),
|
||||
send_queue,
|
||||
recv_queue,
|
||||
}
|
||||
}
|
||||
#(#client_impl)*
|
||||
}
|
||||
};
|
||||
|
||||
let expanded = quote! {
|
||||
#server_enum
|
||||
#client_enum
|
||||
#query_enum
|
||||
#server_trait
|
||||
#client_struct
|
||||
};
|
||||
|
58
tests/expanded.rs
Normal file
58
tests/expanded.rs
Normal file
@ -0,0 +1,58 @@
|
||||
#![feature(prelude_import)]
|
||||
#[prelude_import]
|
||||
use std::prelude::rust_2021::*;
|
||||
#[macro_use]
|
||||
extern crate std;
|
||||
use eagle::Protocol;
|
||||
enum TestProtocol {
|
||||
Addition((i32, i32), i32),
|
||||
SomeKindOfQuestion(String, i32),
|
||||
}
|
||||
enum TestProtocolAnswer {
|
||||
addition(i32),
|
||||
some_kind_of_question(i32),
|
||||
}
|
||||
enum TestProtocolQuestion {
|
||||
addition((i32, i32)),
|
||||
some_kind_of_question(String),
|
||||
}
|
||||
enum TestProtocolQuery {
|
||||
addition((i32, i32), Option<i32>),
|
||||
some_kind_of_question(String, Option<i32>),
|
||||
}
|
||||
trait TestProtocolServer {
|
||||
fn addition(&mut self, arg0: i32, arg1: i32) -> i32;
|
||||
fn some_kind_of_question(&mut self, arg: String) -> i32;
|
||||
}
|
||||
struct TestProtocolClient {
|
||||
queries: ::std::collections::HashMap<u64, TestProtocolQuery>,
|
||||
send_queue: tokio::sync::mpsc::Sender<TestProtocolQuestion>,
|
||||
recv_queue: tokio::sync::mpsc::Receiver<TestProtocolAnswer>,
|
||||
}
|
||||
impl TestProtocolClient {
|
||||
pub fn new(
|
||||
send_queue: tokio::sync::mpsc::Sender<TestProtocolQuestion>,
|
||||
recv_queue: tokio::sync::mpsc::Receiver<TestProtocolAnswer>,
|
||||
) -> Self {
|
||||
Self {
|
||||
queries: ::std::collections::HashMap::new(),
|
||||
send_queue,
|
||||
recv_queue,
|
||||
}
|
||||
}
|
||||
pub fn addition(&mut self, arg0: i32, arg1: i32) -> i32 {
|
||||
panic!("not implemented")
|
||||
}
|
||||
pub fn some_kind_of_question(&mut self, arg: String) -> i32 {
|
||||
panic!("not implemented")
|
||||
}
|
||||
}
|
||||
struct DummyServer;
|
||||
impl TestProtocolServer for DummyServer {
|
||||
fn some_kind_of_question(&mut self, question: String) -> i32 {
|
||||
question.len() as i32
|
||||
}
|
||||
fn addition(&mut self, arg0: i32, arg1: i32) -> i32 {
|
||||
panic!("not yet implemented")
|
||||
}
|
||||
}
|
@ -33,3 +33,5 @@ impl TestProtocolServer for DummyServer {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
Loading…
Reference in New Issue
Block a user