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<geojson::FeatureCollection> for ConcreteVec<T>
62where
63 T: From<IdFeaturePair> + Send,
64{
65 fn from(value: geojson::FeatureCollection) -> ConcreteVec<T> {
66 let values = value.features.into_par_iter().enumerate().map(T::from).collect::<Vec<T>>();
67
68 ConcreteVec(values)
69 }
70}
71
72impl<T> IntoIterator for ConcreteVec<T> {
73 type IntoIter = std::vec::IntoIter<T>;
74 type Item = T;
75
76 fn into_iter(self) -> Self::IntoIter {
77 self.0.into_iter()
78 }
79}
80
81impl<'a, T> IntoIterator for &'a ConcreteVec<T> {
82 type IntoIter = std::slice::Iter<'a, T>;
83 type Item = &'a T;
84
85 fn into_iter(self) -> Self::IntoIter {
86 self.0.iter()
87 }
88}
89
90#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
94pub struct EncodableString(pub Cow<'static, str>);
95
96impl AsRef<str> for EncodableString {
97 fn as_ref(&self) -> &str {
98 self.0.as_ref()
99 }
100}
101
102impl Deref for EncodableString {
103 type Target = Cow<'static, str>;
104
105 fn deref(&self) -> &Self::Target {
106 &self.0
107 }
108}
109
110impl Display for EncodableString {
111 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
112 write!(f, "{}", self.0)
113 }
114}
115
116#[cfg(feature = "self-contained")]
117impl Encode for EncodableString {
118 fn encode<E>(&self, encoder: &mut E) -> Result<(), EncodeError>
119 where
120 E: Encoder,
121 {
122 let data = pad_string_alignment(self);
123
124 data.encode(encoder)
125 }
126}
127
128#[cfg(feature = "self-contained")]
129impl<Context> Decode<Context> for EncodableString {
130 fn decode<D>(decoder: &mut D) -> Result<Self, DecodeError>
131 where
132 D: Decoder,
133 {
134 let data = Vec::decode(decoder)?;
135
136 unpad_string_alignment(&data).map(ToString::to_string).map(Cow::Owned).map(EncodableString)
138 }
139}
140
141#[cfg(feature = "self-contained")]
142impl<'de, Context> BorrowDecode<'de, Context> for EncodableString {
143 fn borrow_decode<D>(decoder: &mut D) -> Result<Self, DecodeError>
144 where
145 D: BorrowDecoder<'de>,
146 {
147 let length = usize::decode(decoder)?;
148 let slice = decoder.borrow_reader().take_bytes(length * std::mem::size_of::<u8>())?;
149
150 let slice = unsafe { std::mem::transmute::<&'_ [u8], &'static [u8]>(slice) };
152
153 unpad_string_alignment(slice).map(Cow::Borrowed).map(EncodableString)
155 }
156}
157
158#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
160pub struct EncodableOptionString(pub Option<Cow<'static, str>>);
161
162impl EncodableOptionString {
163 pub fn as_ref(&self) -> Option<&Cow<'static, str>> {
165 self.0.as_ref()
166 }
167}
168
169impl Deref for EncodableOptionString {
170 type Target = Option<Cow<'static, str>>;
171
172 fn deref(&self) -> &Self::Target {
173 &self.0
174 }
175}
176
177impl Display for EncodableOptionString {
178 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
179 match self.as_ref() {
180 None => write!(f, "None"),
181 Some(cow) => write!(f, "{}", cow),
182 }
183 }
184}
185
186#[cfg(feature = "self-contained")]
187impl Encode for EncodableOptionString {
188 fn encode<E>(&self, encoder: &mut E) -> Result<(), EncodeError>
189 where
190 E: Encoder,
191 {
192 match self.as_ref() {
193 None => 0usize.encode(encoder),
194 Some(cow) => {
195 1usize.encode(encoder)?;
197
198 let data = pad_string_alignment(cow);
200
201 data.encode(encoder)
202 }
203 }
204 }
205}
206
207#[cfg(feature = "self-contained")]
208impl<Context> Decode<Context> for EncodableOptionString {
209 fn decode<D>(decoder: &mut D) -> Result<Self, DecodeError>
210 where
211 D: Decoder,
212 {
213 let variant = usize::decode(decoder)?;
214
215 let result = match variant {
216 0 => EncodableOptionString(None),
217 1 => {
218 let es = EncodableString::decode(decoder)?;
219
220 EncodableOptionString(Some(es.0))
221 }
222 _ => panic!("Unsupported variant."),
223 };
224
225 Ok(result)
226 }
227}
228
229#[cfg(feature = "self-contained")]
230impl<'de, Context> BorrowDecode<'de, Context> for EncodableOptionString {
231 fn borrow_decode<D>(decoder: &mut D) -> Result<Self, DecodeError>
232 where
233 D: BorrowDecoder<'de>,
234 {
235 let variant = usize::decode(decoder)?;
236
237 let result = match variant {
238 0 => EncodableOptionString(None),
239 1 => {
240 let es = EncodableString::borrow_decode(decoder)?;
241
242 EncodableOptionString(Some(es.0))
243 }
244 _ => panic!("Unsupported variant."),
245 };
246
247 Ok(result)
248 }
249}
250
251pub trait HasGeometry {
257 fn id(&self) -> usize;
259 fn geometry(&self) -> &Geometry<Float>;
261}
262
263pub trait HasProperties {
265 fn properties(&self) -> Map<String, Value>;
267}
268
269pub trait ToGeoJsonFeature {
271 fn to_feature(&self) -> geojson::Feature;
273}
274
275impl<T> ToGeoJsonFeature for T
276where
277 T: HasGeometry + HasProperties,
278{
279 fn to_feature(&self) -> geojson::Feature {
280 let geometry = self.geometry();
281 let properties = self.properties();
282
283 geojson::Feature {
284 properties: Some(properties),
285 geometry: Some(geojson::Geometry::from(geometry)),
286 ..geojson::Feature::default()
287 }
288 }
289}
290
291pub trait ToGeoJsonFeatureCollection {
293 fn to_feature_collection(&self) -> geojson::FeatureCollection;
295}
296
297impl<L, D, T> ToGeoJsonFeatureCollection for &L
299where
300 L: Deref<Target = D>,
301 D: Deref<Target = [T]>,
302 T: ToGeoJsonFeature + 'static,
303{
304 fn to_feature_collection(&self) -> geojson::FeatureCollection {
305 let features = self.iter().map(|x| x.to_feature()).collect();
306
307 geojson::FeatureCollection {
308 features,
309 bbox: None,
310 foreign_members: None,
311 }
312 }
313}
314
315pub trait ToGeoJson {
317 fn to_geojson(&self) -> GeoJson;
319}
320
321impl<T> ToGeoJson for T
322where
323 T: ToGeoJsonFeatureCollection,
324{
325 fn to_geojson(&self) -> GeoJson {
326 GeoJson::FeatureCollection(self.to_feature_collection())
327 }
328}
329
330#[cfg(feature = "self-contained")]
334pub fn pad_string_alignment(string: impl AsRef<str>) -> Vec<u8> {
335 let alignment = std::mem::align_of::<Float>();
336 let padding = alignment - (string.as_ref().len() % alignment);
337
338 string.as_ref().as_bytes().iter().chain(std::iter::repeat_n(&0u8, padding)).copied().collect::<Vec<u8>>()
339}
340
341#[cfg(feature = "self-contained")]
343pub fn unpad_string_alignment(data: &[u8]) -> Result<&str, DecodeError> {
344 let terminator = data.iter().position(|&x| x == 0).unwrap_or(data.len());
345 let slice = &data[..terminator];
346
347 let str = str::from_utf8(slice).map_err(|e| DecodeError::Utf8 { inner: e })?;
348
349 Ok(str)
350}
351
352pub fn simplify_geometry(geometry: Geometry<Float>, simplification_epsilon: Float) -> Geometry<Float> {
356 #[cfg(not(feature = "unsimplified"))]
357 let geometry = match geometry {
358 Geometry::Polygon(polygon) => {
359 let simplified = polygon.simplify_vw(simplification_epsilon);
360 Geometry::Polygon(simplified)
361 }
362 Geometry::MultiPolygon(multi_polygon) => {
363 let simplified = multi_polygon.simplify_vw(simplification_epsilon);
364 Geometry::MultiPolygon(simplified)
365 }
366 Geometry::LineString(line_string) => {
367 let simplified = line_string.simplify_vw(simplification_epsilon);
368 Geometry::LineString(simplified)
369 }
370 Geometry::MultiLineString(multi_line_string) => {
371 let simplified = multi_line_string.simplify_vw(simplification_epsilon);
372 Geometry::MultiLineString(simplified)
373 }
374 g => g,
375 };
376
377 geometry
378}
379
380pub fn get_lookup_from_geometries<T>(geometries: &ConcreteVec<T>) -> HashMap<RoundLngLat, EncodableIds>
382where
383 T: HasGeometry + Send + Sync,
384{
385 let map = CHashMap::new();
386
387 (-180..180).into_par_iter().for_each(|x| {
388 for y in -90..90 {
389 let xf = x as Float;
390 let yf = y as Float;
391
392 let rect = Rect::new(Coord { x: xf, y: yf }, Coord { x: xf + 1.0, y: yf + 1.0 });
393
394 let mut intersected = Vec::new();
395
396 for g in geometries {
397 if g.geometry().intersects(&rect) {
398 intersected.push(g.id() as Id);
399 }
400 }
401
402 map.insert((x as RoundDegree, y as RoundDegree), intersected);
403 }
404 });
405
406 let mut cache = HashMap::new();
407 for (key, value) in map.into_iter() {
408 cache.insert(key, EncodableIds(value));
409 }
410
411 cache
412}
413
414#[cfg(feature = "self-contained")]
419#[cfg_attr(coverage_nightly, coverage(off))]
420fn generate_lookup_bincode<T>(bincode_input: impl AsRef<Path>, bincode_destination: impl AsRef<Path>)
421where
422 T: HasGeometry + Decode<()> + Send + Sync + 'static,
423{
424 let data = std::fs::read(bincode_input).unwrap();
425 let (timezones, _len): (ConcreteVec<T>, usize) = bincode::decode_from_slice(&data, get_global_bincode_config()).unwrap();
426
427 let cache = get_lookup_from_geometries(&timezones);
428
429 bincode::encode_into_std_write(cache, &mut std::fs::File::create(bincode_destination).unwrap(), get_global_bincode_config()).unwrap();
430}
431
432pub fn get_items_from_features<T>(features: FeatureCollection) -> ConcreteVec<T>
434where
435 T: HasGeometry + From<IdFeaturePair> + Send,
436{
437 ConcreteVec::from(features)
438}
439
440#[cfg(feature = "self-contained")]
442#[cfg_attr(coverage_nightly, coverage(off))]
443fn generate_item_bincode<T>(geojson_features: FeatureCollection, bincode_destination: impl AsRef<Path>)
444where
445 T: HasGeometry + Encode + From<IdFeaturePair> + Send + 'static,
446{
447 let items: ConcreteVec<T> = get_items_from_features(geojson_features);
448 bincode::encode_into_std_write(items, &mut std::fs::File::create(bincode_destination).unwrap(), get_global_bincode_config()).unwrap();
449}
450
451pub fn get_geojson_features_from_file(geojson_input: impl AsRef<Path>) -> FeatureCollection {
453 let geojson = std::fs::read_to_string(geojson_input).unwrap();
454 FeatureCollection::try_from(geojson.parse::<GeoJson>().unwrap()).unwrap()
455}
456
457pub fn get_geojson_features_from_string(geojson_input: &str) -> FeatureCollection {
459 FeatureCollection::try_from(geojson_input.parse::<GeoJson>().unwrap()).unwrap()
460}
461
462pub fn get_geojson_feature_from_file(geojson_input: impl AsRef<Path>) -> Feature {
464 let geojson = std::fs::read_to_string(geojson_input).unwrap();
465 Feature::try_from(geojson.parse::<GeoJson>().unwrap()).unwrap()
466}
467
468pub fn get_geojson_feature_from_string(geojson_input: &str) -> Feature {
470 Feature::try_from(geojson_input.parse::<GeoJson>().unwrap()).unwrap()
471}
472
473#[cfg(feature = "self-contained")]
475#[cfg_attr(coverage_nightly, coverage(off))]
476pub fn generate_bincodes<T>(geojson_features: FeatureCollection, timezone_bincode_destination: impl AsRef<Path>, lookup_bincode_destination: impl AsRef<Path>)
477where
478 T: HasGeometry + Encode + From<IdFeaturePair> + Decode<()> + Send + Sync + 'static,
479{
480 generate_item_bincode::<T>(geojson_features, timezone_bincode_destination.as_ref());
481 generate_lookup_bincode::<T>(timezone_bincode_destination, lookup_bincode_destination);
482}
483
484pub trait CanGetGeoJsonFeaturesFromSource {
488 fn get_geojson_features_from_source() -> geojson::FeatureCollection;
490}
491
492#[cfg(all(feature = "self-contained", target_endian = "big"))]
496
497pub fn get_global_bincode_config() -> Configuration<bincode::config::BigEndian, bincode::config::Fixint> {
498 bincode::config::legacy().with_big_endian()
499}
500
501#[cfg(all(feature = "self-contained", target_endian = "little"))]
503pub fn get_global_bincode_config() -> Configuration<bincode::config::LittleEndian, bincode::config::Fixint> {
504 bincode::config::legacy()
505}
506
507#[derive(Debug)]
511pub struct EncodableGeometry(pub Geometry<Float>);
512
513#[cfg(not(feature = "owned-decode"))]
524impl Drop for EncodableGeometry {
525 fn drop(&mut self) {
526 let geometry = std::mem::replace(&mut self.0, Geometry::Point(geo::Point::new(0.0, 0.0)));
527 std::mem::forget(geometry);
528 }
529}
530
531#[cfg(feature = "self-contained")]
532fn encode_poly<E>(polygon: &Polygon<Float>, encoder: &mut E) -> Result<(), EncodeError>
533where
534 E: Encoder,
535{
536 let exterior = &polygon.exterior().0;
537
538 exterior.len().encode(encoder)?;
540
541 for point in exterior {
543 point.x.encode(encoder)?;
544 point.y.encode(encoder)?;
545 }
546
547 let interiors = polygon.interiors();
548
549 interiors.len().encode(encoder)?;
551
552 for interior in interiors {
554 let interior = &interior.0;
555
556 interior.len().encode(encoder)?;
558
559 for point in interior {
561 point.x.encode(encoder)?;
562 point.y.encode(encoder)?;
563 }
564 }
565
566 Ok(())
567}
568
569#[cfg(feature = "self-contained")]
570impl Encode for EncodableGeometry {
571 fn encode<E>(&self, encoder: &mut E) -> Result<(), EncodeError>
572 where
573 E: Encoder,
574 {
575 match &self.0 {
576 Geometry::Polygon(polygon) => {
577 0usize.encode(encoder)?;
579
580 encode_poly(polygon, encoder)?;
581 }
582 Geometry::MultiPolygon(multi_polygon) => {
583 1usize.encode(encoder)?;
585
586 let polygons = &multi_polygon.0;
587
588 polygons.len().encode(encoder)?;
590
591 for polygon in polygons {
593 encode_poly(polygon, encoder)?;
594 }
595 }
596 _ => panic!("Unsupported geometry variant."),
597 }
598
599 Ok(())
600 }
601}
602
603#[cfg(feature = "self-contained")]
604fn decode_poly<D>(decoder: &mut D) -> Result<Polygon<Float>, DecodeError>
605where
606 D: Decoder,
607{
608 let exterior_len = usize::decode(decoder)?;
609
610 let mut exterior = Vec::with_capacity(exterior_len);
611
612 for _ in 0..exterior_len {
613 let x = Float::decode(decoder)?;
614 let y = Float::decode(decoder)?;
615
616 exterior.push(Coord { x, y });
617 }
618
619 let interior_len = usize::decode(decoder)?;
620
621 let mut interiors = Vec::with_capacity(interior_len);
622
623 for _ in 0..interior_len {
624 let interior_len = usize::decode(decoder)?;
625
626 let mut interior = Vec::with_capacity(interior_len);
627
628 for _ in 0..interior_len {
629 let x = Float::decode(decoder)?;
630 let y = Float::decode(decoder)?;
631
632 interior.push(Coord { x, y });
633 }
634
635 interiors.push(LineString(interior));
636 }
637
638 Ok(Polygon::new(LineString(exterior), interiors))
639}
640
641#[cfg(feature = "self-contained")]
642fn borrow_decode_poly<'de, D>(decoder: &mut D) -> Result<Polygon<Float>, DecodeError>
643where
644 D: BorrowDecoder<'de>,
645{
646 let exterior_len = usize::decode(decoder)?;
647 let exterior_slice = decoder.borrow_reader().take_bytes(exterior_len * std::mem::size_of::<Float>() * 2)?;
648
649 let exterior = unsafe { Vec::from_raw_parts(exterior_slice.as_ptr() as *mut Coord<Float>, exterior_len, exterior_len) };
653
654 let interior_len = usize::decode(decoder)?;
655
656 let mut interiors = Vec::with_capacity(interior_len);
657
658 for _ in 0..interior_len {
659 let interior_len = usize::decode(decoder)?;
660 let interior_slice = decoder.borrow_reader().take_bytes(interior_len * std::mem::size_of::<Float>() * 2)?;
661
662 let interior = unsafe { Vec::from_raw_parts(interior_slice.as_ptr() as *mut Coord<Float>, interior_len, interior_len) };
664
665 interiors.push(LineString(interior));
666 }
667
668 Ok(Polygon::new(LineString(exterior), interiors))
669}
670
671#[cfg(feature = "self-contained")]
672impl<Context> Decode<Context> for EncodableGeometry {
673 fn decode<D>(decoder: &mut D) -> Result<Self, DecodeError>
674 where
675 D: Decoder,
676 {
677 let variant = usize::decode(decoder)?;
678
679 let geometry = match variant {
680 0 => {
681 let polygon = decode_poly(decoder)?;
682
683 Geometry::Polygon(polygon)
684 }
685 1 => {
686 let polygon_len = usize::decode(decoder)?;
687
688 let mut polygons = Vec::with_capacity(polygon_len);
689
690 for _ in 0..polygon_len {
691 let polygon = decode_poly(decoder)?;
692
693 polygons.push(polygon);
694 }
695
696 Geometry::MultiPolygon(MultiPolygon::new(polygons))
697 }
698 _ => panic!("Unsupported geometry variant."),
699 };
700
701 Ok(EncodableGeometry(geometry))
702 }
703}
704
705#[cfg(feature = "self-contained")]
706impl<'de, Context> BorrowDecode<'de, Context> for EncodableGeometry {
707 fn borrow_decode<D>(decoder: &mut D) -> Result<Self, DecodeError>
708 where
709 D: BorrowDecoder<'de>,
710 {
711 let variant = usize::decode(decoder)?;
712
713 let geometry = match variant {
714 0 => {
715 let polygon = borrow_decode_poly(decoder)?;
716
717 Geometry::Polygon(polygon)
718 }
719 1 => {
720 let polygon_len = usize::decode(decoder)?;
721
722 let mut polygons = Vec::with_capacity(polygon_len);
723
724 for _ in 0..polygon_len {
725 let polygon = borrow_decode_poly(decoder)?;
726
727 polygons.push(polygon);
728 }
729
730 Geometry::MultiPolygon(MultiPolygon::new(polygons))
731 }
732 _ => panic!("Unsupported geometry variant."),
733 };
734
735 Ok(EncodableGeometry(geometry))
736 }
737}
738
739#[derive(Debug)]
741pub struct EncodableIds(pub Vec<Id>);
742
743impl Deref for EncodableIds {
744 type Target = Vec<Id>;
745
746 fn deref(&self) -> &Self::Target {
747 &self.0
748 }
749}
750
751impl AsRef<[Id]> for EncodableIds {
752 fn as_ref(&self) -> &[Id] {
753 &self.0
754 }
755}
756
757#[cfg(feature = "self-contained")]
758impl Encode for EncodableIds {
759 fn encode<E>(&self, encoder: &mut E) -> Result<(), EncodeError>
760 where
761 E: Encoder,
762 {
763 self.0.len().encode(encoder)?;
765
766 for x in &self.0 {
768 x.encode(encoder)?;
769 }
770
771 Ok(())
772 }
773}
774
775#[cfg(feature = "self-contained")]
776impl<Context> Decode<Context> for EncodableIds {
777 fn decode<D>(decoder: &mut D) -> Result<Self, DecodeError>
778 where
779 D: Decoder,
780 {
781 let len = usize::decode(decoder)?;
782
783 let mut vec = Vec::with_capacity(len);
784
785 for _ in 0..len {
786 let x = Id::decode(decoder)?;
787
788 vec.push(x);
789 }
790
791 Ok(EncodableIds(vec))
792 }
793}
794
795#[cfg(feature = "self-contained")]
796impl<'de, Context> BorrowDecode<'de, Context> for EncodableIds {
797 fn borrow_decode<D>(decoder: &mut D) -> Result<Self, DecodeError>
798 where
799 D: BorrowDecoder<'de>,
800 {
801 let len = usize::decode(decoder)?;
802 let slice = decoder.borrow_reader().take_bytes(len * std::mem::size_of::<Id>())?;
803
804 let vec = unsafe { Vec::from_raw_parts(slice.as_ptr() as *mut Id, len, len) };
806
807 Ok(EncodableIds(vec))
808 }
809}
810
811#[cfg(all(test, feature = "self-contained"))]
812mod codec_tests {
813 use super::*;
814 use crate::base::types::Float;
815 use geo::{Coord, Geometry, LineString, MultiPolygon, Polygon};
816 use std::borrow::Cow;
817
818 fn roundtrip_string(s: &str) {
819 let cfg = get_global_bincode_config();
820 let original = EncodableString(Cow::Owned(s.to_string()));
821 let bytes = bincode::encode_to_vec(&original, cfg).unwrap();
822 let (decoded, _len): (EncodableString, usize) = bincode::decode_from_slice(&bytes, cfg).unwrap();
823 assert_eq!(decoded, original, "string roundtrip failed for {s:?}");
824 }
825
826 #[test]
827 fn string_roundtrips_ascii_empty_nonascii_and_alignment() {
828 roundtrip_string(""); roundtrip_string("America/Los_Angeles");
830 roundtrip_string("مصر"); roundtrip_string("abc"); roundtrip_string("abcd"); }
834
835 #[test]
836 fn option_string_roundtrips_none_and_some() {
837 let cfg = get_global_bincode_config();
838 for original in [EncodableOptionString(None), EncodableOptionString(Some(Cow::Owned("x".to_string())))] {
839 let bytes = bincode::encode_to_vec(&original, cfg).unwrap();
840 let (decoded, _len): (EncodableOptionString, usize) = bincode::decode_from_slice(&bytes, cfg).unwrap();
841 assert_eq!(decoded, original);
842 }
843 }
844
845 #[test]
846 fn ids_roundtrip_empty_and_many() {
847 let cfg = get_global_bincode_config();
848 for v in [Vec::<Id>::new(), vec![0u32, 1, 2, 4_000_000]] {
849 let original = EncodableIds(v.clone());
850 let bytes = bincode::encode_to_vec(&original, cfg).unwrap();
851 let (decoded, _len): (EncodableIds, usize) = bincode::decode_from_slice(&bytes, cfg).unwrap();
852 assert_eq!(decoded.0, v);
853 }
854 }
855
856 #[test]
857 fn geometry_roundtrips_polygon_with_interior_and_multipolygon() {
858 let cfg = get_global_bincode_config();
859 let exterior = LineString(vec![
860 Coord { x: 0.0, y: 0.0 },
861 Coord { x: 4.0, y: 0.0 },
862 Coord { x: 4.0, y: 4.0 },
863 Coord { x: 0.0, y: 4.0 },
864 Coord { x: 0.0, y: 0.0 },
865 ]);
866 let interior = LineString(vec![
867 Coord { x: 1.0, y: 1.0 },
868 Coord { x: 2.0, y: 1.0 },
869 Coord { x: 2.0, y: 2.0 },
870 Coord { x: 1.0, y: 1.0 },
871 ]);
872 let poly: Polygon<Float> = Polygon::new(exterior, vec![interior]);
873
874 let original = EncodableGeometry(Geometry::Polygon(poly.clone()));
875 let bytes = bincode::encode_to_vec(&original, cfg).unwrap();
876 let (decoded, _len): (EncodableGeometry, usize) = bincode::decode_from_slice(&bytes, cfg).unwrap();
877 assert_eq!(decoded.0, original.0);
878
879 let multi = EncodableGeometry(Geometry::MultiPolygon(MultiPolygon::new(vec![poly])));
880 let bytes = bincode::encode_to_vec(&multi, cfg).unwrap();
881 let (decoded, _len): (EncodableGeometry, usize) = bincode::decode_from_slice(&bytes, cfg).unwrap();
882 assert_eq!(decoded.0, multi.0);
883 }
884
885 #[test]
886 fn string_borrow_decode_matches_owned() {
887 let cfg = get_global_bincode_config();
894 let original = EncodableString(Cow::Owned("America/Los_Angeles".to_string()));
895 let bytes = bincode::encode_to_vec(&original, cfg).unwrap();
896 let (decoded, _len): (EncodableString, usize) = bincode::borrow_decode_from_slice(&bytes, cfg).unwrap();
897 assert_eq!(decoded.as_ref(), original.as_ref());
898 }
899}