Skip to content

Commit 7d2af93

Browse files
committed
Expose more APIs for accessing the WKB coordinate buffer
1 parent 1909aeb commit 7d2af93

File tree

14 files changed

+227
-17
lines changed

14 files changed

+227
-17
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22

33
## Unreleased
44

5+
- Expose APIs for accessing the underlying WKB buffer. (#85)
6+
- Making structs for individual geometry types public. (#85)
7+
58
## 0.9.1 - 2025-09-24
69

710
- Don't panic when parsing invalid WKB (#74).

src/common.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -200,7 +200,7 @@ impl From<WkbType> for u32 {
200200
}
201201

202202
/// Endianness
203-
#[derive(Debug, Clone, Copy, Default, TryFromPrimitive, IntoPrimitive)]
203+
#[derive(Debug, Clone, Copy, Default, TryFromPrimitive, IntoPrimitive, PartialEq)]
204204
#[repr(u8)]
205205
pub enum Endianness {
206206
/// Big endian

src/reader/coord.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,27 @@ impl<'a> Coord<'a> {
6666
reader.read_f64(self.byte_order).unwrap()
6767
}
6868

69+
/// Get the byte order of WKB coordinate
70+
#[inline]
71+
pub fn byte_order(&self) -> Endianness {
72+
self.byte_order
73+
}
74+
75+
/// Get the slice of bytes containing the coordinate. The byte order
76+
/// of coordinate can be obtained by calling [Coord::byte_order].
77+
#[inline]
78+
pub fn coord_slice(&self) -> &'a [u8] {
79+
let start = self.offset as usize;
80+
let end = start + self.size() as usize;
81+
&self.buf[start..end]
82+
}
83+
84+
/// Get the dimension of this coordinate
85+
#[inline]
86+
pub fn dimension(&self) -> Dimension {
87+
self.dim
88+
}
89+
6990
/// The number of bytes in this object
7091
///
7192
/// Note that this is not the same as the length of the underlying buffer

src/reader/geometry.rs

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,10 @@ use geo_traits::{
2020
///
2121
/// The contained [dimension][geo_traits::Dimensions] will never be `Unknown`.
2222
#[derive(Debug, Clone)]
23-
pub struct Wkb<'a>(WkbInner<'a>);
23+
pub struct Wkb<'a> {
24+
buf: &'a [u8],
25+
inner: WkbInner<'a>,
26+
}
2427

2528
impl<'a> Wkb<'a> {
2629
/// Parse a WKB byte slice into a geometry.
@@ -38,13 +41,13 @@ impl<'a> Wkb<'a> {
3841
/// newly-allocated `f64`.
3942
pub fn try_new(buf: &'a [u8]) -> WkbResult<Self> {
4043
let inner = WkbInner::try_new(buf)?;
41-
Ok(Self(inner))
44+
Ok(Self { buf, inner })
4245
}
4346

4447
/// Return the [Dimension] of this geometry.
4548
pub fn dimension(&self) -> Dimension {
4649
use WkbInner::*;
47-
match &self.0 {
50+
match &self.inner {
4851
Point(g) => g.dimension(),
4952
LineString(g) => g.dimension(),
5053
Polygon(g) => g.dimension(),
@@ -58,7 +61,7 @@ impl<'a> Wkb<'a> {
5861
/// Return the [GeometryType] of this geometry.
5962
pub fn geometry_type(&self) -> GeometryType {
6063
use WkbInner::*;
61-
match &self.0 {
64+
match &self.inner {
6265
Point(_) => GeometryType::Point,
6366
LineString(_) => GeometryType::LineString,
6467
Polygon(_) => GeometryType::Polygon,
@@ -69,9 +72,15 @@ impl<'a> Wkb<'a> {
6972
}
7073
}
7174

75+
/// Return the underlying buffer of this WKB geometry.
76+
#[inline]
77+
pub fn buf(&self) -> &'a [u8] {
78+
self.buf
79+
}
80+
7281
pub(crate) fn size(&self) -> u64 {
7382
use WkbInner::*;
74-
match &self.0 {
83+
match &self.inner {
7584
Point(g) => g.size(),
7685
LineString(g) => g.size(),
7786
Polygon(g) => g.size(),
@@ -189,7 +198,7 @@ impl<'a> GeometryTrait for Wkb<'a> {
189198
> {
190199
use geo_traits::GeometryType as B;
191200
use WkbInner as A;
192-
match &self.0 {
201+
match &self.inner {
193202
A::Point(p) => B::Point(p),
194203
A::LineString(ls) => B::LineString(ls),
195204
A::Polygon(ls) => B::Polygon(ls),
@@ -265,7 +274,7 @@ impl<'a> GeometryTrait for &Wkb<'a> {
265274
> {
266275
use geo_traits::GeometryType as B;
267276
use WkbInner as A;
268-
match &self.0 {
277+
match &self.inner {
269278
A::Point(p) => B::Point(p),
270279
A::LineString(ls) => B::LineString(ls),
271280
A::Polygon(ls) => B::Polygon(ls),

src/reader/geometry_collection.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@ pub struct GeometryCollection<'a> {
2020
}
2121

2222
impl<'a> GeometryCollection<'a> {
23+
/// Construct a new GeometryCollection from a WKB buffer.
24+
///
25+
/// This will parse the WKB header and extract all contained geometries.
2326
pub fn try_new(buf: &'a [u8], byte_order: Endianness, dim: Dimension) -> WkbResult<Self> {
2427
let mut offset = 0;
2528
let has_srid = has_srid(buf, byte_order, offset)?;
@@ -56,10 +59,14 @@ impl<'a> GeometryCollection<'a> {
5659
})
5760
}
5861

62+
/// The dimension of this GeometryCollection
5963
pub fn dimension(&self) -> Dimension {
6064
self.dim
6165
}
6266

67+
/// The number of bytes in this object, including any header
68+
///
69+
/// Note that this is not the same as the length of the underlying buffer
6370
pub fn size(&self) -> u64 {
6471
// - 1: byteOrder
6572
// - 4: wkbType

src/reader/linearring.rs

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,10 +40,19 @@ pub struct LinearRing<'a> {
4040
}
4141

4242
impl<'a> LinearRing<'a> {
43+
/// Construct a new LinearRing from a WKB buffer.
44+
///
45+
/// # Panics
46+
///
47+
/// This will panic if the WKB buffer is invalid. For fallible parsing, use
48+
/// [`try_new`](Self::try_new) instead.
4349
pub fn new(buf: &'a [u8], byte_order: Endianness, offset: u64, dim: Dimension) -> Self {
4450
Self::try_new(buf, byte_order, offset, dim).unwrap()
4551
}
4652

53+
/// Construct a new LinearRing from a WKB buffer.
54+
///
55+
/// This will parse the number of points and validate the buffer length.
4756
pub fn try_new(
4857
buf: &'a [u8],
4958
byte_order: Endianness,
@@ -101,9 +110,26 @@ impl<'a> LinearRing<'a> {
101110
self.offset + 4 + (self.dim.size() as u64 * 8 * i)
102111
}
103112

104-
pub(crate) fn dimension(&self) -> Dimension {
113+
/// The dimension of this LinearRing
114+
#[inline]
115+
pub fn dimension(&self) -> Dimension {
105116
self.dim
106117
}
118+
119+
/// The slice of bytes containing the coordinates of this LinearRing. The byte order
120+
/// of LinearRing can be obtained by calling [LinearRing::byte_order].
121+
#[inline]
122+
pub fn coords_slice(&self) -> &'a [u8] {
123+
let start = self.coord_offset(0) as usize;
124+
let end = start + self.dim.size() * 8 * self.num_points;
125+
&self.buf[start..end]
126+
}
127+
128+
/// Get the byte order of WKB LinearRing
129+
#[inline]
130+
pub fn byte_order(&self) -> Endianness {
131+
self.byte_order
132+
}
107133
}
108134

109135
impl<'a> LineStringTrait for LinearRing<'a> {

src/reader/linestring.rs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,19 @@ pub struct LineString<'a> {
2828
}
2929

3030
impl<'a> LineString<'a> {
31+
/// Construct a new LineString from a WKB buffer.
32+
///
33+
/// # Panics
34+
///
35+
/// This will panic if the WKB buffer is invalid. For fallible parsing, use
36+
/// [`try_new`](Self::try_new) instead.
3137
pub fn new(buf: &'a [u8], byte_order: Endianness, offset: u64, dim: Dimension) -> Self {
3238
Self::try_new(buf, byte_order, offset, dim).unwrap()
3339
}
3440

41+
/// Construct a new LineString from a WKB buffer.
42+
///
43+
/// This will parse the WKB header and validate the buffer length.
3544
pub fn try_new(
3645
buf: &'a [u8],
3746
byte_order: Endianness,
@@ -103,9 +112,26 @@ impl<'a> LineString<'a> {
103112
self.offset + 1 + 4 + 4 + (self.dim.size() as u64 * 8 * i)
104113
}
105114

115+
/// The dimension of this LineString
116+
#[inline]
106117
pub fn dimension(&self) -> Dimension {
107118
self.dim
108119
}
120+
121+
/// The slice of bytes containing the coordinates of this LineString. The byte order
122+
/// of LineString can be obtained by calling [LineString::byte_order].
123+
#[inline]
124+
pub fn coords_slice(&self) -> &'a [u8] {
125+
let start = self.coord_offset(0) as usize;
126+
let end = start + self.dim.size() * 8 * self.num_points;
127+
&self.buf[start..end]
128+
}
129+
130+
/// Get the byte order of WKB LineString
131+
#[inline]
132+
pub fn byte_order(&self) -> Endianness {
133+
self.byte_order
134+
}
109135
}
110136

111137
impl<'a> LineStringTrait for LineString<'a> {
@@ -114,10 +140,12 @@ impl<'a> LineStringTrait for LineString<'a> {
114140
where
115141
Self: 'b;
116142

143+
#[inline]
117144
fn num_coords(&self) -> usize {
118145
self.num_points
119146
}
120147

148+
#[inline]
121149
unsafe fn coord_unchecked(&self, i: usize) -> Self::CoordType<'_> {
122150
Coord::new(
123151
self.buf,
@@ -134,10 +162,12 @@ impl<'a> LineStringTrait for &LineString<'a> {
134162
where
135163
Self: 'b;
136164

165+
#[inline]
137166
fn num_coords(&self) -> usize {
138167
self.num_points
139168
}
140169

170+
#[inline]
141171
unsafe fn coord_unchecked(&self, i: usize) -> Self::CoordType<'_> {
142172
Coord::new(
143173
self.buf,

src/reader/mod.rs

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,16 @@ mod polygon;
1616
mod util;
1717

1818
pub use crate::common::Dimension;
19+
pub use coord::Coord;
1920
pub use geometry::Wkb;
20-
use geometry_collection::GeometryCollection;
21-
use linestring::LineString;
22-
use multilinestring::MultiLineString;
23-
use multipoint::MultiPoint;
24-
use multipolygon::MultiPolygon;
25-
use point::Point;
26-
use polygon::Polygon;
21+
pub use geometry_collection::GeometryCollection;
22+
pub use linearring::LinearRing;
23+
pub use linestring::LineString;
24+
pub use multilinestring::MultiLineString;
25+
pub use multipoint::MultiPoint;
26+
pub use multipolygon::MultiPolygon;
27+
pub use point::Point;
28+
pub use polygon::Polygon;
2729

2830
use crate::error::WkbResult;
2931

src/reader/multilinestring.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ impl<'a> MultiLineString<'a> {
8383
.fold(header, |acc, ls| acc + ls.size())
8484
}
8585

86+
/// The dimension of this MultiLineString
8687
pub fn dimension(&self) -> Dimension {
8788
self.dim
8889
}

src/reader/multipoint.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ impl<'a> MultiPoint<'a> {
9797
header + ((1 + 4 + (self.dim.size() as u64 * 8)) * i)
9898
}
9999

100+
/// The dimension of this MultiPoint
100101
pub fn dimension(&self) -> Dimension {
101102
self.dim
102103
}

0 commit comments

Comments
 (0)