From 689b5d15e5b5bee4cca3c39ff5f76d4a99eed2a8 Mon Sep 17 00:00:00 2001 From: Philipp A Date: Sat, 11 Feb 2023 16:16:53 +0100 Subject: [PATCH 01/35] WIP --- Cargo.lock | 207 ++++++++++++++++++++++++++++++++++++++++++++- Cargo.toml | 4 +- src/lib.rs | 9 ++ src/xdot.rs | 1 + src/xdot/draw.rs | 1 + src/xdot/shapes.rs | 7 ++ 6 files changed, 227 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 922ae4d..a8f8760 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,12 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + [[package]] name = "bitflags" version = "1.3.2" @@ -131,6 +137,12 @@ dependencies = [ "tempfile", ] +[[package]] +name = "indoc" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa799dd5ed20a7e349f3b4639aa80d74549c81716d9ec4f994c9b5815598306" + [[package]] name = "instant" version = "0.1.12" @@ -174,12 +186,31 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f9275e0933cf8bb20f008924c0cb07a0692fe54d8064996520bf998de9eb79aa" +[[package]] +name = "lock_api" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df" +dependencies = [ + "autocfg", + "scopeguard", +] + [[package]] name = "memchr" version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" +[[package]] +name = "memoffset" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d61c719bcfbcf5d62b3a09efa6088de8c54bc0bfcd3ea7ae39fcc186108b8de1" +dependencies = [ + "autocfg", +] + [[package]] name = "minimal-lexical" version = "0.2.1" @@ -202,6 +233,29 @@ version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6f61fba1741ea2b3d6a1e3178721804bb716a68a6aeba1149b5d52e3d464ea66" +[[package]] +name = "parking_lot" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9069cbb9f99e3a5083476ccb29ceb1de18b9118cafa53e90c9551235de2b9521" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-sys", +] + [[package]] name = "pest" version = "2.5.4" @@ -261,6 +315,66 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "pyo3" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06a3d8e8a46ab2738109347433cb7b96dffda2e4a218b03ef27090238886b147" +dependencies = [ + "cfg-if", + "indoc", + "libc", + "memoffset", + "parking_lot", + "pyo3-build-config", + "pyo3-ffi", + "pyo3-macros", + "unindent", +] + +[[package]] +name = "pyo3-build-config" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75439f995d07ddfad42b192dfcf3bc66a7ecfd8b4a1f5f6f046aa5c2c5d7677d" +dependencies = [ + "once_cell", + "target-lexicon", +] + +[[package]] +name = "pyo3-ffi" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "839526a5c07a17ff44823679b68add4a58004de00512a95b6c1c98a6dcac0ee5" +dependencies = [ + "libc", + "pyo3-build-config", +] + +[[package]] +name = "pyo3-macros" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd44cf207476c6a9760c4653559be4f206efafb924d3e4cbf2721475fc0d6cc5" +dependencies = [ + "proc-macro2", + "pyo3-macros-backend", + "quote", + "syn", +] + +[[package]] +name = "pyo3-macros-backend" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc1f43d8e30460f36350d18631ccf85ded64c059829208fe680904c65bcd0a4c" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "quote" version = "1.0.23" @@ -327,6 +441,12 @@ dependencies = [ "semver", ] +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + [[package]] name = "semver" version = "1.0.16" @@ -344,6 +464,12 @@ dependencies = [ "digest", ] +[[package]] +name = "smallvec" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" + [[package]] name = "syn" version = "1.0.107" @@ -355,6 +481,12 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "target-lexicon" +version = "0.12.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ae9980cab1db3fceee2f6c6f643d5d8de2997c58ee8d25fb0cc8a9e9e7348e5" + [[package]] name = "tempfile" version = "3.3.0" @@ -407,6 +539,12 @@ version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc" +[[package]] +name = "unindent" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1766d682d402817b5ac4490b3c3002d91dfa0d22812f341609f97b08757359c" + [[package]] name = "version_check" version = "0.9.4" @@ -441,9 +579,75 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "windows-sys" +version = "0.45.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.42.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e2522491fbfcd58cc84d47aeb2958948c4b8982e9a2d8a2a35bbaed431390e7" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.42.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c9864e83243fdec7fc9c5444389dcbbfd258f745e7853198f365e3c4968a608" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.42.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c8b1b673ffc16c47a9ff48570a9d85e25d265735c503681332589af6253c6c7" + +[[package]] +name = "windows_i686_gnu" +version = "0.42.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de3887528ad530ba7bdbb1faa8275ec7a1155a45ffa57c37993960277145d640" + +[[package]] +name = "windows_i686_msvc" +version = "0.42.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf4d1122317eddd6ff351aa852118a2418ad4214e6613a50e0191f7004372605" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.42.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1040f221285e17ebccbc2591ffdc2d44ee1f9186324dd3e84e99ac68d699c45" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.42.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "628bfdf232daa22b0d64fdb62b09fcc36bb01f05a3939e20ab73aaf9470d0463" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.42.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "447660ad36a13288b1db4d4248e857b510e8c3a225c822ba4fb748c0aafecffd" + [[package]] name = "xdot" -version = "0.1.0" +version = "0.1.1" dependencies = [ "bitflags", "document-features", @@ -451,6 +655,7 @@ dependencies = [ "nom", "pest", "pest_derive", + "pyo3", "rustc_version", "thiserror", ] diff --git a/Cargo.toml b/Cargo.toml index c685999..fb00348 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,7 +15,7 @@ categories = ['parser-implementations', 'rendering::data-formats'] all-features = true [features] -## The layout feature allows to parse `xdot` attributes from +## The `layout` feature allows to parse `xdot` attributes from ## [graphviz_rust]’s [Graph](graphviz_rust::dot_structures::Graph)s ## using [draw_graph]. layout = ['graphviz-rust', 'thiserror'] @@ -28,6 +28,8 @@ nom = '7.1.3' pest = '2.5.4' pest_derive = '2.5.4' thiserror = { version = '1.0.38', optional = true } +## The `pyo3` feature enables using the crate from Python. +pyo3 = { version = '0.18.1', optional = true } [build-dependencies] rustc_version = '0.4.0' diff --git a/src/lib.rs b/src/lib.rs index 26b66c4..c1e644b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -25,3 +25,12 @@ pub use self::xdot::{draw, parse, shapes, ShapeDraw}; pub static ATTR_NAMES: [&str; 6] = [ "_draw_", "_ldraw_", "_hdraw_", "_tdraw_", "_hldraw_", "_tldraw_", ]; + + +/// Python module TODO +#[cfg_attr(feature= "pyo3", pyo3::pymodule)] +fn rust(_py: pyo3::Python, m: &pyo3::types::PyModule) -> pyo3::PyResult<()> { + m.add_class::()?; + // TODO + Ok(()) +} diff --git a/src/xdot.rs b/src/xdot.rs index 97eaeb6..d5a6369 100644 --- a/src/xdot.rs +++ b/src/xdot.rs @@ -12,6 +12,7 @@ use self::shapes::Shape; /// A [Shape] together with a [Pen]. #[derive(Debug, Clone, PartialEq)] +#[cfg_attr(feature= "pyo3", pyo3::pyclass)] pub struct ShapeDraw { pub pen: Pen, pub shape: Shape, diff --git a/src/xdot/draw.rs b/src/xdot/draw.rs index 56147b9..a6ba19c 100644 --- a/src/xdot/draw.rs +++ b/src/xdot/draw.rs @@ -6,6 +6,7 @@ pub use self::attrs::{FontCharacteristics, Rgba, Style}; /// Stores attributes for lines, shapes, and text, such as color and font. #[derive(Debug, Clone, PartialEq)] +#[cfg_attr(feature= "pyo3", pyo3::pyclass)] pub struct Pen { pub color: Rgba, pub fill_color: Rgba, diff --git a/src/xdot/shapes.rs b/src/xdot/shapes.rs index cf5b0c0..e1ca5e1 100644 --- a/src/xdot/shapes.rs +++ b/src/xdot/shapes.rs @@ -2,6 +2,7 @@ /// A drawable shape including closed shapes, lines, and text. #[derive(Debug, Clone, PartialEq)] +#[cfg_attr(feature= "pyo3", pyo3::pyclass)] pub enum Shape { Ellipse(Ellipse), Points(Points), @@ -10,6 +11,7 @@ pub enum Shape { /// A horizontal ellipse shape. #[derive(Debug, Clone, PartialEq)] +#[cfg_attr(feature= "pyo3", pyo3::pyclass)] pub struct Ellipse { pub filled: bool, pub x: f32, @@ -25,6 +27,7 @@ impl From for Shape { /// Type of shape defined by a sequence of points. #[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[cfg_attr(feature= "pyo3", pyo3::pyclass)] pub enum PointsType { Polygon, Polyline, @@ -32,6 +35,7 @@ pub enum PointsType { } /// Shape defined by a sequence of points (line or closed shape). #[derive(Debug, Clone, PartialEq)] +#[cfg_attr(feature= "pyo3", pyo3::pyclass)] pub struct Points { pub filled: bool, pub typ: PointsType, @@ -45,6 +49,7 @@ impl From for Shape { /// Horizontal text alignment: left, center, or right. #[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[cfg_attr(feature= "pyo3", pyo3::pyclass)] pub enum TextAlign { Left, Center, @@ -52,6 +57,7 @@ pub enum TextAlign { } /// Multiline text for node or edge labels. #[derive(Debug, Clone, PartialEq)] +#[cfg_attr(feature= "pyo3", pyo3::pyclass)] pub struct Text { pub x: f32, pub y: f32, @@ -68,4 +74,5 @@ impl From for Shape { /// External image, currently unimplemented. #[doc(hidden)] #[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)] +#[cfg_attr(feature= "pyo3", pyo3::pyclass)] pub struct ExternalImage; From 01144aded39b1edfe166d571739cbf047a197a81 Mon Sep 17 00:00:00 2001 From: Philipp A Date: Tue, 14 Feb 2023 22:54:44 +0100 Subject: [PATCH 02/35] progress --- Cargo.toml | 3 ++- src/layout.rs | 2 +- src/lib.rs | 13 +++++++------ src/{xdot.rs => xdot_parse.rs} | 9 +++++++++ src/{xdot => xdot_parse}/draw.rs | 0 src/{xdot => xdot_parse}/draw/attrs.rs | 0 src/{xdot => xdot_parse}/op_parser.rs | 0 src/{xdot => xdot_parse}/ops.rs | 0 src/{xdot => xdot_parse}/shapes.rs | 0 9 files changed, 19 insertions(+), 8 deletions(-) rename src/{xdot.rs => xdot_parse.rs} (84%) rename src/{xdot => xdot_parse}/draw.rs (100%) rename src/{xdot => xdot_parse}/draw/attrs.rs (100%) rename src/{xdot => xdot_parse}/op_parser.rs (100%) rename src/{xdot => xdot_parse}/ops.rs (100%) rename src/{xdot => xdot_parse}/shapes.rs (100%) diff --git a/Cargo.toml b/Cargo.toml index fb00348..8c483d8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,6 +19,8 @@ all-features = true ## [graphviz_rust]’s [Graph](graphviz_rust::dot_structures::Graph)s ## using [draw_graph]. layout = ['graphviz-rust', 'thiserror'] +## The `pyo3` feature enables using the crate from Python. +pyo3 = ['dep:pyo3'] [dependencies] bitflags = '1.3.2' @@ -28,7 +30,6 @@ nom = '7.1.3' pest = '2.5.4' pest_derive = '2.5.4' thiserror = { version = '1.0.38', optional = true } -## The `pyo3` feature enables using the crate from Python. pyo3 = { version = '0.18.1', optional = true } [build-dependencies] diff --git a/src/layout.rs b/src/layout.rs index aaa4705..f7606ce 100644 --- a/src/layout.rs +++ b/src/layout.rs @@ -10,7 +10,7 @@ mod graph_ext; use self::graph_ext::{Elem, GraphExt}; use super::{ - xdot::{parse, ShapeDraw}, + xdot_parse::{parse, ShapeDraw}, ATTR_NAMES, }; diff --git a/src/lib.rs b/src/lib.rs index c1e644b..5c3ab4f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -13,11 +13,12 @@ #[cfg(feature = "layout")] mod layout; -mod xdot; +mod xdot_parse; #[cfg(feature = "layout")] pub use self::layout::{draw_graph, layout_and_draw_graph, LayoutError}; -pub use self::xdot::{draw, parse, shapes, ShapeDraw}; +pub use self::xdot_parse::{draw, parse, shapes, ShapeDraw}; +use self::xdot_parse::parse_py; /// Known node/edge attribute names holding `xdot` draw instructions that [parse] can handle. /// @@ -26,11 +27,11 @@ pub static ATTR_NAMES: [&str; 6] = [ "_draw_", "_ldraw_", "_hdraw_", "_tdraw_", "_hldraw_", "_tldraw_", ]; - /// Python module TODO -#[cfg_attr(feature= "pyo3", pyo3::pymodule)] -fn rust(_py: pyo3::Python, m: &pyo3::types::PyModule) -> pyo3::PyResult<()> { +#[cfg(feature= "pyo3")] +#[pyo3::pymodule] +fn pymodule(_py: pyo3::Python, m: &pyo3::types::PyModule) -> pyo3::PyResult<()> { m.add_class::()?; - // TODO + m.add_function(pyo3::wrap_pyfunction!(parse_py, m)?); Ok(()) } diff --git a/src/xdot.rs b/src/xdot_parse.rs similarity index 84% rename from src/xdot.rs rename to src/xdot_parse.rs index d5a6369..17846d5 100644 --- a/src/xdot.rs +++ b/src/xdot_parse.rs @@ -43,3 +43,12 @@ pub fn parse(input: &str) -> Result, NomError<&str>> { } Ok(shape_draws) } + +#[cfg(feature= "pyo3")] +#[pyo3::pyfunction] +#[pyo3(name = "parse")] +pub fn parse_py(input: &str) -> pyo3::PyResult> { + use pyo3::{PyErr, exceptions::PyValueError}; + + parse(input).map_err(|e| PyErr::new::(e.to_string())) +} \ No newline at end of file diff --git a/src/xdot/draw.rs b/src/xdot_parse/draw.rs similarity index 100% rename from src/xdot/draw.rs rename to src/xdot_parse/draw.rs diff --git a/src/xdot/draw/attrs.rs b/src/xdot_parse/draw/attrs.rs similarity index 100% rename from src/xdot/draw/attrs.rs rename to src/xdot_parse/draw/attrs.rs diff --git a/src/xdot/op_parser.rs b/src/xdot_parse/op_parser.rs similarity index 100% rename from src/xdot/op_parser.rs rename to src/xdot_parse/op_parser.rs diff --git a/src/xdot/ops.rs b/src/xdot_parse/ops.rs similarity index 100% rename from src/xdot/ops.rs rename to src/xdot_parse/ops.rs diff --git a/src/xdot/shapes.rs b/src/xdot_parse/shapes.rs similarity index 100% rename from src/xdot/shapes.rs rename to src/xdot_parse/shapes.rs From 4169b9bd530f82c8b600f6ac3f0ba506c065ce09 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 14 Feb 2023 21:54:54 +0000 Subject: [PATCH 03/35] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- src/xdot_parse.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/xdot_parse.rs b/src/xdot_parse.rs index 17846d5..f2ccd9a 100644 --- a/src/xdot_parse.rs +++ b/src/xdot_parse.rs @@ -51,4 +51,4 @@ pub fn parse_py(input: &str) -> pyo3::PyResult> { use pyo3::{PyErr, exceptions::PyValueError}; parse(input).map_err(|e| PyErr::new::(e.to_string())) -} \ No newline at end of file +} From 1a73c0315a40bfdf775d710782e6a8334c8db4d6 Mon Sep 17 00:00:00 2001 From: Philipp A Date: Tue, 14 Feb 2023 23:26:03 +0100 Subject: [PATCH 04/35] hacky but compiles --- src/lib.rs | 8 ++++-- src/xdot_parse/draw.rs | 11 ++++++++ src/xdot_parse/draw/attrs.rs | 3 +++ src/xdot_parse/shapes.rs | 51 +++++++++++++++++++++++++++++++++++- 4 files changed, 70 insertions(+), 3 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 5c3ab4f..3e166ea 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -18,6 +18,7 @@ mod xdot_parse; #[cfg(feature = "layout")] pub use self::layout::{draw_graph, layout_and_draw_graph, LayoutError}; pub use self::xdot_parse::{draw, parse, shapes, ShapeDraw}; +#[cfg(feature= "pyo3")] use self::xdot_parse::parse_py; /// Known node/edge attribute names holding `xdot` draw instructions that [parse] can handle. @@ -30,8 +31,11 @@ pub static ATTR_NAMES: [&str; 6] = [ /// Python module TODO #[cfg(feature= "pyo3")] #[pyo3::pymodule] -fn pymodule(_py: pyo3::Python, m: &pyo3::types::PyModule) -> pyo3::PyResult<()> { +#[pyo3(name = "xdot_rs")] +pub fn pymodule(_py: pyo3::Python, m: &pyo3::types::PyModule) -> pyo3::PyResult<()> { m.add_class::()?; - m.add_function(pyo3::wrap_pyfunction!(parse_py, m)?); + m.add_function(pyo3::wrap_pyfunction!(parse_py, m)?)?; + m.add_wrapped(pyo3::wrap_pymodule!(shapes::pymodule))?; + m.add_wrapped(pyo3::wrap_pymodule!(draw::pymodule))?; Ok(()) } diff --git a/src/xdot_parse/draw.rs b/src/xdot_parse/draw.rs index a6ba19c..61800a1 100644 --- a/src/xdot_parse/draw.rs +++ b/src/xdot_parse/draw.rs @@ -29,3 +29,14 @@ impl Default for Pen { } } } + +#[cfg(feature= "pyo3")] +#[pyo3::pymodule] +#[pyo3(name = "draw")] +pub fn pymodule(_py: pyo3::Python, m: &pyo3::types::PyModule) -> pyo3::PyResult<()> { + m.add_class::()?; + m.add_class::()?; + m.add_class::