diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 706983946..27b28858e 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -51,6 +51,11 @@ jobs: runs-on: ubuntu-latest env: CARGO_INCREMENTAL: 0 + # Reduce debug info to save disk space + CARGO_PROFILE_DEV_DEBUG: 1 + CARGO_PROFILE_TEST_DEBUG: 1 + # Limit parallel compilation to reduce memory pressure + CARGO_BUILD_JOBS: 2 steps: - uses: actions/checkout@v4 with: @@ -97,7 +102,7 @@ jobs: - uses: Swatinem/rust-cache@v2 with: # Update this key to force a new cache - prefix-key: "rust-${{ matrix.name }}-v1" + prefix-key: "rust-${{ matrix.name }}-v2" - name: Install dependencies shell: bash @@ -112,6 +117,8 @@ jobs: if: matrix.name == 'test' run: | cargo test --workspace --all-targets --all-features + # Clean up intermediate build artifacts to free disk space + cargo clean -p sedona-s2geography - name: Doctests if: matrix.name == 'test' diff --git a/.gitignore b/.gitignore index a7e0e9250..72eaab64c 100644 --- a/.gitignore +++ b/.gitignore @@ -36,3 +36,6 @@ coverage/ # documentation site/ + +# Python cache files +__pycache__ diff --git a/Cargo.lock b/Cargo.lock index 4b0eb3790..999f2c0a8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -539,9 +539,9 @@ checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" [[package]] name = "aws-config" -version = "1.8.5" +version = "1.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c478f5b10ce55c9a33f87ca3404ca92768b144fc1bfdede7c0121214a8283a25" +checksum = "8bc1b40fb26027769f16960d2f4a6bc20c4bb755d403e552c8c1a73af433c246" dependencies = [ "aws-credential-types", "aws-runtime", @@ -569,9 +569,9 @@ dependencies = [ [[package]] name = "aws-credential-types" -version = "1.2.5" +version = "1.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1541072f81945fa1251f8795ef6c92c4282d74d59f88498ae7d4bf00f0ebdad9" +checksum = "d025db5d9f52cbc413b167136afb3d8aeea708c0d8884783cf6253be5e22f6f2" dependencies = [ "aws-smithy-async", "aws-smithy-runtime-api", @@ -628,9 +628,9 @@ dependencies = [ [[package]] name = "aws-sdk-sso" -version = "1.81.0" +version = "1.83.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79ede098271e3471036c46957cba2ba30888f53bda2515bf04b560614a30a36e" +checksum = "643cd43af212d2a1c4dedff6f044d7e1961e5d9e7cfe773d70f31d9842413886" dependencies = [ "aws-credential-types", "aws-runtime", @@ -650,9 +650,9 @@ dependencies = [ [[package]] name = "aws-sdk-ssooidc" -version = "1.83.0" +version = "1.84.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b49e8fe57ff100a2f717abfa65bdd94e39702fa5ab3f60cddc6ac7784010c68" +checksum = "20ec4a95bd48e0db7a424356a161f8d87bd6a4f0af37204775f0da03d9e39fc3" dependencies = [ "aws-credential-types", "aws-runtime", @@ -672,9 +672,9 @@ dependencies = [ [[package]] name = "aws-sdk-sts" -version = "1.84.0" +version = "1.85.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91abcdbfb48c38a0419eb75e0eac772a4783a96750392680e4f3c25a8a0535b9" +checksum = "410309ad0df4606bc721aff0d89c3407682845453247213a0ccc5ff8801ee107" dependencies = [ "aws-credential-types", "aws-runtime", @@ -748,9 +748,9 @@ dependencies = [ [[package]] name = "aws-smithy-http-client" -version = "1.1.0" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fdbad9bd9dbcc6c5e68c311a841b54b70def3ca3b674c42fbebb265980539f8" +checksum = "147e8eea63a40315d704b97bf9bc9b8c1402ae94f89d5ad6f7550d963309da1b" dependencies = [ "aws-smithy-async", "aws-smithy-runtime-api", @@ -772,9 +772,9 @@ dependencies = [ [[package]] name = "aws-smithy-json" -version = "0.61.4" +version = "0.61.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a16e040799d29c17412943bdbf488fd75db04112d0c0d4b9290bacf5ae0014b9" +checksum = "eaa31b350998e703e9826b2104dd6f63be0508666e1aba88137af060e8944047" dependencies = [ "aws-smithy-types", ] @@ -800,9 +800,9 @@ dependencies = [ [[package]] name = "aws-smithy-runtime" -version = "1.9.0" +version = "1.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3d57c8b53a72d15c8e190475743acf34e4996685e346a3448dd54ef696fc6e0" +checksum = "d3946acbe1ead1301ba6862e712c7903ca9bb230bdf1fbd1b5ac54158ef2ab1f" dependencies = [ "aws-smithy-async", "aws-smithy-http", @@ -975,9 +975,9 @@ dependencies = [ [[package]] name = "bitflags" -version = "2.9.3" +version = "2.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34efbcccd345379ca2868b2b2c9d3782e9cc58ba87bc7d79d5b53d9c9ae6f25d" +checksum = "2261d10cca569e4643e526d8dc2e62e433cc8aba21ab764233731f8d369bf394" [[package]] name = "blake2" @@ -1117,10 +1117,11 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" [[package]] name = "cc" -version = "1.2.34" +version = "1.2.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42bc4aea80032b7bf409b0bc7ccad88853858911b7713a8062fdc0623867bedc" +checksum = "5252b3d2648e5eedbc1a6f501e3c795e07025c1e93bbf8bbdd6eef7f447a6d54" dependencies = [ + "find-msvc-tools", "jobserver", "libc", "shlex", @@ -1157,7 +1158,7 @@ dependencies = [ "iana-time-zone", "num-traits", "serde", - "windows-link", + "windows-link 0.1.3", ] [[package]] @@ -1210,9 +1211,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.46" +version = "4.5.47" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c5e4fcf9c21d2e544ca1ee9d8552de13019a42aa7dbf32747fa7aaf1df76e57" +checksum = "7eac00902d9d136acd712710d71823fb8ac8004ca445a89e73a41d45aa712931" dependencies = [ "clap_builder", "clap_derive", @@ -1220,9 +1221,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.46" +version = "4.5.47" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fecb53a0e6fcfb055f686001bc2e2592fa527efaf38dbe81a6a9563562e57d41" +checksum = "2ad9bbf750e73b5884fb8a211a9424a1906c1e156724260fdae972f31d70e1d6" dependencies = [ "anstream", "anstyle", @@ -1232,9 +1233,9 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.45" +version = "4.5.47" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14cb31bb0a7d536caef2639baa7fad459e15c3144efefa6dbd1c84562c4739f6" +checksum = "bbfd7eae0b0f1a6e63d4b13c9c478de77c2eb546fba158ad50b4203dc24b9f9c" dependencies = [ "heck", "proc-macro2", @@ -1274,9 +1275,9 @@ checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" [[package]] name = "comfy-table" -version = "7.1.4" +version = "7.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a65ebfec4fb190b6f90e944a817d60499ee0744e582530e2c9900a22e591d9a" +checksum = "3f8e18d0dca9578507f13f9803add0df13362b02c501c1c17734f0dbb52eaf0b" dependencies = [ "crossterm", "unicode-segmentation", @@ -1448,14 +1449,15 @@ checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" [[package]] name = "crossterm" -version = "0.28.1" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "829d955a0bb380ef178a640b91779e3987da38c9aea133b20614cfed8cdea9c6" +checksum = "d8b9f2e4c67f833b660cdb0a3523065869fb35570177239812ed4c905aeff87b" dependencies = [ "bitflags", "crossterm_winapi", + "document-features", "parking_lot", - "rustix 0.38.44", + "rustix 1.0.8", "winapi", ] @@ -2263,9 +2265,9 @@ dependencies = [ [[package]] name = "deranged" -version = "0.4.0" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c9e6a11ca8224451684bc0d7d5a7adbf8f2fd6887261a1cfc3c0432f9d4068e" +checksum = "d630bccd429a5bb5a64b5e94f693bfc48c9f8566418fda4c494cc94f911f87cc" dependencies = [ "powerfmt", ] @@ -2299,7 +2301,7 @@ dependencies = [ "libc", "option-ext", "redox_users", - "windows-sys 0.60.2", + "windows-sys 0.61.0", ] [[package]] @@ -2313,6 +2315,15 @@ dependencies = [ "syn 2.0.106", ] +[[package]] +name = "document-features" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95249b50c6c185bee49034bcb378a49dc2b5dff0be90ff6616d31d64febab05d" +dependencies = [ + "litrs", +] + [[package]] name = "dunce" version = "1.0.5" @@ -2415,6 +2426,12 @@ dependencies = [ "windows-sys 0.60.2", ] +[[package]] +name = "find-msvc-tools" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fd99930f64d146689264c637b5af2f0233a933bef0d8570e2526bf9e083192d" + [[package]] name = "fixedbitset" version = "0.5.7" @@ -2610,7 +2627,7 @@ dependencies = [ [[package]] name = "geo-generic-alg" version = "0.1.0" -source = "git+https://github.com/wherobots/geo.git?branch=generic-alg#04c929eb1d63b8738165c019095f9f625f8ecde7" +source = "git+https://github.com/wherobots/geo.git?branch=generic-alg#ebc0ca413d20c0106f832c59eebda386691c1456" dependencies = [ "earcutr", "float_next_after", @@ -2645,7 +2662,7 @@ dependencies = [ [[package]] name = "geo-traits" version = "0.2.0" -source = "git+https://github.com/wherobots/geo.git?branch=generic-alg#04c929eb1d63b8738165c019095f9f625f8ecde7" +source = "git+https://github.com/wherobots/geo.git?branch=generic-alg#ebc0ca413d20c0106f832c59eebda386691c1456" dependencies = [ "geo-types", ] @@ -2662,7 +2679,7 @@ dependencies = [ [[package]] name = "geo-traits-ext" version = "0.1.0" -source = "git+https://github.com/wherobots/geo.git?branch=generic-alg#04c929eb1d63b8738165c019095f9f625f8ecde7" +source = "git+https://github.com/wherobots/geo.git?branch=generic-alg#ebc0ca413d20c0106f832c59eebda386691c1456" dependencies = [ "approx", "geo-traits 0.2.0", @@ -2674,7 +2691,7 @@ dependencies = [ [[package]] name = "geo-types" version = "0.7.16" -source = "git+https://github.com/wherobots/geo.git?branch=generic-alg#04c929eb1d63b8738165c019095f9f625f8ecde7" +source = "git+https://github.com/wherobots/geo.git?branch=generic-alg#ebc0ca413d20c0106f832c59eebda386691c1456" dependencies = [ "approx", "num-traits", @@ -2740,7 +2757,7 @@ dependencies = [ "js-sys", "libc", "r-efi", - "wasi 0.14.2+wasi-0.2.4", + "wasi 0.14.4+wasi-0.2.4", "wasm-bindgen", ] @@ -2987,7 +3004,7 @@ dependencies = [ "libc", "percent-encoding", "pin-project-lite", - "socket2 0.6.0", + "socket2", "tokio", "tower-service", "tracing", @@ -3327,9 +3344,9 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.77" +version = "0.3.78" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" +checksum = "0c0b063578492ceec17683ef2f8c5e89121fbd0b172cbc280635ab7567db2738" dependencies = [ "once_cell", "wasm-bindgen", @@ -3506,18 +3523,18 @@ dependencies = [ [[package]] name = "libz-rs-sys" -version = "0.5.1" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "172a788537a2221661b480fee8dc5f96c580eb34fa88764d3205dc356c7e4221" +checksum = "840db8cf39d9ec4dd794376f38acc40d0fc65eec2a8f484f7fd375b84602becd" dependencies = [ "zlib-rs", ] [[package]] name = "link-cplusplus" -version = "1.0.10" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a6f6da007f968f9def0d65a05b187e2960183de70c160204ecfccf0ee330212" +checksum = "7f78c730aaa7d0b9336a299029ea49f9ee53b0ed06e9202e8cb7db9bae7b8c82" dependencies = [ "cc", ] @@ -3540,6 +3557,12 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956" +[[package]] +name = "litrs" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5e54036fe321fd421e10d732f155734c4e4afd610dd556d9a82833ab3ee0bed" + [[package]] name = "lock_api" version = "0.4.13" @@ -3552,9 +3575,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.27" +version = "0.4.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" +checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432" [[package]] name = "lru" @@ -4041,9 +4064,9 @@ dependencies = [ [[package]] name = "potential_utf" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5a7c30837279ca13e7c867e9e40053bc68740f988cb07f7ca6df43cc734b585" +checksum = "84df19adbe5b5a0782edcab45899906947ab039ccf4573713735ee7de1e6b08a" dependencies = [ "zerovec", ] @@ -4217,9 +4240,9 @@ dependencies = [ [[package]] name = "quinn" -version = "0.11.8" +version = "0.11.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "626214629cda6781b6dc1d316ba307189c85ba657213ce642d9c77670f8202c8" +checksum = "b9e20a958963c291dc322d98411f541009df2ced7b5a4f2bd52337638cfccf20" dependencies = [ "bytes", "cfg_aliases", @@ -4228,7 +4251,7 @@ dependencies = [ "quinn-udp", "rustc-hash 2.1.1", "rustls", - "socket2 0.5.10", + "socket2", "thiserror 2.0.16", "tokio", "tracing", @@ -4237,9 +4260,9 @@ dependencies = [ [[package]] name = "quinn-proto" -version = "0.11.12" +version = "0.11.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49df843a9161c85bb8aae55f101bc0bac8bcafd637a620d9122fd7e0b2f7422e" +checksum = "f1906b49b0c3bc04b5fe5d86a77925ae6524a19b816ae38ce1e426255f1d8a31" dependencies = [ "bytes", "getrandom 0.3.3", @@ -4258,16 +4281,16 @@ dependencies = [ [[package]] name = "quinn-udp" -version = "0.5.13" +version = "0.5.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcebb1209ee276352ef14ff8732e24cc2b02bbac986cd74a4c81bcb2f9881970" +checksum = "addec6a0dcad8a8d96a771f815f0eaf55f9d1805756410b39f5fa81332574cbd" dependencies = [ "cfg_aliases", "libc", "once_cell", - "socket2 0.5.10", + "socket2", "tracing", - "windows-sys 0.59.0", + "windows-sys 0.60.2", ] [[package]] @@ -4744,9 +4767,9 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "security-framework" -version = "3.3.0" +version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80fb1d92c5028aa318b4b8bd7302a5bfcf48be96a37fc6fc790f806b0004ee0c" +checksum = "60b369d18893388b345804dc0007963c99b7d665ae71d275812d828c6f089640" dependencies = [ "bitflags", "core-foundation", @@ -4757,9 +4780,9 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.14.0" +version = "2.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49db231d56a190491cb4aeda9527f1ad45345af50b0851622a7adb8c03b01c32" +checksum = "cc1f0cbffaac4852523ce30d8bd3c5cdc873501d96ff467ca09b6767bb8cd5c0" dependencies = [ "core-foundation-sys", "libc", @@ -5315,16 +5338,6 @@ version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b6b67fb9a61334225b5b790716f609cd58395f895b3fe8b328786812a40bc3b" -[[package]] -name = "socket2" -version = "0.5.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e22376abed350d73dd1cd119b57ffccad95b4e585a7cda43e286245ce23c0678" -dependencies = [ - "libc", - "windows-sys 0.52.0", -] - [[package]] name = "socket2" version = "0.6.0" @@ -5556,9 +5569,9 @@ dependencies = [ [[package]] name = "time" -version = "0.3.41" +version = "0.3.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a7619e19bc266e0f9c5e6686659d394bc57973859340060a69221e57dbc0c40" +checksum = "83bde6f1ec10e72d583d91623c939f623002284ef622b87de38cfd546cbf2031" dependencies = [ "deranged", "num-conv", @@ -5570,15 +5583,15 @@ dependencies = [ [[package]] name = "time-core" -version = "0.1.4" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9e9a38711f559d9e3ce1cdb06dd7c5b8ea546bc90052da6d06bb76da74bb07c" +checksum = "40868e7c1d2f0b8d73e4a8c7f0ff63af4f6d19be117e90bd73eb1d62cf831c6b" [[package]] name = "time-macros" -version = "0.2.22" +version = "0.2.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3526739392ec93fd8b359c8e98514cb3e8e021beb4e5f597b00a0221f8ed8a49" +checksum = "30cfb0125f12d9c277f35663a0a33f8c30190f4e4574868a330595412d34ebf3" dependencies = [ "num-conv", "time-core", @@ -5643,7 +5656,7 @@ dependencies = [ "pin-project-lite", "signal-hook-registry", "slab", - "socket2 0.6.0", + "socket2", "tokio-macros", "windows-sys 0.59.0", ] @@ -5798,9 +5811,9 @@ checksum = "e78122066b0cb818b8afd08f7ed22f7fdbc3e90815035726f0840d0d26c0747a" [[package]] name = "twox-hash" -version = "2.1.1" +version = "2.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b907da542cbced5261bd3256de1b3a1bf340a3d37f93425a07362a1d687de56" +checksum = "9ea3136b675547379c4bd395ca6b938e5ad3c3d20fad76e7fe85f9e0d011419c" [[package]] name = "typed-arena" @@ -5836,9 +5849,9 @@ checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f" [[package]] name = "typewit" -version = "1.13.0" +version = "1.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4dd91acc53c592cb800c11c83e8e7ee1d48378d05cfa33b5474f5f80c5b236bf" +checksum = "4c98488b93df24b7c794d6a58c4198d7a2abde676324beaca84f7fb5b39c0811" [[package]] name = "unicode-ident" @@ -5902,9 +5915,9 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "uuid" -version = "1.18.0" +version = "1.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f33196643e165781c20a5ead5582283a7dacbb87855d867fbc2df3f81eddc1be" +checksum = "2f87b8aa10b915a06587d0dec516c282ff295b475d94abf425d62b57710070a2" dependencies = [ "getrandom 0.3.3", "js-sys", @@ -5957,30 +5970,31 @@ checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" [[package]] name = "wasi" -version = "0.14.2+wasi-0.2.4" +version = "0.14.4+wasi-0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3" +checksum = "88a5f4a424faf49c3c2c344f166f0662341d470ea185e939657aaff130f0ec4a" dependencies = [ - "wit-bindgen-rt", + "wit-bindgen", ] [[package]] name = "wasm-bindgen" -version = "0.2.100" +version = "0.2.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" +checksum = "7e14915cadd45b529bb8d1f343c4ed0ac1de926144b746e2710f9cd05df6603b" dependencies = [ "cfg-if", "once_cell", "rustversion", "wasm-bindgen-macro", + "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-backend" -version = "0.2.100" +version = "0.2.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" +checksum = "e28d1ba982ca7923fd01448d5c30c6864d0a14109560296a162f80f305fb93bb" dependencies = [ "bumpalo", "log", @@ -5992,9 +6006,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.50" +version = "0.4.51" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "555d470ec0bc3bb57890405e5d4322cc9ea83cebb085523ced7be4144dac1e61" +checksum = "0ca85039a9b469b38336411d6d6ced91f3fc87109a2a27b0c197663f5144dffe" dependencies = [ "cfg-if", "js-sys", @@ -6005,9 +6019,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.100" +version = "0.2.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" +checksum = "7c3d463ae3eff775b0c45df9da45d68837702ac35af998361e2c84e7c5ec1b0d" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -6015,9 +6029,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.100" +version = "0.2.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" +checksum = "7bb4ce89b08211f923caf51d527662b75bdc9c9c7aab40f86dcb9fb85ac552aa" dependencies = [ "proc-macro2", "quote", @@ -6028,9 +6042,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.100" +version = "0.2.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" +checksum = "f143854a3b13752c6950862c906306adb27c7e839f7414cec8fea35beab624c1" dependencies = [ "unicode-ident", ] @@ -6050,9 +6064,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.77" +version = "0.3.78" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2" +checksum = "77e4b637749ff0d92b8fad63aa1f7cff3cbe125fd49c175cd6345e7272638b12" dependencies = [ "js-sys", "wasm-bindgen", @@ -6098,11 +6112,11 @@ checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-util" -version = "0.1.10" +version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0978bf7171b3d90bac376700cb56d606feb40f251a475a5d6634613564460b22" +checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" dependencies = [ - "windows-sys 0.60.2", + "windows-sys 0.61.0", ] [[package]] @@ -6119,7 +6133,7 @@ checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3" dependencies = [ "windows-implement", "windows-interface", - "windows-link", + "windows-link 0.1.3", "windows-result", "windows-strings", ] @@ -6152,13 +6166,19 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" +[[package]] +name = "windows-link" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45e46c0661abb7180e7b9c281db115305d49ca1709ab8242adf09666d2173c65" + [[package]] name = "windows-result" version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6" dependencies = [ - "windows-link", + "windows-link 0.1.3", ] [[package]] @@ -6167,7 +6187,7 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57" dependencies = [ - "windows-link", + "windows-link 0.1.3", ] [[package]] @@ -6197,6 +6217,15 @@ dependencies = [ "windows-targets 0.53.3", ] +[[package]] +name = "windows-sys" +version = "0.61.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e201184e40b2ede64bc2ea34968b28e33622acdbbf37104f0e4a33f7abe657aa" +dependencies = [ + "windows-link 0.2.0", +] + [[package]] name = "windows-targets" version = "0.52.6" @@ -6219,7 +6248,7 @@ version = "0.53.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d5fe6031c4041849d7c496a8ded650796e7b6ecc19df1a431c1a363342e5dc91" dependencies = [ - "windows-link", + "windows-link 0.1.3", "windows_aarch64_gnullvm 0.53.0", "windows_aarch64_msvc 0.53.0", "windows_i686_gnu 0.53.0", @@ -6336,13 +6365,10 @@ dependencies = [ ] [[package]] -name = "wit-bindgen-rt" -version = "0.39.0" +name = "wit-bindgen" +version = "0.45.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" -dependencies = [ - "bitflags", -] +checksum = "5c573471f125075647d03df72e026074b7203790d41351cd6edc96f46bcccd36" [[package]] name = "wkb" @@ -6452,18 +6478,18 @@ dependencies = [ [[package]] name = "zerocopy" -version = "0.8.26" +version = "0.8.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1039dd0d3c310cf05de012d8a39ff557cb0d23087fd44cad61df08fc31907a2f" +checksum = "0894878a5fa3edfd6da3f88c4805f4c8558e2b996227a3d864f47fe11e38282c" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.26" +version = "0.8.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ecf5b4cc5364572d7f4c329661bcc82724222973f2cab6f050a4e5c22f75181" +checksum = "88d2b8d9c68ad2b9e4340d7832716a4d21a22a1154777ad56ea55c51a9cf3831" dependencies = [ "proc-macro2", "quote", @@ -6532,9 +6558,9 @@ dependencies = [ [[package]] name = "zlib-rs" -version = "0.5.1" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "626bd9fa9734751fc50d6060752170984d7053f5a39061f524cda68023d4db8a" +checksum = "2f06ae92f42f5e5c42443fd094f245eb656abf56dd7cce9b8b263236565e00f2" [[package]] name = "zstd" @@ -6556,9 +6582,9 @@ dependencies = [ [[package]] name = "zstd-sys" -version = "2.0.15+zstd.1.5.7" +version = "2.0.16+zstd.1.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb81183ddd97d0c74cedf1d50d85c8d08c1b8b68ee863bdee9e706eedba1a237" +checksum = "91e19ebc2adc8f83e43039e79776e3fda8ca919132d68a1fed6a5faca2683748" dependencies = [ "cc", "pkg-config", diff --git a/benchmarks/test_functions.py b/benchmarks/test_functions.py index 8be56d7de..a36de82a5 100644 --- a/benchmarks/test_functions.py +++ b/benchmarks/test_functions.py @@ -115,3 +115,20 @@ def queries(): eng.execute_and_collect(f"SELECT ST_GeometryType(geom1) from {table}") benchmark(queries) + + @pytest.mark.parametrize("eng", [SedonaDB, PostGIS, DuckDB]) + @pytest.mark.parametrize( + "table", + [ + "segments_large", + "collections_simple", + "collections_complex", + ], + ) + def test_st_length(self, benchmark, eng, table): + eng = self._get_eng(eng) + + def queries(): + eng.execute_and_collect(f"SELECT ST_Length(geom1) from {table}") + + benchmark(queries) diff --git a/rust/sedona-functions/src/lib.rs b/rust/sedona-functions/src/lib.rs index c8d95dbc4..3620b67a3 100644 --- a/rust/sedona-functions/src/lib.rs +++ b/rust/sedona-functions/src/lib.rs @@ -37,7 +37,7 @@ mod st_geomfromwkb; mod st_geomfromwkt; mod st_haszm; pub mod st_intersection_aggr; -mod st_isempty; +pub mod st_isempty; mod st_length; mod st_perimeter; mod st_point; diff --git a/rust/sedona-functions/src/register.rs b/rust/sedona-functions/src/register.rs index 3f7f931f4..c0979980d 100644 --- a/rust/sedona-functions/src/register.rs +++ b/rust/sedona-functions/src/register.rs @@ -121,6 +121,7 @@ pub mod stubs { pub use crate::predicates::*; pub use crate::referencing::*; pub use crate::st_area::st_area_udf; + pub use crate::st_centroid::st_centroid_udf; pub use crate::st_length::st_length_udf; pub use crate::st_perimeter::st_perimeter_udf; pub use crate::st_setsrid::st_set_srid_with_engine_udf; diff --git a/rust/sedona-functions/src/st_isempty.rs b/rust/sedona-functions/src/st_isempty.rs index 7069f5493..d41a08b10 100644 --- a/rust/sedona-functions/src/st_isempty.rs +++ b/rust/sedona-functions/src/st_isempty.rs @@ -23,12 +23,8 @@ use datafusion_common::error::Result; use datafusion_expr::{ scalar_doc_sections::DOC_SECTION_OTHER, ColumnarValue, Documentation, Volatility, }; -use geo_traits::{ - GeometryCollectionTrait, GeometryTrait, LineStringTrait, MultiLineStringTrait, MultiPointTrait, - MultiPolygonTrait, PointTrait, PolygonTrait, -}; -use sedona_common::sedona_internal_err; use sedona_expr::scalar_udf::{ArgMatcher, SedonaScalarKernel, SedonaScalarUDF}; +use sedona_geometry::is_empty::is_geometry_empty; use sedona_schema::datatypes::SedonaType; use wkb::reader::Wkb; @@ -87,25 +83,16 @@ impl SedonaScalarKernel for STIsEmpty { } } +pub fn is_wkb_empty(item: &Wkb) -> Result { + invoke_scalar(item) +} + fn invoke_scalar(item: &Wkb) -> Result { - match item.as_type() { - geo_traits::GeometryType::Point(point) => Ok(point.coord().is_none()), - geo_traits::GeometryType::LineString(linestring) => Ok(linestring.num_coords() == 0), - geo_traits::GeometryType::Polygon(polygon) => { - Ok(polygon.num_interiors() == 0 && polygon.exterior().is_none()) - } - geo_traits::GeometryType::MultiPoint(multipoint) => Ok(multipoint.num_points() == 0), - geo_traits::GeometryType::MultiLineString(multilinestring) => { - Ok(multilinestring.num_line_strings() == 0) - } - geo_traits::GeometryType::MultiPolygon(multipolygon) => { - Ok(multipolygon.num_polygons() == 0) - } - geo_traits::GeometryType::GeometryCollection(geometrycollection) => { - Ok(geometrycollection.num_geometries() == 0) - } - _ => sedona_internal_err!("Invalid geometry type"), - } + is_geometry_empty(item).map_err(|e| { + datafusion_common::error::DataFusionError::Execution(format!( + "Failed to check if geometry is empty: {e}" + )) + }) } #[cfg(test)] diff --git a/rust/sedona-geo/src/lib.rs b/rust/sedona-geo/src/lib.rs index edb0959d6..24c640806 100644 --- a/rust/sedona-geo/src/lib.rs +++ b/rust/sedona-geo/src/lib.rs @@ -17,8 +17,10 @@ pub mod centroid; pub mod register; mod st_area; +mod st_centroid; mod st_intersection_aggr; mod st_intersects; +mod st_length; mod st_line_interpolate_point; mod st_union_aggr; pub mod to_geo; diff --git a/rust/sedona-geo/src/register.rs b/rust/sedona-geo/src/register.rs index 59049613a..9db2c32e5 100644 --- a/rust/sedona-geo/src/register.rs +++ b/rust/sedona-geo/src/register.rs @@ -20,12 +20,17 @@ use sedona_expr::scalar_udf::ScalarKernelRef; use crate::st_intersection_aggr::st_intersection_aggr_impl; use crate::st_line_interpolate_point::st_line_interpolate_point_impl; use crate::st_union_aggr::st_union_aggr_impl; -use crate::{st_area::st_area_impl, st_intersects::st_intersects_impl}; +use crate::{ + st_area::st_area_impl, st_centroid::st_centroid_impl, st_intersects::st_intersects_impl, + st_length::st_length_impl, +}; pub fn scalar_kernels() -> Vec<(&'static str, ScalarKernelRef)> { vec![ ("st_intersects", st_intersects_impl()), ("st_area", st_area_impl()), + ("st_centroid", st_centroid_impl()), + ("st_length", st_length_impl()), ("st_lineinterpolatepoint", st_line_interpolate_point_impl()), ] } diff --git a/rust/sedona-geo/src/st_centroid.rs b/rust/sedona-geo/src/st_centroid.rs new file mode 100644 index 000000000..0b4a623d8 --- /dev/null +++ b/rust/sedona-geo/src/st_centroid.rs @@ -0,0 +1,139 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +use std::sync::Arc; + +use arrow_array::builder::BinaryBuilder; +use datafusion_common::{error::Result, exec_err}; +use datafusion_expr::ColumnarValue; +use geo_generic_alg::Centroid; +use sedona_expr::scalar_udf::{ArgMatcher, ScalarKernelRef, SedonaScalarKernel}; +use sedona_functions::executor::WkbExecutor; +use sedona_geometry::is_empty::is_geometry_empty; +use sedona_schema::datatypes::{SedonaType, WKB_GEOMETRY}; +use wkb::reader::Wkb; + +use geo_traits::Dimensions; +use sedona_geometry::wkb_factory::{self, WKB_MIN_PROBABLE_BYTES}; + +/// ST_Centroid() implementation using centroid extraction +pub fn st_centroid_impl() -> ScalarKernelRef { + Arc::new(STCentroid {}) +} + +#[derive(Debug)] +struct STCentroid {} + +impl SedonaScalarKernel for STCentroid { + fn return_type(&self, args: &[SedonaType]) -> Result> { + let matcher = ArgMatcher::new(vec![ArgMatcher::is_geometry()], WKB_GEOMETRY); + + matcher.match_args(args) + } + + fn invoke_batch( + &self, + arg_types: &[SedonaType], + args: &[ColumnarValue], + ) -> Result { + let executor = WkbExecutor::new(arg_types, args); + let mut builder = + BinaryBuilder::with_capacity(executor.num_iterations(), WKB_MIN_PROBABLE_BYTES); + executor.execute_wkb_void(|maybe_wkb| { + match maybe_wkb { + Some(wkb) => { + let centroid_wkb = invoke_scalar(&wkb)?; + builder.append_value(¢roid_wkb); + } + _ => builder.append_null(), + } + + Ok(()) + })?; + + executor.finish(Arc::new(builder.finish())) + } +} + +fn invoke_scalar(wkb: &Wkb) -> Result> { + // Check for empty geometries first - they should return POINT EMPTY + if is_geometry_empty(wkb).map_err(|e| { + datafusion_common::error::DataFusionError::Execution(format!( + "Failed to check if geometry is empty: {e}" + )) + })? { + let mut empty_point_wkb = Vec::new(); + wkb_factory::write_wkb_empty_point(&mut empty_point_wkb, Dimensions::Xy) + .map_err(|e| datafusion_common::error::DataFusionError::External(Box::new(e)))?; + return Ok(empty_point_wkb); + } + + // Use Centroid trait directly on WKB, similar to how st_area uses unsigned_area() + if let Some(centroid_point) = wkb.centroid() { + // Extract coordinates from the centroid point + let x = centroid_point.x(); + let y = centroid_point.y(); + + wkb_factory::wkb_point((x, y)) + .map_err(|e| datafusion_common::error::DataFusionError::External(Box::new(e))) + } else { + // This should not happen for non-empty geometries - this indicates an error + exec_err!("Failed to compute centroid for geometry") + } +} + +#[cfg(test)] +mod tests { + use rstest::rstest; + use sedona_functions::register::stubs::st_centroid_udf; + use sedona_schema::datatypes::{WKB_GEOMETRY, WKB_VIEW_GEOMETRY}; + use sedona_testing::compare::assert_array_equal; + use sedona_testing::create::create_array; + use sedona_testing::testers::ScalarUdfTester; + + use super::*; + + #[rstest] + fn udf(#[values(WKB_GEOMETRY, WKB_VIEW_GEOMETRY)] sedona_type: SedonaType) { + let mut udf = st_centroid_udf(); + udf.add_kernel(st_centroid_impl()); + let tester = ScalarUdfTester::new(udf.into(), vec![sedona_type]); + + assert_eq!(tester.return_type().unwrap(), WKB_GEOMETRY); + + // Test with a polygon + let result = tester + .invoke_scalar("POLYGON ((0 0, 2 0, 2 2, 0 2, 0 0))") + .unwrap(); + tester.assert_scalar_result_equals(result, "POINT (1 1)"); + + // Test with array + let input_wkt = vec![ + Some("POINT(1 2)"), + None, + Some("POLYGON ((0 0, 2 0, 2 2, 0 2, 0 0))"), + ]; + let result_array = tester.invoke_wkb_array(input_wkt).unwrap(); + assert_array_equal( + &result_array, + &create_array( + &[Some("POINT (1 2)"), None, Some("POINT (1 1)")], + &WKB_GEOMETRY, + ), + ); + } +} diff --git a/rust/sedona-geo/src/st_length.rs b/rust/sedona-geo/src/st_length.rs new file mode 100644 index 000000000..b80869fd6 --- /dev/null +++ b/rust/sedona-geo/src/st_length.rs @@ -0,0 +1,115 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +use std::sync::Arc; + +use arrow_array::builder::Float64Builder; +use arrow_schema::DataType; +use datafusion_common::error::Result; +use datafusion_expr::ColumnarValue; +use geo_generic_alg::algorithm::{line_measures::Euclidean, LengthMeasurableExt}; +use sedona_expr::scalar_udf::{ArgMatcher, ScalarKernelRef, SedonaScalarKernel}; +use sedona_functions::executor::WkbExecutor; +use sedona_schema::datatypes::SedonaType; +use wkb::reader::Wkb; + +/// ST_Length() implementation using [LengthMeasurableExt] with Euclidean metric +pub fn st_length_impl() -> ScalarKernelRef { + Arc::new(STLength {}) +} + +#[derive(Debug)] +struct STLength {} + +impl SedonaScalarKernel for STLength { + fn return_type(&self, args: &[SedonaType]) -> Result> { + let matcher = ArgMatcher::new( + vec![ArgMatcher::is_geometry()], + SedonaType::Arrow(DataType::Float64), + ); + + matcher.match_args(args) + } + + fn invoke_batch( + &self, + arg_types: &[SedonaType], + args: &[ColumnarValue], + ) -> Result { + let executor = WkbExecutor::new(arg_types, args); + let mut builder = Float64Builder::with_capacity(executor.num_iterations()); + executor.execute_wkb_void(|maybe_wkb| { + match maybe_wkb { + Some(wkb) => { + builder.append_value(invoke_scalar(&wkb)?); + } + _ => builder.append_null(), + } + + Ok(()) + })?; + + executor.finish(Arc::new(builder.finish())) + } +} + +fn invoke_scalar(wkb: &Wkb) -> Result { + Ok(wkb.length_ext(&Euclidean)) +} + +#[cfg(test)] +mod tests { + use arrow_array::{create_array, ArrayRef}; + use datafusion_common::scalar::ScalarValue; + use rstest::rstest; + use sedona_functions::register::stubs::st_length_udf; + use sedona_schema::datatypes::{WKB_GEOMETRY, WKB_VIEW_GEOMETRY}; + use sedona_testing::testers::ScalarUdfTester; + + use super::*; + + #[rstest] + fn udf(#[values(WKB_GEOMETRY, WKB_VIEW_GEOMETRY)] sedona_type: SedonaType) { + let mut udf = st_length_udf(); + udf.add_kernel(st_length_impl()); + let tester = ScalarUdfTester::new(udf.into(), vec![sedona_type]); + + assert_eq!( + tester.return_type().unwrap(), + SedonaType::Arrow(DataType::Float64) + ); + + // Test with a line string + assert_eq!( + tester + .invoke_wkb_scalar(Some("LINESTRING (0 0, 3 4)")) + .unwrap(), + ScalarValue::Float64(Some(5.0)) + ); + + let input_wkt = vec![ + Some("POINT(1 2)"), // Point should have 0 length + None, + Some("LINESTRING (0 0, 3 4)"), // Should have length 5 + Some("LINESTRING (0 0, 1 0, 1 1)"), // Should have length 2 + Some("POLYGON ((0 0, 1 0, 1 1, 0 1, 0 0))"), // Polygon should have 0 length per OGC standard + ]; + let expected: ArrayRef = + create_array!(Float64, [Some(0.0), None, Some(5.0), Some(2.0), Some(0.0)]); + assert_eq!(&tester.invoke_wkb_array(input_wkt).unwrap(), &expected); + } +} diff --git a/rust/sedona-geometry/src/is_empty.rs b/rust/sedona-geometry/src/is_empty.rs new file mode 100644 index 000000000..ad3f7d50b --- /dev/null +++ b/rust/sedona-geometry/src/is_empty.rs @@ -0,0 +1,151 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +use crate::error::SedonaGeometryError; +use geo_traits::{ + GeometryCollectionTrait, GeometryTrait, LineStringTrait, MultiLineStringTrait, MultiPointTrait, + MultiPolygonTrait, PointTrait, PolygonTrait, +}; + +pub fn is_geometry_empty>( + geometry: &G, +) -> Result { + match geometry.as_type() { + geo_traits::GeometryType::Point(point) => Ok(point.coord().is_none()), + geo_traits::GeometryType::LineString(linestring) => Ok(linestring.num_coords() == 0), + geo_traits::GeometryType::Polygon(polygon) => { + Ok(polygon.num_interiors() == 0 && polygon.exterior().is_none()) + } + geo_traits::GeometryType::MultiPoint(multipoint) => Ok(multipoint.num_points() == 0), + geo_traits::GeometryType::MultiLineString(multilinestring) => { + Ok(multilinestring.num_line_strings() == 0) + } + geo_traits::GeometryType::MultiPolygon(multipolygon) => { + Ok(multipolygon.num_polygons() == 0) + } + geo_traits::GeometryType::GeometryCollection(geometrycollection) => { + Ok(geometrycollection.num_geometries() == 0) + } + _ => Err(SedonaGeometryError::Invalid( + "Invalid geometry type".to_string(), + )), + } +} + +#[cfg(test)] +mod tests { + use super::*; + use std::str::FromStr; + use wkb::reader::read_wkb; + use wkb::writer::write_geometry; + use wkt::Wkt; + + fn create_wkb_bytes_from_wkt(wkt_str: &str) -> Vec { + let wkt: Wkt = Wkt::from_str(wkt_str).unwrap(); + let mut wkb_bytes = vec![]; + write_geometry(&mut wkb_bytes, &wkt, wkb::Endianness::LittleEndian).unwrap(); + wkb_bytes + } + + #[test] + fn test_is_geometry_empty_points() { + // Empty point + let empty_point_bytes = create_wkb_bytes_from_wkt("POINT EMPTY"); + let empty_point = read_wkb(&empty_point_bytes).unwrap(); + assert!(is_geometry_empty(&empty_point).unwrap()); + + // Non-empty point + let point_bytes = create_wkb_bytes_from_wkt("POINT (1 2)"); + let point = read_wkb(&point_bytes).unwrap(); + assert!(!is_geometry_empty(&point).unwrap()); + } + + #[test] + fn test_is_geometry_empty_linestrings() { + // Empty linestring + let empty_linestring_bytes = create_wkb_bytes_from_wkt("LINESTRING EMPTY"); + let empty_linestring = read_wkb(&empty_linestring_bytes).unwrap(); + assert!(is_geometry_empty(&empty_linestring).unwrap()); + + // Non-empty linestring + let linestring_bytes = create_wkb_bytes_from_wkt("LINESTRING (1 2, 2 2)"); + let linestring = read_wkb(&linestring_bytes).unwrap(); + assert!(!is_geometry_empty(&linestring).unwrap()); + } + + #[test] + fn test_is_geometry_empty_polygons() { + // Empty polygon + let empty_polygon_bytes = create_wkb_bytes_from_wkt("POLYGON EMPTY"); + let empty_polygon = read_wkb(&empty_polygon_bytes).unwrap(); + assert!(is_geometry_empty(&empty_polygon).unwrap()); + + // Non-empty polygon + let polygon_bytes = create_wkb_bytes_from_wkt("POLYGON ((0 0, 1 0, 1 1, 0 1, 0 0))"); + let polygon = read_wkb(&polygon_bytes).unwrap(); + assert!(!is_geometry_empty(&polygon).unwrap()); + } + + #[test] + fn test_is_geometry_empty_multigeometries() { + // Empty multipoint + let empty_multipoint_bytes = create_wkb_bytes_from_wkt("MULTIPOINT EMPTY"); + let empty_multipoint = read_wkb(&empty_multipoint_bytes).unwrap(); + assert!(is_geometry_empty(&empty_multipoint).unwrap()); + + // Non-empty multipoint + let multipoint_bytes = create_wkb_bytes_from_wkt("MULTIPOINT ((0 0))"); + let multipoint = read_wkb(&multipoint_bytes).unwrap(); + assert!(!is_geometry_empty(&multipoint).unwrap()); + + // Empty multilinestring + let empty_multilinestring_bytes = create_wkb_bytes_from_wkt("MULTILINESTRING EMPTY"); + let empty_multilinestring = read_wkb(&empty_multilinestring_bytes).unwrap(); + assert!(is_geometry_empty(&empty_multilinestring).unwrap()); + + // Non-empty multilinestring + let multilinestring_bytes = + create_wkb_bytes_from_wkt("MULTILINESTRING ((0 0, 1 0), (1 1, 0 1))"); + let multilinestring = read_wkb(&multilinestring_bytes).unwrap(); + assert!(!is_geometry_empty(&multilinestring).unwrap()); + + // Empty multipolygon + let empty_multipolygon_bytes = create_wkb_bytes_from_wkt("MULTIPOLYGON EMPTY"); + let empty_multipolygon = read_wkb(&empty_multipolygon_bytes).unwrap(); + assert!(is_geometry_empty(&empty_multipolygon).unwrap()); + + // Non-empty multipolygon + let multipolygon_bytes = + create_wkb_bytes_from_wkt("MULTIPOLYGON (((0 0, 1 0, 1 1, 0 1, 0 0)))"); + let multipolygon = read_wkb(&multipolygon_bytes).unwrap(); + assert!(!is_geometry_empty(&multipolygon).unwrap()); + } + + #[test] + fn test_is_geometry_empty_collections() { + // Empty collection + let empty_collection_bytes = create_wkb_bytes_from_wkt("GEOMETRYCOLLECTION EMPTY"); + let empty_collection = read_wkb(&empty_collection_bytes).unwrap(); + assert!(is_geometry_empty(&empty_collection).unwrap()); + + // Non-empty collection + let collection_bytes = + create_wkb_bytes_from_wkt("GEOMETRYCOLLECTION (POINT (1 2), LINESTRING (1 2, 2 2))"); + let collection = read_wkb(&collection_bytes).unwrap(); + assert!(!is_geometry_empty(&collection).unwrap()); + } +} diff --git a/rust/sedona-geometry/src/lib.rs b/rust/sedona-geometry/src/lib.rs index 14fd09670..65cc5936a 100644 --- a/rust/sedona-geometry/src/lib.rs +++ b/rust/sedona-geometry/src/lib.rs @@ -19,6 +19,7 @@ pub mod bounding_box; pub mod bounds; pub mod error; pub mod interval; +pub mod is_empty; pub mod point_count; pub mod transform; pub mod types;