1use core::str;
4use std::{
5 borrow::Cow,
6 collections::HashMap,
7 fmt::{Display, Formatter},
8 ops::Deref,
9};
10
11use chashmap::CHashMap;
12use geo::{Coord, Geometry, Intersects, Rect, SimplifyVw};
13#[cfg(feature = "self-contained")]
16use geo::{LineString, MultiPolygon, Polygon};
17use geojson::{Feature, FeatureCollection, GeoJson};
18use rayon::prelude::{IndexedParallelIterator, IntoParallelIterator, ParallelIterator};
19use serde_json::{Map, Value};
20use std::path::Path;
21
22#[cfg(feature = "self-contained")]
23use bincode::{
24 config::Configuration,
25 de::{read::BorrowReader, BorrowDecoder, Decoder},
26 enc::Encoder,
27 error::{DecodeError, EncodeError},
28 BorrowDecode, Decode, Encode,
29};
30
31use crate::base::types::Float;
32
33pub type Id = u32;
37pub type RoundDegree = i16;
39pub type RoundLngLat = (RoundDegree, RoundDegree);
41pub type IdFeaturePair = (usize, geojson::Feature);
43
44#[derive(Debug)]
48#[cfg_attr(feature = "self-contained", derive(Encode, Decode))]
49pub struct ConcreteVec<T>(Vec<T>)
50where
51 T: 'static;
52
53impl<T> Deref for ConcreteVec<T> {
54 type Target = Vec<T>;
55
56 fn deref(&self) -> &Self::Target {
57 &self.0
58 }
59}
60
61impl<T> From<Vec<T>> for ConcreteVec<T> {
62 fn from(value: Vec<T>) -> ConcreteVec<T> {
63 ConcreteVec(value)
64 }
65}
66
67impl<T> From<geojson::FeatureCollection> for ConcreteVec<T>
68where
69 T: From<IdFeaturePair> + Send,
70{
71 fn from(value: geojson::FeatureCollection) -> ConcreteVec<T> {
72 let values = value.features.into_par_iter().enumerate().map(T::from).collect::<Vec<T>>();
73
74 ConcreteVec(values)
75 }
76}
77
78impl<T> IntoIterator for ConcreteVec<T> {
79 type IntoIter = std::vec::IntoIter<T>;
80 type Item = T;
81
82 fn into_iter(self) -> Self::IntoIter {
83 self.0.into_iter()
84 }
85}
86
87impl<'a, T> IntoIterator for &'a ConcreteVec<T> {
88 type IntoIter = std::slice::Iter<'a, T>;
89 type Item = &'a T;
90
91 fn into_iter(self) -> Self::IntoIter {
92 self.0.iter()
93 }
94}
95
96#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
100pub struct EncodableString(pub Cow<'static, str>);
101
102impl AsRef<str> for EncodableString {
103 fn as_ref(&self) -> &str {
104 self.0.as_ref()
105 }
106}
107
108impl Deref for EncodableString {
109 type Target = Cow<'static, str>;
110
111 fn deref(&self) -> &Self::Target {
112 &self.0
113 }
114}
115
116impl Display for EncodableString {
117 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
118 write!(f, "{}", self.0)
119 }
120}
121
122#[cfg(feature = "self-contained")]
123impl Encode for EncodableString {
124 fn encode<E>(&self, encoder: &mut E) -> Result<(), EncodeError>
125 where
126 E: Encoder,
127 {
128 let data = pad_string_alignment(self);
129
130 data.encode(encoder)
131 }
132}
133
134#[cfg(feature = "self-contained")]
135impl<Context> Decode<Context> for EncodableString {
136 fn decode<D>(decoder: &mut D) -> Result<Self, DecodeError>
137 where
138 D: Decoder,
139 {
140 let data = Vec::decode(decoder)?;
141
142 unpad_string_alignment(&data).map(ToString::to_string).map(Cow::Owned).map(EncodableString)
144 }
145}
146
147#[cfg(feature = "self-contained")]
148impl<'de, Context> BorrowDecode<'de, Context> for EncodableString {
149 fn borrow_decode<D>(decoder: &mut D) -> Result<Self, DecodeError>
150 where
151 D: BorrowDecoder<'de>,
152 {
153 let length = usize::decode(decoder)?;
154 let slice = decoder.borrow_reader().take_bytes(length * std::mem::size_of::<u8>())?;
155
156 let slice = unsafe { std::mem::transmute::<&'_ [u8], &'static [u8]>(slice) };
158
159 unpad_string_alignment(slice).map(Cow::Borrowed).map(EncodableString)
161 }
162}
163
164#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
166pub struct EncodableOptionString(pub Option<Cow<'static, str>>);
167
168impl EncodableOptionString {
169 pub fn as_ref(&self) -> Option<&Cow<'static, str>> {
171 self.0.as_ref()
172 }
173}
174
175impl Deref for EncodableOptionString {
176 type Target = Option<Cow<'static, str>>;
177
178 fn deref(&self) -> &Self::Target {
179 &self.0
180 }
181}
182
183impl Display for EncodableOptionString {
184 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
185 match self.as_ref() {
186 None => write!(f, "None"),
187 Some(cow) => write!(f, "{}", cow),
188 }
189 }
190}
191
192#[cfg(feature = "self-contained")]
193impl Encode for EncodableOptionString {
194 fn encode<E>(&self, encoder: &mut E) -> Result<(), EncodeError>
195 where
196 E: Encoder,
197 {
198 match self.as_ref() {
199 None => 0usize.encode(encoder),
200 Some(cow) => {
201 1usize.encode(encoder)?;
203
204 let data = pad_string_alignment(cow);
206
207 data.encode(encoder)
208 }
209 }
210 }
211}
212
213#[cfg(feature = "self-contained")]
214impl<Context> Decode<Context> for EncodableOptionString {
215 fn decode<D>(decoder: &mut D) -> Result<Self, DecodeError>
216 where
217 D: Decoder,
218 {
219 let variant = usize::decode(decoder)?;
220
221 let result = match variant {
222 0 => EncodableOptionString(None),
223 1 => {
224 let es = EncodableString::decode(decoder)?;
225
226 EncodableOptionString(Some(es.0))
227 }
228 _ => panic!("Unsupported variant."),
229 };
230
231 Ok(result)
232 }
233}
234
235#[cfg(feature = "self-contained")]
236impl<'de, Context> BorrowDecode<'de, Context> for EncodableOptionString {
237 fn borrow_decode<D>(decoder: &mut D) -> Result<Self, DecodeError>
238 where
239 D: BorrowDecoder<'de>,
240 {
241 let variant = usize::decode(decoder)?;
242
243 let result = match variant {
244 0 => EncodableOptionString(None),
245 1 => {
246 let es = EncodableString::borrow_decode(decoder)?;
247
248 EncodableOptionString(Some(es.0))
249 }
250 _ => panic!("Unsupported variant."),
251 };
252
253 Ok(result)
254 }
255}
256
257pub trait HasGeometry {
263 fn id(&self) -> usize;
265 fn geometry(&self) -> &Geometry<Float>;
267
268 fn reorder(items: ConcreteVec<Self>) -> ConcreteVec<Self>
276 where
277 Self: Sized + 'static,
278 {
279 items
280 }
281}
282
283pub trait HasProperties {
285 fn properties(&self) -> Map<String, Value>;
287}
288
289pub trait ToGeoJsonFeature {
291 fn to_feature(&self) -> geojson::Feature;
293}
294
295impl<T> ToGeoJsonFeature for T
296where
297 T: HasGeometry + HasProperties,
298{
299 fn to_feature(&self) -> geojson::Feature {
300 let geometry = self.geometry();
301 let properties = self.properties();
302
303 geojson::Feature {
304 properties: Some(properties),
305 geometry: Some(geojson::Geometry::from(geometry)),
306 ..geojson::Feature::default()
307 }
308 }
309}
310
311pub trait ToGeoJsonFeatureCollection {
313 fn to_feature_collection(&self) -> geojson::FeatureCollection;
315}
316
317impl<L, D, T> ToGeoJsonFeatureCollection for &L
319where
320 L: Deref<Target = D>,
321 D: Deref<Target = [T]>,
322 T: ToGeoJsonFeature + 'static,
323{
324 fn to_feature_collection(&self) -> geojson::FeatureCollection {
325 let features = self.iter().map(|x| x.to_feature()).collect();
326
327 geojson::FeatureCollection {
328 features,
329 bbox: None,
330 foreign_members: None,
331 }
332 }
333}
334
335pub trait ToGeoJson {
337 fn to_geojson(&self) -> GeoJson;
339}
340
341impl<T> ToGeoJson for T
342where
343 T: ToGeoJsonFeatureCollection,
344{
345 fn to_geojson(&self) -> GeoJson {
346 GeoJson::FeatureCollection(self.to_feature_collection())
347 }
348}
349
350#[cfg(feature = "self-contained")]
354pub fn pad_string_alignment(string: impl AsRef<str>) -> Vec<u8> {
355 let alignment = std::mem::align_of::<Float>();
356 let padding = alignment - (string.as_ref().len() % alignment);
357
358 string.as_ref().as_bytes().iter().chain(std::iter::repeat_n(&0u8, padding)).copied().collect::<Vec<u8>>()
359}
360
361#[cfg(feature = "self-contained")]
363pub fn unpad_string_alignment(data: &[u8]) -> Result<&str, DecodeError> {
364 let terminator = data.iter().position(|&x| x == 0).unwrap_or(data.len());
365 let slice = &data[..terminator];
366
367 let str = str::from_utf8(slice).map_err(|e| DecodeError::Utf8 { inner: e })?;
368
369 Ok(str)
370}
371
372pub fn simplify_geometry(geometry: Geometry<Float>, simplification_epsilon: Float) -> Geometry<Float> {
376 #[cfg(not(feature = "unsimplified"))]
377 let geometry = match geometry {
378 Geometry::Polygon(polygon) => {
379 let simplified = polygon.simplify_vw(simplification_epsilon);
380 Geometry::Polygon(simplified)
381 }
382 Geometry::MultiPolygon(multi_polygon) => {
383 let simplified = multi_polygon.simplify_vw(simplification_epsilon);
384 Geometry::MultiPolygon(simplified)
385 }
386 Geometry::LineString(line_string) => {
387 let simplified = line_string.simplify_vw(simplification_epsilon);
388 Geometry::LineString(simplified)
389 }
390 Geometry::MultiLineString(multi_line_string) => {
391 let simplified = multi_line_string.simplify_vw(simplification_epsilon);
392 Geometry::MultiLineString(simplified)
393 }
394 g => g,
395 };
396
397 geometry
398}
399
400pub fn get_lookup_from_geometries<T>(geometries: &ConcreteVec<T>) -> HashMap<RoundLngLat, EncodableIds>
402where
403 T: HasGeometry + Send + Sync,
404{
405 let map = CHashMap::new();
406
407 (-180..180).into_par_iter().for_each(|x| {
408 for y in -90..90 {
409 let xf = x as Float;
410 let yf = y as Float;
411
412 let rect = Rect::new(Coord { x: xf, y: yf }, Coord { x: xf + 1.0, y: yf + 1.0 });
413
414 let mut intersected = Vec::new();
415
416 for g in geometries {
417 if g.geometry().intersects(&rect) {
418 intersected.push(g.id() as Id);
419 }
420 }
421
422 map.insert((x as RoundDegree, y as RoundDegree), intersected);
423 }
424 });
425
426 let mut cache = HashMap::new();
427 for (key, value) in map.into_iter() {
428 cache.insert(key, EncodableIds(value));
429 }
430
431 cache
432}
433
434#[cfg(feature = "self-contained")]
439#[cfg_attr(coverage_nightly, coverage(off))]
440fn generate_lookup_bincode<T>(bincode_input: impl AsRef<Path>, bincode_destination: impl AsRef<Path>)
441where
442 T: HasGeometry + Decode<()> + Send + Sync + 'static,
443{
444 let data = std::fs::read(bincode_input).unwrap();
445 let (timezones, _len): (ConcreteVec<T>, usize) = bincode::decode_from_slice(&data, get_global_bincode_config()).unwrap();
446
447 let cache = get_lookup_from_geometries(&timezones);
448
449 bincode::encode_into_std_write(cache, &mut std::fs::File::create(bincode_destination).unwrap(), get_global_bincode_config()).unwrap();
450}
451
452pub fn get_items_from_features<T>(features: FeatureCollection) -> ConcreteVec<T>
454where
455 T: HasGeometry + From<IdFeaturePair> + Send,
456{
457 ConcreteVec::from(features)
458}
459
460#[cfg(feature = "self-contained")]
462#[cfg_attr(coverage_nightly, coverage(off))]
463fn generate_item_bincode<T>(geojson_features: FeatureCollection, bincode_destination: impl AsRef<Path>)
464where
465 T: HasGeometry + Encode + From<IdFeaturePair> + Send + 'static,
466{
467 let items: ConcreteVec<T> = T::reorder(get_items_from_features(geojson_features));
468 bincode::encode_into_std_write(items, &mut std::fs::File::create(bincode_destination).unwrap(), get_global_bincode_config()).unwrap();
469}
470
471#[cfg(feature = "self-contained")]
479#[cfg_attr(coverage_nightly, coverage(off))]
480pub fn resort_items_bincode<T>(items_path: impl AsRef<Path>, lookup_path: impl AsRef<Path>)
481where
482 T: HasGeometry + Encode + Decode<()> + Send + Sync + 'static,
483{
484 let data = std::fs::read(items_path.as_ref()).unwrap();
485 let (items, _len): (ConcreteVec<T>, usize) = bincode::decode_from_slice(&data, get_global_bincode_config()).unwrap();
486
487 let items = T::reorder(items);
489 let cache = get_lookup_from_geometries(&items);
490
491 bincode::encode_into_std_write(items, &mut std::fs::File::create(items_path.as_ref()).unwrap(), get_global_bincode_config()).unwrap();
492 bincode::encode_into_std_write(cache, &mut std::fs::File::create(lookup_path.as_ref()).unwrap(), get_global_bincode_config()).unwrap();
493}
494
495pub fn get_geojson_features_from_file(geojson_input: impl AsRef<Path>) -> FeatureCollection {
497 let geojson = std::fs::read_to_string(geojson_input).unwrap();
498 FeatureCollection::try_from(geojson.parse::<GeoJson>().unwrap()).unwrap()
499}
500
501pub fn get_geojson_features_from_string(geojson_input: &str) -> FeatureCollection {
503 FeatureCollection::try_from(geojson_input.parse::<GeoJson>().unwrap()).unwrap()
504}
505
506pub fn get_geojson_feature_from_file(geojson_input: impl AsRef<Path>) -> Feature {
508 let geojson = std::fs::read_to_string(geojson_input).unwrap();
509 Feature::try_from(geojson.parse::<GeoJson>().unwrap()).unwrap()
510}
511
512pub fn get_geojson_feature_from_string(geojson_input: &str) -> Feature {
514 Feature::try_from(geojson_input.parse::<GeoJson>().unwrap()).unwrap()
515}
516
517#[cfg(feature = "self-contained")]
519#[cfg_attr(coverage_nightly, coverage(off))]
520pub fn generate_bincodes<T>(geojson_features: FeatureCollection, timezone_bincode_destination: impl AsRef<Path>, lookup_bincode_destination: impl AsRef<Path>)
521where
522 T: HasGeometry + Encode + From<IdFeaturePair> + Decode<()> + Send + Sync + 'static,
523{
524 generate_item_bincode::<T>(geojson_features, timezone_bincode_destination.as_ref());
525 generate_lookup_bincode::<T>(timezone_bincode_destination, lookup_bincode_destination);
526}
527
528pub trait CanGetGeoJsonFeaturesFromSource {
532 fn get_geojson_features_from_source() -> geojson::FeatureCollection;
534}
535
536#[cfg(all(feature = "self-contained", target_endian = "big"))]
540
541pub fn get_global_bincode_config() -> Configuration<bincode::config::BigEndian, bincode::config::Fixint> {
542 bincode::config::legacy().with_big_endian()
543}
544
545#[cfg(all(feature = "self-contained", target_endian = "little"))]
547pub fn get_global_bincode_config() -> Configuration<bincode::config::LittleEndian, bincode::config::Fixint> {
548 bincode::config::legacy()
549}
550
551#[derive(Debug)]
555pub struct EncodableGeometry(pub Geometry<Float>);
556
557#[cfg(not(feature = "owned-decode"))]
568impl Drop for EncodableGeometry {
569 fn drop(&mut self) {
570 let geometry = std::mem::replace(&mut self.0, Geometry::Point(geo::Point::new(0.0, 0.0)));
571 std::mem::forget(geometry);
572 }
573}
574
575#[cfg(feature = "self-contained")]
576fn encode_poly<E>(polygon: &Polygon<Float>, encoder: &mut E) -> Result<(), EncodeError>
577where
578 E: Encoder,
579{
580 let exterior = &polygon.exterior().0;
581
582 exterior.len().encode(encoder)?;
584
585 for point in exterior {
587 point.x.encode(encoder)?;
588 point.y.encode(encoder)?;
589 }
590
591 let interiors = polygon.interiors();
592
593 interiors.len().encode(encoder)?;
595
596 for interior in interiors {
598 let interior = &interior.0;
599
600 interior.len().encode(encoder)?;
602
603 for point in interior {
605 point.x.encode(encoder)?;
606 point.y.encode(encoder)?;
607 }
608 }
609
610 Ok(())
611}
612
613#[cfg(feature = "self-contained")]
614impl Encode for EncodableGeometry {
615 fn encode<E>(&self, encoder: &mut E) -> Result<(), EncodeError>
616 where
617 E: Encoder,
618 {
619 match &self.0 {
620 Geometry::Polygon(polygon) => {
621 0usize.encode(encoder)?;
623
624 encode_poly(polygon, encoder)?;
625 }
626 Geometry::MultiPolygon(multi_polygon) => {
627 1usize.encode(encoder)?;
629
630 let polygons = &multi_polygon.0;
631
632 polygons.len().encode(encoder)?;
634
635 for polygon in polygons {
637 encode_poly(polygon, encoder)?;
638 }
639 }
640 _ => panic!("Unsupported geometry variant."),
641 }
642
643 Ok(())
644 }
645}
646
647#[cfg(feature = "self-contained")]
648fn decode_poly<D>(decoder: &mut D) -> Result<Polygon<Float>, DecodeError>
649where
650 D: Decoder,
651{
652 let exterior_len = usize::decode(decoder)?;
653
654 let mut exterior = Vec::with_capacity(exterior_len);
655
656 for _ in 0..exterior_len {
657 let x = Float::decode(decoder)?;
658 let y = Float::decode(decoder)?;
659
660 exterior.push(Coord { x, y });
661 }
662
663 let interior_len = usize::decode(decoder)?;
664
665 let mut interiors = Vec::with_capacity(interior_len);
666
667 for _ in 0..interior_len {
668 let interior_len = usize::decode(decoder)?;
669
670 let mut interior = Vec::with_capacity(interior_len);
671
672 for _ in 0..interior_len {
673 let x = Float::decode(decoder)?;
674 let y = Float::decode(decoder)?;
675
676 interior.push(Coord { x, y });
677 }
678
679 interiors.push(LineString(interior));
680 }
681
682 Ok(Polygon::new(LineString(exterior), interiors))
683}
684
685#[cfg(feature = "self-contained")]
686fn borrow_decode_poly<'de, D>(decoder: &mut D) -> Result<Polygon<Float>, DecodeError>
687where
688 D: BorrowDecoder<'de>,
689{
690 let exterior_len = usize::decode(decoder)?;
691 let exterior_slice = decoder.borrow_reader().take_bytes(exterior_len * std::mem::size_of::<Float>() * 2)?;
692
693 let exterior = unsafe { Vec::from_raw_parts(exterior_slice.as_ptr() as *mut Coord<Float>, exterior_len, exterior_len) };
697
698 let interior_len = usize::decode(decoder)?;
699
700 let mut interiors = Vec::with_capacity(interior_len);
701
702 for _ in 0..interior_len {
703 let interior_len = usize::decode(decoder)?;
704 let interior_slice = decoder.borrow_reader().take_bytes(interior_len * std::mem::size_of::<Float>() * 2)?;
705
706 let interior = unsafe { Vec::from_raw_parts(interior_slice.as_ptr() as *mut Coord<Float>, interior_len, interior_len) };
708
709 interiors.push(LineString(interior));
710 }
711
712 Ok(Polygon::new(LineString(exterior), interiors))
713}
714
715#[cfg(feature = "self-contained")]
716impl<Context> Decode<Context> for EncodableGeometry {
717 fn decode<D>(decoder: &mut D) -> Result<Self, DecodeError>
718 where
719 D: Decoder,
720 {
721 let variant = usize::decode(decoder)?;
722
723 let geometry = match variant {
724 0 => {
725 let polygon = decode_poly(decoder)?;
726
727 Geometry::Polygon(polygon)
728 }
729 1 => {
730 let polygon_len = usize::decode(decoder)?;
731
732 let mut polygons = Vec::with_capacity(polygon_len);
733
734 for _ in 0..polygon_len {
735 let polygon = decode_poly(decoder)?;
736
737 polygons.push(polygon);
738 }
739
740 Geometry::MultiPolygon(MultiPolygon::new(polygons))
741 }
742 _ => panic!("Unsupported geometry variant."),
743 };
744
745 Ok(EncodableGeometry(geometry))
746 }
747}
748
749#[cfg(feature = "self-contained")]
750impl<'de, Context> BorrowDecode<'de, Context> for EncodableGeometry {
751 fn borrow_decode<D>(decoder: &mut D) -> Result<Self, DecodeError>
752 where
753 D: BorrowDecoder<'de>,
754 {
755 let variant = usize::decode(decoder)?;
756
757 let geometry = match variant {
758 0 => {
759 let polygon = borrow_decode_poly(decoder)?;
760
761 Geometry::Polygon(polygon)
762 }
763 1 => {
764 let polygon_len = usize::decode(decoder)?;
765
766 let mut polygons = Vec::with_capacity(polygon_len);
767
768 for _ in 0..polygon_len {
769 let polygon = borrow_decode_poly(decoder)?;
770
771 polygons.push(polygon);
772 }
773
774 Geometry::MultiPolygon(MultiPolygon::new(polygons))
775 }
776 _ => panic!("Unsupported geometry variant."),
777 };
778
779 Ok(EncodableGeometry(geometry))
780 }
781}
782
783#[derive(Debug)]
785pub struct EncodableIds(pub Vec<Id>);
786
787impl Deref for EncodableIds {
788 type Target = Vec<Id>;
789
790 fn deref(&self) -> &Self::Target {
791 &self.0
792 }
793}
794
795impl AsRef<[Id]> for EncodableIds {
796 fn as_ref(&self) -> &[Id] {
797 &self.0
798 }
799}
800
801#[cfg(feature = "self-contained")]
802impl Encode for EncodableIds {
803 fn encode<E>(&self, encoder: &mut E) -> Result<(), EncodeError>
804 where
805 E: Encoder,
806 {
807 self.0.len().encode(encoder)?;
809
810 for x in &self.0 {
812 x.encode(encoder)?;
813 }
814
815 Ok(())
816 }
817}
818
819#[cfg(feature = "self-contained")]
820impl<Context> Decode<Context> for EncodableIds {
821 fn decode<D>(decoder: &mut D) -> Result<Self, DecodeError>
822 where
823 D: Decoder,
824 {
825 let len = usize::decode(decoder)?;
826
827 let mut vec = Vec::with_capacity(len);
828
829 for _ in 0..len {
830 let x = Id::decode(decoder)?;
831
832 vec.push(x);
833 }
834
835 Ok(EncodableIds(vec))
836 }
837}
838
839#[cfg(feature = "self-contained")]
840impl<'de, Context> BorrowDecode<'de, Context> for EncodableIds {
841 fn borrow_decode<D>(decoder: &mut D) -> Result<Self, DecodeError>
842 where
843 D: BorrowDecoder<'de>,
844 {
845 let len = usize::decode(decoder)?;
846 let slice = decoder.borrow_reader().take_bytes(len * std::mem::size_of::<Id>())?;
847
848 let vec = unsafe { Vec::from_raw_parts(slice.as_ptr() as *mut Id, len, len) };
850
851 Ok(EncodableIds(vec))
852 }
853}
854
855#[cfg(all(test, feature = "self-contained"))]
856mod codec_tests {
857 use super::*;
858 use crate::base::types::Float;
859 use geo::{Coord, Geometry, LineString, MultiPolygon, Polygon};
860 use std::borrow::Cow;
861
862 fn roundtrip_string(s: &str) {
863 let cfg = get_global_bincode_config();
864 let original = EncodableString(Cow::Owned(s.to_string()));
865 let bytes = bincode::encode_to_vec(&original, cfg).unwrap();
866 let (decoded, _len): (EncodableString, usize) = bincode::decode_from_slice(&bytes, cfg).unwrap();
867 assert_eq!(decoded, original, "string roundtrip failed for {s:?}");
868 }
869
870 #[test]
871 fn string_roundtrips_ascii_empty_nonascii_and_alignment() {
872 roundtrip_string(""); roundtrip_string("America/Los_Angeles");
874 roundtrip_string("مصر"); roundtrip_string("abc"); roundtrip_string("abcd"); }
878
879 #[test]
880 fn option_string_roundtrips_none_and_some() {
881 let cfg = get_global_bincode_config();
882 for original in [EncodableOptionString(None), EncodableOptionString(Some(Cow::Owned("x".to_string())))] {
883 let bytes = bincode::encode_to_vec(&original, cfg).unwrap();
884 let (decoded, _len): (EncodableOptionString, usize) = bincode::decode_from_slice(&bytes, cfg).unwrap();
885 assert_eq!(decoded, original);
886 }
887 }
888
889 #[test]
890 fn ids_roundtrip_empty_and_many() {
891 let cfg = get_global_bincode_config();
892 for v in [Vec::<Id>::new(), vec![0u32, 1, 2, 4_000_000]] {
893 let original = EncodableIds(v.clone());
894 let bytes = bincode::encode_to_vec(&original, cfg).unwrap();
895 let (decoded, _len): (EncodableIds, usize) = bincode::decode_from_slice(&bytes, cfg).unwrap();
896 assert_eq!(decoded.0, v);
897 }
898 }
899
900 #[test]
901 fn geometry_roundtrips_polygon_with_interior_and_multipolygon() {
902 let cfg = get_global_bincode_config();
903 let exterior = LineString(vec![
904 Coord { x: 0.0, y: 0.0 },
905 Coord { x: 4.0, y: 0.0 },
906 Coord { x: 4.0, y: 4.0 },
907 Coord { x: 0.0, y: 4.0 },
908 Coord { x: 0.0, y: 0.0 },
909 ]);
910 let interior = LineString(vec![
911 Coord { x: 1.0, y: 1.0 },
912 Coord { x: 2.0, y: 1.0 },
913 Coord { x: 2.0, y: 2.0 },
914 Coord { x: 1.0, y: 1.0 },
915 ]);
916 let poly: Polygon<Float> = Polygon::new(exterior, vec![interior]);
917
918 let original = EncodableGeometry(Geometry::Polygon(poly.clone()));
919 let bytes = bincode::encode_to_vec(&original, cfg).unwrap();
920 let (decoded, _len): (EncodableGeometry, usize) = bincode::decode_from_slice(&bytes, cfg).unwrap();
921 assert_eq!(decoded.0, original.0);
922
923 let multi = EncodableGeometry(Geometry::MultiPolygon(MultiPolygon::new(vec![poly])));
924 let bytes = bincode::encode_to_vec(&multi, cfg).unwrap();
925 let (decoded, _len): (EncodableGeometry, usize) = bincode::decode_from_slice(&bytes, cfg).unwrap();
926 assert_eq!(decoded.0, multi.0);
927 }
928
929 #[test]
930 fn string_borrow_decode_matches_owned() {
931 let cfg = get_global_bincode_config();
938 let original = EncodableString(Cow::Owned("America/Los_Angeles".to_string()));
939 let bytes = bincode::encode_to_vec(&original, cfg).unwrap();
940 let (decoded, _len): (EncodableString, usize) = bincode::borrow_decode_from_slice(&bytes, cfg).unwrap();
941 assert_eq!(decoded.as_ref(), original.as_ref());
942 }
943}