You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sedona.apache.org by im...@apache.org on 2025/12/15 22:32:46 UTC
(sedona-db) 01/01: add sedona deserialization code
This is an automated email from the ASF dual-hosted git repository.
imbruced pushed a commit to branch add-sedona-deserializer
in repository https://gitbox.apache.org/repos/asf/sedona-db.git
commit 9100359e29c2266b01217e47f22ec7d02345d512
Author: pawelkocinski <pa...@gmail.com>
AuthorDate: Mon Dec 15 23:24:37 2025 +0100
add sedona deserialization code
---
Cargo.lock | 288 +++++++++------
Cargo.toml | 1 +
rust/sedona-functions/Cargo.toml | 1 +
.../sedona-functions/src/fixtures/crs_point.sedona | 11 +
.../src/fixtures/empty_geometry_collection.sedona | 5 +
.../src/fixtures/empty_linestring.sedona | 5 +
.../src/fixtures/empty_multilinestring.sedona | 5 +
.../src/fixtures/empty_multipolygon.sedona | 5 +
.../src/fixtures/empty_point.sedona | 5 +
.../src/fixtures/empty_polygon.sedona | 5 +
.../src/fixtures/geometrycollection.sedona | 42 +++
.../src/fixtures/geometrycollectioncomplex.sedona | 52 +++
.../src/fixtures/linestring.sedona | 13 +
.../src/fixtures/multilinestring.sedona | 25 ++
.../src/fixtures/multipoint.sedona | 13 +
.../src/fixtures/multipoint_empty.sedona | 5 +
.../src/fixtures/multipolygon.sedona | 65 ++++
.../src/fixtures/nested_geometry_collection.sedona | 46 +++
rust/sedona-functions/src/fixtures/point.sedona | 11 +
.../src/fixtures/point_float_coords.sedona | 42 +++
rust/sedona-functions/src/fixtures/polygon.sedona | 41 +++
rust/sedona-functions/src/lib.rs | 1 +
rust/sedona-functions/src/register.rs | 1 +
rust/sedona-functions/src/st_from_sedona_spark.rs | 387 +++++++++++++++++++++
rust/{sedona-functions => sedona-serde}/Cargo.toml | 25 +-
rust/sedona-serde/src/deserialize.rs | 130 +++++++
rust/sedona-serde/src/lib.rs | 22 ++
rust/sedona-serde/src/linestring.rs | 98 ++++++
rust/sedona-serde/src/point.rs | 96 +++++
rust/sedona-serde/src/polygon.rs | 104 ++++++
rust/sedona-serde/src/wkb.rs | 24 ++
31 files changed, 1439 insertions(+), 135 deletions(-)
diff --git a/Cargo.lock b/Cargo.lock
index 23630f62..a1b060dc 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -56,8 +56,8 @@ version = "0.21.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a38cdcc3e43dc645038c2b6339dd98610c48ae593cc67839452e6670fa09f27"
dependencies = [
- "arrow-array",
- "arrow-schema",
+ "arrow-array 57.1.0",
+ "arrow-schema 57.1.0",
]
[[package]]
@@ -67,8 +67,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08d36274376fdc4849cf47a78f3baeef4ae1654ef703dc3148d91adde3336c11"
dependencies = [
"adbc_core",
- "arrow-array",
- "arrow-schema",
+ "arrow-array 57.1.0",
+ "arrow-schema 57.1.0",
]
[[package]]
@@ -267,16 +267,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fd798aea3553913a5986813e9c6ad31a2d2b04e931fe8ea4a37155eb541cebb5"
dependencies = [
"arrow-arith",
- "arrow-array",
- "arrow-buffer",
+ "arrow-array 56.2.0",
+ "arrow-buffer 56.2.0",
"arrow-cast",
"arrow-csv",
- "arrow-data",
+ "arrow-data 56.2.0",
"arrow-ipc",
"arrow-json",
"arrow-ord",
"arrow-row",
- "arrow-schema",
+ "arrow-schema 56.2.0",
"arrow-select",
"arrow-string",
]
@@ -287,52 +287,82 @@ version = "56.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "508dafb53e5804a238cab7fd97a59ddcbfab20cc4d9814b1ab5465b9fa147f2e"
dependencies = [
- "arrow-array",
- "arrow-buffer",
- "arrow-data",
- "arrow-schema",
+ "arrow-array 56.2.0",
+ "arrow-buffer 56.2.0",
+ "arrow-data 56.2.0",
+ "arrow-schema 56.2.0",
"chrono",
"num",
]
[[package]]
name = "arrow-array"
-version = "56.0.0"
+version = "56.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e2730bc045d62bb2e53ef8395b7d4242f5c8102f41ceac15e8395b9ac3d08461"
+checksum = "8548ca7c070d8db9ce7aa43f37393e4bfcf3f2d3681df278490772fd1673d08d"
dependencies = [
"ahash",
- "arrow-buffer",
- "arrow-data",
- "arrow-schema",
+ "arrow-buffer 56.2.0",
+ "arrow-data 56.2.0",
+ "arrow-schema 56.2.0",
"chrono",
"chrono-tz",
"half",
- "hashbrown 0.15.5",
+ "hashbrown 0.16.1",
"num",
]
+[[package]]
+name = "arrow-array"
+version = "57.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a23eaff85a44e9fa914660fb0d0bb00b79c4a3d888b5334adb3ea4330c84f002"
+dependencies = [
+ "ahash",
+ "arrow-buffer 57.1.0",
+ "arrow-data 57.1.0",
+ "arrow-schema 57.1.0",
+ "chrono",
+ "half",
+ "hashbrown 0.16.1",
+ "num-complex",
+ "num-integer",
+ "num-traits",
+]
+
[[package]]
name = "arrow-buffer"
-version = "56.0.0"
+version = "56.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "54295b93beb702ee9a6f6fbced08ad7f4d76ec1c297952d4b83cf68755421d1d"
+checksum = "e003216336f70446457e280807a73899dd822feaf02087d31febca1363e2fccc"
dependencies = [
"bytes",
"half",
"num",
]
+[[package]]
+name = "arrow-buffer"
+version = "57.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a2819d893750cb3380ab31ebdc8c68874dd4429f90fd09180f3c93538bd21626"
+dependencies = [
+ "bytes",
+ "half",
+ "num-bigint",
+ "num-traits",
+]
+
[[package]]
name = "arrow-cast"
version = "56.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "67e8bcb7dc971d779a7280593a1bf0c2743533b8028909073e804552e85e75b5"
dependencies = [
- "arrow-array",
- "arrow-buffer",
- "arrow-data",
- "arrow-schema",
+ "arrow-array 56.2.0",
+ "arrow-buffer 56.2.0",
+ "arrow-data 56.2.0",
+ "arrow-schema 56.2.0",
"arrow-select",
"atoi",
"base64",
@@ -350,9 +380,9 @@ version = "56.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "673fd2b5fb57a1754fdbfac425efd7cf54c947ac9950c1cce86b14e248f1c458"
dependencies = [
- "arrow-array",
+ "arrow-array 56.2.0",
"arrow-cast",
- "arrow-schema",
+ "arrow-schema 56.2.0",
"chrono",
"csv",
"csv-core",
@@ -361,26 +391,40 @@ dependencies = [
[[package]]
name = "arrow-data"
-version = "56.0.0"
+version = "56.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "97c22fe3da840039c69e9f61f81e78092ea36d57037b4900151f063615a2f6b4"
+checksum = "a5c64fff1d142f833d78897a772f2e5b55b36cb3e6320376f0961ab0db7bd6d0"
dependencies = [
- "arrow-buffer",
- "arrow-schema",
+ "arrow-buffer 56.2.0",
+ "arrow-schema 56.2.0",
"half",
"num",
]
+[[package]]
+name = "arrow-data"
+version = "57.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "05738f3d42cb922b9096f7786f606fcb8669260c2640df8490533bb2fa38c9d3"
+dependencies = [
+ "arrow-buffer 57.1.0",
+ "arrow-schema 57.1.0",
+ "half",
+ "num-integer",
+ "num-traits",
+]
+
[[package]]
name = "arrow-ipc"
-version = "56.0.0"
+version = "56.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "778de14c5a69aedb27359e3dd06dd5f9c481d5f6ee9fbae912dba332fd64636b"
+checksum = "1d3594dcddccc7f20fd069bc8e9828ce37220372680ff638c5e00dea427d88f5"
dependencies = [
- "arrow-array",
- "arrow-buffer",
- "arrow-data",
- "arrow-schema",
+ "arrow-array 56.2.0",
+ "arrow-buffer 56.2.0",
+ "arrow-data 56.2.0",
+ "arrow-schema 56.2.0",
+ "arrow-select",
"flatbuffers",
"lz4_flex",
"zstd",
@@ -392,11 +436,11 @@ version = "56.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3860db334fe7b19fcf81f6b56f8d9d95053f3839ffe443d56b5436f7a29a1794"
dependencies = [
- "arrow-array",
- "arrow-buffer",
+ "arrow-array 56.2.0",
+ "arrow-buffer 56.2.0",
"arrow-cast",
- "arrow-data",
- "arrow-schema",
+ "arrow-data 56.2.0",
+ "arrow-schema 56.2.0",
"chrono",
"half",
"indexmap",
@@ -414,10 +458,10 @@ version = "56.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "425fa0b42a39d3ff55160832e7c25553e7f012c3f187def3d70313e7a29ba5d9"
dependencies = [
- "arrow-array",
- "arrow-buffer",
- "arrow-data",
- "arrow-schema",
+ "arrow-array 56.2.0",
+ "arrow-buffer 56.2.0",
+ "arrow-data 56.2.0",
+ "arrow-schema 56.2.0",
"arrow-select",
]
@@ -427,35 +471,44 @@ version = "56.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "df9c9423c9e71abd1b08a7f788fcd203ba2698ac8e72a1f236f1faa1a06a7414"
dependencies = [
- "arrow-array",
- "arrow-buffer",
- "arrow-data",
- "arrow-schema",
+ "arrow-array 56.2.0",
+ "arrow-buffer 56.2.0",
+ "arrow-data 56.2.0",
+ "arrow-schema 56.2.0",
"half",
]
[[package]]
name = "arrow-schema"
-version = "56.0.0"
+version = "56.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "85fa1babc4a45fdc64a92175ef51ff00eba5ebbc0007962fecf8022ac1c6ce28"
+checksum = "b3aa9e59c611ebc291c28582077ef25c97f1975383f1479b12f3b9ffee2ffabe"
dependencies = [
"bitflags",
"serde",
"serde_json",
]
+[[package]]
+name = "arrow-schema"
+version = "57.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d27609cd7dd45f006abae27995c2729ef6f4b9361cde1ddd019dc31a5aa017e0"
+dependencies = [
+ "bitflags",
+]
+
[[package]]
name = "arrow-select"
-version = "56.0.0"
+version = "56.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d8854d15f1cf5005b4b358abeb60adea17091ff5bdd094dca5d3f73787d81170"
+checksum = "8c41dbbd1e97bfcaee4fcb30e29105fb2c75e4d82ae4de70b792a5d3f66b2e7a"
dependencies = [
"ahash",
- "arrow-array",
- "arrow-buffer",
- "arrow-data",
- "arrow-schema",
+ "arrow-array 56.2.0",
+ "arrow-buffer 56.2.0",
+ "arrow-data 56.2.0",
+ "arrow-schema 56.2.0",
"num",
]
@@ -465,10 +518,10 @@ version = "56.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2c477e8b89e1213d5927a2a84a72c384a9bf4dd0dbf15f9fd66d821aafd9e95e"
dependencies = [
- "arrow-array",
- "arrow-buffer",
- "arrow-data",
- "arrow-schema",
+ "arrow-array 56.2.0",
+ "arrow-buffer 56.2.0",
+ "arrow-data 56.2.0",
+ "arrow-schema 56.2.0",
"arrow-select",
"memchr",
"num",
@@ -1579,7 +1632,7 @@ checksum = "2af15bb3c6ffa33011ef579f6b0bcbe7c26584688bd6c994f548e44df67f011a"
dependencies = [
"arrow",
"arrow-ipc",
- "arrow-schema",
+ "arrow-schema 56.2.0",
"async-trait",
"bytes",
"bzip2 0.6.1",
@@ -1927,7 +1980,7 @@ checksum = "25ddb7c4e645df080c27dad13a198d191da328dd1c98e198664a7a0f64b335cc"
dependencies = [
"abi_stable",
"arrow",
- "arrow-schema",
+ "arrow-schema 56.2.0",
"async-ffi",
"async-trait",
"datafusion",
@@ -1948,7 +2001,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7de2782136bd6014670fd84fe3b0ca3b3e4106c96403c3ae05c0598577139977"
dependencies = [
"arrow",
- "arrow-buffer",
+ "arrow-buffer 56.2.0",
"base64",
"blake2",
"blake3",
@@ -2182,7 +2235,7 @@ dependencies = [
"ahash",
"arrow",
"arrow-ord",
- "arrow-schema",
+ "arrow-schema 56.2.0",
"async-trait",
"chrono",
"datafusion-common",
@@ -2238,7 +2291,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cd1e59e2ca14fe3c30f141600b10ad8815e2856caa59ebbd0e3e07cd3d127a65"
dependencies = [
"arrow",
- "arrow-schema",
+ "arrow-schema 56.2.0",
"datafusion-common",
"datafusion-datasource",
"datafusion-expr-common",
@@ -3863,12 +3916,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c7288a07ed5d25939a90f9cb1ca5afa6855faa08ec7700613511ae64bdb0620c"
dependencies = [
"ahash",
- "arrow-array",
- "arrow-buffer",
+ "arrow-array 56.2.0",
+ "arrow-buffer 56.2.0",
"arrow-cast",
- "arrow-data",
+ "arrow-data 56.2.0",
"arrow-ipc",
- "arrow-schema",
+ "arrow-schema 56.2.0",
"arrow-select",
"base64",
"brotli",
@@ -4762,8 +4815,8 @@ name = "sedona"
version = "0.3.0"
dependencies = [
"abi_stable",
- "arrow-array",
- "arrow-schema",
+ "arrow-array 56.2.0",
+ "arrow-schema 56.2.0",
"async-trait",
"aws-config",
"aws-credential-types",
@@ -4807,8 +4860,8 @@ version = "0.3.0"
dependencies = [
"adbc_core",
"adbc_ffi",
- "arrow-array",
- "arrow-schema",
+ "arrow-array 56.2.0",
+ "arrow-schema 56.2.0",
"datafusion",
"futures",
"sedona",
@@ -4847,8 +4900,8 @@ dependencies = [
name = "sedona-datasource"
version = "0.3.0"
dependencies = [
- "arrow-array",
- "arrow-schema",
+ "arrow-array 56.2.0",
+ "arrow-schema 56.2.0",
"async-trait",
"datafusion",
"datafusion-catalog",
@@ -4871,7 +4924,7 @@ dependencies = [
name = "sedona-expr"
version = "0.3.0"
dependencies = [
- "arrow-schema",
+ "arrow-schema 56.2.0",
"datafusion-common",
"datafusion-expr",
"datafusion-physical-expr",
@@ -4889,8 +4942,8 @@ dependencies = [
name = "sedona-extension"
version = "0.3.0"
dependencies = [
- "arrow-array",
- "arrow-schema",
+ "arrow-array 56.2.0",
+ "arrow-schema 56.2.0",
"datafusion-common",
"datafusion-expr",
"libc",
@@ -4904,9 +4957,9 @@ dependencies = [
name = "sedona-functions"
version = "0.3.0"
dependencies = [
- "arrow-array",
+ "arrow-array 56.2.0",
"arrow-json",
- "arrow-schema",
+ "arrow-schema 56.2.0",
"criterion",
"datafusion",
"datafusion-common",
@@ -4917,6 +4970,7 @@ dependencies = [
"sedona-expr",
"sedona-geometry",
"sedona-schema",
+ "sedona-serde",
"sedona-testing",
"serde_json",
"tokio",
@@ -4928,8 +4982,8 @@ dependencies = [
name = "sedona-geo"
version = "0.3.0"
dependencies = [
- "arrow-array",
- "arrow-schema",
+ "arrow-array 56.2.0",
+ "arrow-schema 56.2.0",
"criterion",
"datafusion-common",
"datafusion-expr",
@@ -4988,8 +5042,8 @@ dependencies = [
name = "sedona-geoarrow-c"
version = "0.3.0"
dependencies = [
- "arrow-array",
- "arrow-schema",
+ "arrow-array 56.2.0",
+ "arrow-schema 56.2.0",
"cc",
"criterion",
"datafusion-common",
@@ -5025,8 +5079,8 @@ dependencies = [
name = "sedona-geoparquet"
version = "0.3.0"
dependencies = [
- "arrow-array",
- "arrow-schema",
+ "arrow-array 56.2.0",
+ "arrow-schema 56.2.0",
"async-trait",
"bytes",
"chrono",
@@ -5062,8 +5116,8 @@ dependencies = [
name = "sedona-geos"
version = "0.3.0"
dependencies = [
- "arrow-array",
- "arrow-schema",
+ "arrow-array 56.2.0",
+ "arrow-schema 56.2.0",
"byteorder",
"criterion",
"datafusion-common",
@@ -5086,8 +5140,8 @@ dependencies = [
name = "sedona-libgpuspatial"
version = "0.3.0"
dependencies = [
- "arrow-array",
- "arrow-schema",
+ "arrow-array 56.2.0",
+ "arrow-schema 56.2.0",
"bindgen",
"cmake",
"log",
@@ -5104,8 +5158,8 @@ name = "sedona-proj"
version = "0.3.0"
dependencies = [
"approx",
- "arrow-array",
- "arrow-schema",
+ "arrow-array 56.2.0",
+ "arrow-schema 56.2.0",
"cc",
"criterion",
"datafusion-common",
@@ -5129,9 +5183,9 @@ name = "sedona-raster"
version = "0.3.0"
dependencies = [
"approx",
- "arrow-array",
- "arrow-buffer",
- "arrow-schema",
+ "arrow-array 56.2.0",
+ "arrow-buffer 56.2.0",
+ "arrow-schema 56.2.0",
"sedona-common",
"sedona-schema",
"sedona-testing",
@@ -5141,9 +5195,9 @@ dependencies = [
name = "sedona-raster-functions"
version = "0.3.0"
dependencies = [
- "arrow-array",
- "arrow-buffer",
- "arrow-schema",
+ "arrow-array 56.2.0",
+ "arrow-buffer 56.2.0",
+ "arrow-schema 56.2.0",
"criterion",
"datafusion-common",
"datafusion-expr",
@@ -5160,8 +5214,8 @@ dependencies = [
name = "sedona-s2geography"
version = "0.3.0"
dependencies = [
- "arrow-array",
- "arrow-schema",
+ "arrow-array 56.2.0",
+ "arrow-schema 56.2.0",
"cmake",
"criterion",
"datafusion-common",
@@ -5182,20 +5236,30 @@ dependencies = [
name = "sedona-schema"
version = "0.3.0"
dependencies = [
- "arrow-array",
- "arrow-schema",
+ "arrow-array 56.2.0",
+ "arrow-schema 56.2.0",
"datafusion-common",
"sedona-common",
"serde_json",
]
+[[package]]
+name = "sedona-serde"
+version = "0.3.0"
+dependencies = [
+ "arrow-array 56.2.0",
+ "byteorder",
+ "datafusion-common",
+ "wkt 0.14.0",
+]
+
[[package]]
name = "sedona-spatial-join"
version = "0.3.0"
dependencies = [
"arrow",
- "arrow-array",
- "arrow-schema",
+ "arrow-array 56.2.0",
+ "arrow-schema 56.2.0",
"criterion",
"datafusion",
"datafusion-common",
@@ -5235,9 +5299,9 @@ dependencies = [
name = "sedona-testing"
version = "0.3.0"
dependencies = [
- "arrow-array",
+ "arrow-array 56.2.0",
"arrow-cast",
- "arrow-schema",
+ "arrow-schema 56.2.0",
"criterion",
"datafusion-common",
"datafusion-expr",
@@ -5262,8 +5326,8 @@ dependencies = [
name = "sedona-tg"
version = "0.3.0"
dependencies = [
- "arrow-array",
- "arrow-schema",
+ "arrow-array 56.2.0",
+ "arrow-schema 56.2.0",
"cc",
"criterion",
"datafusion-common",
@@ -5284,8 +5348,8 @@ name = "sedonadb"
version = "0.3.0"
dependencies = [
"adbc_core",
- "arrow-array",
- "arrow-schema",
+ "arrow-array 56.2.0",
+ "arrow-schema 56.2.0",
"async-trait",
"datafusion",
"datafusion-common",
@@ -5312,8 +5376,8 @@ dependencies = [
name = "sedonadbr"
version = "0.3.0"
dependencies = [
- "arrow-array",
- "arrow-schema",
+ "arrow-array 56.2.0",
+ "arrow-schema 56.2.0",
"datafusion",
"datafusion-common",
"datafusion-expr",
diff --git a/Cargo.toml b/Cargo.toml
index 9780fbe1..def576c1 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -39,6 +39,7 @@ members = [
"rust/sedona-schema",
"rust/sedona-spatial-join",
"rust/sedona-testing",
+ "rust/sedona-serde",
"rust/sedona",
"sedona-cli",
]
diff --git a/rust/sedona-functions/Cargo.toml b/rust/sedona-functions/Cargo.toml
index 57afd240..393aaf5a 100644
--- a/rust/sedona-functions/Cargo.toml
+++ b/rust/sedona-functions/Cargo.toml
@@ -48,6 +48,7 @@ sedona-common = { workspace = true }
sedona-expr = { workspace = true }
sedona-geometry = { workspace = true }
sedona-schema = { workspace = true }
+sedona-serde = { path = "../sedona-serde" }
wkb = { workspace = true }
wkt = { workspace = true }
serde_json = { workspace = true }
diff --git a/rust/sedona-functions/src/fixtures/crs_point.sedona b/rust/sedona-functions/src/fixtures/crs_point.sedona
new file mode 100644
index 00000000..e534b3a2
--- /dev/null
+++ b/rust/sedona-functions/src/fixtures/crs_point.sedona
@@ -0,0 +1,11 @@
+// Point XY with CRS EPSG:4326
+19
+
+// CRS EPSG:4326
+0 16 230
+
+// number of coordinates
+1 0 0 0
+
+// coordinates (2 doubles per coordinate)
+0 0 0 0 0 0 240 63 0 0 0 0 0 0 240 63
\ No newline at end of file
diff --git a/rust/sedona-functions/src/fixtures/empty_geometry_collection.sedona b/rust/sedona-functions/src/fixtures/empty_geometry_collection.sedona
new file mode 100644
index 00000000..39dca86b
--- /dev/null
+++ b/rust/sedona-functions/src/fixtures/empty_geometry_collection.sedona
@@ -0,0 +1,5 @@
+114
+
+0 0 0
+
+0 0 0 0
\ No newline at end of file
diff --git a/rust/sedona-functions/src/fixtures/empty_linestring.sedona b/rust/sedona-functions/src/fixtures/empty_linestring.sedona
new file mode 100644
index 00000000..68e7aed8
--- /dev/null
+++ b/rust/sedona-functions/src/fixtures/empty_linestring.sedona
@@ -0,0 +1,5 @@
+34
+
+0 0 0
+
+0 0 0 0
\ No newline at end of file
diff --git a/rust/sedona-functions/src/fixtures/empty_multilinestring.sedona b/rust/sedona-functions/src/fixtures/empty_multilinestring.sedona
new file mode 100644
index 00000000..085f9d52
--- /dev/null
+++ b/rust/sedona-functions/src/fixtures/empty_multilinestring.sedona
@@ -0,0 +1,5 @@
+82
+
+0 0 0
+
+0 0 0 0 0 0 0 0
\ No newline at end of file
diff --git a/rust/sedona-functions/src/fixtures/empty_multipolygon.sedona b/rust/sedona-functions/src/fixtures/empty_multipolygon.sedona
new file mode 100644
index 00000000..559c5a3d
--- /dev/null
+++ b/rust/sedona-functions/src/fixtures/empty_multipolygon.sedona
@@ -0,0 +1,5 @@
+98
+
+0 0 0
+
+0 0 0 0 0 0 0 0
\ No newline at end of file
diff --git a/rust/sedona-functions/src/fixtures/empty_point.sedona b/rust/sedona-functions/src/fixtures/empty_point.sedona
new file mode 100644
index 00000000..5ab2f596
--- /dev/null
+++ b/rust/sedona-functions/src/fixtures/empty_point.sedona
@@ -0,0 +1,5 @@
+18
+
+0 0 0
+
+0 0 0 0
\ No newline at end of file
diff --git a/rust/sedona-functions/src/fixtures/empty_polygon.sedona b/rust/sedona-functions/src/fixtures/empty_polygon.sedona
new file mode 100644
index 00000000..3acc9bc3
--- /dev/null
+++ b/rust/sedona-functions/src/fixtures/empty_polygon.sedona
@@ -0,0 +1,5 @@
+50
+
+0 0 0
+
+0 0 0 0
\ No newline at end of file
diff --git a/rust/sedona-functions/src/fixtures/geometrycollection.sedona b/rust/sedona-functions/src/fixtures/geometrycollection.sedona
new file mode 100644
index 00000000..3918cbaf
--- /dev/null
+++ b/rust/sedona-functions/src/fixtures/geometrycollection.sedona
@@ -0,0 +1,42 @@
+// metadata GeometryCollection XY NO SRID
+114
+
+// missing srid information
+0 0 0
+
+// number of geometries
+3 0 0 0
+
+// point geometry
+18
+
+0 0 0
+
+1 0 0 0
+
+0 0 0 0 0 0 16 64 0 0 0 0 0 0 24 64
+
+// linestring geometry
+34
+
+0 0 0
+
+2 0 0 0
+
+0 0 0 0 0 0 16 64 0 0 0 0 0 0 24 64
+0 0 0 0 0 0 28 64 0 0 0 0 0 0 36 64
+
+// polygon geometry
+50
+
+0 0 0
+
+4 0 0 0
+
+0 0 0 0 0 0 16 64 0 0 0 0 0 0 24 64
+0 0 0 0 0 0 28 64 0 0 0 0 0 0 36 64
+0 0 0 0 0 0 16 64 0 0 0 0 0 0 36 64
+0 0 0 0 0 0 16 64 0 0 0 0 0 0 24 64
+
+1 0 0 0
+4 0 0 0
\ No newline at end of file
diff --git a/rust/sedona-functions/src/fixtures/geometrycollectioncomplex.sedona b/rust/sedona-functions/src/fixtures/geometrycollectioncomplex.sedona
new file mode 100644
index 00000000..6dfb04c8
--- /dev/null
+++ b/rust/sedona-functions/src/fixtures/geometrycollectioncomplex.sedona
@@ -0,0 +1,52 @@
+// // metadata GeometryCollection XY NO SRID
+114
+
+// missing srid information
+0 0 0
+
+// number of geometries
+4 0 0 0
+
+// point geometry
+18
+
+0 0 0
+
+1 0 0 0
+
+0 0 0 0 0 0 16 64 0 0 0 0 0 0 24 64
+
+// linestring geometry
+34
+
+0 0 0
+
+2 0 0 0
+
+0 0 0 0 0 0 16 64 0 0 0 0 0 0 24 64
+0 0 0 0 0 0 28 64 0 0 0 0 0 0 36 64
+
+// polygon geometry
+50
+
+0 0 0
+
+4 0 0 0
+
+0 0 0 0 0 0 16 64 0 0 0 0 0 0 24 64
+0 0 0 0 0 0 28 64 0 0 0 0 0 0 36 64
+0 0 0 0 0 0 16 64 0 0 0 0 0 0 36 64
+0 0 0 0 0 0 16 64 0 0 0 0 0 0 24 64
+
+1 0 0 0
+4 0 0 0
+
+// multipoint geometry
+66
+
+0 0 0
+
+2 0 0 0
+
+0 0 0 0 0 0 240 63 0 0 0 0 0 0 0 64
+0 0 0 0 0 0 8 64 0 0 0 0 0 0 16 64
\ No newline at end of file
diff --git a/rust/sedona-functions/src/fixtures/linestring.sedona b/rust/sedona-functions/src/fixtures/linestring.sedona
new file mode 100644
index 00000000..02e1ba01
--- /dev/null
+++ b/rust/sedona-functions/src/fixtures/linestring.sedona
@@ -0,0 +1,13 @@
+// metadata LINESTRING XY NO SRID
+34
+
+// missing srid information
+0 0 0
+
+// number of coordinates
+3 0 0 0
+
+// coordinates (2 doubles per coordinate)
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 240 63 0 0 0 0 0 0 240 63
+0 0 0 0 0 0 0 64 0 0 0 0 0 0 0 64
\ No newline at end of file
diff --git a/rust/sedona-functions/src/fixtures/multilinestring.sedona b/rust/sedona-functions/src/fixtures/multilinestring.sedona
new file mode 100644
index 00000000..22466c88
--- /dev/null
+++ b/rust/sedona-functions/src/fixtures/multilinestring.sedona
@@ -0,0 +1,25 @@
+// metadata MultiLinestring XY NO SRID
+82
+
+// missing srid information
+0 0 0
+
+// number of points
+4 0 0 0
+
+// coordinates linestring 1
+0 0 0 0 0 0 240 63 0 0 0 0 0 0 240 63
+0 0 0 0 0 0 0 64 0 0 0 0 0 0 0 64
+
+// coordinates linestring 2
+0 0 0 0 0 0 16 64 0 0 0 0 0 0 20 64
+0 0 0 0 0 0 24 64 0 0 0 0 0 0 28 64
+
+// number of linestrings
+2 0 0 0
+
+// linestring 1 has 2 points
+2 0 0 0
+
+// linestring 2 has 2 points
+2 0 0 0
\ No newline at end of file
diff --git a/rust/sedona-functions/src/fixtures/multipoint.sedona b/rust/sedona-functions/src/fixtures/multipoint.sedona
new file mode 100644
index 00000000..256068cb
--- /dev/null
+++ b/rust/sedona-functions/src/fixtures/multipoint.sedona
@@ -0,0 +1,13 @@
+// metadata Multipoint XY NO SRID
+66
+
+// missing srid information
+0 0 0
+
+// number of points
+3 0 0 0
+
+// coordinates (2 doubles per point)
+0 0 0 0 0 0 240 63 0 0 0 0 0 0 240 63
+0 0 0 0 0 0 0 64 0 0 0 0 0 0 0 64
+0 0 0 0 0 0 16 64 0 0 0 0 0 0 20 64
\ No newline at end of file
diff --git a/rust/sedona-functions/src/fixtures/multipoint_empty.sedona b/rust/sedona-functions/src/fixtures/multipoint_empty.sedona
new file mode 100644
index 00000000..f11bc982
--- /dev/null
+++ b/rust/sedona-functions/src/fixtures/multipoint_empty.sedona
@@ -0,0 +1,5 @@
+66
+
+0 0 0
+
+0 0 0 0
\ No newline at end of file
diff --git a/rust/sedona-functions/src/fixtures/multipolygon.sedona b/rust/sedona-functions/src/fixtures/multipolygon.sedona
new file mode 100644
index 00000000..562aa70c
--- /dev/null
+++ b/rust/sedona-functions/src/fixtures/multipolygon.sedona
@@ -0,0 +1,65 @@
+// metadata Multipolygon XY NO SRID
+98
+
+// missing srid information
+0 0 0
+
+// number of points
+30 0 0 0
+
+// polygon 1 coordinates
+0 0 0 0 0 0 240 63 0 0 0 0 0 0 240 63
+0 0 0 0 0 0 36 64 0 0 0 0 0 0 240 63
+0 0 0 0 0 0 36 64 0 0 0 0 0 0 36 64
+0 0 0 0 0 0 240 63 0 0 0 0 0 0 36 64
+0 0 0 0 0 0 240 63 0 0 0 0 0 0 240 63
+
+0 0 0 0 0 0 0 64 0 0 0 0 0 0 0 64
+0 0 0 0 0 0 16 64 0 0 0 0 0 0 0 64
+0 0 0 0 0 0 16 64 0 0 0 0 0 0 16 64
+0 0 0 0 0 0 0 64 0 0 0 0 0 0 16 64
+0 0 0 0 0 0 0 64 0 0 0 0 0 0 0 64
+
+0 0 0 0 0 0 24 64 0 0 0 0 0 0 24 64
+0 0 0 0 0 0 32 64 0 0 0 0 0 0 24 64
+0 0 0 0 0 0 32 64 0 0 0 0 0 0 32 64
+0 0 0 0 0 0 24 64 0 0 0 0 0 0 32 64
+0 0 0 0 0 0 24 64 0 0 0 0 0 0 24 64
+
+// polygon 2 coordinates
+0 0 0 0 0 0 40 64 0 0 0 0 0 0 240 63
+0 0 0 0 0 0 52 64 0 0 0 0 0 0 240 63
+0 0 0 0 0 0 52 64 0 0 0 0 0 0 34 64
+0 0 0 0 0 0 40 64 0 0 0 0 0 0 34 64
+0 0 0 0 0 0 40 64 0 0 0 0 0 0 240 63
+
+0 0 0 0 0 0 42 64 0 0 0 0 0 0 0 64
+0 0 0 0 0 0 46 64 0 0 0 0 0 0 0 64
+0 0 0 0 0 0 46 64 0 0 0 0 0 0 16 64
+0 0 0 0 0 0 42 64 0 0 0 0 0 0 16 64
+0 0 0 0 0 0 42 64 0 0 0 0 0 0 0 64
+
+0 0 0 0 0 0 49 64 0 0 0 0 0 0 20 64
+0 0 0 0 0 0 51 64 0 0 0 0 0 0 20 64
+0 0 0 0 0 0 51 64 0 0 0 0 0 0 28 64
+0 0 0 0 0 0 49 64 0 0 0 0 0 0 28 64
+0 0 0 0 0 0 49 64 0 0 0 0 0 0 20 64
+
+// number of polygons
+2 0 0 0
+
+// number of polygon 1 components
+3 0 0 0
+
+// number of points in polygon 1 components
+5 0 0 0
+5 0 0 0
+5 0 0 0
+
+// number of polygon 2 components
+3 0 0 0
+
+// number of points in polygon 2 components
+5 0 0 0
+5 0 0 0
+5 0 0 0
\ No newline at end of file
diff --git a/rust/sedona-functions/src/fixtures/nested_geometry_collection.sedona b/rust/sedona-functions/src/fixtures/nested_geometry_collection.sedona
new file mode 100644
index 00000000..1bb0f57d
--- /dev/null
+++ b/rust/sedona-functions/src/fixtures/nested_geometry_collection.sedona
@@ -0,0 +1,46 @@
+// metadata GeometryCollection XY NO SRID
+114
+
+0 0 0
+
+2 0 0 0
+
+// point geometry
+18
+
+0 0 0
+
+1 0 0 0
+
+0 0 0 0 0 0 240 63 0 0 0 0 0 0 240 63
+
+// geometry collection geometry
+114 0 0 0
+
+2 0 0 0
+
+// linestring geometry
+34
+
+0 0 0
+
+2 0 0 0
+
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 240 63 0 0 0 0 0 0 240 63
+
+// polygon geometry
+50
+
+0 0 0
+
+5 0 0 0
+
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 64 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 64 0 0 0 0 0 0 0 64
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 64
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+
+1 0 0 0
+5 0 0 0
\ No newline at end of file
diff --git a/rust/sedona-functions/src/fixtures/point.sedona b/rust/sedona-functions/src/fixtures/point.sedona
new file mode 100644
index 00000000..94e872a1
--- /dev/null
+++ b/rust/sedona-functions/src/fixtures/point.sedona
@@ -0,0 +1,11 @@
+// metadata POINT XY NO SRID
+18
+
+// srid information
+0 0 0
+
+// number of coordinates
+1 0 0 0
+
+// coordinates (2 doubles per coordinate)
+0 0 0 0 0 0 240 63 0 0 0 0 0 0 240 63
\ No newline at end of file
diff --git a/rust/sedona-functions/src/fixtures/point_float_coords.sedona b/rust/sedona-functions/src/fixtures/point_float_coords.sedona
new file mode 100644
index 00000000..a75f94d0
--- /dev/null
+++ b/rust/sedona-functions/src/fixtures/point_float_coords.sedona
@@ -0,0 +1,42 @@
+50
+
+0 0 0
+
+11 0 0 0
+
+59 111 47 211 252 176 40 64
+243 214 83 60 230 214 70 64
+
+164 49 237 31 240 116 55 64
+235 19 96 200 247 248 80 64
+
+131 251 161 159 176 72 65 64
+228 105 70 91 254 100 76 64
+
+243 214 83 60 230 214 70 64
+131 251 161 159 176 72 65 64
+
+81 184 200 34 101 224 61 64
+157 183 151 105 126 88 54 64
+
+59 111 47 211 252 176 40 64
+243 214 83 60 230 214 70 64
+
+149 70 55 221 154 31 57 64
+59 111 240 116 107 254 70 64
+
+118 222 224 233 214 252 62 64
+75 163 155 110 205 15 73 64
+
+210 152 246 15 120 186 65 64
+210 152 246 15 120 186 70 64
+
+31 197 40 164 12 60 62 64
+59 111 240 116 107 126 68 64
+
+149 70 55 221 154 31 57 64
+59 111 240 116 107 254 70 64
+
+2 0 0 0
+6 0 0 0
+5 0 0 0
diff --git a/rust/sedona-functions/src/fixtures/polygon.sedona b/rust/sedona-functions/src/fixtures/polygon.sedona
new file mode 100644
index 00000000..7a2ab605
--- /dev/null
+++ b/rust/sedona-functions/src/fixtures/polygon.sedona
@@ -0,0 +1,41 @@
+// metadata Polygon XY NO SRID
+50
+
+// no srid
+0 0 0
+
+// number of points
+15 0 0 0
+
+// polygon 1 ring 1
+0 0 0 0 0 0 240 63 0 0 0 0 0 0 240 63
+0 0 0 0 0 0 36 64 0 0 0 0 0 0 240 63
+0 0 0 0 0 0 36 64 0 0 0 0 0 0 36 64
+0 0 0 0 0 0 240 63 0 0 0 0 0 0 36 64
+0 0 0 0 0 0 240 63 0 0 0 0 0 0 240 63
+
+// hole 1 ring 1
+0 0 0 0 0 0 0 64 0 0 0 0 0 0 0 64
+0 0 0 0 0 0 16 64 0 0 0 0 0 0 0 64
+0 0 0 0 0 0 16 64 0 0 0 0 0 0 16 64
+0 0 0 0 0 0 0 64 0 0 0 0 0 0 16 64
+0 0 0 0 0 0 0 64 0 0 0 0 0 0 0 64
+
+// hole 2 ring 1
+0 0 0 0 0 0 24 64 0 0 0 0 0 0 24 64
+0 0 0 0 0 0 32 64 0 0 0 0 0 0 24 64
+0 0 0 0 0 0 32 64 0 0 0 0 0 0 32 64
+0 0 0 0 0 0 24 64 0 0 0 0 0 0 32 64
+0 0 0 0 0 0 24 64 0 0 0 0 0 0 24 64
+
+// number of rings
+3 0 0 0
+
+// number of points internal 1
+5 0 0 0
+
+// number of points hole 1
+5 0 0 0
+
+// number of points hole 2
+5 0 0 0
\ No newline at end of file
diff --git a/rust/sedona-functions/src/lib.rs b/rust/sedona-functions/src/lib.rs
index 44c8ad02..9eec6398 100644
--- a/rust/sedona-functions/src/lib.rs
+++ b/rust/sedona-functions/src/lib.rs
@@ -67,3 +67,4 @@ pub mod st_union_agg;
mod st_xyzm;
mod st_xyzm_minmax;
mod st_zmflag;
+mod st_from_sedona_spark;
diff --git a/rust/sedona-functions/src/register.rs b/rust/sedona-functions/src/register.rs
index ff439578..e9bc4a14 100644
--- a/rust/sedona-functions/src/register.rs
+++ b/rust/sedona-functions/src/register.rs
@@ -120,6 +120,7 @@ pub fn default_function_set() -> FunctionSet {
crate::st_xyzm::st_y_udf,
crate::st_xyzm::st_z_udf,
crate::st_zmflag::st_zmflag_udf,
+ crate::st_from_sedona_spark::st_geomfromsedona_udf,
);
register_aggregate_udfs!(
diff --git a/rust/sedona-functions/src/st_from_sedona_spark.rs b/rust/sedona-functions/src/st_from_sedona_spark.rs
new file mode 100644
index 00000000..b96b4bb7
--- /dev/null
+++ b/rust/sedona-functions/src/st_from_sedona_spark.rs
@@ -0,0 +1,387 @@
+use crate::executor::WkbExecutor;
+use arrow_array::builder::BinaryBuilder;
+use arrow_schema::DataType;
+use datafusion_common::cast::as_binary_array;
+use datafusion_common::ScalarValue;
+use datafusion_expr::scalar_doc_sections::DOC_SECTION_OTHER;
+use datafusion_expr::{ColumnarValue, Documentation, Volatility};
+use sedona_expr::scalar_udf::{SedonaScalarKernel, SedonaScalarUDF};
+use sedona_geometry::wkb_factory::WKB_MIN_PROBABLE_BYTES;
+use sedona_schema::crs::{deserialize_crs, Crs};
+use sedona_schema::datatypes::{Edges, SedonaType, WKB_GEOGRAPHY, WKB_GEOMETRY};
+use sedona_schema::matchers::ArgMatcher;
+use sedona_serde::deserialize::deserialize;
+use std::any::Any;
+use std::io::{Read, Seek};
+use std::sync::Arc;
+
+fn to_crs_str(scalar_arg: &ScalarValue) -> Option<String> {
+ if let Ok(ScalarValue::Utf8(Some(crs))) = scalar_arg.cast_to(&DataType::Utf8) {
+ if crs.chars().all(|c| c.is_ascii_digit()) {
+ return Some(format!("EPSG:{crs}"));
+ } else {
+ return Some(crs);
+ }
+ }
+
+ None
+}
+
+#[derive(Debug)]
+struct STGeomFromSedona {
+ out_type: SedonaType,
+}
+
+pub fn st_geomfromsedona_udf() -> SedonaScalarUDF {
+ let kernel = Arc::new(STGeomFromSedona {
+ out_type: WKB_GEOMETRY,
+ });
+
+ SedonaScalarUDF::new(
+ "st_geomfromsedona",
+ vec![kernel],
+ Volatility::Immutable,
+ None,
+ )
+}
+
+impl SedonaScalarKernel for STGeomFromSedona {
+ fn return_type(&self, args: &[SedonaType]) -> datafusion_common::Result<Option<SedonaType>> {
+ let matcher = ArgMatcher::new(
+ vec![ArgMatcher::is_binary(), ArgMatcher::is_string()],
+ self.out_type.clone(),
+ );
+
+ matcher.match_args(args)
+ }
+
+ fn return_type_from_args_and_scalars(
+ &self,
+ args: &[SedonaType],
+ _scalar_args: &[Option<&ScalarValue>],
+ ) -> datafusion_common::Result<Option<SedonaType>> {
+ let matcher = ArgMatcher::new(
+ vec![ArgMatcher::is_geometry(), ArgMatcher::is_string()],
+ self.out_type.clone(),
+ );
+
+ if !matcher.matches(args) {
+ return Ok(None);
+ }
+
+ let crs_scalar = _scalar_args.get(1).unwrap();
+
+ let crs_str_opt = if let Some(scalar_crs) = crs_scalar {
+ to_crs_str(scalar_crs)
+ } else {
+ None
+ };
+
+ match crs_str_opt {
+ Some(to_crs) => {
+ let val = serde_json::Value::String(to_crs.to_string());
+ let crs = deserialize_crs(&val)?;
+ Ok(Some(SedonaType::Wkb(Edges::Planar, crs)))
+ }
+ _ => Ok(Some(SedonaType::Wkb(Edges::Planar, None))),
+ }
+ }
+
+ fn invoke_batch(
+ &self,
+ arg_types: &[SedonaType],
+ args: &[ColumnarValue],
+ ) -> datafusion_common::Result<ColumnarValue> {
+ let executor = WkbExecutor::new(arg_types, args);
+ let arg_array = args[0]
+ .cast_to(&DataType::Binary, None)?
+ .to_array(executor.num_iterations())?;
+
+ let mut builder = BinaryBuilder::with_capacity(
+ executor.num_iterations(),
+ WKB_MIN_PROBABLE_BYTES * executor.num_iterations(),
+ );
+
+ for item in as_binary_array(&arg_array)? {
+ if let Some(sedona_bytes) = item {
+ deserialize(&mut builder, sedona_bytes)?;
+ builder.append_value(vec![]);
+ }
+ }
+
+ let new_array = builder.finish();
+ executor.finish(Arc::new(new_array))
+ }
+}
+
+fn doc(name: &str, out_type_name: &str) -> Documentation {
+ Documentation::builder(
+ DOC_SECTION_OTHER,
+ format!("Construct a {out_type_name} from Sedona internal geometry representation."),
+ format!("{name} (geom: Binary)"),
+ )
+ .with_argument(
+ "geom",
+ format!(
+ "Binary: Sedona representation of the {}",
+ out_type_name.to_lowercase()
+ ),
+ )
+ .with_sql_example(format!("SELECT {name}('SedonaBinary')"))
+ .with_related_udf("ST_FromSedona")
+ .build()
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+ use sedona_testing::testers::ScalarUdfTester;
+
+ fn get_tester() -> ScalarUdfTester {
+ ScalarUdfTester::new(
+ st_geomfromsedona_udf().into(),
+ vec![
+ SedonaType::Wkb(Edges::Planar, Crs::None),
+ SedonaType::Arrow(DataType::Utf8),
+ ],
+ )
+ }
+
+ fn fixture_to_bytes(wkb: &str) -> Vec<u8> {
+ wkb.split("\n")
+ .filter(|line| !line.starts_with("//") && !line.is_empty())
+ .flat_map(|s| s.split_whitespace())
+ .map(|num| num.parse::<u8>().expect("invalid byte"))
+ .collect::<Vec<u8>>()
+ }
+
+ #[test]
+ fn test_st_from_sedona_spark_point_1() {
+ let binary_geometry = fixture_to_bytes(include_str!("fixtures/point.sedona"));
+ let tester = get_tester();
+
+ let result = tester
+ .invoke_scalar_scalar(binary_geometry, ScalarValue::Utf8(Some("4326".to_string())))
+ .unwrap();
+
+ tester.assert_scalar_result_equals(result, "POINT (1 1)");
+ }
+
+ #[test]
+ fn test_st_from_sedona_spark_linestring_1() {
+ let binary_geometry = fixture_to_bytes(include_str!("fixtures/linestring.sedona"));
+ let tester = get_tester();
+
+ let result = tester
+ .invoke_scalar_scalar(binary_geometry, ScalarValue::Utf8(Some("4326".to_string())))
+ .unwrap();
+
+ tester.assert_scalar_result_equals(result, "LINESTRING (0 0, 1 1, 2 2)");
+ }
+
+ #[test]
+ fn test_multipoint_geometry() {
+ let binary_geometry = fixture_to_bytes(include_str!("fixtures/multipoint.sedona"));
+ let tester = get_tester();
+
+ let result = tester
+ .invoke_scalar_scalar(binary_geometry, ScalarValue::Utf8(Some("4326".to_string())))
+ .unwrap();
+
+ tester.assert_scalar_result_equals(result, "MULTIPOINT((1 1), (2 2), (4 5))");
+ }
+
+ #[test]
+ fn test_multilinestring_geometry() {
+ let binary_geometry = fixture_to_bytes(include_str!("fixtures/multilinestring.sedona"));
+ let tester = get_tester();
+
+ let result = tester
+ .invoke_scalar_scalar(binary_geometry, ScalarValue::Utf8(Some("4326".to_string())))
+ .unwrap();
+
+ tester.assert_scalar_result_equals(result, "MULTILINESTRING((1 1, 2 2), (4 5, 6 7))");
+ }
+
+ #[test]
+ fn test_polygon_geometry() {
+ let binary_geometry = fixture_to_bytes(include_str!("fixtures/polygon.sedona"));
+ let tester = get_tester();
+
+ let result = tester
+ .invoke_scalar_scalar(binary_geometry, ScalarValue::Utf8(Some("4326".to_string())))
+ .unwrap();
+
+ tester.assert_scalar_result_equals(
+ result,
+ "
+ POLYGON (
+ (1 1, 10 1, 10 10, 1 10, 1 1),
+ (2 2, 4 2, 4 4, 2 4, 2 2),
+ (6 6, 8 6, 8 8, 6 8, 6 6)
+ )",
+ );
+ }
+
+ #[test]
+ fn test_multipolygon_geometry() {
+ let binary_geometry = fixture_to_bytes(include_str!("fixtures/multipolygon.sedona"));
+ let tester = get_tester();
+
+ let result = tester
+ .invoke_scalar_scalar(binary_geometry, ScalarValue::Utf8(Some("4326".to_string())))
+ .unwrap();
+
+ tester.assert_scalar_result_equals(
+ result,
+ "MULTIPOLYGON (
+ (
+ (1 1, 10 1, 10 10, 1 10, 1 1),
+ (2 2, 4 2, 4 4, 2 4, 2 2),
+ (6 6, 8 6, 8 8, 6 8, 6 6)
+ ),
+ (
+ (12 1, 20 1, 20 9, 12 9, 12 1),
+ (13 2, 15 2, 15 4, 13 4, 13 2),
+ (17 5, 19 5, 19 7, 17 7, 17 5)
+ )
+ )",
+ );
+ }
+
+ #[test]
+ fn test_geometrycollection_geometry() {
+ let binary_geometry = fixture_to_bytes(include_str!("fixtures/geometrycollection.sedona"));
+ let tester = get_tester();
+
+ let result = tester
+ .invoke_scalar_scalar(binary_geometry, ScalarValue::Utf8(Some("4326".to_string())))
+ .unwrap();
+
+ tester.assert_scalar_result_equals(
+ result,
+ "GEOMETRYCOLLECTION(
+ POINT(4 6),
+ LINESTRING(4 6,7 10),
+ POLYGON((4 6,7 10,4 10,4 6))
+ )",
+ );
+ }
+
+ #[test]
+ fn test_complex_geometry_collection() {
+ let binary_geometry =
+ fixture_to_bytes(include_str!("fixtures/geometrycollectioncomplex.sedona"));
+ let tester = get_tester();
+
+ let result = tester
+ .invoke_scalar_scalar(binary_geometry, ScalarValue::Utf8(Some("4326".to_string())))
+ .unwrap();
+
+ tester.assert_scalar_result_equals(
+ result,
+ "GEOMETRYCOLLECTION(
+ POINT(4 6),
+ LINESTRING(4 6,7 10),
+ POLYGON((4 6,7 10,4 10,4 6)),
+ MULTIPOINT((1 2),(3 4))
+ )",
+ );
+ }
+
+ #[test]
+ fn test_geometry_collection_in_geometry_collection() {
+ let binary_geometry =
+ fixture_to_bytes(include_str!("fixtures/nested_geometry_collection.sedona"));
+ let tester = get_tester();
+
+ let result = tester
+ .invoke_scalar_scalar(binary_geometry, ScalarValue::Utf8(Some("4326".to_string())))
+ .unwrap();
+
+ tester.assert_scalar_result_equals(
+ result,
+ "GEOMETRYCOLLECTION (
+ POINT (1 1),
+ GEOMETRYCOLLECTION (
+ LINESTRING (0 0, 1 1),
+ POLYGON ((0 0, 2 0, 2 2, 0 2, 0 0))
+ )
+ )",
+ );
+ }
+
+ #[test]
+ fn test_empty_geometries() {
+ let test_data = vec![
+ (include_str!("fixtures/empty_point.sedona"), "POINT EMPTY"),
+ (
+ include_str!("fixtures/multipoint_empty.sedona"),
+ "MULTIPOINT EMPTY",
+ ),
+ (
+ include_str!("fixtures/empty_linestring.sedona"),
+ "LINESTRING EMPTY",
+ ),
+ (
+ include_str!("fixtures/empty_polygon.sedona"),
+ "POLYGON EMPTY",
+ ),
+ (
+ include_str!("fixtures/empty_multipolygon.sedona"),
+ "MULTIPOLYGON EMPTY",
+ ),
+ (
+ include_str!("fixtures/empty_multilinestring.sedona"),
+ "MULTILINESTRING EMPTY",
+ ),
+ (
+ include_str!("fixtures/empty_geometry_collection.sedona"),
+ "GEOMETRYCOLLECTION EMPTY",
+ ),
+ ];
+
+ let tester = get_tester();
+
+ for (test_fixture, expected_wkt) in test_data {
+ let binary_geometry = fixture_to_bytes(test_fixture);
+
+ let result = tester
+ .invoke_scalar_scalar(binary_geometry, ScalarValue::Utf8(Some("4326".to_string())))
+ .unwrap();
+
+ tester.assert_scalar_result_equals(result, expected_wkt);
+ }
+ }
+
+ #[test]
+ fn test_non_integer_coordinates() {
+ let binary_geometry = fixture_to_bytes(include_str!("fixtures/point_float_coords.sedona"));
+ let tester = get_tester();
+
+ let result = tester
+ .invoke_scalar_scalar(binary_geometry, ScalarValue::Utf8(Some("4326".to_string())))
+ .unwrap();
+
+ tester.assert_scalar_result_equals(
+ result,
+ "POLYGON (
+ (
+ 12.345678901234 45.678901234567,
+ 23.456789012345 67.890123456789,
+ 34.567890123456 56.789012345678,
+ 45.678901234567 34.567890123456,
+ 29.876543210987 22.345678901234,
+ 12.345678901234 45.678901234567
+ ),
+ (
+ 25.123456789012 45.987654321098,
+ 30.987654321098 50.123456789012,
+ 35.456789012345 45.456789012345,
+ 30.234567890123 40.987654321098,
+ 25.123456789012 45.987654321098
+ )
+ )"
+ );
+ }
+}
diff --git a/rust/sedona-functions/Cargo.toml b/rust/sedona-serde/Cargo.toml
similarity index 61%
copy from rust/sedona-functions/Cargo.toml
copy to rust/sedona-serde/Cargo.toml
index 57afd240..7eddb106 100644
--- a/rust/sedona-functions/Cargo.toml
+++ b/rust/sedona-serde/Cargo.toml
@@ -15,11 +15,8 @@
# specific language governing permissions and limitations
# under the License.
[package]
-name = "sedona-functions"
+name = "sedona-serde"
version.workspace = true
-license.workspace = true
-keywords.workspace = true
-categories.workspace = true
homepage.workspace = true
repository.workspace = true
description.workspace = true
@@ -31,27 +28,9 @@ rust-version.workspace = true
result_large_err = "allow"
[dev-dependencies]
-arrow-json = { workspace = true }
-criterion = { workspace = true }
-rstest = { workspace = true }
-sedona-testing = { workspace = true, features = ["criterion"] }
-datafusion = { workspace = true }
-tokio = { workspace = true, features = ["rt", "macros"] }
[dependencies]
-arrow-schema = { workspace = true }
arrow-array = { workspace = true }
datafusion-common = { workspace = true }
-datafusion-expr = { workspace = true }
-geo-traits = { workspace = true }
-sedona-common = { workspace = true }
-sedona-expr = { workspace = true }
-sedona-geometry = { workspace = true }
-sedona-schema = { workspace = true }
-wkb = { workspace = true }
wkt = { workspace = true }
-serde_json = { workspace = true }
-
-[[bench]]
-harness = false
-name = "native-functions"
+byteorder = "1.5.0"
diff --git a/rust/sedona-serde/src/deserialize.rs b/rust/sedona-serde/src/deserialize.rs
new file mode 100644
index 00000000..a28811ca
--- /dev/null
+++ b/rust/sedona-serde/src/deserialize.rs
@@ -0,0 +1,130 @@
+// 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::linestring::{parse_linestring, parse_multilinestring};
+use crate::point::{parse_multipoint, parse_point, write_empty_point};
+use crate::polygon::{parse_multipolygon, parse_polygon, write_empty_polygon};
+use arrow_array::builder::BinaryBuilder;
+use byteorder::{ByteOrder, LittleEndian, ReadBytesExt, WriteBytesExt};
+use datafusion_common::error::DataFusionError;
+use std::io::{Cursor};
+use wkt::types::Dimension;
+
+pub fn deserialize<'a>(builder: &mut BinaryBuilder, bytes: &[u8]) -> datafusion_common::Result<()> {
+ use std::io::Cursor;
+
+ if bytes.len() < 8 {
+ return Err(DataFusionError::Internal(
+ "Sedona bytes are too short".to_string(),
+ ));
+ }
+
+ let mut reader = Cursor::new(bytes);
+
+ parse_geometry::<LittleEndian, LittleEndian>(builder, &mut reader, bytes)
+}
+
+pub fn parse_geometry<'a, IN: ByteOrder, OUT: ByteOrder>(
+ builder: &mut BinaryBuilder,
+ cursor: &mut Cursor<&[u8]>,
+ bytes: &[u8],
+) -> datafusion_common::Result<()> {
+ let preamble_byte = cursor.read_u8()? & 0xFF;
+
+ let wkb_type = preamble_byte >> 4;
+
+ let dimension = get_dimension((preamble_byte & 0x0F) >> 1);
+
+ let has_srid = (preamble_byte & 0x01) != 0;
+
+ cursor.set_position(cursor.position() + 3); // Skip 3 bytes
+
+ match wkb_type {
+ 1 => {
+ let number_of_coordinates = cursor.read_u32::<IN>()?;
+ if number_of_coordinates == 0 {
+ write_empty_point::<OUT>(builder, dimension)?;
+ return Ok(());
+ }
+
+ parse_point::<IN, OUT>(builder, cursor, dimension)?;
+ }
+ 2 => {
+ parse_linestring::<IN, OUT>(builder, cursor, dimension)?;
+ }
+ 3 => {
+ let mut meta_data_reader = Cursor::new(bytes);
+
+ let number_of_points = cursor.read_u32::<IN>()?;
+ if number_of_points == 0 {
+ write_empty_polygon::<OUT>(builder, dimension)?;
+
+ return Ok(());
+ }
+
+ let metadata_start_position = number_of_points * 8 * 2;
+ meta_data_reader.set_position(cursor.position() + (metadata_start_position) as u64);
+
+ parse_polygon::<IN, OUT>(builder, cursor, &mut meta_data_reader, dimension)?;
+ cursor.set_position(meta_data_reader.position());
+ }
+ 4 => {
+ parse_multipoint::<IN, OUT>(builder, cursor, dimension)?;
+ }
+ 5 => {
+ // let bytes = cursor.into_inner();
+ let mut meta_data_reader = Cursor::new(bytes);
+ parse_multilinestring::<IN, OUT>(builder, cursor, &mut meta_data_reader, dimension)?;
+ cursor.set_position(meta_data_reader.position());
+ }
+ 6 => {
+ let mut meta_data_reader = Cursor::new(bytes);
+ parse_multipolygon::<IN, OUT>(builder, cursor, &mut meta_data_reader, dimension)?;
+ cursor.set_position(meta_data_reader.position());
+ }
+ 7 => {
+ let number_of_geometries = cursor.read_u32::<IN>()?;
+ builder.write_i8(1)?;
+ builder.write_u32::<OUT>(7u32)?;
+
+ builder.write_u32::<OUT>(number_of_geometries)?;
+
+ for i in 0..number_of_geometries {
+ parse_geometry::<IN, OUT>(builder, cursor, bytes)?;
+ }
+ }
+ _ => {
+ return Err(DataFusionError::Execution(format!(
+ "Unsupported geometry type: {}",
+ wkb_type
+ )))
+ }
+ }
+
+ Ok(())
+}
+
+
+fn get_dimension(b: u8) -> Dimension {
+ match b {
+ 1 => Dimension::XY,
+ 2 => Dimension::XYZ,
+ 3 => Dimension::XYM,
+ 4 => Dimension::XYZM,
+ _ => Dimension::XY,
+ }
+}
diff --git a/rust/sedona-serde/src/lib.rs b/rust/sedona-serde/src/lib.rs
new file mode 100644
index 00000000..77397606
--- /dev/null
+++ b/rust/sedona-serde/src/lib.rs
@@ -0,0 +1,22 @@
+// 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.
+
+pub mod deserialize;
+mod point;
+mod linestring;
+mod polygon;
+mod wkb;
diff --git a/rust/sedona-serde/src/linestring.rs b/rust/sedona-serde/src/linestring.rs
new file mode 100644
index 00000000..1f7af45d
--- /dev/null
+++ b/rust/sedona-serde/src/linestring.rs
@@ -0,0 +1,98 @@
+// 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 arrow_array::builder::BinaryBuilder;
+use byteorder::{ByteOrder, ReadBytesExt, WriteBytesExt};
+use std::io::{Cursor, Read, Write};
+use wkt::types::Dimension;
+use crate::wkb::write_wkb_byte_order_marker;
+
+fn get_linestring_marker(dimension: Dimension) -> u32 {
+ match dimension {
+ Dimension::XY => 2u32,
+ Dimension::XYZ => 1002u32,
+ Dimension::XYM => 2002u32,
+ Dimension::XYZM => 3002u32,
+ }
+}
+
+pub fn parse_linestring<IN: ByteOrder, OUT: ByteOrder>(
+ builder: &mut BinaryBuilder,
+ cursor: &mut Cursor<&[u8]>,
+ dimension: Dimension,
+) -> datafusion_common::Result<()> {
+ let number_of_points = cursor.read_u32::<IN>()?;
+ let byte_type = get_linestring_marker(dimension);
+
+ write_wkb_byte_order_marker(builder)?;
+
+ builder.write_u32::<OUT>(byte_type)?;
+
+ builder.write_u32::<OUT>(number_of_points)?;
+
+ let mut buf = [0u8; 8];
+ for _ in 0..number_of_points * 2 {
+ cursor.read_exact(&mut buf)?;
+ builder.write(&buf)?;
+ }
+
+ Ok(())
+}
+
+pub fn parse_multilinestring<IN: ByteOrder, OUT: ByteOrder>(
+ builder: &mut BinaryBuilder,
+ cursor: &mut Cursor<&[u8]>,
+ metadata_reader: &mut Cursor<&[u8]>,
+ dimension: Dimension,
+) -> datafusion_common::Result<()> {
+ let byte_type = match dimension {
+ Dimension::XY => 5u32,
+ Dimension::XYZ => 1005u32,
+ Dimension::XYM => 2005u32,
+ Dimension::XYZM => 3005u32,
+ };
+
+ let linestring_type = get_linestring_marker(dimension);
+
+ write_wkb_byte_order_marker(builder)?;
+ builder.write_u32::<OUT>(byte_type)?;
+
+ let number_of_points = cursor.read_u32::<IN>()?;
+
+ metadata_reader.set_position(cursor.position() + (number_of_points * 8 * 2) as u64);
+
+ let number_of_geometries = metadata_reader.read_u32::<IN>()?;
+
+ builder.write_u32::<OUT>(number_of_geometries)?;
+
+ for _ in 0..number_of_geometries {
+ let number_of_points_in_linestring = metadata_reader.read_u32::<IN>()?;
+ write_wkb_byte_order_marker(builder)?;
+ builder.write_u32::<OUT>(linestring_type)?;
+
+ builder.write_u32::<OUT>(number_of_points_in_linestring)?;
+
+ for _ in 0..number_of_points_in_linestring * 2{
+ let mut buf = [0u8; 8];
+ cursor.read_exact(&mut buf)?;
+
+ builder.write(&buf)?;
+ }
+ }
+
+ Ok(())
+}
diff --git a/rust/sedona-serde/src/point.rs b/rust/sedona-serde/src/point.rs
new file mode 100644
index 00000000..5a6d7400
--- /dev/null
+++ b/rust/sedona-serde/src/point.rs
@@ -0,0 +1,96 @@
+// 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::wkb::write_wkb_byte_order_marker;
+use arrow_array::builder::BinaryBuilder;
+use byteorder::{ByteOrder, ReadBytesExt, WriteBytesExt};
+use datafusion_common::error::Result;
+use std::io::{Cursor, Read, Write};
+use wkt::types::Dimension;
+
+fn get_byte_type_for_point(dimension: Dimension) -> u32 {
+ match dimension {
+ Dimension::XY => 1u32,
+ Dimension::XYZ => 1001u32,
+ Dimension::XYM => 2001u32,
+ Dimension::XYZM => 3001u32,
+ }
+}
+
+pub fn write_empty_point<OUT: ByteOrder>(
+ builder: &mut BinaryBuilder,
+ dimension: Dimension,
+) -> Result<()> {
+ write_wkb_byte_order_marker(builder)?;
+ builder.write_u32::<OUT>(get_byte_type_for_point(dimension))?;
+
+ builder.write_f64::<OUT>(f64::NAN)?; // X
+ builder.write_f64::<OUT>(f64::NAN)?; // Y
+
+ Ok(())
+}
+
+pub fn parse_point<IN: ByteOrder, OUT: ByteOrder>(
+ builder: &mut BinaryBuilder,
+ cursor: &mut Cursor<&[u8]>,
+ dimension: Dimension,
+) -> Result<()> {
+ write_wkb_byte_order_marker(builder)?;
+ builder.write_u32::<OUT>(get_byte_type_for_point(dimension))?;
+
+ let mut buf = [0u8; 8];
+ cursor.read_exact(&mut buf)?;
+
+ builder.write(&buf)?;
+
+ cursor.read_exact(&mut buf)?;
+ builder.write(&buf)?;
+
+ Ok(())
+}
+
+pub fn parse_multipoint<IN: ByteOrder, OUT: ByteOrder>(
+ builder: &mut BinaryBuilder,
+ cursor: &mut Cursor<&[u8]>,
+ dimension: Dimension,
+) -> Result<()> {
+ let number_of_points = cursor.read_u32::<IN>()?;
+
+ let byte_type = match dimension {
+ Dimension::XY => 4u32,
+ Dimension::XYZ => 1004u32,
+ Dimension::XYM => 2004u32,
+ Dimension::XYZM => 3004u32,
+ };
+
+ write_wkb_byte_order_marker(builder)?;
+ builder.write_u32::<OUT>(byte_type)?;
+
+ if number_of_points == 0 {
+ builder.write_u32::<OUT>(0)?;
+ return Ok(());
+ }
+
+
+ builder.write_u32::<OUT>(number_of_points)?;
+
+ for _ in 0..number_of_points {
+ parse_point::<IN, OUT>(builder, cursor, dimension)?;
+ }
+
+ Ok(())
+}
diff --git a/rust/sedona-serde/src/polygon.rs b/rust/sedona-serde/src/polygon.rs
new file mode 100644
index 00000000..e46f1d22
--- /dev/null
+++ b/rust/sedona-serde/src/polygon.rs
@@ -0,0 +1,104 @@
+// 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::io::{Cursor, Read, Write};
+use arrow_array::builder::BinaryBuilder;
+use byteorder::{ByteOrder, ReadBytesExt, WriteBytesExt};
+use wkt::types::Dimension;
+use crate::wkb::write_wkb_byte_order_marker;
+
+
+pub(crate) fn get_polygon_marker(dimension: Dimension) -> u32 {
+ match dimension {
+ Dimension::XY => 3u32,
+ Dimension::XYZ => 1003u32,
+ Dimension::XYM => 2003u32,
+ Dimension::XYZM => 3003u32,
+ }
+}
+
+pub fn parse_polygon<IN: ByteOrder, OUT: ByteOrder>(
+ builder: &mut BinaryBuilder,
+ cursor: &mut Cursor<&[u8]>,
+ metadata_reader: &mut Cursor<&[u8]>,
+ dimension: Dimension,
+) -> datafusion_common::Result<()> {
+ let byte_type = get_polygon_marker(dimension);
+ let number_of_rings = metadata_reader.read_u32::<IN>()?;
+
+ write_wkb_byte_order_marker(builder)?;
+ builder.write_u32::<OUT>(byte_type)?;
+ builder.write_u32::<OUT>(number_of_rings)?;
+
+ for _ in 0..number_of_rings {
+ let ring_number_of_points = metadata_reader.read_u32::<IN>()?;
+ builder.write_u32::<OUT>(ring_number_of_points)?;
+
+ let mut buf = [0u8; 8];
+ for _ in 0..ring_number_of_points * 2 {
+ cursor.read_exact(&mut buf)?;
+ builder.write(&buf)?;
+ }
+ }
+
+ Ok(())
+}
+
+pub(crate) fn parse_multipolygon<IN: ByteOrder, OUT: ByteOrder>(
+ builder: &mut BinaryBuilder,
+ cursor: &mut Cursor<&[u8]>,
+ metadata_reader: &mut Cursor<&[u8]>,
+ dimension: Dimension,
+) -> datafusion_common::Result<()> {
+ let byte_type = match dimension {
+ Dimension::XY => 6u32,
+ Dimension::XYZ => 1006u32,
+ Dimension::XYM => 2006u32,
+ Dimension::XYZM => 3006u32,
+ };
+
+ let number_of_points = cursor.read_u32::<IN>()?;
+ let metadata_start_position = number_of_points * 8 * 2;
+ metadata_reader.set_position(cursor.position() + (metadata_start_position) as u64);
+
+ let number_of_geometries = metadata_reader.read_u32::<IN>()?;
+ write_wkb_byte_order_marker(builder)?;
+ builder.write_u32::<OUT>(byte_type)?;
+ builder.write_u32::<OUT>(number_of_geometries)?;
+
+ for _ in 0..number_of_geometries {
+ parse_polygon::<IN, OUT>(builder, cursor, metadata_reader, dimension)?;
+ }
+
+ Ok(())
+}
+
+
+pub (crate) fn write_empty_polygon<OUT: ByteOrder>(builder: &mut BinaryBuilder, dimension: Dimension) -> datafusion_common::Result<()> {
+ let byte_type = match dimension {
+ Dimension::XY => 3u32,
+ Dimension::XYZ => 1003u32,
+ Dimension::XYM => 2003u32,
+ Dimension::XYZM => 3003u32,
+ };
+
+ write_wkb_byte_order_marker(builder)?;
+ builder.write_u32::<OUT>(byte_type)?;
+ builder.write_u32::<OUT>(0u32)?; // 0 rings
+
+ Ok(())
+}
diff --git a/rust/sedona-serde/src/wkb.rs b/rust/sedona-serde/src/wkb.rs
new file mode 100644
index 00000000..d3b642ce
--- /dev/null
+++ b/rust/sedona-serde/src/wkb.rs
@@ -0,0 +1,24 @@
+// 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 byteorder::WriteBytesExt;
+
+pub(crate) const WKB_LITTLE_ENDIAN_MARKER: u8 = 1;
+
+pub fn write_wkb_byte_order_marker<W: std::io::Write>(writer: &mut W) -> std::io::Result<()> {
+ writer.write_u8(WKB_LITTLE_ENDIAN_MARKER)
+}