diff --git a/Cargo.lock b/Cargo.lock index 8d4334c..5103b70 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -11,7 +11,7 @@ dependencies = [ "attribute-derive-macro", "proc-macro2", "quote", - "syn 2.0.55", + "syn 2.0.57", ] [[package]] @@ -27,7 +27,7 @@ dependencies = [ "proc-macro2", "quote", "quote-use", - "syn 2.0.55", + "syn 2.0.57", ] [[package]] @@ -62,13 +62,13 @@ checksum = "62d671cc41a825ebabc75757b62d3d168c577f9149b2d49ece1dad1f72119d25" dependencies = [ "proc-macro2", "quote", - "syn 2.0.55", + "syn 2.0.57", ] [[package]] name = "flatbuffers" version = "24.3.25" -source = "git+https://github.com/google/flatbuffers?branch=master#8f2e1dbd88d25ca76cbcaf9ac8c9919e0a787d31" +source = "git+https://github.com/google/flatbuffers?branch=master#f4a9c5325b7cba8ae432466bdfb90f857da0d593" dependencies = [ "bitflags", "rustc_version", @@ -91,7 +91,7 @@ checksum = "13a1bcfb855c1f340d5913ab542e36f25a1c56f57de79022928297632435dec2" dependencies = [ "attribute-derive", "quote", - "syn 2.0.55", + "syn 2.0.57", ] [[package]] @@ -218,9 +218,9 @@ dependencies = [ [[package]] name = "pyo3" -version = "0.21.0" +version = "0.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a02a88a17e74cadbc8ce77855e1d6c8ad0ab82901a4a9b5046bd01c1c0bd95cd" +checksum = "a7a8b1990bd018761768d5e608a13df8bd1ac5f678456e0f301bb93e5f3ea16b" dependencies = [ "cfg-if", "indoc", @@ -236,9 +236,9 @@ dependencies = [ [[package]] name = "pyo3-build-config" -version = "0.21.0" +version = "0.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5eb0b6ecba38961f6f4bd6cd5906dfab3cd426ff37b2eed5771006aa31656f1" +checksum = "650dca34d463b6cdbdb02b1d71bfd6eb6b6816afc708faebb3bac1380ff4aef7" dependencies = [ "once_cell", "target-lexicon", @@ -246,9 +246,9 @@ dependencies = [ [[package]] name = "pyo3-ffi" -version = "0.21.0" +version = "0.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba8a6e48a29b5d22e4fdaf132d8ba8d3203ee9f06362d48f244346902a594ec3" +checksum = "09a7da8fc04a8a2084909b59f29e1b8474decac98b951d77b80b26dc45f046ad" dependencies = [ "libc", "pyo3-build-config", @@ -256,27 +256,27 @@ dependencies = [ [[package]] name = "pyo3-macros" -version = "0.21.0" +version = "0.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e80493c5965f94a747d0782a607b2328a4eea5391327b152b00e2f3b001cede" +checksum = "4b8a199fce11ebb28e3569387228836ea98110e43a804a530a9fd83ade36d513" dependencies = [ "proc-macro2", "pyo3-macros-backend", "quote", - "syn 2.0.55", + "syn 2.0.57", ] [[package]] name = "pyo3-macros-backend" -version = "0.21.0" +version = "0.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcd7d86f42004025200e12a6a8119bd878329e6fddef8178eaafa4e4b5906c5b" +checksum = "93fbbfd7eb553d10036513cb122b888dcd362a945a00b06c165f2ab480d4cc3b" dependencies = [ "heck", "proc-macro2", "pyo3-build-config", "quote", - "syn 2.0.55", + "syn 2.0.57", ] [[package]] @@ -296,7 +296,7 @@ checksum = "a7b5abe3fe82fdeeb93f44d66a7b444dedf2e4827defb0a8e69c437b2de2ef94" dependencies = [ "quote", "quote-use-macros", - "syn 2.0.55", + "syn 2.0.57", ] [[package]] @@ -308,7 +308,7 @@ dependencies = [ "derive-where", "proc-macro2", "quote", - "syn 2.0.55", + "syn 2.0.57", ] [[package]] @@ -322,7 +322,7 @@ dependencies = [ [[package]] name = "rlbot-flatbuffers-py" -version = "0.3.0" +version = "0.3.1" dependencies = [ "flatbuffers", "get-size", @@ -368,7 +368,7 @@ checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.55", + "syn 2.0.57", ] [[package]] @@ -389,9 +389,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.55" +version = "2.0.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "002a1b3dbf967edfafc32655d0f377ab0bb7b994aa1d32c8cc7e9b8bf3ebb8f0" +checksum = "11a6ae1e52eb25aab8f3fb9fca13be982a373b8f1157ca14b897a825ba4a2d35" dependencies = [ "proc-macro2", "quote", diff --git a/Cargo.toml b/Cargo.toml index bda3b83..2cb00ab 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rlbot-flatbuffers-py" -version = "0.3.0" +version = "0.3.1" edition = "2021" description = "A Python module implemented in Rust for serializing and deserializing RLBot's flatbuffers" repository = "https://github.com/VirxEC/rlbot-flatbuffers-py" diff --git a/build.rs b/build.rs index b2e39eb..0afd74a 100644 --- a/build.rs +++ b/build.rs @@ -274,6 +274,8 @@ impl PythonBindGenerator { "Vec>", variable_type.trim_start_matches("Vec<").trim_end_matches("T>") ); + } else if variable_type.starts_with("Vec<") && variable_type.ends_with('>') { + variable_type = String::from("Py"); } else if variable_type.starts_with("Box<") && variable_type.ends_with('>') { variable_type = format!( "Py", @@ -315,8 +317,11 @@ impl PythonBindGenerator { let variable_type = &variable_info[1]; if variable_type.starts_with("Vec<") { - self.file_contents - .push(Cow::Owned(format!(" {variable_name}: Vec::new(),"))); + self.file_contents.push(Cow::Owned(if variable_type == "Vec" { + format!(" {variable_name}: PyBytes::new_bound(py, &[]).unbind(),") + } else { + format!(" {variable_name}: Vec::new(),") + })); } else if variable_type.starts_with("Option<") { self.file_contents .push(Cow::Owned(format!(" {variable_name}: None,"))); @@ -495,19 +500,22 @@ impl PythonBindGenerator { let variable_type = variable_info[1].as_str(); if variable_type.starts_with("Vec<") { - let inner_type = variable_type.trim_start_matches("Vec<").trim_end_matches('>'); - if Self::BASE_TYPES.contains(&inner_type) { - self.file_contents - .push(Cow::Owned(format!(" {variable_name}: flat_t.{variable_name},"))); + self.file_contents + .push(Cow::Owned(if variable_type == "Vec" { + format!(" {variable_name}: PyBytes::new_bound(py, &flat_t.{variable_name}).unbind(),") } else { - self.file_contents.push(Cow::Owned(format!( + format!( " {variable_name}: flat_t.{variable_name}.into_iter().map(|x| x.into_gil(py)).collect(),", - ))); - } + ) + })); } else if variable_type.starts_with("Option<") { - self.file_contents.push(Cow::Owned(format!( - " {variable_name}: flat_t.{variable_name}.map(|x| x.into_gil(py)),", - ))); + self.file_contents.push(Cow::Owned( + if variable_type.trim_start_matches("Option<").trim_end_matches('>') == "String" { + format!(" {variable_name}: flat_t.{variable_name},") + } else { + format!(" {variable_name}: flat_t.{variable_name}.map(|x| x.into_gil(py)),") + }, + )); } else if variable_type.starts_with("Box<") || variable_type.ends_with('T') { self.file_contents.push(Cow::Owned(format!( " {variable_name}: flat_t.{variable_name}.into_gil(py),", @@ -642,19 +650,25 @@ impl PythonBindGenerator { let variable_type = variable_info[1].as_str(); if variable_type.starts_with("Vec<") { - let inner_type = variable_type.trim_start_matches("Vec<").trim_end_matches('>'); - if Self::BASE_TYPES.contains(&inner_type) { - self.file_contents - .push(Cow::Owned(format!(" {variable_name}: py_type.{variable_name},"))); + self.file_contents.push(Cow::Owned(if variable_type == "Vec" { + format!( + " {variable_name}: py_type.{variable_name}.as_bytes(py).to_vec()," + ) } else { - self.file_contents.push(Cow::Owned(format!( + format!( " {variable_name}: py_type.{variable_name}.iter().map(|x| x.into_gil(py)).collect(),", - ))); - } + ) + })); } else if variable_type.starts_with("Option<") { - self.file_contents.push(Cow::Owned(format!( - " {variable_name}: py_type.{variable_name}.as_ref().map(|x| x.into_gil(py)),", - ))); + self.file_contents.push(Cow::Owned( + if variable_type.trim_start_matches("Option<").trim_end_matches('>') == "String" { + format!(" {variable_name}: py_type.{variable_name}.clone(),") + } else { + format!( + " {variable_name}: py_type.{variable_name}.as_ref().map(|x| x.into_gil(py))," + ) + }, + )); } else if variable_type == "String" { self.file_contents.push(Cow::Owned(format!( " {variable_name}: py_type.{variable_name}.clone(),", @@ -702,19 +716,25 @@ impl PythonBindGenerator { let variable_type = variable_info[1].as_str(); if variable_type.starts_with("Vec<") { - let inner_type = variable_type.trim_start_matches("Vec<").trim_end_matches('>'); - if Self::BASE_TYPES.contains(&inner_type) { - self.file_contents - .push(Cow::Owned(format!(" {variable_name}: borrow.{variable_name},"))); + if variable_type == "Vec" { + self.file_contents.push(Cow::Owned(format!( + " {variable_name}: borrow.{variable_name}.as_bytes(py).to_vec()," + ))); } else { self.file_contents.push(Cow::Owned(format!( " {variable_name}: borrow.{variable_name}.iter().map(|x| x.into_gil(py)).collect(),", ))); } } else if variable_type.starts_with("Option<") { - self.file_contents.push(Cow::Owned(format!( - " {variable_name}: borrow.{variable_name}.as_ref().map(|x| x.into_gil(py)),", - ))); + self.file_contents.push(Cow::Owned( + if variable_type.trim_start_matches("Option<").trim_end_matches('>') == "String" { + format!(" {variable_name}: borrow.{variable_name}.clone(),") + } else { + format!( + " {variable_name}: borrow.{variable_name}.as_ref().map(|x| x.into_gil(py))," + ) + }, + )); } else if variable_type == "String" { self.file_contents.push(Cow::Owned(format!( " {variable_name}: borrow.{variable_name}.clone(),", @@ -845,6 +865,8 @@ impl PythonBindGenerator { && (variable_type.starts_with("Box<") || variable_type.ends_with('T')) { signature_parts.push(format!("{variable_name}=crate::get_py_default()")); + } else if variable_type == "Vec" { + signature_parts.push(format!("{variable_name}=crate::get_empty_pybytes()")); } else { signature_parts.push(format!("{variable_name}=Default::default()")); } @@ -866,6 +888,8 @@ impl PythonBindGenerator { "Vec>", variable_type.trim_start_matches("Vec<").trim_end_matches("T>") ); + } else if variable_type == "Vec" { + variable_type = String::from("Py"); } else if variable_type.starts_with("Box<") && variable_type.ends_with('>') { variable_type = format!( "Py", @@ -978,7 +1002,7 @@ impl PythonBindGenerator { return; } - self.write_str("#[allow(unused_variables)]"); + self.write_str(" #[allow(unused_variables)]"); self.write_str(" pub fn __repr__(&self, py: Python) -> String {"); self.write_str(" format!("); @@ -991,6 +1015,8 @@ impl PythonBindGenerator { if variable_type == "String" { format!("{variable_name}={{:?}}") + } else if variable_type == "Vec" { + format!("{variable_name}=bytes([{{}}])") } else if variable_type.starts_with("Vec<") { format!("{variable_name}=[{{}}]") } else { @@ -1015,16 +1041,28 @@ impl PythonBindGenerator { self.file_contents .push(Cow::Owned(format!(" self.{variable_name}"))); self.file_contents.push(Cow::Borrowed(" .as_ref()")); - self.file_contents - .push(Cow::Borrowed(" .map(|x| x.borrow(py).__repr__(py))")); + if Self::BASE_TYPES.into_iter().any(|t| variable_type.contains(t)) { + self.file_contents + .push(Cow::Borrowed(" .map(ToString::to_string)")); + } else { + self.file_contents + .push(Cow::Borrowed(" .map(|x| x.borrow(py).__repr__(py))")); + } self.file_contents .push(Cow::Borrowed(" .unwrap_or_else(crate::none_str),")); } else if variable_type.starts_with("Vec<") { self.file_contents .push(Cow::Owned(format!(" self.{variable_name}"))); - self.file_contents.push(Cow::Borrowed(" .iter()")); - self.file_contents - .push(Cow::Borrowed(" .map(|x| x.borrow(py).__repr__(py))")); + if Self::BASE_TYPES.into_iter().any(|t| variable_type.contains(t)) { + self.file_contents.push(Cow::Borrowed(" .as_bytes(py)")); + self.file_contents.push(Cow::Borrowed(" .iter()")); + self.file_contents + .push(Cow::Borrowed(" .map(ToString::to_string)")); + } else { + self.file_contents.push(Cow::Borrowed(" .iter()")); + self.file_contents + .push(Cow::Borrowed(" .map(|x| x.borrow(py).__repr__(py))")); + } self.file_contents .push(Cow::Borrowed(" .collect::>()")); self.file_contents.push(Cow::Borrowed(" .join(\", \"),")); @@ -1196,6 +1234,7 @@ fn pyi_generator(type_data: &[(String, String, Vec>)]) -> io::Result ("f32", "float"), ("String", "str"), ("u8", "int"), + ("Vec", "bytes"), ]; for (_, type_name, types) in type_data { @@ -1326,6 +1365,7 @@ fn pyi_generator(type_data: &[(String, String, Vec>)]) -> io::Result "bool" => Cow::Borrowed("False"), "i32" | "u32" | "f32" | "u8" => Cow::Borrowed("0"), "String" => Cow::Borrowed("\"\""), + "Vec" => Cow::Borrowed("b\"\""), t => { if t.starts_with("Vec<") { Cow::Borrowed("[]") diff --git a/flatbuffers-schema b/flatbuffers-schema index 5c23471..5907b45 160000 --- a/flatbuffers-schema +++ b/flatbuffers-schema @@ -1 +1 @@ -Subproject commit 5c234716bdd31886201257a1b1eebc9e7e2ebde0 +Subproject commit 5907b45038a66a4480c3606f2e23eada18bbdee9 diff --git a/pytest.py b/pytest.py index f6376a8..12ab1b8 100644 --- a/pytest.py +++ b/pytest.py @@ -35,6 +35,12 @@ eval(repr(render_type)) print() + comm = MatchComm(3, 1, False, "Ready!", b"Hello, world!") + print(repr(comm)) + print(comm) + print(comm.content.decode("utf-8")) + print() + num_trials = 1_000_000 total_make_time = 0 @@ -44,8 +50,8 @@ start = time_ns() desired_game_state = DesiredGameState( DesiredBallState(DesiredPhysics()), - car_states=[DesiredCarState(boost_amount=Float(100))], - game_info_state=DesiredGameInfoState(game_speed=1, world_gravity_z=Float(-650), end_match=True), + car_states=[DesiredCarState(boost_amount=100)], + game_info_state=DesiredGameInfoState(game_speed=1, world_gravity_z=-650, end_match=True), console_commands=[ConsoleCommand("freeze")], ) total_make_time += time_ns() - start diff --git a/src/lib.rs b/src/lib.rs index 84db86b..f960b47 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -12,7 +12,7 @@ pub mod generated; #[allow(clippy::enum_variant_names)] mod python; -use pyo3::{prelude::*, PyClass}; +use pyo3::{prelude::*, types::PyBytes, PyClass}; use python::*; pub trait FromGil { @@ -43,6 +43,10 @@ impl>> PyDefault for T { } } +pub fn get_empty_pybytes() -> Py { + Python::with_gil(|py| PyBytes::new_bound(py, &[]).unbind()) +} + pub fn get_py_default() -> Py { Python::with_gil(|py| T::py_default(py)) } @@ -120,91 +124,92 @@ pynamedmodule! { doc: "rlbot_flatbuffers is a Python module implemented in Rust for serializing and deserializing RLBot's flatbuffers.", name: rlbot_flatbuffers, classes: [ - MessagePacket, - PredictionSlice, - SphereShape, - PartyMember, - GameMode, - Physics, + ExistingMatchBehavior, PlayerStatEvent, - RenderMessage, - GameStateType, - GameMessage, + MatchComm, + DesiredCarState, + RemoveRenderGroup, BallPrediction, - MutatorSettings, - Vector3, - RotatorPartial, - DesiredBallState, - PlayerInputChange, - BallSizeOption, + PlayerInfo, + GameStateType, + GameSpeedOption, ScoreInfo, - PlayerLoadout, - PlayerConfiguration, - BoostStrengthOption, - ReadyMessage, - Line3D, - PlayerClass, - CollisionShape, - Color, - Float, - MatchLength, - RLBot, - RemoveRenderGroup, - DesiredGameInfoState, - GravityOption, - Bool, + MessagePacket, DemolishOption, - GameTickPacket, - Psyonix, - GameMessageWrapper, - OvertimeOption, - BoostOption, - DesiredCarState, Vector3Partial, - PlayerSpectate, - AirState, - Launcher, - String3D, + TextHAlign, + BoostOption, + RumbleOption, + Vector3, + GravityOption, BallInfo, - ExistingMatchBehavior, - RenderGroup, - PlayerInput, + ReadyMessage, StartCommand, - FieldInfo, + MatchSettings, + OvertimeOption, + PlayerSpectate, + SphereShape, + Touch, + TextVAlign, ConsoleCommand, - SeriesLengthOption, + DesiredGameInfoState, + PredictionSlice, + PolyLine3D, + Rotator, BallTypeOption, - DesiredGameState, - String2D, - StopCommand, - DesiredBoostState, - Human, - DesiredPhysics, - ScriptConfiguration, - ControllerState, + LoadoutPaint, + RotatorPartial, + RLBot, CylinderShape, + PlayerInputChange, + DesiredBallState, + CollisionShape, + RenderMessage, + BoostPadState, + GameMode, + ControllerState, + BoostStrengthOption, + GoalInfo, BallBouncinessOption, - TeamInfo, - PolyLine3D, + MaxScore, + SeriesLengthOption, + GameMessage, + DesiredBoostState, + BallSizeOption, + BallMaxSpeedOption, + MatchLength, BallWeightOption, - LoadoutPaint, - BoxShape, + PlayerLoadout, + Psyonix, + DesiredPhysics, + AirState, + GameMessageWrapper, + GameTickPacket, + Human, + String3D, + Float, + FieldInfo, + PlayerClass, BoostPad, - MatchSettings, - BallMaxSpeedOption, + Bool, + RespawnTimeOption, + String2D, + PartyMember, GameInfo, - Touch, - RumbleOption, - TextVAlign, + StopCommand, + PlayerInput, + Color, + Line3D, + Physics, + MutatorSettings, + PlayerConfiguration, + DesiredGameState, + TeamInfo, RenderType, - GoalInfo, - TextHAlign, - GameSpeedOption, - MaxScore, - BoostPadState, - PlayerInfo, - RespawnTimeOption, - Rotator + RenderGroup, + ScriptConfiguration, + Launcher, + BoxShape ], vars: [ ("__version__", env!("CARGO_PKG_VERSION"))