ogcapi_types/common/
bbox.rs1use std::{fmt, str};
2
3use serde::{Deserialize, Serialize};
4
5type Bbox2D = [f64; 4];
6type Bbox3D = [f64; 6];
7
8#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
9#[serde(untagged)]
10pub enum Bbox {
11 Bbox2D(Bbox2D),
12 Bbox3D(Bbox3D),
13}
14
15impl fmt::Display for Bbox {
16 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
17 match self {
18 Bbox::Bbox2D(bbox) => write!(f, "{},{},{},{}", bbox[0], bbox[1], bbox[2], bbox[3]),
19 Bbox::Bbox3D(bbox) => {
20 write!(
21 f,
22 "{},{},{},{},{},{}",
23 bbox[0], bbox[1], bbox[2], bbox[3], bbox[4], bbox[5]
24 )
25 }
26 }
27 }
28}
29
30impl From<[f64; 4]> for Bbox {
31 fn from(slice: [f64; 4]) -> Self {
32 Bbox::Bbox2D(slice)
33 }
34}
35
36impl From<[f64; 6]> for Bbox {
37 fn from(slice: [f64; 6]) -> Self {
38 Bbox::Bbox3D(slice)
39 }
40}
41
42impl str::FromStr for Bbox {
43 type Err = &'static str;
44
45 fn from_str(s: &str) -> Result<Self, Self::Err> {
46 let numbers: Vec<f64> = s
47 .split(',')
48 .map(|d| d.trim().parse::<f64>())
49 .collect::<Result<Vec<f64>, std::num::ParseFloatError>>()
50 .map_err(|_| "Unable to convert bbox coordinates to float")?;
51
52 match numbers.len() {
53 4 => Ok(Bbox::Bbox2D([
54 numbers[0], numbers[1], numbers[2], numbers[3],
55 ])),
56 6 => Ok(Bbox::Bbox3D([
57 numbers[0], numbers[1], numbers[2], numbers[3], numbers[4], numbers[5],
58 ])),
59 _ => Err("Expected 4 or 6 numbers"),
60 }
61 }
62}
63
64impl TryFrom<&[f64]> for Bbox {
65 type Error = &'static str;
66
67 fn try_from(value: &[f64]) -> Result<Self, Self::Error> {
68 match value.len() {
69 4 => Ok(Bbox::Bbox2D([value[0], value[1], value[2], value[3]])),
70 6 => Ok(Bbox::Bbox3D([
71 value[0], value[1], value[2], value[3], value[4], value[5],
72 ])),
73 _ => Err("Bbox can only be of lenth 4 or 6!"),
74 }
75 }
76}
77
78#[cfg(test)]
79mod tests {
80 use std::str::FromStr;
81
82 use super::*;
83
84 #[test]
85 fn from() {
86 let numbers = [160.6, -55.95, -170.0, -25.89];
87 let _bbox: Bbox = numbers.into();
88 }
89
90 #[test]
91 fn try_from() {
92 let numbers = &[160.6, -55.95, -170.0, -25.89];
93 let _bbox: Bbox = numbers.as_slice().try_into().unwrap();
94 }
95
96 #[test]
97 fn from_str() {
98 let s = "160.6,-55.95, -170, -25.89";
99 let _bbox: Bbox = Bbox::from_str(s).unwrap();
100 }
101
102 #[test]
103 fn serde_json() {
104 let s = "[ 160.6, -55.95, -170, -25.89 ]";
105 let bbox: Bbox = serde_json::from_str(s).unwrap();
106
107 match bbox {
108 Bbox::Bbox2D { .. } => {}
109 Bbox::Bbox3D { .. } => panic!("expected bbox to be 2 dimensional"),
110 }
111 assert_eq!(
112 "[160.6,-55.95,-170.0,-25.89]",
113 serde_json::to_string(&bbox).unwrap()
114 );
115 }
116}