ogcapi_types/common/
extent.rs

1use chrono::{DateTime, SecondsFormat, Utc};
2use serde::{Deserialize, Serialize, ser::SerializeSeq, ser::Serializer};
3use serde_with::DisplayFromStr;
4
5use crate::common::{Bbox, Crs};
6
7#[serde_with::skip_serializing_none]
8#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
9pub struct Extent {
10    pub spatial: Option<SpatialExtent>,
11    pub temporal: Option<TemporalExtent>,
12}
13
14impl Default for Extent {
15    fn default() -> Self {
16        Self {
17            spatial: Some(SpatialExtent::default()),
18            temporal: Some(TemporalExtent::default()),
19        }
20    }
21}
22
23#[serde_with::serde_as]
24#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
25pub struct SpatialExtent {
26    #[serde(skip_serializing_if = "Vec::is_empty")]
27    pub bbox: Vec<Bbox>,
28    #[serde(default)]
29    #[serde_as(as = "DisplayFromStr")]
30    pub crs: Crs,
31}
32
33impl Default for SpatialExtent {
34    fn default() -> Self {
35        Self {
36            bbox: vec![Bbox::Bbox2D([-180.0, -90.0, 180.0, 90.0])],
37            crs: Default::default(),
38        }
39    }
40}
41
42#[serde_with::serde_as]
43#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
44pub struct TemporalExtent {
45    #[serde(skip_serializing_if = "Vec::is_empty")]
46    #[serde(serialize_with = "serialize_interval")]
47    pub interval: Vec<Vec<Option<DateTime<Utc>>>>,
48    #[serde(default = "default_trs")]
49    pub trs: String,
50}
51
52impl Default for TemporalExtent {
53    fn default() -> Self {
54        Self {
55            interval: vec![vec![None, None]],
56            trs: default_trs(),
57        }
58    }
59}
60
61fn serialize_interval<S>(
62    interval: &Vec<Vec<Option<DateTime<Utc>>>>,
63    serializer: S,
64) -> Result<S::Ok, S::Error>
65where
66    S: Serializer,
67{
68    let mut outer_seq = serializer.serialize_seq(Some(interval.len()))?;
69    for inner_vec in interval {
70        let serialized_inner_vec: Vec<_> = inner_vec
71            .iter()
72            .map(|item| {
73                item.as_ref()
74                    .map(|dt| dt.to_rfc3339_opts(SecondsFormat::Secs, true))
75            })
76            .collect();
77
78        outer_seq.serialize_element(&serialized_inner_vec)?;
79    }
80    outer_seq.end()
81}
82
83fn default_trs() -> String {
84    "http://www.opengis.net/def/uom/ISO-8601/0/Gregorian".to_string()
85}