1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
//! The EWKB value and the crate's entry points.
use Vec;
use Cartesian;
use ;
use DynGeometry;
use Srid;
use ;
use crateEwkbError;
use crate;
/// A geometry, the spatial-reference id its record carried, and the
/// byte order its record declared.
///
/// Returned by [`from_ewkb`]. To serialize a geometry, pass it and the
/// desired SRID and byte order directly to [`to_ewkb`].
///
/// # Comparison carries the byte order
///
/// The derived `PartialEq` includes [`Ewkb::byte_order`], so **two
/// readings of the same geometry with the same SRID compare unequal if
/// the two records declared different byte orders**. That is a
/// difference of pure transport. A caller diffing a big-endian row
/// against a little-endian one should compare `srid` and `geometry`
/// field-wise rather than comparing whole `Ewkb` values.
///
/// # There is deliberately no `Display`
///
/// A geometry has no single display form. Hex is one encoding among
/// several and a caller asks for it by name, through [`to_ewkb_hex`]:
///
/// ```compile_fail,E0277
/// use geometry_io_ewkb::{ByteOrder, Ewkb};
///
/// // `Ewkb` has no `Display`, so this does not compile:
/// let value = Ewkb { srid: None, geometry: 0u8, byte_order: ByteOrder::LittleEndian };
/// let s = format!("{value}");
/// ```
///
/// [`to_ewkb_hex`]: crate::to_ewkb_hex
/// Read an EWKB record: strip the `PostGIS` header, parse the OGC
/// record underneath it, and return both with the byte order the record
/// declared.
///
/// Allocates nothing of its own: the body is parsed in place, borrowed
/// from `bytes`.
///
/// # Errors
///
/// Returns [`EwkbError::BoundingBoxFlag`], [`EwkbError::DimensionFlag`]
/// or [`EwkbError::TruncatedSrid`] for a header this reader refuses, and
/// [`EwkbError::Wkb`] for anything `geometry-io-wkb` rejects in the
/// record underneath.
///
/// Only the **outermost** record is inspected for EWKB flags. A flag on
/// a nested member is the WKB reader's to refuse, and it reports its own
/// error for it — `PostGIS`'s writer never emits one.
///
/// # Examples
///
/// ```
/// use geometry_io_ewkb::{ByteOrder, Srid, from_ewkb};
/// use geometry_model::DynKind;
///
/// // Little-endian POINT(1 2) with SRID 4326.
/// let bytes = [
/// 0x01, // little-endian
/// 0x01, 0x00, 0x00, 0x20, // type 1 | SRID flag
/// 0xE6, 0x10, 0x00, 0x00, // SRID 4326
/// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x3F, // 1.0
/// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, // 2.0
/// ];
/// let e = from_ewkb(&bytes).unwrap();
/// assert_eq!(e.srid, Some(Srid::new(4326)));
/// assert_eq!(e.byte_order, ByteOrder::LittleEndian);
/// assert_eq!(e.geometry.kind(), DynKind::Point);
/// ```
/// Write a geometry to EWKB, with or without an SRID.
///
/// With `srid: None` the output is byte-identical to
/// `geometry_io_wkb::to_wkb` — plain OGC WKB, no EWKB flag set. With
/// `Some`, the SRID flag is set on the **outermost** type word only and
/// four bytes carry the id; every member record keeps a plain OGC
/// header, which is what `PostGIS` emits.
///
/// Empty polygons are encoded as zero rings. Other geometry structure
/// is written unchanged without validation: a consumer may reject
/// short or unclosed rings, empty interiors, or holes without an exterior.
///
/// # Panics
///
/// Panics if a custom [`WriteWkb`] implementation supplies an excessive
/// capacity hint or fails to append a WKB header when an SRID is requested.
/// Geometry accessors and writers must also honor their own contracts,
/// including providing the two ordinates this 2D codec writes.
///
/// # Examples
///
/// ```
/// use geometry_cs::Cartesian;
/// use geometry_io_ewkb::{ByteOrder, Srid, to_ewkb};
/// use geometry_io_wkb::to_wkb;
/// use geometry_model::Point2D;
///
/// let p = Point2D::<f64, Cartesian>::new(1.0, 2.0);
/// // No SRID: byte-identical to plain WKB.
/// assert_eq!(
/// to_ewkb(&p, None, ByteOrder::LittleEndian),
/// to_wkb(&p, ByteOrder::LittleEndian),
/// );
/// // With one: four more bytes, and the flag on the type word.
/// let with = to_ewkb(&p, Some(Srid::new(4326)), ByteOrder::LittleEndian);
/// assert_eq!(with.len(), to_wkb(&p, ByteOrder::LittleEndian).len() + 4);
/// assert_eq!(&with[..9], &[0x01, 0x01, 0x00, 0x00, 0x20, 0xE6, 0x10, 0x00, 0x00]);
/// ```
/// Write a caller's own polygon type to EWKB, through the geometry
/// traits.
///
/// The EWKB counterpart to `geometry_io_wkb::to_wkb_polygon`, for a
/// caller whose polygon is not a `geometry-model` type. Writes into one
/// output buffer with no intermediate body copy. Empty polygons use zero rings; other
/// ring structures are preserved without validation, as in [`to_ewkb`].
///
/// # Panics
///
/// Panics if custom polygon accessors violate their contracts, for
/// example by reporting iterator lengths that imply an excessive allocation
/// or by failing to supply the first two point ordinates.
///
/// # Examples
///
/// ```
/// use geometry_cs::Cartesian;
/// use geometry_io_ewkb::{ByteOrder, Srid, from_ewkb, to_ewkb_polygon};
/// use geometry_model::{Point2D, Polygon, Ring};
///
/// type Pt = Point2D<f64, Cartesian>;
/// let pg = Polygon::<Pt>::new(Ring::from_vec(vec![
/// Pt::new(0.0, 0.0),
/// Pt::new(0.0, 1.0),
/// Pt::new(1.0, 1.0),
/// Pt::new(0.0, 0.0),
/// ]));
///
/// let bytes = to_ewkb_polygon(&pg, Some(Srid::new(4326)), ByteOrder::LittleEndian);
/// assert_eq!(from_ewkb(&bytes).unwrap().srid, Some(Srid::new(4326)));
/// ```