fastquadtree 2.2.0__tar.gz → 2.3.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {fastquadtree-2.2.0 → fastquadtree-2.3.0}/Cargo.lock +82 -48
- {fastquadtree-2.2.0 → fastquadtree-2.3.0}/Cargo.toml +3 -3
- {fastquadtree-2.2.0 → fastquadtree-2.3.0}/LICENSE +1 -1
- {fastquadtree-2.2.0 → fastquadtree-2.3.0}/PKG-INFO +6 -2
- {fastquadtree-2.2.0 → fastquadtree-2.3.0}/README.md +5 -1
- {fastquadtree-2.2.0 → fastquadtree-2.3.0}/docs/2.0_migration_guide.md +3 -1
- {fastquadtree-2.2.0 → fastquadtree-2.3.0}/docs/benchmark.md +9 -9
- {fastquadtree-2.2.0 → fastquadtree-2.3.0}/docs/index.md +2 -2
- {fastquadtree-2.2.0 → fastquadtree-2.3.0}/pysrc/fastquadtree/_base_quadtree.py +40 -5
- {fastquadtree-2.2.0 → fastquadtree-2.3.0}/pysrc/fastquadtree/_base_quadtree_objects.py +39 -5
- {fastquadtree-2.2.0 → fastquadtree-2.3.0}/pysrc/fastquadtree/_common.py +41 -3
- {fastquadtree-2.2.0 → fastquadtree-2.3.0}/pysrc/fastquadtree/point_quadtree.py +10 -2
- {fastquadtree-2.2.0 → fastquadtree-2.3.0}/pysrc/fastquadtree/point_quadtree_objects.py +10 -2
- {fastquadtree-2.2.0 → fastquadtree-2.3.0}/pysrc/fastquadtree/rect_quadtree.py +10 -2
- {fastquadtree-2.2.0 → fastquadtree-2.3.0}/pysrc/fastquadtree/rect_quadtree_objects.py +10 -2
- {fastquadtree-2.2.0 → fastquadtree-2.3.0}/src/geom.rs +6 -8
- {fastquadtree-2.2.0 → fastquadtree-2.3.0}/src/lib.rs +26 -4
- {fastquadtree-2.2.0 → fastquadtree-2.3.0}/src/quadtree.rs +40 -12
- {fastquadtree-2.2.0 → fastquadtree-2.3.0}/src/rect_quadtree.rs +42 -14
- fastquadtree-2.3.0/src/serialization.rs +258 -0
- fastquadtree-2.3.0/tests/serialization.rs +151 -0
- {fastquadtree-2.2.0 → fastquadtree-2.3.0}/tests/test_python/common/test_internal_edges.py +26 -5
- {fastquadtree-2.2.0 → fastquadtree-2.3.0}/tests/test_python/points/test_point_quadtree_serialization.py +53 -1
- {fastquadtree-2.2.0 → fastquadtree-2.3.0}/tests/test_python/points_objects/test_point_quadtree_objects_serialization.py +27 -1
- {fastquadtree-2.2.0 → fastquadtree-2.3.0}/tests/test_python/rects/test_rect_quadtree_serialization.py +34 -1
- fastquadtree-2.2.0/tests/serialization.rs +0 -63
- {fastquadtree-2.2.0 → fastquadtree-2.3.0}/.github/workflows/docs.yml +0 -0
- {fastquadtree-2.2.0 → fastquadtree-2.3.0}/.github/workflows/release.yml +0 -0
- {fastquadtree-2.2.0 → fastquadtree-2.3.0}/.github/workflows/test.yml +0 -0
- {fastquadtree-2.2.0 → fastquadtree-2.3.0}/.gitignore +0 -0
- {fastquadtree-2.2.0 → fastquadtree-2.3.0}/.pre-commit-config.yaml +0 -0
- {fastquadtree-2.2.0 → fastquadtree-2.3.0}/assets/ballpit.png +0 -0
- {fastquadtree-2.2.0 → fastquadtree-2.3.0}/assets/interactive_v2_rect_screenshot.png +0 -0
- {fastquadtree-2.2.0 → fastquadtree-2.3.0}/assets/interactive_v2_screenshot.png +0 -0
- {fastquadtree-2.2.0 → fastquadtree-2.3.0}/assets/pygame_sprites_demo.png +0 -0
- {fastquadtree-2.2.0 → fastquadtree-2.3.0}/assets/quadtree_bench_throughput.png +0 -0
- {fastquadtree-2.2.0 → fastquadtree-2.3.0}/assets/quadtree_bench_time.png +0 -0
- {fastquadtree-2.2.0 → fastquadtree-2.3.0}/benchmarks/benchmark_native_vs_shim.py +0 -0
- {fastquadtree-2.2.0 → fastquadtree-2.3.0}/benchmarks/benchmark_np_vs_list.py +0 -0
- {fastquadtree-2.2.0 → fastquadtree-2.3.0}/benchmarks/benchmark_serialization_vs_rebuild.py +0 -0
- {fastquadtree-2.2.0 → fastquadtree-2.3.0}/benchmarks/cross_library_bench.py +0 -0
- {fastquadtree-2.2.0 → fastquadtree-2.3.0}/benchmarks/quadtree_bench/__init__.py +0 -0
- {fastquadtree-2.2.0 → fastquadtree-2.3.0}/benchmarks/quadtree_bench/engines.py +0 -0
- {fastquadtree-2.2.0 → fastquadtree-2.3.0}/benchmarks/quadtree_bench/main.py +0 -0
- {fastquadtree-2.2.0 → fastquadtree-2.3.0}/benchmarks/quadtree_bench/optimizer.py +0 -0
- {fastquadtree-2.2.0 → fastquadtree-2.3.0}/benchmarks/quadtree_bench/plotting.py +0 -0
- {fastquadtree-2.2.0 → fastquadtree-2.3.0}/benchmarks/quadtree_bench/runner.py +0 -0
- {fastquadtree-2.2.0 → fastquadtree-2.3.0}/benchmarks/runner.py +0 -0
- {fastquadtree-2.2.0 → fastquadtree-2.3.0}/benchmarks/system_info_collector.py +0 -0
- {fastquadtree-2.2.0 → fastquadtree-2.3.0}/docs/2.0_proposal.md +0 -0
- {fastquadtree-2.2.0 → fastquadtree-2.3.0}/docs/api/insert_result.md +0 -0
- {fastquadtree-2.2.0 → fastquadtree-2.3.0}/docs/api/item.md +0 -0
- {fastquadtree-2.2.0 → fastquadtree-2.3.0}/docs/api/point_item.md +0 -0
- {fastquadtree-2.2.0 → fastquadtree-2.3.0}/docs/api/pygame.md +0 -0
- {fastquadtree-2.2.0 → fastquadtree-2.3.0}/docs/api/pyqtree.md +0 -0
- {fastquadtree-2.2.0 → fastquadtree-2.3.0}/docs/api/quadtree.md +0 -0
- {fastquadtree-2.2.0 → fastquadtree-2.3.0}/docs/api/quadtree_objects.md +0 -0
- {fastquadtree-2.2.0 → fastquadtree-2.3.0}/docs/api/rect_item.md +0 -0
- {fastquadtree-2.2.0 → fastquadtree-2.3.0}/docs/api/rect_quadtree.md +0 -0
- {fastquadtree-2.2.0 → fastquadtree-2.3.0}/docs/api/rect_quadtree_objects.md +0 -0
- {fastquadtree-2.2.0 → fastquadtree-2.3.0}/docs/future_features.md +0 -0
- {fastquadtree-2.2.0 → fastquadtree-2.3.0}/docs/quickstart.md +0 -0
- {fastquadtree-2.2.0 → fastquadtree-2.3.0}/docs/runnables.md +0 -0
- {fastquadtree-2.2.0 → fastquadtree-2.3.0}/docs/rust_usage.md +0 -0
- {fastquadtree-2.2.0 → fastquadtree-2.3.0}/docs/styles/overrides.css +0 -0
- {fastquadtree-2.2.0 → fastquadtree-2.3.0}/examples/custom_id_example.py +0 -0
- {fastquadtree-2.2.0 → fastquadtree-2.3.0}/examples/object_tracking_example.py +0 -0
- {fastquadtree-2.2.0 → fastquadtree-2.3.0}/interactive/ballpit.py +0 -0
- {fastquadtree-2.2.0 → fastquadtree-2.3.0}/interactive/interactive.py +0 -0
- {fastquadtree-2.2.0 → fastquadtree-2.3.0}/interactive/interactive_v2.py +0 -0
- {fastquadtree-2.2.0 → fastquadtree-2.3.0}/interactive/interactive_v2_rect.py +0 -0
- {fastquadtree-2.2.0 → fastquadtree-2.3.0}/interactive/pygame_sprites.py +0 -0
- {fastquadtree-2.2.0 → fastquadtree-2.3.0}/mkdocs.yml +0 -0
- {fastquadtree-2.2.0 → fastquadtree-2.3.0}/pyproject.toml +0 -0
- {fastquadtree-2.2.0 → fastquadtree-2.3.0}/pyrightconfig.json +0 -0
- {fastquadtree-2.2.0 → fastquadtree-2.3.0}/pysrc/fastquadtree/__init__.py +0 -0
- {fastquadtree-2.2.0 → fastquadtree-2.3.0}/pysrc/fastquadtree/_insert_result.py +0 -0
- {fastquadtree-2.2.0 → fastquadtree-2.3.0}/pysrc/fastquadtree/_item.py +0 -0
- {fastquadtree-2.2.0 → fastquadtree-2.3.0}/pysrc/fastquadtree/_obj_store.py +0 -0
- {fastquadtree-2.2.0 → fastquadtree-2.3.0}/pysrc/fastquadtree/py.typed +0 -0
- {fastquadtree-2.2.0 → fastquadtree-2.3.0}/pysrc/fastquadtree/pygame.py +0 -0
- {fastquadtree-2.2.0 → fastquadtree-2.3.0}/pysrc/fastquadtree/pyqtree.py +0 -0
- {fastquadtree-2.2.0 → fastquadtree-2.3.0}/tests/__init__.py +0 -0
- {fastquadtree-2.2.0 → fastquadtree-2.3.0}/tests/insertions.rs +0 -0
- {fastquadtree-2.2.0 → fastquadtree-2.3.0}/tests/nearest_neighbor.rs +0 -0
- {fastquadtree-2.2.0 → fastquadtree-2.3.0}/tests/query.rs +0 -0
- {fastquadtree-2.2.0 → fastquadtree-2.3.0}/tests/rect_quadtree.rs +0 -0
- {fastquadtree-2.2.0 → fastquadtree-2.3.0}/tests/rectangle_traversal.rs +0 -0
- {fastquadtree-2.2.0 → fastquadtree-2.3.0}/tests/test_delete.rs +0 -0
- {fastquadtree-2.2.0 → fastquadtree-2.3.0}/tests/test_python/__init__.py +0 -0
- {fastquadtree-2.2.0 → fastquadtree-2.3.0}/tests/test_python/common/test_common_validation.py +0 -0
- {fastquadtree-2.2.0 → fastquadtree-2.3.0}/tests/test_python/common/test_insert_result_and_items.py +0 -0
- {fastquadtree-2.2.0 → fastquadtree-2.3.0}/tests/test_python/common/test_obj_store.py +0 -0
- {fastquadtree-2.2.0 → fastquadtree-2.3.0}/tests/test_python/common/test_serialization_container.py +0 -0
- {fastquadtree-2.2.0 → fastquadtree-2.3.0}/tests/test_python/conftest.py +0 -0
- {fastquadtree-2.2.0 → fastquadtree-2.3.0}/tests/test_python/integration/test_migration_breaks_and_safety.py +0 -0
- {fastquadtree-2.2.0 → fastquadtree-2.3.0}/tests/test_python/integration/test_optional_pygame_dependency.py +0 -0
- {fastquadtree-2.2.0 → fastquadtree-2.3.0}/tests/test_python/integration/test_public_api_contracts.py +0 -0
- {fastquadtree-2.2.0 → fastquadtree-2.3.0}/tests/test_python/integration/test_pygame_integration.py +0 -0
- {fastquadtree-2.2.0 → fastquadtree-2.3.0}/tests/test_python/points/test_point_quadtree_core.py +0 -0
- {fastquadtree-2.2.0 → fastquadtree-2.3.0}/tests/test_python/points/test_point_quadtree_mutation.py +0 -0
- {fastquadtree-2.2.0 → fastquadtree-2.3.0}/tests/test_python/points/test_point_quadtree_numpy.py +0 -0
- {fastquadtree-2.2.0 → fastquadtree-2.3.0}/tests/test_python/points/test_point_quadtree_precision.py +0 -0
- {fastquadtree-2.2.0 → fastquadtree-2.3.0}/tests/test_python/points_objects/test_point_quadtree_objects_core.py +0 -0
- {fastquadtree-2.2.0 → fastquadtree-2.3.0}/tests/test_python/points_objects/test_point_quadtree_objects_deletion_update.py +0 -0
- {fastquadtree-2.2.0 → fastquadtree-2.3.0}/tests/test_python/points_objects/test_point_quadtree_objects_numpy.py +0 -0
- {fastquadtree-2.2.0 → fastquadtree-2.3.0}/tests/test_python/rects/test_rect_quadtree_core.py +0 -0
- {fastquadtree-2.2.0 → fastquadtree-2.3.0}/tests/test_python/rects/test_rect_quadtree_mutation.py +0 -0
- {fastquadtree-2.2.0 → fastquadtree-2.3.0}/tests/test_python/rects/test_rect_quadtree_numpy.py +0 -0
- {fastquadtree-2.2.0 → fastquadtree-2.3.0}/tests/test_python/rects_objects/test_rect_quadtree_objects_core.py +0 -0
- {fastquadtree-2.2.0 → fastquadtree-2.3.0}/tests/test_python/rects_objects/test_rect_quadtree_objects_deletion_update.py +0 -0
- {fastquadtree-2.2.0 → fastquadtree-2.3.0}/tests/test_python/rects_objects/test_rect_quadtree_objects_numpy.py +0 -0
- {fastquadtree-2.2.0 → fastquadtree-2.3.0}/tests/test_python/rects_objects/test_rect_quadtree_objects_serialization.py +0 -0
- {fastquadtree-2.2.0 → fastquadtree-2.3.0}/tests/test_python/test_pyqtree_shim_compat.py +0 -0
- {fastquadtree-2.2.0 → fastquadtree-2.3.0}/tests/unconventional_bounds.rs +0 -0
|
@@ -9,35 +9,48 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
|
9
9
|
checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
|
|
10
10
|
|
|
11
11
|
[[package]]
|
|
12
|
-
name = "
|
|
13
|
-
version = "
|
|
12
|
+
name = "darling"
|
|
13
|
+
version = "0.23.0"
|
|
14
14
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
15
|
-
checksum = "
|
|
15
|
+
checksum = "25ae13da2f202d56bd7f91c25fba009e7717a1e4a1cc98a76d844b65ae912e9d"
|
|
16
16
|
dependencies = [
|
|
17
|
-
"
|
|
18
|
-
"
|
|
19
|
-
"unty",
|
|
17
|
+
"darling_core",
|
|
18
|
+
"darling_macro",
|
|
20
19
|
]
|
|
21
20
|
|
|
22
21
|
[[package]]
|
|
23
|
-
name = "
|
|
24
|
-
version = "
|
|
22
|
+
name = "darling_core"
|
|
23
|
+
version = "0.23.0"
|
|
25
24
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
26
|
-
checksum = "
|
|
25
|
+
checksum = "9865a50f7c335f53564bb694ef660825eb8610e0a53d3e11bf1b0d3df31e03b0"
|
|
27
26
|
dependencies = [
|
|
28
|
-
"
|
|
27
|
+
"ident_case",
|
|
28
|
+
"proc-macro2",
|
|
29
|
+
"quote",
|
|
30
|
+
"strsim",
|
|
31
|
+
"syn",
|
|
32
|
+
]
|
|
33
|
+
|
|
34
|
+
[[package]]
|
|
35
|
+
name = "darling_macro"
|
|
36
|
+
version = "0.23.0"
|
|
37
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
38
|
+
checksum = "ac3984ec7bd6cfa798e62b4a642426a5be0e68f9401cfc2a01e3fa9ea2fcdb8d"
|
|
39
|
+
dependencies = [
|
|
40
|
+
"darling_core",
|
|
41
|
+
"quote",
|
|
42
|
+
"syn",
|
|
29
43
|
]
|
|
30
44
|
|
|
31
45
|
[[package]]
|
|
32
46
|
name = "fastquadtree"
|
|
33
|
-
version = "2.
|
|
47
|
+
version = "2.3.0"
|
|
34
48
|
dependencies = [
|
|
35
|
-
"bincode",
|
|
36
49
|
"num-traits",
|
|
37
50
|
"numpy",
|
|
38
51
|
"pyo3",
|
|
39
|
-
"serde",
|
|
40
52
|
"smallvec",
|
|
53
|
+
"wincode",
|
|
41
54
|
]
|
|
42
55
|
|
|
43
56
|
[[package]]
|
|
@@ -46,6 +59,12 @@ version = "0.5.0"
|
|
|
46
59
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
47
60
|
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
|
|
48
61
|
|
|
62
|
+
[[package]]
|
|
63
|
+
name = "ident_case"
|
|
64
|
+
version = "1.0.1"
|
|
65
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
66
|
+
checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
|
|
67
|
+
|
|
49
68
|
[[package]]
|
|
50
69
|
name = "libc"
|
|
51
70
|
version = "0.2.186"
|
|
@@ -126,6 +145,12 @@ version = "1.21.4"
|
|
|
126
145
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
127
146
|
checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50"
|
|
128
147
|
|
|
148
|
+
[[package]]
|
|
149
|
+
name = "pastey"
|
|
150
|
+
version = "0.2.3"
|
|
151
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
152
|
+
checksum = "2ee67f1008b1ba2321834326597b8e186293b049a023cdef258527550b9935b4"
|
|
153
|
+
|
|
129
154
|
[[package]]
|
|
130
155
|
name = "portable-atomic"
|
|
131
156
|
version = "1.13.1"
|
|
@@ -230,57 +255,53 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
|
230
255
|
checksum = "94300abf3f1ae2e2b8ffb7b58043de3d399c73fa6f4b73826402a5c457614dbe"
|
|
231
256
|
|
|
232
257
|
[[package]]
|
|
233
|
-
name = "
|
|
234
|
-
version = "1.
|
|
258
|
+
name = "smallvec"
|
|
259
|
+
version = "1.15.1"
|
|
235
260
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
236
|
-
checksum = "
|
|
237
|
-
dependencies = [
|
|
238
|
-
"serde_core",
|
|
239
|
-
"serde_derive",
|
|
240
|
-
]
|
|
261
|
+
checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03"
|
|
241
262
|
|
|
242
263
|
[[package]]
|
|
243
|
-
name = "
|
|
244
|
-
version = "
|
|
264
|
+
name = "strsim"
|
|
265
|
+
version = "0.11.1"
|
|
245
266
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
246
|
-
checksum = "
|
|
247
|
-
dependencies = [
|
|
248
|
-
"serde_derive",
|
|
249
|
-
]
|
|
267
|
+
checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
|
|
250
268
|
|
|
251
269
|
[[package]]
|
|
252
|
-
name = "
|
|
253
|
-
version = "
|
|
270
|
+
name = "syn"
|
|
271
|
+
version = "2.0.117"
|
|
254
272
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
255
|
-
checksum = "
|
|
273
|
+
checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99"
|
|
256
274
|
dependencies = [
|
|
257
275
|
"proc-macro2",
|
|
258
276
|
"quote",
|
|
259
|
-
"
|
|
277
|
+
"unicode-ident",
|
|
260
278
|
]
|
|
261
279
|
|
|
262
280
|
[[package]]
|
|
263
|
-
name = "
|
|
264
|
-
version = "
|
|
281
|
+
name = "target-lexicon"
|
|
282
|
+
version = "0.13.5"
|
|
265
283
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
266
|
-
checksum = "
|
|
284
|
+
checksum = "adb6935a6f5c20170eeceb1a3835a49e12e19d792f6dd344ccc76a985ca5a6ca"
|
|
267
285
|
|
|
268
286
|
[[package]]
|
|
269
|
-
name = "
|
|
270
|
-
version = "2.0.
|
|
287
|
+
name = "thiserror"
|
|
288
|
+
version = "2.0.18"
|
|
271
289
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
272
|
-
checksum = "
|
|
290
|
+
checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4"
|
|
273
291
|
dependencies = [
|
|
274
|
-
"
|
|
275
|
-
"quote",
|
|
276
|
-
"unicode-ident",
|
|
292
|
+
"thiserror-impl",
|
|
277
293
|
]
|
|
278
294
|
|
|
279
295
|
[[package]]
|
|
280
|
-
name = "
|
|
281
|
-
version = "0.
|
|
296
|
+
name = "thiserror-impl"
|
|
297
|
+
version = "2.0.18"
|
|
282
298
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
283
|
-
checksum = "
|
|
299
|
+
checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5"
|
|
300
|
+
dependencies = [
|
|
301
|
+
"proc-macro2",
|
|
302
|
+
"quote",
|
|
303
|
+
"syn",
|
|
304
|
+
]
|
|
284
305
|
|
|
285
306
|
[[package]]
|
|
286
307
|
name = "unicode-ident"
|
|
@@ -289,13 +310,26 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
|
289
310
|
checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75"
|
|
290
311
|
|
|
291
312
|
[[package]]
|
|
292
|
-
name = "
|
|
293
|
-
version = "0.
|
|
313
|
+
name = "wincode"
|
|
314
|
+
version = "0.5.5"
|
|
294
315
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
295
|
-
checksum = "
|
|
316
|
+
checksum = "66d967db7705dc29120bb6e8ce5b5a2e27734ed5976d1c904e95bd238d1c3c5a"
|
|
317
|
+
dependencies = [
|
|
318
|
+
"pastey",
|
|
319
|
+
"proc-macro2",
|
|
320
|
+
"quote",
|
|
321
|
+
"thiserror",
|
|
322
|
+
"wincode-derive",
|
|
323
|
+
]
|
|
296
324
|
|
|
297
325
|
[[package]]
|
|
298
|
-
name = "
|
|
299
|
-
version = "0.
|
|
326
|
+
name = "wincode-derive"
|
|
327
|
+
version = "0.4.6"
|
|
300
328
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
301
|
-
checksum = "
|
|
329
|
+
checksum = "15ab90b719560d0fda79c74550ad1c948d17b118765942838055ebaf34d67071"
|
|
330
|
+
dependencies = [
|
|
331
|
+
"darling",
|
|
332
|
+
"proc-macro2",
|
|
333
|
+
"quote",
|
|
334
|
+
"syn",
|
|
335
|
+
]
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
[package]
|
|
2
2
|
name = "fastquadtree"
|
|
3
|
-
version = "2.
|
|
3
|
+
version = "2.3.0"
|
|
4
4
|
edition = "2021"
|
|
5
|
+
rust-version = "1.89"
|
|
5
6
|
readme = "README.md"
|
|
6
7
|
|
|
7
8
|
[lib]
|
|
@@ -11,8 +12,7 @@ crate-type = ["rlib", "cdylib"]
|
|
|
11
12
|
pyo3 = { version = "0.28", features = ["extension-module", "abi3-py39"] }
|
|
12
13
|
smallvec = "1.15.1"
|
|
13
14
|
numpy = "0.28"
|
|
14
|
-
|
|
15
|
-
bincode = {version = "2.0.1", features = ["serde"]}
|
|
15
|
+
wincode = { version = "0.5.5", features = ["derive"] }
|
|
16
16
|
num-traits = "0.2"
|
|
17
17
|
|
|
18
18
|
[profile.release]
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: fastquadtree
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.3.0
|
|
4
4
|
Classifier: Programming Language :: Python :: 3
|
|
5
5
|
Classifier: Programming Language :: Python :: 3 :: Only
|
|
6
6
|
Classifier: Programming Language :: Python :: 3.9
|
|
@@ -62,6 +62,7 @@ Rust-optimized quadtree with a clean Python API
|
|
|
62
62
|
- Support for [inserting bounding boxes](https://elan456.github.io/fastquadtree/api/rect_quadtree/) or points
|
|
63
63
|
- Fast KNN and range queries
|
|
64
64
|
- Optional object tracking for id ↔ object mapping
|
|
65
|
+
- Mostly drop-in [pygame sprite-group integration](https://elan456.github.io/fastquadtree/api/pygame/) that adds automatic broadphase culling for faster collision detection (depending on workload)
|
|
65
66
|
- Fast [serialization](https://elan456.github.io/fastquadtree/benchmark/#serialization-vs-rebuild) to/from bytes
|
|
66
67
|
- Support for multiple data types (f32, f64, i32, i64) for coordinates
|
|
67
68
|
- [100% test coverage](https://codecov.io/gh/Elan456/fastquadtree) and CI on GitHub Actions
|
|
@@ -88,6 +89,7 @@ from fastquadtree.pyqtree import Index # Drop-in pyqtree shim (~10x faster whil
|
|
|
88
89
|
| `QuadTreeObjects` | Points | Yes | Point indexing with attached Python objects. |
|
|
89
90
|
| `RectQuadTreeObjects` | Bounding boxes | Yes | Rectangle indexing with attached objects. |
|
|
90
91
|
| `fastquadtree.pyqtree.Index` | Bounding boxes | Yes | pyqtree-compatible API, much faster. |
|
|
92
|
+
| `fastquadtree.pygame.Group` | pygame sprites | Yes | Mostly drop-in replacement for `pygame.sprite.Group` with quadtree indexing for faster collision detection. |
|
|
91
93
|
|
|
92
94
|
|
|
93
95
|
## Quickstart
|
|
@@ -233,7 +235,9 @@ qt.insert_many_np(points) # Use insert_many_np for NumPy arrays
|
|
|
233
235
|
```
|
|
234
236
|
|
|
235
237
|
**Does fastquadtree support multiprocessing?**
|
|
236
|
-
Yes, fastquadtree objects can be serialized to bytes using the `to_bytes()` method and deserialized back using `from_bytes()`. This allows you to share quadtree data across processes and even cache prebuilt trees to disk. When using `QuadTreeObjects` or `RectQuadTreeObjects`, you must pass `include_objects=True` to `to_bytes()` to serialize Python objects, and `allow_objects=True` to `from_bytes()` when loading. By default, objects are skipped for safety, as deserializing untrusted Python objects can be unsafe. See the [interactive v2 demo](https://github.com/Elan456/fastquadtree/blob/main/interactive/interactive_v2.py) for an example of saving and loading a quadtree, and the [QuadTreeObjects API docs](https://elan456.github.io/fastquadtree/api/quadtree_objects/#fastquadtree.QuadTreeObjects.to_bytes) for full details on the serialization methods.
|
|
238
|
+
Yes, fastquadtree objects can be serialized to bytes using the `to_bytes()` method and deserialized back using `from_bytes()`. This allows you to share quadtree data across processes and even cache prebuilt trees to disk. When using `QuadTreeObjects` or `RectQuadTreeObjects`, you must pass `include_objects=True` to `to_bytes()` to serialize Python objects, and `allow_objects=True` to `from_bytes()` when loading. By default, objects are skipped for safety, as deserializing untrusted Python objects can be unsafe. Native decode uses a default preallocation limit of 67,108,864 bytes (64 MiB); if loading needs more than the configured bucket, `from_bytes()` fails with a `ValueError` unless you choose a larger allowed bucket or pass `disable_preallocation_limit=True` for trusted data. See the [interactive v2 demo](https://github.com/Elan456/fastquadtree/blob/main/interactive/interactive_v2.py) for an example of saving and loading a quadtree, and the [QuadTreeObjects API docs](https://elan456.github.io/fastquadtree/api/quadtree_objects/#fastquadtree.QuadTreeObjects.to_bytes) for full details on the serialization methods.
|
|
239
|
+
|
|
240
|
+
Serialization uses the current fastquadtree binary format. Data serialized by bincode-backed fastquadtree releases, including v2.2 and earlier, is not loadable by newer wincode-backed releases.
|
|
237
241
|
|
|
238
242
|
## License
|
|
239
243
|
|
|
@@ -32,6 +32,7 @@ Rust-optimized quadtree with a clean Python API
|
|
|
32
32
|
- Support for [inserting bounding boxes](https://elan456.github.io/fastquadtree/api/rect_quadtree/) or points
|
|
33
33
|
- Fast KNN and range queries
|
|
34
34
|
- Optional object tracking for id ↔ object mapping
|
|
35
|
+
- Mostly drop-in [pygame sprite-group integration](https://elan456.github.io/fastquadtree/api/pygame/) that adds automatic broadphase culling for faster collision detection (depending on workload)
|
|
35
36
|
- Fast [serialization](https://elan456.github.io/fastquadtree/benchmark/#serialization-vs-rebuild) to/from bytes
|
|
36
37
|
- Support for multiple data types (f32, f64, i32, i64) for coordinates
|
|
37
38
|
- [100% test coverage](https://codecov.io/gh/Elan456/fastquadtree) and CI on GitHub Actions
|
|
@@ -58,6 +59,7 @@ from fastquadtree.pyqtree import Index # Drop-in pyqtree shim (~10x faster whil
|
|
|
58
59
|
| `QuadTreeObjects` | Points | Yes | Point indexing with attached Python objects. |
|
|
59
60
|
| `RectQuadTreeObjects` | Bounding boxes | Yes | Rectangle indexing with attached objects. |
|
|
60
61
|
| `fastquadtree.pyqtree.Index` | Bounding boxes | Yes | pyqtree-compatible API, much faster. |
|
|
62
|
+
| `fastquadtree.pygame.Group` | pygame sprites | Yes | Mostly drop-in replacement for `pygame.sprite.Group` with quadtree indexing for faster collision detection. |
|
|
61
63
|
|
|
62
64
|
|
|
63
65
|
## Quickstart
|
|
@@ -203,7 +205,9 @@ qt.insert_many_np(points) # Use insert_many_np for NumPy arrays
|
|
|
203
205
|
```
|
|
204
206
|
|
|
205
207
|
**Does fastquadtree support multiprocessing?**
|
|
206
|
-
Yes, fastquadtree objects can be serialized to bytes using the `to_bytes()` method and deserialized back using `from_bytes()`. This allows you to share quadtree data across processes and even cache prebuilt trees to disk. When using `QuadTreeObjects` or `RectQuadTreeObjects`, you must pass `include_objects=True` to `to_bytes()` to serialize Python objects, and `allow_objects=True` to `from_bytes()` when loading. By default, objects are skipped for safety, as deserializing untrusted Python objects can be unsafe. See the [interactive v2 demo](https://github.com/Elan456/fastquadtree/blob/main/interactive/interactive_v2.py) for an example of saving and loading a quadtree, and the [QuadTreeObjects API docs](https://elan456.github.io/fastquadtree/api/quadtree_objects/#fastquadtree.QuadTreeObjects.to_bytes) for full details on the serialization methods.
|
|
208
|
+
Yes, fastquadtree objects can be serialized to bytes using the `to_bytes()` method and deserialized back using `from_bytes()`. This allows you to share quadtree data across processes and even cache prebuilt trees to disk. When using `QuadTreeObjects` or `RectQuadTreeObjects`, you must pass `include_objects=True` to `to_bytes()` to serialize Python objects, and `allow_objects=True` to `from_bytes()` when loading. By default, objects are skipped for safety, as deserializing untrusted Python objects can be unsafe. Native decode uses a default preallocation limit of 67,108,864 bytes (64 MiB); if loading needs more than the configured bucket, `from_bytes()` fails with a `ValueError` unless you choose a larger allowed bucket or pass `disable_preallocation_limit=True` for trusted data. See the [interactive v2 demo](https://github.com/Elan456/fastquadtree/blob/main/interactive/interactive_v2.py) for an example of saving and loading a quadtree, and the [QuadTreeObjects API docs](https://elan456.github.io/fastquadtree/api/quadtree_objects/#fastquadtree.QuadTreeObjects.to_bytes) for full details on the serialization methods.
|
|
209
|
+
|
|
210
|
+
Serialization uses the current fastquadtree binary format. Data serialized by bincode-backed fastquadtree releases, including v2.2 and earlier, is not loadable by newer wincode-backed releases.
|
|
207
211
|
|
|
208
212
|
## License
|
|
209
213
|
|
|
@@ -288,6 +288,8 @@ rqt_obj.update(id_, new_min_x, new_min_y, new_max_x, new_max_y)
|
|
|
288
288
|
|
|
289
289
|
The serialization format has changed. **v1 serialized data cannot be loaded in v2.**
|
|
290
290
|
|
|
291
|
+
The native core codec changed again after v2.2 from bincode to wincode. Bincode-backed serialized data from fastquadtree v2.2 and earlier is not loadable by newer wincode-backed releases.
|
|
292
|
+
|
|
291
293
|
### Before (v1.x)
|
|
292
294
|
|
|
293
295
|
```python
|
|
@@ -455,4 +457,4 @@ from fastquadtree import (
|
|
|
455
457
|
PointItem,
|
|
456
458
|
RectItem,
|
|
457
459
|
)
|
|
458
|
-
```
|
|
460
|
+
```
|
|
@@ -132,22 +132,22 @@ If your data is already in a NumPy array, using the `insert_many_np` method dire
|
|
|
132
132
|
|
|
133
133
|
| Variant | Mean (s) | Stdev (s) |
|
|
134
134
|
|---|---:|---:|
|
|
135
|
-
| Serialize to bytes | 0.
|
|
136
|
-
| Rebuild from points | 0.
|
|
137
|
-
| Rebuild from bytes | 0.
|
|
138
|
-
| Rebuild from file | 0.
|
|
135
|
+
| Serialize to bytes | 0.011789 | 0.000617 |
|
|
136
|
+
| Rebuild from points | 0.088791 | 0.001616 |
|
|
137
|
+
| Rebuild from bytes | 0.007105 | 0.000137 |
|
|
138
|
+
| Rebuild from file | 0.012052 | 0.000442 |
|
|
139
139
|
|
|
140
140
|
### Summary
|
|
141
141
|
|
|
142
|
-
- Rebuild from bytes is **
|
|
143
|
-
- Rebuild from file is **
|
|
144
|
-
- Serialized blob size is **
|
|
142
|
+
- Rebuild from bytes is **12.497145x** faster than reinserting points.
|
|
143
|
+
- Rebuild from file is **7.367322x** faster than reinserting points.
|
|
144
|
+
- Serialized blob size is **18,104,173 bytes**.
|
|
145
145
|
|
|
146
146
|
----------------
|
|
147
147
|
|
|
148
148
|
## System Info
|
|
149
|
-
- **OS**: CachyOS
|
|
150
|
-
- **Python**: CPython 3.14.
|
|
149
|
+
- **OS**: CachyOS 7.0.10-1-cachyos x86_64
|
|
150
|
+
- **Python**: CPython 3.14.5
|
|
151
151
|
- **CPU**: AMD Ryzen 7 3700X 8-Core Processor (16 threads)
|
|
152
152
|
- **Memory**: 31.3 GB
|
|
153
153
|
- **GPU**: NVIDIA GeForce RTX 5070 (11.9 GB)
|
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
- Support for [inserting bounding boxes](api/rect_quadtree.md) or points
|
|
42
42
|
- Fast KNN and range queries
|
|
43
43
|
- Optional object tracking for id ↔ object mapping
|
|
44
|
-
-
|
|
44
|
+
- Mostly drop-in [pygame sprite-group integration](api/pygame.md) that adds automatic broadphase culling for faster collision detection (depending on workload)
|
|
45
45
|
- Fast [serialization](benchmark.md#serialization-vs-rebuild) to/from bytes
|
|
46
46
|
- Support for multiple data types (f32, f64, i32, i64) for coordinates
|
|
47
47
|
- [100% test coverage](https://codecov.io/gh/Elan456/fastquadtree) and CI on GitHub Actions
|
|
@@ -63,5 +63,5 @@ from fastquadtree import RectQuadTree # Bounding box handling
|
|
|
63
63
|
from fastquadtree import QuadTreeObjects # Point handling with object tracking
|
|
64
64
|
from fastquadtree import RectQuadTreeObjects # Bounding box handling with object tracking
|
|
65
65
|
from fastquadtree.pyqtree import Index # Drop-in replacement for pyqtree (~10x faster while keeping the same API)
|
|
66
|
-
from fastquadtree.pygame import Group #
|
|
66
|
+
from fastquadtree.pygame import Group # Mostly drop-in replacement for pygame.sprite.Group with quadtree indexing (pygame install required)
|
|
67
67
|
```
|
|
@@ -8,7 +8,10 @@ from collections.abc import Sequence
|
|
|
8
8
|
from typing import Any, Generic, TypeVar
|
|
9
9
|
|
|
10
10
|
from ._common import (
|
|
11
|
+
FLAG_CORE_CODEC_WINCODE,
|
|
12
|
+
FLAG_MAX_DEPTH_PRESENT,
|
|
11
13
|
SERIALIZATION_FORMAT_VERSION,
|
|
14
|
+
UNSUPPORTED_BINCODE_MESSAGE,
|
|
12
15
|
Bounds,
|
|
13
16
|
QuadTreeDType,
|
|
14
17
|
SerializationError,
|
|
@@ -17,6 +20,7 @@ from ._common import (
|
|
|
17
20
|
parse_container,
|
|
18
21
|
validate_bounds,
|
|
19
22
|
validate_np_dtype,
|
|
23
|
+
validate_preallocation_limit_bucket,
|
|
20
24
|
)
|
|
21
25
|
from ._insert_result import InsertResult
|
|
22
26
|
|
|
@@ -54,7 +58,13 @@ class _BaseQuadTree(Generic[G], ABC):
|
|
|
54
58
|
|
|
55
59
|
@classmethod
|
|
56
60
|
@abstractmethod
|
|
57
|
-
def _new_native_from_bytes(
|
|
61
|
+
def _new_native_from_bytes(
|
|
62
|
+
cls,
|
|
63
|
+
data: bytes,
|
|
64
|
+
dtype: QuadTreeDType,
|
|
65
|
+
preallocation_limit_bytes: int | None = None,
|
|
66
|
+
disable_preallocation_limit: bool = False,
|
|
67
|
+
) -> Any:
|
|
58
68
|
"""Create the native engine instance from serialized bytes."""
|
|
59
69
|
|
|
60
70
|
# ---- Initialization ----
|
|
@@ -301,9 +311,9 @@ class _BaseQuadTree(Generic[G], ABC):
|
|
|
301
311
|
"""
|
|
302
312
|
core_bytes = self._native.to_bytes()
|
|
303
313
|
|
|
304
|
-
flags =
|
|
314
|
+
flags = FLAG_CORE_CODEC_WINCODE
|
|
305
315
|
if self._max_depth is not None:
|
|
306
|
-
flags |=
|
|
316
|
+
flags |= FLAG_MAX_DEPTH_PRESENT
|
|
307
317
|
|
|
308
318
|
return build_container(
|
|
309
319
|
fmt_ver=SERIALIZATION_FORMAT_VERSION,
|
|
@@ -319,16 +329,37 @@ class _BaseQuadTree(Generic[G], ABC):
|
|
|
319
329
|
)
|
|
320
330
|
|
|
321
331
|
@classmethod
|
|
322
|
-
def from_bytes(
|
|
332
|
+
def from_bytes(
|
|
333
|
+
cls,
|
|
334
|
+
data: bytes,
|
|
335
|
+
preallocation_limit_bytes: int | None = None,
|
|
336
|
+
disable_preallocation_limit: bool = False,
|
|
337
|
+
) -> _BaseQuadTree[G]:
|
|
323
338
|
"""
|
|
324
339
|
Deserialize a quadtree from bytes.
|
|
325
340
|
|
|
326
341
|
Args:
|
|
327
342
|
data: Bytes from to_bytes().
|
|
343
|
+
preallocation_limit_bytes: Optional native decode preallocation limit.
|
|
344
|
+
Must be one of the supported bucket values in bytes:
|
|
345
|
+
1024, 1048576, 4194304, 16777216, 67108864, 268435456, 1073741824.
|
|
346
|
+
If omitted, defaults to 67108864 bytes (64 MiB).
|
|
347
|
+
disable_preallocation_limit: Explicitly disable native preallocation
|
|
348
|
+
limits. Use only for trusted data.
|
|
328
349
|
|
|
329
350
|
Returns:
|
|
330
351
|
A new instance.
|
|
352
|
+
|
|
353
|
+
Raises:
|
|
354
|
+
SerializationError: If the container is malformed, the format version
|
|
355
|
+
is unsupported, or the payload uses legacy bincode encoding.
|
|
356
|
+
ValueError: If the requested preallocation bucket is invalid, or if
|
|
357
|
+
decoding would exceed the configured preallocation limit.
|
|
331
358
|
"""
|
|
359
|
+
validate_preallocation_limit_bucket(
|
|
360
|
+
preallocation_limit_bytes, disable_preallocation_limit
|
|
361
|
+
)
|
|
362
|
+
|
|
332
363
|
parsed = parse_container(data)
|
|
333
364
|
|
|
334
365
|
fmt_ver = parsed["fmt_ver"]
|
|
@@ -337,6 +368,8 @@ class _BaseQuadTree(Generic[G], ABC):
|
|
|
337
368
|
f"Unsupported serialization format version {fmt_ver}; "
|
|
338
369
|
f"this package supports up to {SERIALIZATION_FORMAT_VERSION}"
|
|
339
370
|
)
|
|
371
|
+
if fmt_ver < 2 or not (parsed["flags"] & FLAG_CORE_CODEC_WINCODE):
|
|
372
|
+
raise SerializationError(UNSUPPORTED_BINCODE_MESSAGE)
|
|
340
373
|
|
|
341
374
|
dtype = parsed["dtype"]
|
|
342
375
|
core = parsed["core"]
|
|
@@ -348,6 +381,8 @@ class _BaseQuadTree(Generic[G], ABC):
|
|
|
348
381
|
qt._max_depth = parsed["max_depth"]
|
|
349
382
|
qt._next_id = parsed["next_id"]
|
|
350
383
|
qt._count = parsed["count"]
|
|
351
|
-
qt._native = cls._new_native_from_bytes(
|
|
384
|
+
qt._native = cls._new_native_from_bytes(
|
|
385
|
+
core, dtype, preallocation_limit_bytes, disable_preallocation_limit
|
|
386
|
+
)
|
|
352
387
|
|
|
353
388
|
return qt
|
|
@@ -9,9 +9,12 @@ from collections.abc import Sequence
|
|
|
9
9
|
from typing import Any, Generic, TypeVar
|
|
10
10
|
|
|
11
11
|
from ._common import (
|
|
12
|
+
FLAG_CORE_CODEC_WINCODE,
|
|
13
|
+
FLAG_MAX_DEPTH_PRESENT,
|
|
12
14
|
SECTION_ITEMS,
|
|
13
15
|
SECTION_OBJECTS,
|
|
14
16
|
SERIALIZATION_FORMAT_VERSION,
|
|
17
|
+
UNSUPPORTED_BINCODE_MESSAGE,
|
|
15
18
|
Bounds,
|
|
16
19
|
Point,
|
|
17
20
|
QuadTreeDType,
|
|
@@ -21,6 +24,7 @@ from ._common import (
|
|
|
21
24
|
parse_container,
|
|
22
25
|
validate_bounds,
|
|
23
26
|
validate_np_dtype,
|
|
27
|
+
validate_preallocation_limit_bucket,
|
|
24
28
|
)
|
|
25
29
|
from ._insert_result import InsertResult
|
|
26
30
|
from ._item import Item
|
|
@@ -210,7 +214,13 @@ class _BaseQuadTreeObjects(Generic[G, ItemType], ABC):
|
|
|
210
214
|
|
|
211
215
|
@classmethod
|
|
212
216
|
@abstractmethod
|
|
213
|
-
def _new_native_from_bytes(
|
|
217
|
+
def _new_native_from_bytes(
|
|
218
|
+
cls,
|
|
219
|
+
data: bytes,
|
|
220
|
+
dtype: QuadTreeDType,
|
|
221
|
+
preallocation_limit_bytes: int | None = None,
|
|
222
|
+
disable_preallocation_limit: bool = False,
|
|
223
|
+
) -> Any:
|
|
214
224
|
"""Create the native engine instance from serialized bytes."""
|
|
215
225
|
|
|
216
226
|
@staticmethod
|
|
@@ -704,9 +714,9 @@ class _BaseQuadTreeObjects(Generic[G, ItemType], ABC):
|
|
|
704
714
|
"""
|
|
705
715
|
core_bytes = self._native.to_bytes()
|
|
706
716
|
|
|
707
|
-
flags =
|
|
717
|
+
flags = FLAG_CORE_CODEC_WINCODE
|
|
708
718
|
if self._max_depth is not None:
|
|
709
|
-
flags |=
|
|
719
|
+
flags |= FLAG_MAX_DEPTH_PRESENT
|
|
710
720
|
|
|
711
721
|
# Always store items (id + geom) safely.
|
|
712
722
|
items_payload = _encode_items_section(list(self._store.items()))
|
|
@@ -731,7 +741,11 @@ class _BaseQuadTreeObjects(Generic[G, ItemType], ABC):
|
|
|
731
741
|
|
|
732
742
|
@classmethod
|
|
733
743
|
def from_bytes(
|
|
734
|
-
cls,
|
|
744
|
+
cls,
|
|
745
|
+
data: bytes,
|
|
746
|
+
allow_objects: bool = False,
|
|
747
|
+
preallocation_limit_bytes: int | None = None,
|
|
748
|
+
disable_preallocation_limit: bool = False,
|
|
735
749
|
) -> _BaseQuadTreeObjects[G, ItemType]:
|
|
736
750
|
"""
|
|
737
751
|
Deserialize a quadtree from bytes.
|
|
@@ -740,6 +754,12 @@ class _BaseQuadTreeObjects(Generic[G, ItemType], ABC):
|
|
|
740
754
|
data: Bytes from to_bytes().
|
|
741
755
|
allow_objects: If True, load pickled Python objects (unsafe).
|
|
742
756
|
If False (default), object payloads are silently ignored.
|
|
757
|
+
preallocation_limit_bytes: Optional native decode preallocation limit.
|
|
758
|
+
Must be one of the supported bucket values in bytes:
|
|
759
|
+
1024, 1048576, 4194304, 16777216, 67108864, 268435456, 1073741824.
|
|
760
|
+
If omitted, defaults to 67108864 bytes (64 MiB).
|
|
761
|
+
disable_preallocation_limit: Explicitly disable native preallocation
|
|
762
|
+
limits. Use only for trusted data.
|
|
743
763
|
|
|
744
764
|
Returns:
|
|
745
765
|
A new instance.
|
|
@@ -747,7 +767,17 @@ class _BaseQuadTreeObjects(Generic[G, ItemType], ABC):
|
|
|
747
767
|
Note:
|
|
748
768
|
Object deserialization uses pickle-like semantics. Never load
|
|
749
769
|
serialized data from untrusted sources with allow_objects=True.
|
|
770
|
+
|
|
771
|
+
Raises:
|
|
772
|
+
SerializationError: If the container is malformed, the format version
|
|
773
|
+
is unsupported, or the payload uses legacy bincode encoding.
|
|
774
|
+
ValueError: If the requested preallocation bucket is invalid, or if
|
|
775
|
+
decoding would exceed the configured preallocation limit.
|
|
750
776
|
"""
|
|
777
|
+
validate_preallocation_limit_bucket(
|
|
778
|
+
preallocation_limit_bytes, disable_preallocation_limit
|
|
779
|
+
)
|
|
780
|
+
|
|
751
781
|
parsed = parse_container(data)
|
|
752
782
|
|
|
753
783
|
fmt_ver = parsed["fmt_ver"]
|
|
@@ -756,6 +786,8 @@ class _BaseQuadTreeObjects(Generic[G, ItemType], ABC):
|
|
|
756
786
|
f"Unsupported serialization format version {fmt_ver}; "
|
|
757
787
|
f"this package supports up to {SERIALIZATION_FORMAT_VERSION}"
|
|
758
788
|
)
|
|
789
|
+
if fmt_ver < 2 or not (parsed["flags"] & FLAG_CORE_CODEC_WINCODE):
|
|
790
|
+
raise SerializationError(UNSUPPORTED_BINCODE_MESSAGE)
|
|
759
791
|
|
|
760
792
|
dtype = parsed["dtype"]
|
|
761
793
|
core = parsed["core"]
|
|
@@ -790,7 +822,9 @@ class _BaseQuadTreeObjects(Generic[G, ItemType], ABC):
|
|
|
790
822
|
qt._capacity = parsed["capacity"]
|
|
791
823
|
qt._max_depth = parsed["max_depth"]
|
|
792
824
|
qt._count = parsed["count"]
|
|
793
|
-
qt._native = cls._new_native_from_bytes(
|
|
825
|
+
qt._native = cls._new_native_from_bytes(
|
|
826
|
+
core, dtype, preallocation_limit_bytes, disable_preallocation_limit
|
|
827
|
+
)
|
|
794
828
|
|
|
795
829
|
# Rebuild store from decoded ids/geoms (+ optional objects)
|
|
796
830
|
store: ObjStore[ItemType] = ObjStore()
|
|
@@ -5,13 +5,27 @@ from __future__ import annotations
|
|
|
5
5
|
import math
|
|
6
6
|
from typing import Any, Final, Literal, Union, overload
|
|
7
7
|
|
|
8
|
-
SERIALIZATION_FORMAT_VERSION: Final[int] =
|
|
8
|
+
SERIALIZATION_FORMAT_VERSION: Final[int] = 2
|
|
9
9
|
|
|
10
10
|
# Serialization container constants (shared by Objects and non-Objects trees)
|
|
11
11
|
SERIALIZATION_MAGIC: Final[bytes] = b"FQT0" # fastquadtree container v0
|
|
12
12
|
SERIALIZATION_ENDIANNESS: Final[str] = "<" # little-endian
|
|
13
|
+
FLAG_MAX_DEPTH_PRESENT: Final[int] = 1
|
|
14
|
+
FLAG_CORE_CODEC_WINCODE: Final[int] = 1 << 1
|
|
15
|
+
UNSUPPORTED_BINCODE_MESSAGE: Final[str] = (
|
|
16
|
+
"bincode serialization from fastquadtree v2.2 and earlier is no longer supported"
|
|
17
|
+
)
|
|
13
18
|
SECTION_ITEMS: int = 1 # safe: ids + geometry only
|
|
14
19
|
SECTION_OBJECTS: int = 2 # unsafe: pickle payload (opt-in)
|
|
20
|
+
NATIVE_PREALLOCATION_LIMIT_BUCKETS: Final[tuple[int, ...]] = (
|
|
21
|
+
1024,
|
|
22
|
+
1024 * 1024,
|
|
23
|
+
4 * 1024 * 1024,
|
|
24
|
+
16 * 1024 * 1024,
|
|
25
|
+
64 * 1024 * 1024,
|
|
26
|
+
256 * 1024 * 1024,
|
|
27
|
+
1024 * 1024 * 1024,
|
|
28
|
+
)
|
|
15
29
|
|
|
16
30
|
# Type aliases
|
|
17
31
|
Bounds = tuple[
|
|
@@ -132,6 +146,30 @@ def validate_np_dtype(geoms: Any, expected_dtype: QuadTreeDType) -> None:
|
|
|
132
146
|
)
|
|
133
147
|
|
|
134
148
|
|
|
149
|
+
def validate_preallocation_limit_bucket(
|
|
150
|
+
preallocation_limit_bytes: int | None, disable_preallocation_limit: bool
|
|
151
|
+
) -> None:
|
|
152
|
+
"""
|
|
153
|
+
Validate that runtime native decode preallocation limits use a supported bucket.
|
|
154
|
+
|
|
155
|
+
Args:
|
|
156
|
+
preallocation_limit_bytes: Optional requested preallocation limit.
|
|
157
|
+
disable_preallocation_limit: If True, limit validation is skipped.
|
|
158
|
+
|
|
159
|
+
Raises:
|
|
160
|
+
ValueError: If preallocation_limit_bytes is not a supported bucket value.
|
|
161
|
+
"""
|
|
162
|
+
if disable_preallocation_limit or preallocation_limit_bytes is None:
|
|
163
|
+
return
|
|
164
|
+
|
|
165
|
+
if preallocation_limit_bytes not in NATIVE_PREALLOCATION_LIMIT_BUCKETS:
|
|
166
|
+
buckets = ", ".join(str(v) for v in NATIVE_PREALLOCATION_LIMIT_BUCKETS)
|
|
167
|
+
raise ValueError(
|
|
168
|
+
"preallocation_limit_bytes must be one of the supported buckets "
|
|
169
|
+
f"(bytes): {buckets}"
|
|
170
|
+
)
|
|
171
|
+
|
|
172
|
+
|
|
135
173
|
# ---------------------------
|
|
136
174
|
# Serialization helpers
|
|
137
175
|
# ---------------------------
|
|
@@ -323,7 +361,7 @@ def build_container(
|
|
|
323
361
|
)
|
|
324
362
|
|
|
325
363
|
md_bytes = b""
|
|
326
|
-
if flags &
|
|
364
|
+
if flags & FLAG_MAX_DEPTH_PRESENT:
|
|
327
365
|
if max_depth is None:
|
|
328
366
|
raise SerializationError("max_depth flag set but max_depth is None")
|
|
329
367
|
if int(max_depth) < 0:
|
|
@@ -415,7 +453,7 @@ def parse_container(data: bytes) -> dict[str, Any]:
|
|
|
415
453
|
dtype = code_to_dtype(int(dtype_code))
|
|
416
454
|
|
|
417
455
|
max_depth = None
|
|
418
|
-
if flags &
|
|
456
|
+
if flags & FLAG_MAX_DEPTH_PRESENT:
|
|
419
457
|
if len(buf) < off + 4:
|
|
420
458
|
raise SerializationError("Data too short while reading max_depth")
|
|
421
459
|
(md,) = struct.unpack_from(f"{SERIALIZATION_ENDIANNESS}i", buf, off)
|