From 5782951e6893981b03cffe95698933b6276c61b9 Mon Sep 17 00:00:00 2001 From: Maple Date: Wed, 12 Nov 2025 22:41:34 +0100 Subject: [PATCH] optimize --- Cargo.lock | 245 ++++++++++ macros/src/lib.rs | 64 ++- macros/src/protos.rs | 2 + prudpv1/src/executables/proxy_insecure.rs | 4 +- prudpv1/src/executables/proxy_secure.rs | 4 +- rnex-core/Cargo.toml | 8 +- rnex-core/benches/rmc_serialization.rs | 99 ++++ .../executables/backend_server_insecure.rs | 2 +- rnex-core/src/kerberos/mod.rs | 4 +- rnex-core/src/lib.rs | 4 + rnex-core/src/main.rs | 447 ++++-------------- rnex-core/src/nex/auth_handler.rs | 2 + rnex-core/src/prudp/station_url.rs | 70 +-- rnex-core/src/rmc/structures/any.rs | 4 +- rnex-core/src/rmc/structures/buffer.rs | 16 +- rnex-core/src/rmc/structures/helpers.rs | 48 ++ rnex-core/src/rmc/structures/list.rs | 30 +- rnex-core/src/rmc/structures/mod.rs | 41 +- rnex-core/src/rmc/structures/networking.rs | 14 +- rnex-core/src/rmc/structures/primitives.rs | 213 +++++++-- rnex-core/src/rmc/structures/qbuffer.rs | 4 +- rnex-core/src/rmc/structures/qresult.rs | 4 +- rnex-core/src/rmc/structures/rmc_struct.rs | 104 +++- rnex-core/src/rmc/structures/string.rs | 32 +- rnex-core/src/rmc/structures/variant.rs | 4 +- 25 files changed, 962 insertions(+), 507 deletions(-) create mode 100644 rnex-core/benches/rmc_serialization.rs create mode 100644 rnex-core/src/rmc/structures/helpers.rs diff --git a/Cargo.lock b/Cargo.lock index 82797de..7965148 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -41,6 +41,24 @@ dependencies = [ "libc", ] +[[package]] +name = "anes" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" + +[[package]] +name = "anstyle" +version = "1.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78" + +[[package]] +name = "anyhow" +version = "1.0.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61" + [[package]] name = "async-stream" version = "0.3.6" @@ -222,6 +240,12 @@ version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" +[[package]] +name = "cast" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" + [[package]] name = "cc" version = "1.2.31" @@ -257,6 +281,33 @@ dependencies = [ "windows-link", ] +[[package]] +name = "ciborium" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42e69ffd6f0917f5c029256a24d0161db17cea3997d185db0d35926308770f0e" +dependencies = [ + "ciborium-io", + "ciborium-ll", + "serde", +] + +[[package]] +name = "ciborium-io" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05afea1e0a06c9be33d539b876f1ce3692f4afea2cb41f740e7743225ed1c757" + +[[package]] +name = "ciborium-ll" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57663b653d948a338bfb3eeba9bb2fd5fcfaecb9e199e87e1eda4d9e8b240fd9" +dependencies = [ + "ciborium-io", + "half", +] + [[package]] name = "cipher" version = "0.4.4" @@ -267,6 +318,31 @@ dependencies = [ "inout", ] +[[package]] +name = "clap" +version = "4.5.51" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c26d721170e0295f191a69bd9a1f93efcdb0aff38684b61ab5750468972e5f5" +dependencies = [ + "clap_builder", +] + +[[package]] +name = "clap_builder" +version = "4.5.51" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75835f0c7bf681bfd05abe44e965760fea999a5286c6eb2d59883634fd02011a" +dependencies = [ + "anstyle", + "clap_lex", +] + +[[package]] +name = "clap_lex" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1d728cc89cf3aee9ff92b05e62b19ee65a02b5702cff7d5a377e32c6ae29d8d" + [[package]] name = "cookie" version = "0.18.1" @@ -294,6 +370,70 @@ version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" +[[package]] +name = "criterion" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1c047a62b0cc3e145fa84415a3191f628e980b194c2755aa12300a4e6cbd928" +dependencies = [ + "anes", + "cast", + "ciborium", + "clap", + "criterion-plot", + "itertools", + "num-traits", + "oorandom", + "plotters", + "rayon", + "regex", + "serde", + "serde_json", + "tinytemplate", + "walkdir", +] + +[[package]] +name = "criterion-plot" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b1bcc0dc7dfae599d84ad0b1a55f80cde8af3725da8313b528da95ef783e338" +dependencies = [ + "cast", + "itertools", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" + +[[package]] +name = "crunchy" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" + [[package]] name = "crypto-common" version = "0.1.6" @@ -626,6 +766,17 @@ dependencies = [ "tracing", ] +[[package]] +name = "half" +version = "2.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ea2d84b969582b4b1864a92dc5d27cd2b77b622a8d79306834f1be5ba20d84b" +dependencies = [ + "cfg-if", + "crunchy", + "zerocopy", +] + [[package]] name = "hashbrown" version = "0.12.3" @@ -1048,6 +1199,15 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "itertools" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" +dependencies = [ + "either", +] + [[package]] name = "itoa" version = "1.0.15" @@ -1308,6 +1468,12 @@ version = "1.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" +[[package]] +name = "oorandom" +version = "11.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6790f58c7ff633d8771f42965289203411a5e5c68388703c06e14f24770b41e" + [[package]] name = "openssl" version = "0.10.73" @@ -1454,6 +1620,34 @@ version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" +[[package]] +name = "plotters" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5aeb6f403d7a4911efb1e33402027fc44f29b5bf6def3effcc22d7bb75f2b747" +dependencies = [ + "num-traits", + "plotters-backend", + "plotters-svg", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "plotters-backend" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df42e13c12958a16b3f7f4386b9ab1f3e7933914ecea48da7139435263a4172a" + +[[package]] +name = "plotters-svg" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51bae2ac328883f7acdfea3d66a7c35751187f870bc81f94563733a154d7a670" +dependencies = [ + "plotters-backend", +] + [[package]] name = "potential_utf" version = "0.1.2" @@ -1572,6 +1766,26 @@ dependencies = [ "getrandom 0.2.16", ] +[[package]] +name = "rayon" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "368f01d005bf8fd9b1206fb6fa653e6c4a81ceb1466406b81792d87c5677a58f" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22e18b0f0062d30d4230b2e85ff77fdfe4326feb054b9783a3460d8435c8ab91" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] + [[package]] name = "rc4" version = "0.1.0" @@ -1714,9 +1928,11 @@ dependencies = [ name = "rnex-core" version = "0.1.1" dependencies = [ + "anyhow", "async-trait", "bytemuck", "chrono", + "criterion", "ctrlc", "dotenv", "hex", @@ -1885,6 +2101,15 @@ version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + [[package]] name = "schannel" version = "0.1.27" @@ -2242,6 +2467,16 @@ dependencies = [ "zerovec", ] +[[package]] +name = "tinytemplate" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc" +dependencies = [ + "serde", + "serde_json", +] + [[package]] name = "tokio" version = "1.47.1" @@ -2607,6 +2842,16 @@ version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] + [[package]] name = "want" version = "0.3.1" diff --git a/macros/src/lib.rs b/macros/src/lib.rs index 39639b3..67486ef 100644 --- a/macros/src/lib.rs +++ b/macros/src/lib.rs @@ -48,7 +48,7 @@ impl Parse for ProtoInputParams { fn gen_serialize_data_struct( s: DataStruct, struct_attr: Option<&Attribute>, -) -> (proc_macro2::TokenStream, proc_macro2::TokenStream) { +) -> (proc_macro2::TokenStream, proc_macro2::TokenStream, proc_macro2::TokenStream) { let serialize_base_content = { let mut serialize_content = quote! {}; @@ -119,6 +119,29 @@ fn gen_serialize_data_struct( } }; + let write_size = { + let mut size_content = quote! { 0 }; + + for f in &s.fields { + + + let ident = f.ident.as_ref().unwrap(); + let ty = &f.ty; + + size_content.append_all(quote! { + + rnex_core::rmc::structures::RmcSerialize::serialize_write_size(&self.#ident)? + }) + } + + size_content + }; + let write_size = if let Some(_) = struct_attr { + quote!{ #write_size + if rnex_core::config::FEATURE_HAS_STRUCT_HEADER{ 5 } else { 0 } } + } else { + write_size + }; + + // generate base with extends stuff let serialize_base_content = if let Some(attr) = struct_attr { @@ -143,9 +166,18 @@ fn gen_serialize_data_struct( quote! { #pre_inner - rnex_core::rmc::structures::rmc_struct::write_struct(writer, #version, |mut writer|{ - #serialize_base_content - })?; + rnex_core::rmc::structures::rmc_struct::write_struct( + writer, + #version, + rnex_core::rmc::structures::helpers::len_of_write( + |writer|{ + #serialize_base_content + } + ), + |writer|{ + #serialize_base_content + } + )?; Ok(()) } @@ -184,7 +216,13 @@ fn gen_serialize_data_struct( deserialize_base_content }; - (serialize_base_content, deserialize_base_content) + let write_size = quote!{ + fn serialize_write_size(&self) -> rnex_core::rmc::structures::Result{ + Ok(#write_size) + } + }; + + (serialize_base_content, deserialize_base_content, write_size) } #[proc_macro_derive(RmcSerialize, attributes(extends, rmc_struct))] @@ -210,7 +248,7 @@ pub fn rmc_serialize(input: TokenStream) -> TokenStream { panic!("rmc struct type MUST be a struct"); };*/ - let (serialize_base_content, deserialize_base_content) = match derive_input.data { + let (serialize_base_content, deserialize_base_content, write_size) = match derive_input.data { Data::Struct(s) => gen_serialize_data_struct(s, struct_attr), Data::Enum(e) => { let Some(repr_attr) = repr_attr else { @@ -221,6 +259,7 @@ pub fn rmc_serialize(input: TokenStream) -> TokenStream { let mut inner_match_de = quote! {}; let mut inner_match_se = quote! {}; + let mut inner_match_len = quote!{}; for variant in e.variants { let Some((_, val)) = variant.discriminant else { @@ -352,7 +391,7 @@ pub fn rmc_serialize(input: TokenStream) -> TokenStream { Ok(val) }; - (serialize_base_content, deserialize_base_content) + (serialize_base_content, deserialize_base_content, quote!{}) } Data::Union(_) => { unimplemented!() @@ -365,15 +404,16 @@ pub fn rmc_serialize(input: TokenStream) -> TokenStream { let tokens = quote! { impl rnex_core::rmc::structures::RmcSerialize for #ident{ - fn serialize(&self, writer: &mut dyn ::std::io::Write) -> rnex_core::rmc::structures::Result<()>{ + #[inline(always)] + fn serialize(&self, writer: &mut impl ::std::io::Write) -> rnex_core::rmc::structures::Result<()>{ #serialize_base_content - - } - - fn deserialize(reader: &mut dyn ::std::io::Read) -> rnex_core::rmc::structures::Result{ + #[inline(always)] + fn deserialize(reader: &mut impl ::std::io::Read) -> rnex_core::rmc::structures::Result{ #deserialize_base_content } + + #write_size } }; diff --git a/macros/src/protos.rs b/macros/src/protos.rs index a19f01e..7dd7bf1 100644 --- a/macros/src/protos.rs +++ b/macros/src/protos.rs @@ -55,6 +55,7 @@ impl RmcProtocolData{ let raw_name = Ident::new(&format!("raw_{}", name), name.span()); quote!{ + #[inline(always)] async fn #raw_name }.to_tokens(tokens); @@ -125,6 +126,7 @@ impl RmcProtocolData{ } quote!{ + #[inline(always)] async fn rmc_call_proto( &self, remote_response_connection: &rnex_core::util::SendingBufferConnection, diff --git a/prudpv1/src/executables/proxy_insecure.rs b/prudpv1/src/executables/proxy_insecure.rs index cbfacec..50446d5 100644 --- a/prudpv1/src/executables/proxy_insecure.rs +++ b/prudpv1/src/executables/proxy_insecure.rs @@ -31,7 +31,7 @@ async fn main() { let conn: SplittableBufferConnection = conn.into(); - conn.send(Register(SocketAddrV4::new(*OWN_IP_PUBLIC, *SERVER_PORT)).to_data()).await; + conn.send(Register(SocketAddrV4::new(*OWN_IP_PUBLIC, *SERVER_PORT)).to_data().unwrap()).await; let conn = new_rmc_gateway_connection(conn, |r| Arc::new(OnlyRemote::::new(r))); @@ -67,7 +67,7 @@ async fn main() { if let Err(e) = stream.send_buffer(&ConnectionInitData{ prudpsock_addr: conn.socket_addr, pid: conn.user_id - }.to_data()).await{ + }.to_data().unwrap()).await{ error!("error connecting to backend: {}", e); return; }; diff --git a/prudpv1/src/executables/proxy_secure.rs b/prudpv1/src/executables/proxy_secure.rs index b25a03a..d11b944 100644 --- a/prudpv1/src/executables/proxy_secure.rs +++ b/prudpv1/src/executables/proxy_secure.rs @@ -28,7 +28,7 @@ async fn main() { let conn: SplittableBufferConnection = conn.into(); - conn.send(Register(SocketAddrV4::new(*OWN_IP_PUBLIC, *SERVER_PORT)).to_data()).await; + conn.send(Register(SocketAddrV4::new(*OWN_IP_PUBLIC, *SERVER_PORT)).to_data().unwrap()).await; let conn = new_rmc_gateway_connection(conn, |r| Arc::new(OnlyRemote::::new(r))); @@ -67,7 +67,7 @@ async fn main() { if let Err(e) = stream.send_buffer(&ConnectionInitData{ prudpsock_addr: conn.socket_addr, pid: conn.user_id - }.to_data()).await{ + }.to_data().unwrap()).await{ error!("error connecting to backend: {}", e); return; }; diff --git a/rnex-core/Cargo.toml b/rnex-core/Cargo.toml index 90ce871..b609afb 100644 --- a/rnex-core/Cargo.toml +++ b/rnex-core/Cargo.toml @@ -29,9 +29,15 @@ typenum = "1.18.0" reqwest = { version= "0.12.18", features = ["blocking"]} json = "0.12.4" ctrlc = "3.4.7" +criterion = "0.7.0" +anyhow = "1.0.100" +[features] +rmc_struct_header = [] - +[[bench]] +name = "rmc_serialization" +harness = false [[bin]] name = "backend_server_insecure" diff --git a/rnex-core/benches/rmc_serialization.rs b/rnex-core/benches/rmc_serialization.rs new file mode 100644 index 0000000..4b506f8 --- /dev/null +++ b/rnex-core/benches/rmc_serialization.rs @@ -0,0 +1,99 @@ +use std::hint::black_box; +use std::io::Cursor; +use std::ops::Deref; +use criterion::{criterion_group, criterion_main, Criterion}; +use once_cell::sync::Lazy; +use rnex_core::kerberos::KerberosDateTime; +use rnex_core::rmc::structures::matchmake::{AutoMatchmakeParam, Gathering, MatchmakeParam, MatchmakeSession, MatchmakeSessionSearchCriteria}; +use rnex_core::rmc::structures::RmcSerialize; +use rnex_core::rmc::structures::variant::Variant; + +static DUMMY: Lazy = Lazy::new(|| AutoMatchmakeParam{ + additional_participants: vec![1,2,3,4], + auto_matchmake_option: 10, + gid_for_participation_check: 9, + join_message: "hi".to_string(), + participation_count: 32, + target_gids: vec![45,2,51,1,1,1,1], + search_criteria: vec![MatchmakeSessionSearchCriteria{ + attribs: vec!["hi".to_string(), "ig".to_string(), "gotta put data here".to_string()], + exclude_locked: true, + exclude_non_host_pid: false, + exclude_system_password_set: true, + exclude_user_password_set: false, + game_mode: "some gamemode".to_string(), + matchmake_param: MatchmakeParam{ + params: vec![ + ("SR".to_string(), Variant::Bool(true)), + ("SR2".to_string(), Variant::Double(1.0)), + ("SR3".to_string(), Variant::SInt64(42)), + ("SR4".to_string(), Variant::String("test".to_string())) + ] + }, + matchmake_system_type: "some type".to_string(), + maximum_participants: "???".to_string(), + minimum_participants: "-99".to_string(), + refer_gid: 123, + selection_method: 9999999, + vacant_only: true, + vacant_participants: 1000 + }], + matchmake_session: MatchmakeSession{ + refer_gid: 10, + matchmake_system_type: 139, + matchmake_param: MatchmakeParam{ + params: vec![ + ("QSR".to_string(), Variant::Bool(false)), + ("SRQ2".to_string(), Variant::Double(1.1)), + ("SQR3".to_string(), Variant::SInt64(422)), + ("SDR4".to_string(), Variant::String("tetst".to_string())) + ] + }, + participation_count: 99, + application_buffer: vec![1,2,3,4,5,6,7,8,9], + attributes: vec![10,20,99,100000], + datetime: KerberosDateTime::now(), + gamemode: 111, + open_participation: false, + option0: 100, + progress_score: 1, + system_password_enabled: false, + user_password: "aaa".to_string(), + session_key: vec![91,123,5,2,1,2,4,124,4], + user_password_enabled: false, + gathering: Gathering{ + minimum_participants: 1, + maximum_participants: 12, + description: "aaargh".to_string(), + flags: 100, + host_pid: 999999919, + owner_pid: 138830, + participant_policy: 1, + policy_argument: 99837, + self_gid: 129, + state: 1389488 + } + } +}); + +static DUMMY_SER: Lazy> = Lazy::new(|| serialize_to_vec(DUMMY.deref())); + +fn serialize_to_vec(r: &impl RmcSerialize) -> Vec{ + let mut vec = r.to_data(); + + vec.unwrap() +} + +fn read_struct(r: &[u8]) -> T{ + T::deserialize(&mut Cursor::new(r)).unwrap() +} +fn matchmake_with_param(c: &mut Criterion) { + let raw = DUMMY.deref(); + let ser = DUMMY_SER.deref().as_slice(); + c.bench_function("mmparam: ser", |b| b.iter(move || serialize_to_vec(black_box(raw)))); + c.bench_function("mmparam: de", |b| b.iter(move || read_struct::(black_box(ser)))); +} + +criterion_group!(benches, matchmake_with_param); +criterion_main!(benches); + diff --git a/rnex-core/src/executables/backend_server_insecure.rs b/rnex-core/src/executables/backend_server_insecure.rs index 6b2625c..4cbe591 100644 --- a/rnex-core/src/executables/backend_server_insecure.rs +++ b/rnex-core/src/executables/backend_server_insecure.rs @@ -30,7 +30,7 @@ async fn main() { let conn: SplittableBufferConnection = conn.into(); - conn.send(DontRegister.to_data()).await; + conn.send(DontRegister.to_data().unwrap()).await; let conn = new_rmc_gateway_connection(conn, |r| Arc::new(OnlyRemote::::new(r))); diff --git a/rnex-core/src/kerberos/mod.rs b/rnex-core/src/kerberos/mod.rs index 09dc46c..a54764e 100644 --- a/rnex-core/src/kerberos/mod.rs +++ b/rnex-core/src/kerberos/mod.rs @@ -83,11 +83,11 @@ impl KerberosDateTime{ } impl RmcSerialize for KerberosDateTime{ - fn serialize(&self, writer: &mut dyn Write) -> crate::rmc::structures::Result<()> { + fn serialize(&self, writer: &mut impl Write) -> crate::rmc::structures::Result<()> { Ok(self.0.serialize(writer)?) } - fn deserialize(reader: &mut dyn Read) -> crate::rmc::structures::Result { + fn deserialize(reader: &mut impl Read) -> crate::rmc::structures::Result { Ok(Self(u64::deserialize(reader)?)) } } diff --git a/rnex-core/src/lib.rs b/rnex-core/src/lib.rs index 21b354a..4a4f1ef 100644 --- a/rnex-core/src/lib.rs +++ b/rnex-core/src/lib.rs @@ -24,3 +24,7 @@ pub mod rnex_proxy_common; pub mod util; pub mod executables; pub use macros::*; + +pub mod config{ + pub const FEATURE_HAS_STRUCT_HEADER: bool = cfg!(feature = "rmc_struct_header"); +} diff --git a/rnex-core/src/main.rs b/rnex-core/src/main.rs index 0af4975..cfa323d 100644 --- a/rnex-core/src/main.rs +++ b/rnex-core/src/main.rs @@ -20,6 +20,8 @@ use std::fs::File; use std::net::{Ipv4Addr}; use std::sync::Once; use std::{env, fs}; +use std::hint::black_box; +use criterion::{criterion_group, criterion_main, Criterion}; mod prudp; pub mod rmc; @@ -35,360 +37,111 @@ pub mod reggie; pub mod util; pub mod common; - - -static KERBEROS_SERVER_PASSWORD: Lazy = Lazy::new(|| { - env::var("AUTH_SERVER_PASSWORD") - .ok() - .unwrap_or("password".to_owned()) -}); - -static AUTH_SERVER_ACCOUNT: Lazy = - Lazy::new(|| Account::new(1, "Quazal Authentication", &KERBEROS_SERVER_PASSWORD)); -static SECURE_SERVER_ACCOUNT: Lazy = - Lazy::new(|| Account::new(2, "Quazal Rendez-Vous", &KERBEROS_SERVER_PASSWORD)); - -static AUTH_SERVER_PORT: Lazy = Lazy::new(|| { - env::var("AUTH_SERVER_PORT") - .ok() - .and_then(|s| s.parse().ok()) - .unwrap_or(10000) -}); -static SECURE_SERVER_PORT: Lazy = Lazy::new(|| { - env::var("SECURE_SERVER_PORT") - .ok() - .and_then(|s| s.parse().ok()) - .unwrap_or(10001) -}); - -static OWN_IP_PRIVATE: Lazy = Lazy::new(|| { - env::var("SERVER_IP") - .ok() - .and_then(|s| s.parse().ok()) - .expect("no private ip specified") -}); - -static OWN_IP_PUBLIC: Lazy = - Lazy::new(|| env::var("SERVER_IP_PUBLIC").unwrap_or(OWN_IP_PRIVATE.to_string())); - -static SECURE_STATION_URL: Lazy = Lazy::new(|| { - format!( - "prudps:/PID=2;sid=1;stream=10;type=2;address={};port={};CID=1", - *OWN_IP_PUBLIC, *SECURE_SERVER_PORT - ) -}); - -static FORCE_EXIT: Once = Once::new(); - -#[tokio::main] -async fn main() { - CombinedLogger::init(vec![ - TermLogger::new( - LevelFilter::Info, - Config::default(), - TerminalMode::Mixed, - ColorChoice::Auto, - ), - WriteLogger::new(LevelFilter::max(), Config::default(), { - fs::create_dir_all("log").unwrap(); - let date = Local::now().to_rfc3339_opts(SecondsFormat::Secs, false); - // this fixes windows being windows - let date = date.replace(":", "-"); - let filename = format!("{}.log", date); - if cfg!(windows) { - File::create(format!("log\\{}", filename)).unwrap() - } else { - File::create(format!("log/{}", filename)).unwrap() - } - }), - ]) - .unwrap(); - - ctrlc::set_handler(||{ - FORCE_EXIT.call_once_force(|_|{ - println!("attempting exit"); - }); - }).unwrap(); - - dotenv::dotenv().ok(); - - //start_servers().await; -} -/* - -struct AuthServer{ - router: Arc, - join_handle: JoinHandle<()>, - socket: Socket +pub mod config{ + pub const FEATURE_HAS_STRUCT_HEADER: bool = cfg!(feature = "rmc_struct_header"); } -async fn start_auth_server() -> AuthServer{ - info!("starting auth server on {}:{}", *OWN_IP_PRIVATE, *AUTH_SERVER_PORT); +use std::io::Cursor; +use std::ops::Deref; +use rnex_core::kerberos::KerberosDateTime; +use rnex_core::rmc::structures::matchmake::{AutoMatchmakeParam, Gathering, MatchmakeParam, MatchmakeSession, MatchmakeSessionSearchCriteria}; +use rnex_core::rmc::structures::RmcSerialize; +use rnex_core::rmc::structures::variant::Variant; - let (router, join_handle) = - Router::new(SocketAddrV4::new(*OWN_IP_PRIVATE, *AUTH_SERVER_PORT)).await - .expect("unable to startauth server"); - - info!("setting up endpoints"); - - // dont assign it to the name _ as that will make it drop right here and now - - let auth_protocol_config = AuthProtocolConfig{ - secure_server_account: &SECURE_SERVER_ACCOUNT, - build_name: "branch:origin/project/wup-agmj build:3_8_15_2004_0", - station_url: &SECURE_STATION_URL - }; - - let rmcserver = RMCProtocolServer::new(Box::new([ - Box::new(auth::bound_protocol(auth_protocol_config)) - ])); - - let socket = - Socket::new( - router.clone(), - VirtualPort::new(1,10), - "6f599f81", - Box::new(|_, count|{ - Box::pin( - async move { - - - let encryption_pairs = Vec::from_iter((0..=count).map(|_v| { - let rc4: Rc4 = Rc4::new_from_slice( "CD&ML".as_bytes()).unwrap(); - let cypher = Box::new(rc4); - let server_cypher: Box = cypher; - - let rc4: Rc4 = Rc4::new_from_slice( "CD&ML".as_bytes()).unwrap(); - let cypher = Box::new(rc4); - let client_cypher: Box = cypher; - - EncryptionPair{ - recv: client_cypher, - send: server_cypher - } - })); - - Some((Vec::new(), encryption_pairs, None)) - } - ) - }), - Box::new(move |packet, socket, connection|{ - let rmcserver = rmcserver.clone(); - Box::pin(async move { rmcserver.process_message(packet, socket, connection).await; }) - }) - ).await.expect("unable to create socket"); - - AuthServer{ - join_handle, - router, - socket, +static DUMMY: Lazy = Lazy::new(|| AutoMatchmakeParam{ + additional_participants: vec![1,2,3,4], + auto_matchmake_option: 10, + gid_for_participation_check: 9, + join_message: "hi".to_string(), + participation_count: 32, + target_gids: vec![45,2,51,1,1,1,1], + search_criteria: vec![MatchmakeSessionSearchCriteria{ + attribs: vec!["hi".to_string(), "ig".to_string(), "gotta put data here".to_string()], + exclude_locked: true, + exclude_non_host_pid: false, + exclude_system_password_set: true, + exclude_user_password_set: false, + game_mode: "some gamemode".to_string(), + matchmake_param: MatchmakeParam{ + params: vec![ + ("SR".to_string(), Variant::Bool(true)), + ("SR2".to_string(), Variant::Double(1.0)), + ("SR3".to_string(), Variant::SInt64(42)), + ("SR4".to_string(), Variant::String("test".to_string())) + ] + }, + matchmake_system_type: "some type".to_string(), + maximum_participants: "???".to_string(), + minimum_participants: "-99".to_string(), + refer_gid: 123, + selection_method: 9999999, + vacant_only: true, + vacant_participants: 1000 + }], + matchmake_session: MatchmakeSession{ + refer_gid: 10, + matchmake_system_type: 139, + matchmake_param: MatchmakeParam{ + params: vec![ + ("QSR".to_string(), Variant::Bool(false)), + ("SRQ2".to_string(), Variant::Double(1.1)), + ("SQR3".to_string(), Variant::SInt64(422)), + ("SDR4".to_string(), Variant::String("tetst".to_string())) + ] + }, + participation_count: 99, + application_buffer: vec![1,2,3,4,5,6,7,8,9], + attributes: vec![10,20,99,100000], + datetime: KerberosDateTime::now(), + gamemode: 111, + open_participation: false, + option0: 100, + progress_score: 1, + system_password_enabled: false, + user_password: "aaa".to_string(), + session_key: vec![91,123,5,2,1,2,4,124,4], + user_password_enabled: false, + gathering: Gathering{ + minimum_participants: 1, + maximum_participants: 12, + description: "aaargh".to_string(), + flags: 100, + host_pid: 999999919, + owner_pid: 138830, + participant_policy: 1, + policy_argument: 99837, + self_gid: 129, + state: 1389488 + } } +}); + +static DUMMY_SER: Lazy> = Lazy::new(|| serialize_to_vec(DUMMY.deref())); + +fn serialize_to_vec(r: &impl RmcSerialize) -> Vec{ + let mut vec = r.to_data(); + + vec.unwrap() } -struct SecureServer{ - router: Arc, - join_handle: JoinHandle<()>, - socket: Socket +fn read_struct(r: &[u8]) -> T{ + T::deserialize(&mut Cursor::new(r)).unwrap() +} +fn matchmake_with_param(c: &mut Criterion) { + let raw = DUMMY.deref(); + let ser = DUMMY_SER.deref().as_slice(); + c.bench_function("mmparam: ser", |b| b.iter(move || serialize_to_vec(black_box(raw)))); + c.bench_function("mmparam: de", |b| b.iter(move || read_struct::(black_box(ser)))); } -async fn start_secure_server() -> SecureServer{ - info!("starting secure server on {}:{}", *OWN_IP_PRIVATE, *SECURE_SERVER_PORT); +criterion_group!(benches, matchmake_with_param); +//criterion_main!(benches); - let (router, join_handle) = - Router::new(SocketAddrV4::new(*OWN_IP_PRIVATE, *SECURE_SERVER_PORT)).await - .expect("unable to startauth server"); - - info!("setting up endpoints"); - - let matchmake_data = Arc::new(RwLock::new( - MatchmakeData{ - matchmake_sessions: BTreeMap::new() - } - )); - - let rmcserver = RMCProtocolServer::new(Box::new([ - Box::new(block_if_maintenance), - Box::new(protocols::secure::bound_protocol()), - Box::new(protocols::matchmake::bound_protocol(matchmake_data.clone())), - Box::new(protocols::matchmake_extension::bound_protocol(matchmake_data)), - Box::new(protocols::nat_traversal::bound_protocol()) - ])); - - let socket = - Socket::new( - router.clone(), - VirtualPort::new(1,10), - "6f599f81", - Box::new(|p, count|{ - Box::pin( - async move { - let (session_key, pid, check_value) = read_secure_connection_data(&p.payload, &SECURE_SERVER_ACCOUNT)?; - - let check_value_response = check_value + 1; - - let data = bytemuck::bytes_of(&check_value_response); - - let mut response = Vec::new(); - - data.serialize(&mut response).ok()?; - - let encryption_pairs = generate_secure_encryption_pairs(session_key, count); - - Some((response, encryption_pairs, Some( - ActiveSecureConnectionData{ - pid, - session_key - } - ))) - } - ) - }), - Box::new(move |packet, socket, connection|{ - let rmcserver = rmcserver.clone(); - Box::pin(async move { rmcserver.process_message(packet, socket, connection).await; }) - }) - ).await.expect("unable to create socket"); - - SecureServer{ - join_handle, - router, - socket, +fn main(){ + for _ in 0..10000000 { + let v = serialize_to_vec(black_box(DUMMY.deref())); + let u = read_struct::(black_box(DUMMY_SER.deref().as_slice())); + black_box(v); + black_box(u); } -}*/ -/* -async fn start_auth() -> JoinHandle<()> { - tokio::spawn(async { - let (router_secure, _) = Router::new(SocketAddrV4::new(*OWN_IP_PRIVATE, *AUTH_SERVER_PORT)) - .await - .expect("unable to start router"); - - let mut socket_secure = router_secure - .add_socket(VirtualPort::new(1, 10), Unsecure( - "6f599f81" - )) - .await - .expect("unable to add socket"); - - // let conn = socket_secure.connect(auth_sockaddr).await.unwrap(); - - while !FORCE_EXIT.is_completed() { - let Some(conn) = socket_secure.accept().await else { - error!("server crashed"); - return; - }; - - info!("new connected user!"); - - let _ = new_rmc_gateway_connection(conn, |_| { - Arc::new(AuthHandler { - destination_server_acct: &SECURE_SERVER_ACCOUNT, - build_name: "branch:origin/project/wup-agmj build:3_8_15_2004_0", - station_url: &SECURE_STATION_URL, - }) - }); - } - }) -} - -async fn start_secure() -> JoinHandle<()> { - tokio::spawn(async { - let mmm = Arc::new(MatchmakeManager{ - gid_counter: AtomicU32::new(1), - sessions: Default::default(), - users: Default::default(), - rv_cid_counter: AtomicU32::new(1), - }); - - let weak_mmm = Arc::downgrade(&mmm); - - MatchmakeManager::initialize_garbage_collect_thread(weak_mmm).await; - - let web_server = web::start_web(mmm.clone()).await; - - let (router_secure, _) = - Router::new(SocketAddrV4::new(*OWN_IP_PRIVATE, *SECURE_SERVER_PORT)) - .await - .expect("unable to start router"); - - let mut socket_secure = router_secure - .add_socket( - VirtualPort::new(1, 10), - Secure( - "6f599f81", - &SECURE_SERVER_ACCOUNT - ), - ) - .await - .expect("unable to add socket"); - - // let conn = socket_secure.connect(auth_sockaddr).await.unwrap(); - - while !FORCE_EXIT.is_completed() { - let Some(conn) = socket_secure.accept().await else { - error!("server crashed"); - return; - }; - - info!("new connected user on secure :D!"); - - let ip = conn.socket_addr; - let pid = conn.user_id; - - let _ = new_rmc_gateway_connection(conn, |r| { - Arc::new_cyclic(|w| User { - ip, - pid, - this: w.clone(), - remote: RemoteConsole::new(r), - station_url: Default::default(), - matchmake_manager: mmm.clone() - }) - }); - } - }) -} - -async fn start_test() { - let addr = SocketAddrV4::new(*OWN_IP_PRIVATE, *SECURE_SERVER_PORT); - - let virt_addr = VirtualPort::new(1, 10); - let prudp_addr = PRUDPSockAddr::new(addr, virt_addr); - - let (router_test, _) = Router::new(SocketAddrV4::new(*OWN_IP_PRIVATE, 26969)) - .await - .expect("unable to start router"); - - let mut socket_secure = router_test - .add_socket(VirtualPort::new(1, 10), Unsecure("6f599f81")) - .await - .expect("unable to add socket"); - - let conn = socket_secure.connect(prudp_addr).await.unwrap(); - - let remote = new_rmc_gateway_connection(conn, |r| { - Arc::new(OnlyRemote::::new(r)) - }); - - tokio::time::sleep(Duration::from_secs(1)).await; - let urls = vec!["prudp:/address=192.168.178.45;port=60146;Pl=2;natf=0;natm=0;pmp=0;sid=15;upnp=0".to_owned()]; -} - -async fn start_servers() { - #[cfg(feature = "auth")] - let auth_server = start_auth().await; - #[cfg(feature = "secure")] - let secure_server = start_secure().await; - - - tokio::time::sleep(Duration::from_secs(1)).await; - - //start_test().await; - - - - #[cfg(feature = "auth")] - auth_server.await.expect("auth server crashed"); - #[cfg(feature = "secure")] - secure_server.await.expect("auth server crashed"); -} -*/ \ No newline at end of file +} \ No newline at end of file diff --git a/rnex-core/src/nex/auth_handler.rs b/rnex-core/src/nex/auth_handler.rs index 134c1bc..e5184d0 100644 --- a/rnex-core/src/nex/auth_handler.rs +++ b/rnex-core/src/nex/auth_handler.rs @@ -162,6 +162,8 @@ mod test { use rnex_core::rmc::structures::RmcSerialize; use rnex_core::rmc::response::RMCResponse; use std::io::Cursor; + + #[test] fn test() { diff --git a/rnex-core/src/prudp/station_url.rs b/rnex-core/src/prudp/station_url.rs index b2f70bb..a193b21 100644 --- a/rnex-core/src/prudp/station_url.rs +++ b/rnex-core/src/prudp/station_url.rs @@ -5,6 +5,7 @@ use std::io::Read; use crate::prudp::station_url::Type::{PRUDP, PRUDPS, UDP}; use crate::prudp::station_url::UrlOptions::{Address, ConnectionID, NatFiltering, NatMapping, NatType, Platform, PMP, Port, PrincipalID, RVConnectionID, StreamID, StreamType, UPNP, PID}; use crate::rmc::structures::Error::StationUrlInvalid; +use crate::rmc::structures::helpers::DummyFormatWriter; use crate::rmc::structures::RmcSerialize; #[derive(Clone, Copy, PartialEq, Eq)] pub enum Type{ @@ -135,59 +136,66 @@ impl TryFrom<&str> for StationUrl{ } } -impl<'a> Into for &'a StationUrl{ - fn into(self) -> String { - let mut url = match self.url_type{ +impl Display for StationUrl{ + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + let url_type_str = match self.url_type{ UDP => "udp:/", PRUDP => "prudp:/", PRUDPS => "prudps:/" - }.to_owned(); + }; + write!(f, "{}",url_type_str)?; for option in &self.options{ match option{ - Address(v) => write!(url, "address={}", v).expect("failed to write"), - Port(v) => write!(url, "port={}", v).expect("failed to write"), - StreamType(v) => write!(url, "stream={}", v).expect("failed to write"), - StreamID(v) => write!(url, "sid={}", v).expect("failed to write"), - ConnectionID(v) => write!(url, "CID={}", v).expect("failed to write"), - PrincipalID(v) => write!(url, "PID={}", v).expect("failed to write"), - NatType(v) => write!(url, "type={}", v).expect("failed to write"), - NatMapping(v) => write!(url, "natm={}", v).expect("failed to write"), - NatFiltering(v) => write!(url, "natf={}", v).expect("failed to write"), - UPNP(v) => write!(url, "upnp={}", v).expect("failed to write"), - RVConnectionID(v) => write!(url, "RVCID={}", v).expect("failed to write"), - Platform(v) => write!(url, "pl={}", v).expect("failed to write"), - PMP(v) => write!(url, "pmp={}", v).expect("failed to write"), - PID(v) => write!(url, "PID={}", v).expect("failed to write"), + Address(v) => write!(f, "address={}", v)?, + Port(v) => write!(f, "port={}", v)?, + StreamType(v) => write!(f, "stream={}", v)?, + StreamID(v) => write!(f, "sid={}", v)?, + ConnectionID(v) => write!(f, "CID={}", v)?, + PrincipalID(v) => write!(f, "PID={}", v)?, + NatType(v) => write!(f, "type={}", v)?, + NatMapping(v) => write!(f, "natm={}", v)?, + NatFiltering(v) => write!(f, "natf={}", v)?, + UPNP(v) => write!(f, "upnp={}", v)?, + RVConnectionID(v) => write!(f, "RVCID={}", v)?, + Platform(v) => write!(f, "pl={}", v)?, + PMP(v) => write!(f, "pmp={}", v)?, + PID(v) => write!(f, "PID={}", v)?, } - write!(url, ";").expect("failed to write"); + write!(f, ";")?; } + Ok(()) + } +} + +impl<'a> Into for &'a StationUrl{ + fn into(self) -> String { + let mut url = self.to_string(); + url[0..url.len()-1].into() } } -impl Display for StationUrl{ - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - let str: String = self.into(); - - write!(f, "{}", str) - } - - -} - impl RmcSerialize for StationUrl{ - fn deserialize(reader: &mut dyn Read) -> crate::rmc::structures::Result { + fn deserialize(reader: &mut impl Read) -> crate::rmc::structures::Result { let str = String::deserialize(reader)?; Self::try_from(str.as_str()).map_err(|_| StationUrlInvalid) } - fn serialize(&self, writer: &mut dyn std::io::Write) -> crate::rmc::structures::Result<()> { + fn serialize(&self, writer: &mut impl std::io::Write) -> crate::rmc::structures::Result<()> { let str: String = self.into(); str.serialize(writer) } + + fn serialize_write_size(&self) -> crate::rmc::structures::Result { + let mut dummy = DummyFormatWriter::new(); + + write!(&mut dummy, "{}", self)?; + + Ok(dummy.serialize_str_len()) + } } impl Debug for StationUrl{ diff --git a/rnex-core/src/rmc/structures/any.rs b/rnex-core/src/rmc/structures/any.rs index c1e68a4..e76b60a 100644 --- a/rnex-core/src/rmc/structures/any.rs +++ b/rnex-core/src/rmc/structures/any.rs @@ -9,7 +9,7 @@ pub struct Any{ } impl RmcSerialize for Any{ - fn serialize(&self, writer: &mut dyn Write) -> Result<()> { + fn serialize(&self, writer: &mut impl Write) -> Result<()> { self.name.serialize(writer)?; let u32_len = self.data.len() as u32; @@ -21,7 +21,7 @@ impl RmcSerialize for Any{ Ok(()) } - fn deserialize(mut reader: &mut dyn Read) -> Result { + fn deserialize(mut reader: &mut impl Read) -> Result { let name = String::deserialize(reader)?; // also length ? diff --git a/rnex-core/src/rmc/structures/buffer.rs b/rnex-core/src/rmc/structures/buffer.rs index 5db53cf..085f053 100644 --- a/rnex-core/src/rmc/structures/buffer.rs +++ b/rnex-core/src/rmc/structures/buffer.rs @@ -4,7 +4,7 @@ use crate::rmc::structures::RmcSerialize; impl<'a> RmcSerialize for &'a [u8]{ - fn serialize(&self, writer: &mut dyn Write) -> crate::rmc::structures::Result<()> { + fn serialize(&self, writer: &mut impl Write) -> crate::rmc::structures::Result<()> { let u32_size = self.len() as u32; writer.write(bytemuck::bytes_of(&u32_size))?; writer.write(self)?; @@ -13,17 +13,25 @@ impl<'a> RmcSerialize for &'a [u8]{ } /// DO NOT USE (also maybe split off the serialize and deserialize functions at some point) - fn deserialize(_reader: &mut dyn Read) -> crate::rmc::structures::Result { + fn deserialize(_reader: &mut impl Read) -> crate::rmc::structures::Result { panic!("cannot deserialize to a u8 slice reference (use this ONLY for writing)") } + + fn serialize_write_size(&self) -> crate::rmc::structures::Result { + Ok(4 + self.len() as u32) + } } impl RmcSerialize for Box<[u8]>{ - fn serialize(&self, writer: &mut dyn Write) -> crate::rmc::structures::Result<()> { + fn serialize(&self, writer: &mut impl Write) -> crate::rmc::structures::Result<()> { (&self[..]).serialize(writer) } - fn deserialize(reader: &mut dyn Read) -> crate::rmc::structures::Result { + fn deserialize(reader: &mut impl Read) -> crate::rmc::structures::Result { Vec::deserialize(reader).map(|v| v.into_boxed_slice()) } + + fn serialize_write_size(&self) -> crate::rmc::structures::Result { + (&self[..]).serialize_write_size() + } } \ No newline at end of file diff --git a/rnex-core/src/rmc/structures/helpers.rs b/rnex-core/src/rmc/structures/helpers.rs new file mode 100644 index 0000000..eeadbd6 --- /dev/null +++ b/rnex-core/src/rmc/structures/helpers.rs @@ -0,0 +1,48 @@ +use std::{fmt, io}; + +pub struct DummyFormatWriter(u32); + +impl fmt::Write for DummyFormatWriter{ + fn write_str(&mut self, s: &str) -> fmt::Result { + self.0 += s.as_bytes().len() as u32; + Ok(()) + } +} + +impl DummyFormatWriter{ + pub const fn new() -> Self{ Self(0) } + pub const fn serialize_str_len(&self) -> u32 { + 2 + self.0 + 1 + } +} + +pub struct DummyWriter(u32); + +impl io::Write for DummyWriter{ + fn write(&mut self, buf: &[u8]) -> io::Result { + self.0 += buf.len() as u32; + Ok(buf.len()) + } + fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { + self.0 += buf.len() as u32; + Ok(()) + } + + fn flush(&mut self) -> io::Result<()> { + Ok(()) + } +} + +impl DummyWriter{ + pub const fn new() -> Self{ Self(0) } + pub const fn get_total_len(&self) -> u32{ + self.0 + } +} + + +pub fn len_of_write(f: impl FnOnce(&mut DummyWriter) -> anyhow::Result<()>) -> u32{ + let mut dummy = DummyWriter::new(); + f(&mut dummy).ok(); + dummy.get_total_len() +} \ No newline at end of file diff --git a/rnex-core/src/rmc/structures/list.rs b/rnex-core/src/rmc/structures/list.rs index f4843c1..980907d 100644 --- a/rnex-core/src/rmc/structures/list.rs +++ b/rnex-core/src/rmc/structures/list.rs @@ -9,7 +9,7 @@ use crate::rmc::structures::RmcSerialize; // this is also for implementing `Buffer` this is tecnically not the same as its handled internaly // probably but as it has the same mapping it doesn't matter and simplifies things impl RmcSerialize for Vec{ - fn serialize(&self, writer: &mut dyn Write) -> crate::rmc::structures::Result<()> { + fn serialize(&self, writer: &mut impl Write) -> crate::rmc::structures::Result<()> { let u32_len = self.len() as u32; writer.write_all(bytes_of(&u32_len))?; @@ -20,21 +20,27 @@ impl RmcSerialize for Vec{ Ok(()) } - fn deserialize(mut reader: &mut dyn Read) -> crate::rmc::structures::Result { + fn deserialize(mut reader: &mut impl Read) -> crate::rmc::structures::Result { let len: u32 = reader.read_struct(IS_BIG_ENDIAN)?; - let mut vec = Vec::with_capacity(len as usize); + //let mut vec = Vec::with_capacity(len as usize); - for _ in 0..len{ - vec.push(T::deserialize(reader)?); - } + let vec = (0..len).map(|_| T::deserialize(reader)).collect::, _>>()?; Ok(vec) } + + fn serialize_write_size(&self) -> crate::rmc::structures::Result { + let mut val = 0u32; + for i in self{ + val += i.serialize_write_size()?; + } + Ok(4 + val) + } } impl RmcSerialize for [T; LEN]{ - fn serialize(&self, writer: &mut dyn Write) -> crate::rmc::structures::Result<()> { + fn serialize(&self, writer: &mut impl Write) -> crate::rmc::structures::Result<()> { for i in 0..LEN{ self[i].serialize(writer)?; } @@ -42,7 +48,7 @@ impl RmcSerialize for [T; LEN]{ Ok(()) } - fn deserialize(reader: &mut dyn Read) -> crate::rmc::structures::Result { + fn deserialize(reader: &mut impl Read) -> crate::rmc::structures::Result { let mut arr = [const { MaybeUninit::::uninit() }; LEN]; for i in 0..LEN{ @@ -55,4 +61,12 @@ impl RmcSerialize for [T; LEN]{ Ok(arr) } + #[inline(always)] + fn serialize_write_size(&self) -> crate::rmc::structures::Result { + let mut val = 0u32; + for i in self{ + val += i.serialize_write_size()?; + } + Ok(val) + } } diff --git a/rnex-core/src/rmc/structures/mod.rs b/rnex-core/src/rmc/structures/mod.rs index 9d127f7..7a1610c 100644 --- a/rnex-core/src/rmc/structures/mod.rs +++ b/rnex-core/src/rmc/structures/mod.rs @@ -1,8 +1,8 @@ -use std::io; +use std::{fmt, io}; use std::io::{Read, Write}; use std::string::FromUtf8Error; use thiserror::Error; - +use crate::rmc::structures::helpers::DummyWriter; //ideas for the future: make a proc macro library which allows generation of struct reads #[derive(Error, Debug)] @@ -16,7 +16,9 @@ pub enum Error{ #[error("version mismatch: {0}")] VersionMismatch(u8), #[error("an error occurred reading the station url")] - StationUrlInvalid + StationUrlInvalid, + #[error("error formatting text: {0}")] + FormatError(#[from] fmt::Error) } pub type Result = std::result::Result; @@ -33,28 +35,43 @@ pub mod primitives; pub mod matchmake; pub mod variant; pub mod ranking; -mod networking; +pub mod networking; +pub mod helpers; pub trait RmcSerialize{ - fn serialize(&self, writer: &mut dyn Write) -> Result<()>; - fn deserialize(reader: &mut dyn Read) -> Result where Self: Sized; + fn serialize(&self, writer: &mut impl Write) -> Result<()>; + fn serialize_write_size(&self) -> Result{ + let mut dummy = DummyWriter::new(); - fn to_data(&self) -> Vec{ - let mut data = Vec::new(); + self.serialize(&mut dummy)?; - self.serialize(&mut data).expect("out of memory or something"); + Ok(dummy.get_total_len()) + } + fn deserialize(reader: &mut impl Read) -> Result where Self: Sized; - data + fn to_data(&self) -> Result>{ + let mut data = Vec::with_capacity( + self.serialize_write_size()? as usize + ); + + self.serialize(&mut data)?; + + debug_assert_eq!(self.serialize_write_size().unwrap(), data.len() as u32); + + Ok(data) } } impl RmcSerialize for (){ - fn serialize(&self, _writer: &mut dyn Write) -> Result<()> { + fn serialize(&self, _writer: &mut impl Write) -> Result<()> { Ok(()) } - fn deserialize(_reader: &mut dyn Read) -> Result { + fn deserialize(_reader: &mut impl Read) -> Result { Ok(()) } + fn serialize_write_size(&self) -> Result { + Ok(0) + } } \ No newline at end of file diff --git a/rnex-core/src/rmc/structures/networking.rs b/rnex-core/src/rmc/structures/networking.rs index 824a442..03627af 100644 --- a/rnex-core/src/rmc/structures/networking.rs +++ b/rnex-core/src/rmc/structures/networking.rs @@ -4,30 +4,36 @@ use rnex_core::prudp::virtual_port::VirtualPort; use crate::rmc::structures::RmcSerialize; impl RmcSerialize for SocketAddrV4{ - fn serialize(&self, writer: &mut dyn Write) -> crate::rmc::structures::Result<()> { + fn serialize(&self, writer: &mut impl Write) -> crate::rmc::structures::Result<()> { self.ip().to_bits().serialize(writer)?; self.port().serialize(writer)?; Ok(()) } - fn deserialize(reader: &mut dyn Read) -> crate::rmc::structures::Result { + fn deserialize(reader: &mut impl Read) -> crate::rmc::structures::Result { let ip = u32::deserialize(reader)?; let port = u16::deserialize(reader)?; Ok(SocketAddrV4::new(Ipv4Addr::from_bits(ip), port)) } + fn serialize_write_size(&self) -> crate::rmc::structures::Result { + Ok(6) + } } impl RmcSerialize for VirtualPort{ - fn serialize(&self, writer: &mut dyn Write) -> crate::rmc::structures::Result<()> { + fn serialize(&self, writer: &mut impl Write) -> crate::rmc::structures::Result<()> { self.0.serialize(writer)?; Ok(()) } - fn deserialize(reader: &mut dyn Read) -> crate::rmc::structures::Result { + fn deserialize(reader: &mut impl Read) -> crate::rmc::structures::Result { Ok(Self(u8::deserialize(reader)?)) } + fn serialize_write_size(&self) -> crate::rmc::structures::Result { + Ok(1) + } } \ No newline at end of file diff --git a/rnex-core/src/rmc/structures/primitives.rs b/rnex-core/src/rmc/structures/primitives.rs index 73985ed..65e732c 100644 --- a/rnex-core/src/rmc/structures/primitives.rs +++ b/rnex-core/src/rmc/structures/primitives.rs @@ -4,97 +4,146 @@ use v_byte_helpers::{IS_BIG_ENDIAN, ReadExtensions}; use crate::rmc::structures::RmcSerialize; impl RmcSerialize for u8{ - fn serialize(&self, writer: &mut dyn Write) -> crate::rmc::structures::Result<()> { + #[inline(always)] + fn serialize(&self, writer: &mut impl Write) -> crate::rmc::structures::Result<()> { Ok(writer.write_all(bytes_of(self))?) } - fn deserialize(mut reader: &mut dyn Read) -> crate::rmc::structures::Result { + #[inline(always)] + fn deserialize(mut reader: &mut impl Read) -> crate::rmc::structures::Result { Ok(reader.read_struct(IS_BIG_ENDIAN)?) } + #[inline(always)] + fn serialize_write_size(&self) -> crate::rmc::structures::Result { + Ok(1) + } } impl RmcSerialize for i8{ - fn serialize(&self, writer: &mut dyn Write) -> crate::rmc::structures::Result<()> { + #[inline(always)] + fn serialize(&self, writer: &mut impl Write) -> crate::rmc::structures::Result<()> { Ok(writer.write_all(bytes_of(self))?) } - fn deserialize(mut reader: &mut dyn Read) -> crate::rmc::structures::Result { + #[inline(always)] + fn deserialize(mut reader: &mut impl Read) -> crate::rmc::structures::Result { Ok(reader.read_struct(IS_BIG_ENDIAN)?) } + #[inline(always)] + fn serialize_write_size(&self) -> crate::rmc::structures::Result { + Ok(1) + } } impl RmcSerialize for u16{ - fn serialize(&self, writer: &mut dyn Write) -> crate::rmc::structures::Result<()> { + #[inline(always)] + fn serialize(&self, writer: &mut impl Write) -> crate::rmc::structures::Result<()> { Ok(writer.write_all(bytes_of(self))?) } - - fn deserialize(mut reader: &mut dyn Read) -> crate::rmc::structures::Result { + #[inline(always)] + fn deserialize(mut reader: &mut impl Read) -> crate::rmc::structures::Result { Ok(reader.read_struct(IS_BIG_ENDIAN)?) } + #[inline(always)] + fn serialize_write_size(&self) -> crate::rmc::structures::Result { + Ok(2) + } } impl RmcSerialize for i16{ - fn serialize(&self, writer: &mut dyn Write) -> crate::rmc::structures::Result<()> { + #[inline(always)] + fn serialize(&self, writer: &mut impl Write) -> crate::rmc::structures::Result<()> { Ok(writer.write_all(bytes_of(self))?) } - - fn deserialize(mut reader: &mut dyn Read) -> crate::rmc::structures::Result { + #[inline(always)] + fn deserialize(mut reader: &mut impl Read) -> crate::rmc::structures::Result { Ok(reader.read_struct(IS_BIG_ENDIAN)?) } + #[inline(always)] + fn serialize_write_size(&self) -> crate::rmc::structures::Result { + Ok(2) + } } impl RmcSerialize for u32{ - fn serialize(&self, writer: &mut dyn Write) -> crate::rmc::structures::Result<()> { + #[inline(always)] + fn serialize(&self, writer: &mut impl Write) -> crate::rmc::structures::Result<()> { Ok(writer.write_all(bytes_of(self))?) } - - fn deserialize(mut reader: &mut dyn Read) -> crate::rmc::structures::Result { + #[inline(always)] + fn deserialize(mut reader: &mut impl Read) -> crate::rmc::structures::Result { Ok(reader.read_struct(IS_BIG_ENDIAN)?) } + #[inline(always)] + fn serialize_write_size(&self) -> crate::rmc::structures::Result { + Ok(4) + } } impl RmcSerialize for i32{ - fn serialize(&self, writer: &mut dyn Write) -> crate::rmc::structures::Result<()> { + #[inline(always)] + fn serialize(&self, writer: &mut impl Write) -> crate::rmc::structures::Result<()> { Ok(writer.write_all(bytes_of(self))?) } - - fn deserialize(mut reader: &mut dyn Read) -> crate::rmc::structures::Result { + #[inline(always)] + fn deserialize(mut reader: &mut impl Read) -> crate::rmc::structures::Result { Ok(reader.read_struct(IS_BIG_ENDIAN)?) } + #[inline(always)] + fn serialize_write_size(&self) -> crate::rmc::structures::Result { + Ok(4) + } } impl RmcSerialize for u64{ - fn serialize(&self, writer: &mut dyn Write) -> crate::rmc::structures::Result<()> { + #[inline(always)] + fn serialize(&self, writer: &mut impl Write) -> crate::rmc::structures::Result<()> { Ok(writer.write_all(bytes_of(self))?) } - - fn deserialize(mut reader: &mut dyn Read) -> crate::rmc::structures::Result { + #[inline(always)] + fn deserialize(mut reader: &mut impl Read) -> crate::rmc::structures::Result { Ok(reader.read_struct(IS_BIG_ENDIAN)?) } + #[inline(always)] + fn serialize_write_size(&self) -> crate::rmc::structures::Result { + Ok(8) + } } impl RmcSerialize for i64{ - fn serialize(&self, writer: &mut dyn Write) -> crate::rmc::structures::Result<()> { + #[inline(always)] + fn serialize(&self, writer: &mut impl Write) -> crate::rmc::structures::Result<()> { Ok(writer.write_all(bytes_of(self))?) } - - fn deserialize(mut reader: &mut dyn Read) -> crate::rmc::structures::Result { + #[inline(always)] + fn deserialize(mut reader: &mut impl Read) -> crate::rmc::structures::Result { Ok(reader.read_struct(IS_BIG_ENDIAN)?) } + #[inline(always)] + fn serialize_write_size(&self) -> crate::rmc::structures::Result { + Ok(8) + } } impl RmcSerialize for f64{ - fn serialize(&self, writer: &mut dyn Write) -> crate::rmc::structures::Result<()> { + #[inline(always)] + fn serialize(&self, writer: &mut impl Write) -> crate::rmc::structures::Result<()> { Ok(writer.write_all(bytes_of(self))?) } - fn deserialize(mut reader: &mut dyn Read) -> crate::rmc::structures::Result { + #[inline(always)] + fn deserialize(mut reader: &mut impl Read) -> crate::rmc::structures::Result { Ok(reader.read_struct(IS_BIG_ENDIAN)?) } + #[inline(always)] + fn serialize_write_size(&self) -> crate::rmc::structures::Result { + Ok(8) + } } impl RmcSerialize for bool{ - fn serialize(&self, writer: &mut dyn Write) -> crate::rmc::structures::Result<()> { + #[inline(always)] + fn serialize(&self, writer: &mut impl Write) -> crate::rmc::structures::Result<()> { match self{ true => writer.write_all(&[1])?, false => writer.write_all(&[0])?, @@ -102,54 +151,77 @@ impl RmcSerialize for bool{ Ok(()) } - fn deserialize(reader: &mut dyn Read) -> crate::rmc::structures::Result { + #[inline(always)] + fn deserialize(reader: &mut impl Read) -> crate::rmc::structures::Result { Ok(u8::deserialize(reader)? != 0) } + #[inline(always)] + fn serialize_write_size(&self) -> crate::rmc::structures::Result { + Ok(1) + } } impl RmcSerialize for (T, U){ - fn serialize(&self, writer: &mut dyn Write) -> crate::rmc::structures::Result<()> { + #[inline(always)] + fn serialize(&self, writer: &mut impl Write) -> crate::rmc::structures::Result<()> { self.0.serialize(writer)?; self.1.serialize(writer)?; Ok(()) } - - fn deserialize(reader: &mut dyn Read) -> crate::rmc::structures::Result { + #[inline(always)] + fn deserialize(reader: &mut impl Read) -> crate::rmc::structures::Result { let first = T::deserialize(reader)?; let second = U::deserialize(reader)?; Ok((first, second)) } + #[inline(always)] + fn serialize_write_size(&self) -> crate::rmc::structures::Result { + Ok( + self.0.serialize_write_size()? + + self.1.serialize_write_size()? + ) + } } impl RmcSerialize for (T, U, V){ - fn serialize(&self, writer: &mut dyn Write) -> crate::rmc::structures::Result<()> { + #[inline(always)] + fn serialize(&self, writer: &mut impl Write) -> crate::rmc::structures::Result<()> { self.0.serialize(writer)?; self.1.serialize(writer)?; self.2.serialize(writer)?; Ok(()) } - - fn deserialize(reader: &mut dyn Read) -> crate::rmc::structures::Result { + #[inline(always)] + fn deserialize(reader: &mut impl Read) -> crate::rmc::structures::Result { let first = T::deserialize(reader)?; let second = U::deserialize(reader)?; let third = V::deserialize(reader)?; Ok((first, second, third)) } + #[inline(always)] + fn serialize_write_size(&self) -> crate::rmc::structures::Result { + Ok( + self.0.serialize_write_size()? + + self.1.serialize_write_size()? + + self.2.serialize_write_size()? + ) + } } impl RmcSerialize for (T, U, V, W){ - fn serialize(&self, writer: &mut dyn Write) -> crate::rmc::structures::Result<()> { + #[inline(always)] + fn serialize(&self, writer: &mut impl Write) -> crate::rmc::structures::Result<()> { self.0.serialize(writer)?; self.1.serialize(writer)?; self.2.serialize(writer)?; self.3.serialize(writer)?; Ok(()) } - - fn deserialize(reader: &mut dyn Read) -> crate::rmc::structures::Result { + #[inline(always)] + fn deserialize(reader: &mut impl Read) -> crate::rmc::structures::Result { let first = T::deserialize(reader)?; let second = U::deserialize(reader)?; let third = V::deserialize(reader)?; @@ -157,10 +229,20 @@ impl RmcSeri Ok((first, second, third, fourth)) } + #[inline(always)] + fn serialize_write_size(&self) -> crate::rmc::structures::Result { + Ok( + self.0.serialize_write_size()? + + self.1.serialize_write_size()? + + self.2.serialize_write_size()? + + self.3.serialize_write_size()? + ) + } } impl RmcSerialize for (T, U, V, W, X){ - fn serialize(&self, writer: &mut dyn Write) -> crate::rmc::structures::Result<()> { + #[inline(always)] + fn serialize(&self, writer: &mut impl Write) -> crate::rmc::structures::Result<()> { self.0.serialize(writer)?; self.1.serialize(writer)?; self.2.serialize(writer)?; @@ -170,7 +252,8 @@ impl crate::rmc::structures::Result { + #[inline(always)] + fn deserialize(reader: &mut impl Read) -> crate::rmc::structures::Result { let first = T::deserialize(reader)?; let second = U::deserialize(reader)?; let third = V::deserialize(reader)?; @@ -179,10 +262,21 @@ impl crate::rmc::structures::Result { + Ok( + self.0.serialize_write_size()? + + self.1.serialize_write_size()? + + self.2.serialize_write_size()? + + self.2.serialize_write_size()? + + self.3.serialize_write_size()? + ) + } } impl RmcSerialize for (T, U, V, W, X, Y){ - fn serialize(&self, writer: &mut dyn Write) -> crate::rmc::structures::Result<()> { + #[inline(always)] + fn serialize(&self, writer: &mut impl Write) -> crate::rmc::structures::Result<()> { self.0.serialize(writer)?; self.1.serialize(writer)?; self.2.serialize(writer)?; @@ -193,7 +287,8 @@ impl crate::rmc::structures::Result { + #[inline(always)] + fn deserialize(reader: &mut impl Read) -> crate::rmc::structures::Result { let first = T::deserialize(reader)?; let second = U::deserialize(reader)?; let third = V::deserialize(reader)?; @@ -203,10 +298,22 @@ impl crate::rmc::structures::Result { + Ok( + self.0.serialize_write_size()? + + self.1.serialize_write_size()? + + self.2.serialize_write_size()? + + self.3.serialize_write_size()? + + self.4.serialize_write_size()? + + self.5.serialize_write_size()? + ) + } } impl RmcSerialize for (T, U, V, W, X, Y, Z){ - fn serialize(&self, writer: &mut dyn Write) -> crate::rmc::structures::Result<()> { + #[inline(always)] + fn serialize(&self, writer: &mut impl Write) -> crate::rmc::structures::Result<()> { self.0.serialize(writer)?; self.1.serialize(writer)?; self.2.serialize(writer)?; @@ -217,8 +324,8 @@ impl crate::rmc::structures::Result { + #[inline(always)] + fn deserialize(reader: &mut impl Read) -> crate::rmc::structures::Result { let first = T::deserialize(reader)?; let second = U::deserialize(reader)?; let third = V::deserialize(reader)?; @@ -229,13 +336,31 @@ impl crate::rmc::structures::Result { + Ok( + self.0.serialize_write_size()? + + self.1.serialize_write_size()? + + self.2.serialize_write_size()? + + self.3.serialize_write_size()? + + self.4.serialize_write_size()? + + self.5.serialize_write_size()? + + self.6.serialize_write_size()? + ) + } } impl RmcSerialize for Box{ - fn serialize(&self, writer: &mut dyn Write) -> crate::rmc::structures::Result<()> { + #[inline(always)] + fn serialize(&self, writer: &mut impl Write) -> crate::rmc::structures::Result<()> { self.as_ref().serialize(writer) } - fn deserialize(reader: &mut dyn Read) -> crate::rmc::structures::Result { + #[inline(always)] + fn deserialize(reader: &mut impl Read) -> crate::rmc::structures::Result { T::deserialize(reader).map(Box::new) } + #[inline(always)] + fn serialize_write_size(&self) -> crate::rmc::structures::Result { + T::serialize_write_size(self.as_ref()) + } } \ No newline at end of file diff --git a/rnex-core/src/rmc/structures/qbuffer.rs b/rnex-core/src/rmc/structures/qbuffer.rs index 8fbfd5e..d459091 100644 --- a/rnex-core/src/rmc/structures/qbuffer.rs +++ b/rnex-core/src/rmc/structures/qbuffer.rs @@ -8,7 +8,7 @@ use crate::rmc::structures::{Result, RmcSerialize}; pub struct QBuffer(pub Vec); impl RmcSerialize for QBuffer{ - fn serialize(&self, writer: &mut dyn Write) -> Result<()> { + fn serialize(&self, writer: &mut impl Write) -> Result<()> { let len_u16 = self.0.len() as u16; writer.write(bytes_of(&len_u16))?; @@ -17,7 +17,7 @@ impl RmcSerialize for QBuffer{ Ok(()) } - fn deserialize(mut reader: &mut dyn Read) -> Result { + fn deserialize(mut reader: &mut impl Read) -> Result { let size: u16 = reader.read_struct(IS_BIG_ENDIAN)?; let mut vec = vec![0; size as usize]; diff --git a/rnex-core/src/rmc/structures/qresult.rs b/rnex-core/src/rmc/structures/qresult.rs index 77ad70e..c614080 100644 --- a/rnex-core/src/rmc/structures/qresult.rs +++ b/rnex-core/src/rmc/structures/qresult.rs @@ -26,12 +26,12 @@ impl QResult{ } impl RmcSerialize for QResult{ - fn serialize(&self, writer: &mut dyn Write) -> Result<()> { + fn serialize(&self, writer: &mut impl Write) -> Result<()> { writer.write(bytes_of(self))?; Ok(()) } - fn deserialize(mut reader: &mut dyn Read) -> Result { + fn deserialize(mut reader: &mut impl Read) -> Result { Ok(reader.read_struct(IS_BIG_ENDIAN)?) } } \ No newline at end of file diff --git a/rnex-core/src/rmc/structures/rmc_struct.rs b/rnex-core/src/rmc/structures/rmc_struct.rs index 071cfdb..670b1e0 100644 --- a/rnex-core/src/rmc/structures/rmc_struct.rs +++ b/rnex-core/src/rmc/structures/rmc_struct.rs @@ -1,6 +1,12 @@ -use std::io::{Cursor, Read, Write}; +use std::any::Any; +use std::cmp::max; +use std::fmt::Arguments; +use std::io; +use std::io::{Cursor, ErrorKind, IoSlice, Read, Write}; +use std::ops::Sub; use bytemuck::bytes_of; use v_byte_helpers::{IS_BIG_ENDIAN, ReadExtensions}; +use crate::rmc::structures; use crate::rmc::structures::Error::VersionMismatch; use crate::rmc::structures::Result; @@ -10,35 +16,97 @@ struct StructureHeader{ length: u32 } -pub fn write_struct(writer: &mut dyn Write, version: u8, pred: impl FnOnce(&mut Vec) -> Result<()> ) -> Result<()> { +#[cfg(feature = "rmc_struct_header")] +pub const HEADER_SIZE: u32 = 0; +#[cfg(not(feature = "rmc_struct_header"))] +pub const HEADER_SIZE: u32 = 5; + +pub struct OnlyWriteVec<'a>(&'a mut Vec); + +impl Write for OnlyWriteVec<'_> { + fn flush(&mut self) -> io::Result<()> { + self.0.flush() + } + fn write(&mut self, buf: &[u8]) -> io::Result { + self.0.write(buf) + } + fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { + self.0.write_all(buf) + } + fn write_fmt(&mut self, args: Arguments<'_>) -> io::Result<()> { + self.0.write_fmt(args) + } + fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { + self.0.write_vectored(bufs) + } +} + +#[cfg(feature = "rmc_struct_header")] +pub fn write_struct(writer: &mut T, version: u8, inner_size: u32, pred: impl FnOnce(&mut T) -> Result<()> ) -> Result<()> { writer.write_all(&[version])?; - let mut scratch_space: Vec = Vec::new(); + writer.write_all(bytes_of(&inner_size))?; - (pred)(&mut scratch_space)?; - - let u32_size = scratch_space.len() as u32; - - writer.write_all(bytes_of(&u32_size))?; - writer.write_all(&scratch_space)?; + (pred)(writer)?; Ok(()) } -pub fn read_struct(mut reader: &mut dyn Read, version: u8, pred: impl FnOnce(&mut Cursor>) -> Result) -> Result { + + +#[cfg(not(feature = "rmc_struct_header"))] +pub fn write_struct(writer: &mut T, version: u8, _inner_size: u32, pred: impl FnOnce(&mut T) -> Result<()> ) -> Result<()> { + pred(writer) +} + + +pub struct SubRead<'a, T: Read>{ + left_to_read: usize, + origin: &'a mut T +} + +impl<'a, T: Read> SubRead<'a, T>{ + pub const fn new(origin: &'a mut T, left_to_read: usize) -> Self{ + Self{ + left_to_read, + origin + } + } +} + +impl Read for SubRead<'_, T>{ + #[inline(always)] + fn read(&mut self, buf: &mut [u8]) -> io::Result { + let max_read = max(self.left_to_read, buf.len()); + let read = self.origin.read(&mut buf[..max_read])?; + self.left_to_read -= read; + Ok(read) + } + + #[inline(always)] + fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> { + if buf.len() > self.left_to_read{ + return Err(io::Error::new(ErrorKind::UnexpectedEof, "Would run over end of SubRead")); + } + self.left_to_read -= buf.len(); + self.origin.read_exact(buf) + } +} + +#[cfg(feature = "rmc_struct_header")] +pub fn read_struct(mut reader: &mut R, version: u8, pred: impl FnOnce(&mut SubRead) -> Result) -> Result { let ver: u8 = reader.read_struct(IS_BIG_ENDIAN)?; - if ver != version{ + if ver != version { return Err(VersionMismatch(ver)); } let size: u32 = reader.read_struct(IS_BIG_ENDIAN)?; - let mut vec = vec![0u8; size as usize]; + Ok(pred(&mut SubRead::new(reader, size as usize))?) +} - reader.read_exact(&mut vec)?; - - let mut cursor = Cursor::new(vec); - - Ok(pred(&mut cursor)?) -} \ No newline at end of file +#[cfg(not(feature = "rmc_struct_header"))] +pub fn read_struct(mut reader: &mut R, version: u8, pred: impl FnOnce(&mut R) -> Result) -> Result { + Ok(pred(&mut reader)?) +} diff --git a/rnex-core/src/rmc/structures/string.rs b/rnex-core/src/rmc/structures/string.rs index d25bc81..e090957 100644 --- a/rnex-core/src/rmc/structures/string.rs +++ b/rnex-core/src/rmc/structures/string.rs @@ -1,39 +1,49 @@ use std::io::{Read, Write}; use bytemuck::bytes_of; use log::error; +use rocket::form::validate::Len; use v_byte_helpers::{IS_BIG_ENDIAN, ReadExtensions}; use super::{Result, RmcSerialize}; impl RmcSerialize for String{ - fn deserialize(mut reader: &mut dyn Read) -> Result { + fn deserialize(mut reader: &mut impl Read) -> Result { let len: u16 = reader.read_struct(IS_BIG_ENDIAN)?; - let mut data = vec![0; len as usize - 1]; + if len == 0{ + return Ok("".to_string()); + } + let mut data = vec![0; len as usize]; reader.read_exact(&mut data)?; - - let null: u8 = reader.read_struct(IS_BIG_ENDIAN)?; - if null != 0{ + if *data.last().unwrap() != 0{ error!("unable to find null terminator... continuing anyways"); } + data.pop(); Ok(String::from_utf8(data)?) } - fn serialize(&self, writer: &mut dyn Write) -> Result<()> { + fn serialize(&self, writer: &mut impl Write) -> Result<()> { (&self[..]).serialize(writer) } + fn serialize_write_size(&self) -> Result { + (&self[..]).serialize_write_size() + } } impl RmcSerialize for &str{ - fn deserialize(_reader: &mut dyn Read) -> Result { + fn deserialize(_reader: &mut impl Read) -> Result { panic!("cannot serialize to &str") } - fn serialize(&self, writer: &mut dyn Write) -> Result<()> { + fn serialize(&self, writer: &mut impl Write) -> Result<()> { let u16_len: u16 = (self.len() + 1) as u16; - writer.write(bytes_of(&u16_len))?; + writer.write_all(bytes_of(&u16_len))?; - writer.write(self.as_bytes())?; - writer.write(&[0])?; + writer.write_all(self.as_bytes())?; + writer.write_all(&[0])?; Ok(()) } + #[inline(always)] + fn serialize_write_size(&self) -> Result { + Ok(2 + self.as_bytes().len() as u32 + 1) + } } diff --git a/rnex-core/src/rmc/structures/variant.rs b/rnex-core/src/rmc/structures/variant.rs index ebd25b8..6056f3f 100644 --- a/rnex-core/src/rmc/structures/variant.rs +++ b/rnex-core/src/rmc/structures/variant.rs @@ -16,7 +16,7 @@ pub enum Variant{ } impl RmcSerialize for Variant{ - fn serialize(&self, writer: &mut dyn Write) -> crate::rmc::structures::Result<()> { + fn serialize(&self, writer: &mut impl Write) -> crate::rmc::structures::Result<()> { match self{ Variant::None => { writer.write_all(&[0])?; @@ -50,7 +50,7 @@ impl RmcSerialize for Variant{ Ok(()) } - fn deserialize(reader: &mut dyn Read) -> crate::rmc::structures::Result { + fn deserialize(reader: &mut impl Read) -> crate::rmc::structures::Result { match u8::deserialize(reader)?{ 0 => Ok(Variant::None), 1 => Ok(Variant::SInt64(i64::deserialize(reader)?)),