1use core::fmt;
2
3pub(crate) const COORD_SIZE_IN_BYTES: usize = std::mem::size_of::<f64>() * 2;
4pub(crate) const COORD_SIZE_IN_FLOATS: usize = 2;
5
6#[repr(transparent)]
7pub struct Coord {
8 data: [f64],
9}
10
11impl<'a> Coord {
12 pub fn from_bytes(data: &'a [u8]) -> &'a Self {
13 debug_assert_eq!(
14 data.len(),
15 COORD_SIZE_IN_BYTES,
16 "Bad number of bytes: `{}`, expected `{COORD_SIZE_IN_BYTES}`",
17 data.len()
18 );
19 debug_assert!(
20 data.as_ptr() as usize % std::mem::align_of::<f64>() == 0,
21 "data is not aligned"
22 );
23 unsafe { std::mem::transmute(data) }
24 }
25
26 pub fn from_slice(data: &[f64]) -> &Self {
27 debug_assert_eq!(data.len(), 2);
28 unsafe { std::mem::transmute(data) }
29 }
30
31 pub fn from_slice_mut(data: &mut [f64]) -> &mut Self {
32 debug_assert_eq!(data.len(), 2);
33 unsafe { std::mem::transmute(data) }
34 }
35
36 pub fn lng(&self) -> f64 {
37 self.data[0]
38 }
39
40 pub fn lng_mut(&mut self) -> &mut f64 {
41 &mut self.data[0]
42 }
43
44 pub fn lat(&self) -> f64 {
45 self.data[1]
46 }
47
48 pub fn lat_mut(&mut self) -> &mut f64 {
49 &mut self.data[1]
50 }
51
52 pub fn x(&self) -> f64 {
53 self.lng()
54 }
55
56 pub fn y(&self) -> f64 {
57 self.lat()
58 }
59
60 pub fn to_geo(&self) -> geo_types::Coord<f64> {
61 geo_types::Coord {
62 x: self.lng(),
63 y: self.lat(),
64 }
65 }
66}
67
68impl fmt::Debug for Coord {
69 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
70 f.debug_struct("Coord")
71 .field("x", &self.lng())
72 .field("y", &self.lat())
73 .finish()
74 }
75}
76
77#[cfg(test)]
78mod tests {
79 use bytemuck::cast_slice;
80
81 use super::*;
82
83 #[test]
84 fn test_basic_create_coord_from_bytes() {
85 let data = [1.0, 2.0];
86 let coord = Coord::from_bytes(cast_slice(&data));
87 assert_eq!(coord.lng(), 1.0);
88 assert_eq!(coord.lat(), 2.0);
89 }
90
91 #[test]
92 #[should_panic]
93 fn test_coord_panic_on_too_short_bytes() {
94 let data = [1.0];
95 Coord::from_bytes(cast_slice(&data));
96 }
97 #[test]
98 #[should_panic]
99 fn test_coord_panic_on_too_long_bytes() {
100 let data = [1.0, 2.0, 3.0];
101 Coord::from_bytes(cast_slice(&data));
102 }
103
104 #[test]
105 #[should_panic]
106 fn test_coord_panic_on_unaligned_bytes() {
107 let data = [1.0, 2.0, 3.0];
108 Coord::from_bytes(&cast_slice(&data)[1..]);
109 }
110
111 #[test]
112 #[should_panic]
113 fn test_coord_panic_on_too_short_slice() {
114 let data = [1.0];
115 Coord::from_bytes(cast_slice(&data));
116 }
117
118 #[test]
119 #[should_panic]
120 fn test_coord_panic_on_too_long_slice() {
121 let data = [1.0, 2.0, 3.0];
122 Coord::from_bytes(cast_slice(&data));
123 }
124
125 #[test]
126 fn debug_impl_support_precision_settings() {
127 let data = [1.123456789, 2.987654321];
128 let coord = Coord::from_bytes(cast_slice(&data));
129 insta::assert_snapshot!(format!("{:.2?}", coord), @"Coord { x: 1.12, y: 2.99 }");
130 }
131}