Skip to content

Commit cdea642

Browse files
committed
Use PyList instead of Vec<T>
1 parent e01d3a2 commit cdea642

File tree

6 files changed

+87
-25
lines changed

6 files changed

+87
-25
lines changed

Cargo.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "rlbot-flatbuffers-py"
3-
version = "0.11.4"
3+
version = "0.11.5"
44
edition = "2021"
55
description = "A Python module implemented in Rust for serializing and deserializing RLBot's flatbuffers"
66
repository = "https://github.com/VirxEC/rlbot_flatbuffers_py"

codegen/structs.rs

Lines changed: 32 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ impl StructBindGenerator {
105105
file_contents.push(Cow::Borrowed(if is_frozen {
106106
"use pyo3::{pyclass, pymethods, types::PyBytes, Bound, PyResult, Python};"
107107
} else {
108-
"use pyo3::{pyclass, pymethods, types::PyBytes, Bound, Py, PyResult, Python};"
108+
"use pyo3::{pyclass, pymethods, types::{PyAnyMethods, PyBytes, PyList, PyListMethods}, Bound, Py, PyResult, Python};"
109109
}));
110110

111111
file_contents.push(Cow::Borrowed(""));
@@ -306,6 +306,10 @@ impl StructBindGenerator {
306306
needs_python = true;
307307
format!("{variable_name}=None")
308308
}
309+
RustType::Vec(InnerVecType::Custom(_)) if !self.is_frozen => {
310+
needs_python = true;
311+
format!("{variable_name}=Vec::new()")
312+
}
309313
_ => {
310314
format!("{variable_name}=Default::default()")
311315
}
@@ -409,15 +413,18 @@ impl StructBindGenerator {
409413
}
410414
}
411415
RustType::Box(inner_type) | RustType::Custom(inner_type) if !self.is_frozen => {
416+
write_fmt!(self, " {variable_name}: {variable_name}.unwrap_or_else(|| super::{inner_type}::py_default(py)),",);
417+
}
418+
RustType::Vec(InnerVecType::U8) => {
412419
write_fmt!(
413420
self,
414-
" {variable_name}: {variable_name}.unwrap_or_else(|| super::{inner_type}::py_default(py)),",
421+
" {variable_name}: {variable_name}.unwrap_or_else(|| PyBytes::new(py, &[]).unbind()),"
415422
);
416423
}
417-
RustType::Vec(InnerVecType::U8) => {
424+
RustType::Vec(InnerVecType::Custom(_)) if !self.is_frozen => {
418425
write_fmt!(
419426
self,
420-
" {variable_name}: {variable_name}.unwrap_or_else(|| PyBytes::new(py, &[]).unbind()),"
427+
" {variable_name}: PyList::new(py, {variable_name}).unwrap().unbind(),"
421428
);
422429
}
423430
_ => write_fmt!(self, " {variable_name},"),
@@ -490,16 +497,17 @@ impl StructBindGenerator {
490497
write_str!(self, " .iter()");
491498
write_str!(self, " .map(ToString::to_string)");
492499
}
493-
InnerVecType::Custom(_) => {
500+
InnerVecType::Custom(type_name) => {
501+
if !self.is_frozen {
502+
write_str!(self, " .bind_borrowed(py)");
503+
}
504+
494505
write_str!(self, " .iter()");
495-
write_str!(
496-
self,
497-
if self.is_frozen {
498-
" .map(|x| x.__repr__(py))"
499-
} else {
500-
" .map(|x| x.borrow(py).__repr__(py))"
501-
}
502-
);
506+
if self.is_frozen {
507+
write_str!(self, " .map(|x| x.__repr__(py))");
508+
} else {
509+
write_fmt!(self, " .map(|x| x.downcast_into::<super::{type_name}>().unwrap().borrow().__repr__(py))");
510+
}
503511
}
504512
}
505513
write_str!(self, " .collect::<Vec<String>>()");
@@ -759,7 +767,7 @@ impl Generator for StructBindGenerator {
759767
if self.is_frozen {
760768
format!("Vec<super::{inner_type}>")
761769
} else {
762-
format!("Vec<Py<super::{inner_type}>>")
770+
String::from("Py<PyList>")
763771
}
764772
}
765773
RustType::Box(inner_type) => {
@@ -815,6 +823,9 @@ impl Generator for StructBindGenerator {
815823

816824
let end = match &variable_info.rust_type {
817825
RustType::Vec(InnerVecType::U8) => Cow::Borrowed("PyBytes::new(py, &[]).unbind()"),
826+
RustType::Vec(InnerVecType::Custom(_)) if !self.is_frozen => {
827+
Cow::Borrowed("PyList::empty(py).unbind()")
828+
}
818829
RustType::Vec(_) => Cow::Borrowed("Vec::new()"),
819830
RustType::Option(_, _) => Cow::Borrowed("None"),
820831
RustType::Union(inner_type)
@@ -890,7 +901,7 @@ impl Generator for StructBindGenerator {
890901
RustType::Vec(InnerVecType::String | InnerVecType::Base(_)) => {
891902
write_fmt!(self, " {variable_name}: flat_t.{variable_name},")
892903
}
893-
RustType::Vec(InnerVecType::Custom(_)) => {
904+
RustType::Vec(InnerVecType::Custom(type_name)) => {
894905
if self.is_frozen {
895906
let map_out = if variable_info.frozen_needs_py {
896907
"|x| x.into_gil(py)"
@@ -905,7 +916,7 @@ impl Generator for StructBindGenerator {
905916
} else {
906917
write_fmt!(
907918
self,
908-
" {variable_name}: flat_t.{variable_name}.into_iter().map(|x| crate::into_py_from(py, x)).collect(),",
919+
" {variable_name}: PyList::new(py, flat_t.{variable_name}.into_iter().map(|x| crate::into_py_from::<_, super::{type_name}>(py, x))).unwrap().unbind(),",
909920
)
910921
}
911922
}
@@ -1041,7 +1052,7 @@ impl Generator for StructBindGenerator {
10411052
} else {
10421053
write_fmt!(
10431054
self,
1044-
" {variable_name}: py_type.{variable_name}.iter().map(|x| crate::from_py_into(py, x)).collect(),",
1055+
" {variable_name}: py_type.{variable_name}.bind_borrowed(py).iter().map(|x| crate::from_pyany_into(py, x)).collect(),",
10451056
)
10461057
}
10471058
}
@@ -1052,7 +1063,10 @@ impl Generator for StructBindGenerator {
10521063
"crate::from_py_into(py, x)"
10531064
};
10541065

1055-
write_fmt!(self, " {variable_name}: py_type.{variable_name}.as_ref().map(|x| Box::new({inner})),");
1066+
write_fmt!(
1067+
self,
1068+
" {variable_name}: py_type.{variable_name}.as_ref().map(|x| Box::new({inner})),"
1069+
);
10561070
}
10571071
RustType::Option(InnerOptionType::String, _) => {
10581072
write_fmt!(

codegen/unions.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -139,9 +139,11 @@ impl UnionBindGenerator {
139139
let variable_name = variable_info.name.as_str();
140140

141141
if variable_info.value.is_some() {
142-
write_fmt!(self,
142+
write_fmt!(
143+
self,
143144
" Some({}Union::{variable_name}(item)) => format!(\"{}({{}})\", item{borrow_str}.__repr__(py)),",
144-
self.struct_name, self.struct_name
145+
self.struct_name,
146+
self.struct_name
145147
);
146148
} else {
147149
write_fmt!(

pybench.py

Lines changed: 40 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ def test_ballpred():
3939

4040
times = []
4141

42-
ballPred = flat.BallPrediction([flat.PredictionSlice(1) for _ in range(120 * 8)])
42+
ballPred = flat.BallPrediction([flat.PredictionSlice(1) for _ in range(120 * 10)])
4343

4444
print(len(ballPred.pack()))
4545

@@ -72,11 +72,35 @@ def find_slice_at_time(ball_prediction: flat.BallPrediction, game_time: float):
7272

7373

7474
def test_loop():
75-
times = []
76-
7775
ballPred = flat.BallPrediction([flat.PredictionSlice(1) for _ in range(120 * 6)])
7876

77+
start = time_ns()
7978
for _ in range(100):
79+
80+
li = []
81+
for t in range(1, 301):
82+
ball_in_future = find_slice_at_time(ballPred, t / 60)
83+
li.append(ball_in_future)
84+
print(f"Total time: {(time_ns() - start) / 1_000_000:.3f}ms")
85+
86+
times = []
87+
for _ in range(50_000):
88+
start = time_ns()
89+
90+
li = []
91+
for t in range(1, 301):
92+
ball_in_future = find_slice_at_time(ballPred, t / 60)
93+
li.append(ball_in_future)
94+
95+
times.append(time_ns() - start)
96+
97+
print(f"Total time: {sum(times) / 1_000_000_000:.3f}s")
98+
avg_time_ns = sum(times) / len(times)
99+
print(f"Average time per: {avg_time_ns / 1000:.1f}us")
100+
print(f"Minimum time per: {min(times) / 1000:.1f}us")
101+
102+
times = []
103+
for _ in range(50_000):
80104
start = time_ns()
81105

82106
li = [find_slice_at_time(ballPred, t / 60) for t in range(1, 301)]
@@ -88,6 +112,19 @@ def test_loop():
88112
print(f"Average time per: {avg_time_ns / 1000:.1f}us")
89113
print(f"Minimum time per: {min(times) / 1000:.1f}us")
90114

115+
times = []
116+
for _ in range(1_000_000):
117+
start = time_ns()
118+
119+
li = list(ballPred.slices[1:602:2])
120+
121+
times.append(time_ns() - start)
122+
123+
print(f"Total time: {sum(times) / 1_000_000_000:.3f}s")
124+
avg_time_ns = sum(times) / len(times)
125+
print(f"Average time per: {avg_time_ns / 1000:.1f}us")
126+
print(f"Minimum time per: {min(times) / 1000:.1f}us")
127+
91128

92129
if __name__ == "__main__":
93130
test_gtp()

src/lib.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,15 @@ where
8080
(&*obj.borrow(py)).into_gil(py)
8181
}
8282

83+
#[inline(never)]
84+
fn from_pyany_into<T, U>(py: Python, obj: Bound<PyAny>) -> U
85+
where
86+
T: PyClass,
87+
U: for<'a> FromGil<&'a T>,
88+
{
89+
(&*obj.downcast_into::<T>().unwrap().borrow()).into_gil(py)
90+
}
91+
8392
pub trait PyDefault: Sized + PyClass {
8493
fn py_default(py: Python) -> Py<Self>;
8594
}

0 commit comments

Comments
 (0)