pycadkit 0.5.1__tar.gz → 0.5.2__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.
- {pycadkit-0.5.1 → pycadkit-0.5.2}/Cargo.lock +13 -13
- {pycadkit-0.5.1 → pycadkit-0.5.2}/Cargo.toml +10 -10
- {pycadkit-0.5.1 → pycadkit-0.5.2}/PKG-INFO +1 -1
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit/src/lib.rs +14 -0
- pycadkit-0.5.2/crates/cadkit-core/src/svg/bounded_tests.rs +219 -0
- pycadkit-0.5.2/crates/cadkit-core/src/svg/buffer.rs +143 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-core/src/svg.rs +412 -96
- {pycadkit-0.5.1 → pycadkit-0.5.2}/LICENSE-APACHE +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/LICENSE-MIT +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/NOTICE +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/README.md +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit/Cargo.toml +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit/LICENSE-APACHE +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit/LICENSE-MIT +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit/NOTICE +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit/README.md +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit/examples/interchange.rs +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit/src/prelude.rs +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-core/Cargo.toml +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-core/LICENSE-APACHE +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-core/LICENSE-MIT +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-core/NOTICE +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-core/README.md +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-core/src/aci.rs +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-core/src/bytes.rs +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-core/src/doc_ops.rs +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-core/src/error.rs +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-core/src/export.rs +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-core/src/geom.rs +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-core/src/geom_ops.rs +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-core/src/lib.rs +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-core/src/model.rs +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-core/src/model_builders.rs +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-core/src/ops.rs +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-core/src/options.rs +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-core/src/polygon.rs +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-core/src/text.rs +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-core/src/units.rs +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-core/tests/schema.rs +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-dgn/Cargo.toml +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-dgn/LICENSE-APACHE +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-dgn/LICENSE-MIT +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-dgn/NOTICE +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-dgn/README.md +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-dgn/examples/dgn_summary.rs +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-dgn/examples/raster_structure.rs +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-dgn/src/budget.rs +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-dgn/src/cfb.rs +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-dgn/src/fuzz_tests.rs +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-dgn/src/le.rs +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-dgn/src/level_names.rs +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-dgn/src/lib.rs +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-dgn/src/map/mod.rs +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-dgn/src/map/v7.rs +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-dgn/src/map/v8.rs +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-dgn/src/native/decode_v8.rs +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-dgn/src/native/element.rs +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-dgn/src/native/linkage.rs +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-dgn/src/native/mod.rs +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-dgn/src/native/v7.rs +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-dgn/src/native/v8.rs +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-dgn/src/palette.rs +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-dgn/src/symbology.rs +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-dgn/src/text.rs +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-dgn/src/writer/container.rs +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-dgn/src/writer/encode.rs +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-dgn/src/writer/mod.rs +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-dgn/src/writer/named.rs +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-dgn/src/writer/polyline.rs +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-dgn/src/writer/raster.rs +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-dgn/src/writer/raster_builtin.rs +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-dgn/src/writer/raster_template.rs +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-dgn/src/writer/seed_prepare.rs +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-dgn/src/writer/tables.rs +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-dgn/src/writer/tests/application.rs +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-dgn/src/writer/tests/dictionary.rs +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-dgn/src/writer/tests/microstation.rs +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-dgn/src/writer/tests/raster.rs +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-dgn/src/writer/tests/raster_template.rs +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-dgn/src/writer/tests/regressions.rs +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-dgn/src/writer/tests/text.rs +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-dgn/src/writer/tests.rs +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-dgn/src/writer/text.rs +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-dgn/src/zlib.rs +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-dgn/tests/common/mod.rs +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-dgn/tests/private_corpus.rs +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-dgn/tests/private_dictionary.rs +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-dgn/tests/robustness.rs +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-dgn/tests/v7_corpus.rs +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-dgn/tests/v8_oracle.rs +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-dgn/tests/v8_public.rs +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-dgn/tests/v8_range.rs +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-dwg/Cargo.toml +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-dwg/LICENSE-APACHE +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-dwg/LICENSE-MIT +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-dwg/NOTICE +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-dwg/README.md +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-dwg/examples/docsummary.rs +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-dwg/examples/dwgdump.rs +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-dwg/src/bits.rs +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-dwg/src/classes.rs +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-dwg/src/codepage.rs +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-dwg/src/container/lz77_r2004.rs +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-dwg/src/container/lz77_r2007.rs +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-dwg/src/container/mod.rs +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-dwg/src/container/r13.rs +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-dwg/src/container/r2004.rs +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-dwg/src/container/r2007.rs +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-dwg/src/container/reed_solomon.rs +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-dwg/src/crc.rs +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-dwg/src/handles.rs +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-dwg/src/header.rs +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-dwg/src/lib.rs +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-dwg/src/mapping/entity.rs +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-dwg/src/mapping/mod.rs +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-dwg/src/native/entities.rs +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-dwg/src/native/mod.rs +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-dwg/src/object/annotation.rs +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-dwg/src/object/curves.rs +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-dwg/src/object/entities.rs +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-dwg/src/object/hatch.rs +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-dwg/src/object/misc.rs +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-dwg/src/object/mod.rs +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-dwg/src/object/registry.rs +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-dwg/src/object/tables.rs +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-dwg/src/reader.rs +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-dwg/src/version.rs +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-dwg/tests/corpus.rs +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-dwg/tests/oracle.rs +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-dwg/tests/robustness.rs +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-dxf/Cargo.toml +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-dxf/LICENSE-APACHE +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-dxf/LICENSE-MIT +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-dxf/NOTICE +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-dxf/README.md +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-dxf/examples/dump.rs +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-dxf/src/lib.rs +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-dxf/src/native/mod.rs +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-dxf/src/native/text.rs +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-dxf/src/ocs.rs +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-dxf/src/reader/common.rs +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-dxf/src/reader/entities.rs +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-dxf/src/reader/hatch.rs +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-dxf/src/reader/mod.rs +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-dxf/src/reader/records.rs +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-dxf/src/reader/tables.rs +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-dxf/src/writer/curves.rs +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-dxf/src/writer/entities.rs +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-dxf/src/writer/mod.rs +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-dxf/src/writer/out.rs +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-dxf/tests/ascii_vs_binary.rs +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-dxf/tests/common/mod.rs +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-dxf/tests/compare_reader_with_ezdxf.py +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-dxf/tests/review_fixes.rs +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-dxf/tests/robustness.rs +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-dxf/tests/roundtrip.rs +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-dxf/tests/synthetic_read.rs +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-dxf/tests/synthetic_write.rs +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-dxf/tests/validate_with_ezdxf.py +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-gml/Cargo.toml +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-gml/LICENSE-APACHE +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-gml/LICENSE-MIT +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-gml/NOTICE +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-gml/README.md +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-gml/src/curves.rs +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-gml/src/export.rs +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-gml/src/geometry.rs +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-gml/src/lib.rs +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-gml/src/mapping.rs +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-gml/src/native.rs +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-gml/src/tkgm.rs +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-gml/src/validate.rs +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-gml/src/xml.rs +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-gml/tests/roundtrip.rs +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-gml/tests/support/export_cases.rs +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-gml/tests/support/tkgm_cases.rs +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-py/Cargo.toml +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-py/LICENSE-APACHE +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-py/LICENSE-MIT +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-py/NOTICE +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-py/README.md +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-py/src/lib.rs +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-py/tests/conftest.py +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-py/tests/test_cadkit.py +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/crates/cadkit-py/tests/test_citygml.py +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/pyproject.toml +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/python/cadkit/__init__.py +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/python/cadkit/__init__.pyi +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/python/cadkit/_cadkit.pyi +0 -0
- {pycadkit-0.5.1 → pycadkit-0.5.2}/python/cadkit/py.typed +0 -0
|
@@ -152,7 +152,7 @@ dependencies = [
|
|
|
152
152
|
|
|
153
153
|
[[package]]
|
|
154
154
|
name = "cadkit"
|
|
155
|
-
version = "0.5.
|
|
155
|
+
version = "0.5.2"
|
|
156
156
|
dependencies = [
|
|
157
157
|
"cadkit-core",
|
|
158
158
|
"cadkit-dgn",
|
|
@@ -164,7 +164,7 @@ dependencies = [
|
|
|
164
164
|
|
|
165
165
|
[[package]]
|
|
166
166
|
name = "cadkit-capi"
|
|
167
|
-
version = "0.5.
|
|
167
|
+
version = "0.5.2"
|
|
168
168
|
dependencies = [
|
|
169
169
|
"cadkit",
|
|
170
170
|
"serde",
|
|
@@ -173,7 +173,7 @@ dependencies = [
|
|
|
173
173
|
|
|
174
174
|
[[package]]
|
|
175
175
|
name = "cadkit-cli"
|
|
176
|
-
version = "0.5.
|
|
176
|
+
version = "0.5.2"
|
|
177
177
|
dependencies = [
|
|
178
178
|
"cadkit",
|
|
179
179
|
"clap",
|
|
@@ -182,7 +182,7 @@ dependencies = [
|
|
|
182
182
|
|
|
183
183
|
[[package]]
|
|
184
184
|
name = "cadkit-core"
|
|
185
|
-
version = "0.5.
|
|
185
|
+
version = "0.5.2"
|
|
186
186
|
dependencies = [
|
|
187
187
|
"schemars",
|
|
188
188
|
"serde",
|
|
@@ -192,7 +192,7 @@ dependencies = [
|
|
|
192
192
|
|
|
193
193
|
[[package]]
|
|
194
194
|
name = "cadkit-dgn"
|
|
195
|
-
version = "0.5.
|
|
195
|
+
version = "0.5.2"
|
|
196
196
|
dependencies = [
|
|
197
197
|
"cadkit-core",
|
|
198
198
|
"cfb",
|
|
@@ -203,7 +203,7 @@ dependencies = [
|
|
|
203
203
|
|
|
204
204
|
[[package]]
|
|
205
205
|
name = "cadkit-dwg"
|
|
206
|
-
version = "0.5.
|
|
206
|
+
version = "0.5.2"
|
|
207
207
|
dependencies = [
|
|
208
208
|
"cadkit-core",
|
|
209
209
|
"cadkit-dxf",
|
|
@@ -213,7 +213,7 @@ dependencies = [
|
|
|
213
213
|
|
|
214
214
|
[[package]]
|
|
215
215
|
name = "cadkit-dxf"
|
|
216
|
-
version = "0.5.
|
|
216
|
+
version = "0.5.2"
|
|
217
217
|
dependencies = [
|
|
218
218
|
"cadkit-core",
|
|
219
219
|
"encoding_rs",
|
|
@@ -222,7 +222,7 @@ dependencies = [
|
|
|
222
222
|
|
|
223
223
|
[[package]]
|
|
224
224
|
name = "cadkit-geom"
|
|
225
|
-
version = "0.5.
|
|
225
|
+
version = "0.5.2"
|
|
226
226
|
dependencies = [
|
|
227
227
|
"i_overlay",
|
|
228
228
|
"robust",
|
|
@@ -234,7 +234,7 @@ dependencies = [
|
|
|
234
234
|
|
|
235
235
|
[[package]]
|
|
236
236
|
name = "cadkit-gml"
|
|
237
|
-
version = "0.5.
|
|
237
|
+
version = "0.5.2"
|
|
238
238
|
dependencies = [
|
|
239
239
|
"cadkit-core",
|
|
240
240
|
"quick-xml",
|
|
@@ -244,7 +244,7 @@ dependencies = [
|
|
|
244
244
|
|
|
245
245
|
[[package]]
|
|
246
246
|
name = "cadkit-gpu"
|
|
247
|
-
version = "0.5.
|
|
247
|
+
version = "0.5.2"
|
|
248
248
|
dependencies = [
|
|
249
249
|
"cadkit",
|
|
250
250
|
"cadkit-geom",
|
|
@@ -257,7 +257,7 @@ dependencies = [
|
|
|
257
257
|
|
|
258
258
|
[[package]]
|
|
259
259
|
name = "cadkit-py"
|
|
260
|
-
version = "0.5.
|
|
260
|
+
version = "0.5.2"
|
|
261
261
|
dependencies = [
|
|
262
262
|
"cadkit",
|
|
263
263
|
"pyo3",
|
|
@@ -267,7 +267,7 @@ dependencies = [
|
|
|
267
267
|
|
|
268
268
|
[[package]]
|
|
269
269
|
name = "cadkit-scene"
|
|
270
|
-
version = "0.5.
|
|
270
|
+
version = "0.5.2"
|
|
271
271
|
dependencies = [
|
|
272
272
|
"cadkit-core",
|
|
273
273
|
"cadkit-geom",
|
|
@@ -276,7 +276,7 @@ dependencies = [
|
|
|
276
276
|
|
|
277
277
|
[[package]]
|
|
278
278
|
name = "cadkit-wasm"
|
|
279
|
-
version = "0.5.
|
|
279
|
+
version = "0.5.2"
|
|
280
280
|
dependencies = [
|
|
281
281
|
"cadkit",
|
|
282
282
|
"js-sys",
|
|
@@ -4,7 +4,7 @@ members = ["crates/*"]
|
|
|
4
4
|
exclude = ["fuzz"]
|
|
5
5
|
|
|
6
6
|
[workspace.package]
|
|
7
|
-
version = "0.5.
|
|
7
|
+
version = "0.5.2"
|
|
8
8
|
edition = "2024"
|
|
9
9
|
rust-version = "1.88"
|
|
10
10
|
license = "MIT OR Apache-2.0"
|
|
@@ -14,18 +14,18 @@ keywords = ["cad", "dwg", "dgn", "dxf", "citygml"]
|
|
|
14
14
|
categories = ["parser-implementations", "graphics", "encoding", "science::geo"]
|
|
15
15
|
|
|
16
16
|
[workspace.dependencies]
|
|
17
|
-
cadkit-geom = { path = "crates/cadkit-geom", version = "0.5.
|
|
18
|
-
cadkit-scene = { path = "crates/cadkit-scene", version = "0.5.
|
|
19
|
-
cadkit-gpu = { path = "crates/cadkit-gpu", version = "0.5.
|
|
17
|
+
cadkit-geom = { path = "crates/cadkit-geom", version = "0.5.2" }
|
|
18
|
+
cadkit-scene = { path = "crates/cadkit-scene", version = "0.5.2" }
|
|
19
|
+
cadkit-gpu = { path = "crates/cadkit-gpu", version = "0.5.2" }
|
|
20
20
|
i_overlay = "=9.0.0"
|
|
21
21
|
robust = "=1.2.0"
|
|
22
22
|
schemars = "1.2.2"
|
|
23
|
-
cadkit-core = { path = "crates/cadkit-core", version = "0.5.
|
|
24
|
-
cadkit-dgn = { path = "crates/cadkit-dgn", version = "0.5.
|
|
25
|
-
cadkit-dwg = { path = "crates/cadkit-dwg", version = "0.5.
|
|
26
|
-
cadkit-dxf = { path = "crates/cadkit-dxf", version = "0.5.
|
|
27
|
-
cadkit-gml = { path = "crates/cadkit-gml", version = "0.5.
|
|
28
|
-
cadkit = { path = "crates/cadkit", version = "0.5.
|
|
23
|
+
cadkit-core = { path = "crates/cadkit-core", version = "0.5.2" }
|
|
24
|
+
cadkit-dgn = { path = "crates/cadkit-dgn", version = "0.5.2", default-features = false }
|
|
25
|
+
cadkit-dwg = { path = "crates/cadkit-dwg", version = "0.5.2" }
|
|
26
|
+
cadkit-dxf = { path = "crates/cadkit-dxf", version = "0.5.2" }
|
|
27
|
+
cadkit-gml = { path = "crates/cadkit-gml", version = "0.5.2" }
|
|
28
|
+
cadkit = { path = "crates/cadkit", version = "0.5.2" }
|
|
29
29
|
serde = { version = "1", features = ["derive"] }
|
|
30
30
|
serde_json = "1"
|
|
31
31
|
thiserror = "2"
|
|
@@ -333,6 +333,20 @@ pub fn to_svg_all_layers(doc: &Document, options: &SvgOptions) -> String {
|
|
|
333
333
|
cadkit_core::svg::render_all_layers(doc, options)
|
|
334
334
|
}
|
|
335
335
|
|
|
336
|
+
/// Renders a complete SVG within the output byte and work budgets in `options`.
|
|
337
|
+
/// `include_hidden_layers` includes hidden and frozen layers when true.
|
|
338
|
+
/// Returns [`Error::LimitExceeded`] rather than a truncated drawing. The byte
|
|
339
|
+
/// cap includes all markup and bounds temporary SVG strings during generation;
|
|
340
|
+
/// it does not bound the memory already owned by the parsed document.
|
|
341
|
+
#[cfg(feature = "svg")]
|
|
342
|
+
pub fn to_svg_bounded(
|
|
343
|
+
doc: &Document,
|
|
344
|
+
options: &SvgOptions,
|
|
345
|
+
include_hidden_layers: bool,
|
|
346
|
+
) -> Result<String> {
|
|
347
|
+
cadkit_core::svg::render_bounded(doc, options, include_hidden_layers)
|
|
348
|
+
}
|
|
349
|
+
|
|
336
350
|
/// Writes an SVG rendering of `doc` into `writer`.
|
|
337
351
|
#[cfg(feature = "svg")]
|
|
338
352
|
pub fn write_svg_to(doc: &Document, options: &SvgOptions, mut writer: impl Write) -> Result<()> {
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
use super::*;
|
|
2
|
+
use crate::model::{Block, Layer, Model};
|
|
3
|
+
|
|
4
|
+
fn line() -> Entity {
|
|
5
|
+
Entity::new(EntityKind::Line {
|
|
6
|
+
start: Point3::xy(0.0, 0.0),
|
|
7
|
+
end: Point3::xy(10.0, 5.0),
|
|
8
|
+
})
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
fn document(entities: Vec<Entity>) -> Document {
|
|
12
|
+
Document {
|
|
13
|
+
models: vec![Model {
|
|
14
|
+
entities,
|
|
15
|
+
..Model::default()
|
|
16
|
+
}],
|
|
17
|
+
..Document::default()
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
fn text(value: String) -> Entity {
|
|
22
|
+
Entity::new(EntityKind::Text {
|
|
23
|
+
position: Point3::default(),
|
|
24
|
+
end_point: None,
|
|
25
|
+
height: 1.0,
|
|
26
|
+
rotation: 0.0,
|
|
27
|
+
width_factor: 1.0,
|
|
28
|
+
oblique: 0.0,
|
|
29
|
+
value,
|
|
30
|
+
style: None,
|
|
31
|
+
halign: HAlign::Left,
|
|
32
|
+
valign: VAlign::Baseline,
|
|
33
|
+
normal: Vec3::Z,
|
|
34
|
+
})
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
fn assert_output_limit(result: crate::Result<String>) {
|
|
38
|
+
assert!(matches!(
|
|
39
|
+
result,
|
|
40
|
+
Err(crate::Error::LimitExceeded {
|
|
41
|
+
limit: crate::LimitKind::Output,
|
|
42
|
+
..
|
|
43
|
+
})
|
|
44
|
+
));
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
#[test]
|
|
48
|
+
fn exact_utf8_budget_includes_markup_and_hidden_layer_names() {
|
|
49
|
+
let mut entity = text("測定<&>🙂".into());
|
|
50
|
+
entity.layer = Some("隠れた<&>🙂".into());
|
|
51
|
+
let mut doc = document(vec![entity]);
|
|
52
|
+
doc.layers.push(Layer {
|
|
53
|
+
name: "隠れた<&>🙂".into(),
|
|
54
|
+
visible: false,
|
|
55
|
+
..Layer::default()
|
|
56
|
+
});
|
|
57
|
+
let options = SvgOptions::default();
|
|
58
|
+
for hidden in [false, true] {
|
|
59
|
+
let expected = if hidden {
|
|
60
|
+
render_all_layers(&doc, &options)
|
|
61
|
+
} else {
|
|
62
|
+
render(&doc, &options)
|
|
63
|
+
};
|
|
64
|
+
let exact = options.clone().with_max_output_bytes(expected.len());
|
|
65
|
+
assert_eq!(
|
|
66
|
+
render_bounded(&doc, &exact, hidden).expect("exact budget"),
|
|
67
|
+
expected
|
|
68
|
+
);
|
|
69
|
+
assert_output_limit(render_bounded(
|
|
70
|
+
&doc,
|
|
71
|
+
&exact.with_max_output_bytes(expected.len() - 1),
|
|
72
|
+
hidden,
|
|
73
|
+
));
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
#[test]
|
|
78
|
+
fn a_single_path_is_stopped_before_the_next_entity() {
|
|
79
|
+
let polyline = Entity::new(EntityKind::Polyline {
|
|
80
|
+
vertices: (0..20_000)
|
|
81
|
+
.map(|i| Vertex {
|
|
82
|
+
position: Point3::xy(f64::from(i), f64::from(i % 2)),
|
|
83
|
+
..Vertex::default()
|
|
84
|
+
})
|
|
85
|
+
.collect(),
|
|
86
|
+
closed: false,
|
|
87
|
+
normal: Vec3::Z,
|
|
88
|
+
});
|
|
89
|
+
let options = SvgOptions::default().with_max_output_bytes(1024);
|
|
90
|
+
assert_output_limit(render_bounded(&document(vec![polyline]), &options, true));
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
#[test]
|
|
94
|
+
fn escaping_and_background_do_not_allocate_an_oversized_result() {
|
|
95
|
+
let options = SvgOptions::default().with_max_output_bytes(1024);
|
|
96
|
+
// Input fits but XML escaping expands it beyond the cap within one entity.
|
|
97
|
+
assert_output_limit(render_bounded(
|
|
98
|
+
&document(vec![text("&".repeat(600))]),
|
|
99
|
+
&options,
|
|
100
|
+
true,
|
|
101
|
+
));
|
|
102
|
+
let options = options.with_background(Some("&".repeat(600)));
|
|
103
|
+
assert_output_limit(render_bounded(&Document::default(), &options, true));
|
|
104
|
+
assert_output_limit(render_bounded(
|
|
105
|
+
&Document::default(),
|
|
106
|
+
&SvgOptions::default().with_max_output_bytes(1),
|
|
107
|
+
true,
|
|
108
|
+
));
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
#[test]
|
|
112
|
+
fn many_layers_and_entities_cannot_accumulate_unbounded_output() {
|
|
113
|
+
let doc = document(
|
|
114
|
+
(0..10_000)
|
|
115
|
+
.map(|i| {
|
|
116
|
+
let mut entity = line();
|
|
117
|
+
entity.layer = Some(format!("layer-{i}-{}", "&".repeat(32)));
|
|
118
|
+
entity
|
|
119
|
+
})
|
|
120
|
+
.collect(),
|
|
121
|
+
);
|
|
122
|
+
assert_output_limit(render_bounded(
|
|
123
|
+
&doc,
|
|
124
|
+
&SvgOptions::default().with_max_output_bytes(16_384),
|
|
125
|
+
true,
|
|
126
|
+
));
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
#[test]
|
|
130
|
+
fn work_exhaustion_is_an_error_instead_of_an_empty_or_partial_success() {
|
|
131
|
+
let doc = document(vec![line(); 100]);
|
|
132
|
+
for work in [0, 10] {
|
|
133
|
+
assert!(matches!(
|
|
134
|
+
render_bounded(&doc, &SvgOptions::default().with_max_work(work), true),
|
|
135
|
+
Err(crate::Error::LimitExceeded {
|
|
136
|
+
limit: crate::LimitKind::Work,
|
|
137
|
+
..
|
|
138
|
+
})
|
|
139
|
+
));
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
#[test]
|
|
144
|
+
fn block_array_expansion_obeys_output_and_work_limits() {
|
|
145
|
+
let insert = Entity::new(EntityKind::Insert {
|
|
146
|
+
block: "lines".into(),
|
|
147
|
+
position: Point3::default(),
|
|
148
|
+
scale: Vec3::new(1.0, 1.0, 1.0),
|
|
149
|
+
rotation: 0.0,
|
|
150
|
+
normal: Vec3::Z,
|
|
151
|
+
columns: 100,
|
|
152
|
+
rows: 100,
|
|
153
|
+
column_spacing: 20.0,
|
|
154
|
+
row_spacing: 20.0,
|
|
155
|
+
});
|
|
156
|
+
let mut doc = document(vec![insert]);
|
|
157
|
+
doc.blocks.push(Block {
|
|
158
|
+
name: "lines".into(),
|
|
159
|
+
entities: vec![line()],
|
|
160
|
+
..Block::default()
|
|
161
|
+
});
|
|
162
|
+
assert_output_limit(render_bounded(
|
|
163
|
+
&doc,
|
|
164
|
+
&SvgOptions::default().with_max_output_bytes(4096),
|
|
165
|
+
true,
|
|
166
|
+
));
|
|
167
|
+
assert!(matches!(
|
|
168
|
+
render_bounded(&doc, &SvgOptions::default().with_max_work(10), true),
|
|
169
|
+
Err(crate::Error::LimitExceeded {
|
|
170
|
+
limit: crate::LimitKind::Work,
|
|
171
|
+
..
|
|
172
|
+
})
|
|
173
|
+
));
|
|
174
|
+
let small = document(vec![line()]);
|
|
175
|
+
assert_eq!(
|
|
176
|
+
render_bounded(&small, &SvgOptions::default(), true).expect("next document"),
|
|
177
|
+
render_all_layers(&small, &SvgOptions::default())
|
|
178
|
+
);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
#[test]
|
|
182
|
+
fn hatch_definitions_are_part_of_the_exact_output_budget() {
|
|
183
|
+
let hatch = Entity::new(EntityKind::Hatch {
|
|
184
|
+
loops: vec![crate::model::HatchLoop {
|
|
185
|
+
edges: vec![HatchEdge::Polyline {
|
|
186
|
+
vertices: vec![
|
|
187
|
+
Vertex {
|
|
188
|
+
position: Point3::xy(0.0, 0.0),
|
|
189
|
+
..Vertex::default()
|
|
190
|
+
},
|
|
191
|
+
Vertex {
|
|
192
|
+
position: Point3::xy(5.0, 5.0),
|
|
193
|
+
..Vertex::default()
|
|
194
|
+
},
|
|
195
|
+
],
|
|
196
|
+
closed: true,
|
|
197
|
+
}],
|
|
198
|
+
external: true,
|
|
199
|
+
}],
|
|
200
|
+
solid: false,
|
|
201
|
+
pattern: Some("ANSI37".into()),
|
|
202
|
+
pattern_scale: 1.0,
|
|
203
|
+
pattern_angle: 0.0,
|
|
204
|
+
normal: Vec3::Z,
|
|
205
|
+
});
|
|
206
|
+
let doc = document(vec![hatch]);
|
|
207
|
+
let expected = render_all_layers(&doc, &SvgOptions::default());
|
|
208
|
+
assert!(expected.contains("<defs>"));
|
|
209
|
+
let options = SvgOptions::default().with_max_output_bytes(expected.len());
|
|
210
|
+
assert_eq!(
|
|
211
|
+
render_bounded(&doc, &options, true).expect("exact hatch budget"),
|
|
212
|
+
expected
|
|
213
|
+
);
|
|
214
|
+
assert_output_limit(render_bounded(
|
|
215
|
+
&doc,
|
|
216
|
+
&options.with_max_output_bytes(expected.len() - 1),
|
|
217
|
+
true,
|
|
218
|
+
));
|
|
219
|
+
}
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
//! Bounded SVG buffers share a failure flag, including temporary paths and escaped text.
|
|
2
|
+
//! Once a write would exceed the cap, no buffer in that render grows again.
|
|
3
|
+
|
|
4
|
+
use std::cell::Cell;
|
|
5
|
+
use std::fmt::{self, Write};
|
|
6
|
+
use std::ops::Deref;
|
|
7
|
+
use std::rc::Rc;
|
|
8
|
+
|
|
9
|
+
#[derive(Clone, Default)]
|
|
10
|
+
pub(super) struct Budget(Option<Rc<State>>);
|
|
11
|
+
|
|
12
|
+
struct State {
|
|
13
|
+
cap: usize,
|
|
14
|
+
exceeded: Cell<bool>,
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
impl Budget {
|
|
18
|
+
pub(super) fn is_unlimited(&self) -> bool {
|
|
19
|
+
self.0.is_none()
|
|
20
|
+
}
|
|
21
|
+
pub(super) fn new(cap: usize) -> Self {
|
|
22
|
+
Self(Some(Rc::new(State {
|
|
23
|
+
cap,
|
|
24
|
+
exceeded: Cell::new(false),
|
|
25
|
+
})))
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
pub(super) fn exceeded(&self) -> bool {
|
|
29
|
+
self.0.as_ref().is_some_and(|state| state.exceeded.get())
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
pub(super) fn allows(&self, bytes: usize) -> bool {
|
|
33
|
+
let Some(state) = &self.0 else { return true };
|
|
34
|
+
if bytes > state.cap {
|
|
35
|
+
state.exceeded.set(true);
|
|
36
|
+
}
|
|
37
|
+
!state.exceeded.get()
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
pub(super) fn reject(&self) {
|
|
41
|
+
if let Some(state) = &self.0 {
|
|
42
|
+
state.exceeded.set(true);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
pub(super) fn buffer(&self) -> Buffer {
|
|
47
|
+
Buffer {
|
|
48
|
+
text: String::new(),
|
|
49
|
+
budget: self.clone(),
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
pub(super) fn format(&self, args: fmt::Arguments<'_>) -> Buffer {
|
|
54
|
+
let mut buffer = self.buffer();
|
|
55
|
+
// Failure is remembered by the shared budget and reported by the public renderer.
|
|
56
|
+
let _ = buffer.write_fmt(args);
|
|
57
|
+
buffer
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
pub(super) struct Buffer {
|
|
62
|
+
text: String,
|
|
63
|
+
budget: Budget,
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
impl Buffer {
|
|
67
|
+
pub(super) fn exceeded(&self) -> bool {
|
|
68
|
+
self.budget.exceeded()
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
pub(super) fn push_str(&mut self, value: &str) {
|
|
72
|
+
let _ = self.write_str(value);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
pub(super) fn push(&mut self, value: char) {
|
|
76
|
+
let _ = self.write_char(value);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
pub(super) fn into_string(self) -> String {
|
|
80
|
+
self.text
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
impl Write for Buffer {
|
|
85
|
+
fn write_str(&mut self, value: &str) -> fmt::Result {
|
|
86
|
+
let Some(bytes) = self.text.len().checked_add(value.len()) else {
|
|
87
|
+
self.budget.reject();
|
|
88
|
+
return Err(fmt::Error);
|
|
89
|
+
};
|
|
90
|
+
if !self.budget.allows(bytes) {
|
|
91
|
+
return Err(fmt::Error);
|
|
92
|
+
}
|
|
93
|
+
// Avoid geometric String growth beyond the requested output budget.
|
|
94
|
+
if let Some(state) = &self.budget.0
|
|
95
|
+
&& bytes > self.text.capacity()
|
|
96
|
+
{
|
|
97
|
+
let capacity = self
|
|
98
|
+
.text
|
|
99
|
+
.capacity()
|
|
100
|
+
.max(32)
|
|
101
|
+
.saturating_mul(2)
|
|
102
|
+
.min(state.cap)
|
|
103
|
+
.max(bytes);
|
|
104
|
+
self.text.reserve_exact(capacity - self.text.len());
|
|
105
|
+
}
|
|
106
|
+
self.text.push_str(value);
|
|
107
|
+
Ok(())
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
impl Deref for Buffer {
|
|
112
|
+
type Target = str;
|
|
113
|
+
|
|
114
|
+
fn deref(&self) -> &str {
|
|
115
|
+
&self.text
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
impl fmt::Display for Buffer {
|
|
120
|
+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
121
|
+
f.write_str(&self.text)
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
#[cfg(test)]
|
|
126
|
+
mod tests {
|
|
127
|
+
use super::*;
|
|
128
|
+
|
|
129
|
+
#[test]
|
|
130
|
+
fn rejection_happens_before_growth_and_stops_other_buffers() {
|
|
131
|
+
let budget = Budget::new(4);
|
|
132
|
+
let mut a = budget.buffer();
|
|
133
|
+
a.push_str("éé");
|
|
134
|
+
assert_eq!(&*a, "éé");
|
|
135
|
+
assert_eq!(a.text.capacity(), 4);
|
|
136
|
+
a.push('x');
|
|
137
|
+
assert!(budget.exceeded());
|
|
138
|
+
assert_eq!(&*a, "éé");
|
|
139
|
+
let b = budget.format(format_args!("{}", "must not be allocated"));
|
|
140
|
+
assert!(b.is_empty());
|
|
141
|
+
assert_eq!(b.text.capacity(), 0);
|
|
142
|
+
}
|
|
143
|
+
}
|