egml_core/model/geometry/
abstract_geometry.rs1use crate::model::base::{AbstractGml, AsAbstractGml, AsAbstractGmlMut};
2use crate::model::geometry::SrsReferenceGroup;
3
4#[derive(Debug, Clone, PartialEq, Eq, Hash, Default)]
14pub struct AbstractGeometry {
15 pub abstract_gml: AbstractGml,
16 srs_reference_group: Option<Box<SrsReferenceGroup>>,
19}
20
21impl AbstractGeometry {
22 pub fn new() -> Self {
24 Self {
25 abstract_gml: AbstractGml::default(),
26 srs_reference_group: None,
27 }
28 }
29
30 pub fn from_abstract_gml(abstract_gml: AbstractGml) -> Self {
31 Self {
32 abstract_gml,
33 srs_reference_group: None,
34 }
35 }
36
37 fn update_srs_reference_group(&mut self, update: impl FnOnce(&mut SrsReferenceGroup)) {
40 let group = self.srs_reference_group.get_or_insert_with(Box::default);
41 update(group);
42 if group.is_empty() {
43 self.srs_reference_group = None;
44 }
45 }
46}
47
48pub trait AsAbstractGeometry: AsAbstractGml {
50 fn abstract_geometry(&self) -> &AbstractGeometry;
52
53 fn srs_reference_group(&self) -> Option<&SrsReferenceGroup> {
55 self.abstract_geometry().srs_reference_group.as_deref()
56 }
57
58 fn srs_name(&self) -> Option<&str> {
59 self.srs_reference_group()
60 .and_then(SrsReferenceGroup::srs_name)
61 }
62
63 fn srs_dimension(&self) -> Option<u32> {
64 self.srs_reference_group()
65 .and_then(SrsReferenceGroup::srs_dimension)
66 }
67}
68
69pub trait AsAbstractGeometryMut: AsAbstractGeometry + AsAbstractGmlMut {
71 fn abstract_geometry_mut(&mut self) -> &mut AbstractGeometry;
73
74 fn set_srs_reference_group(&mut self, srs_reference_group: SrsReferenceGroup) {
76 self.abstract_geometry_mut().srs_reference_group =
77 (!srs_reference_group.is_empty()).then(|| Box::new(srs_reference_group));
78 }
79
80 fn clear_srs_reference_group(&mut self) {
82 self.abstract_geometry_mut().srs_reference_group = None;
83 }
84
85 fn set_srs_name(&mut self, srs_name: impl Into<String>) {
86 self.abstract_geometry_mut()
87 .update_srs_reference_group(|group| group.set_srs_name(srs_name));
88 }
89
90 fn set_srs_name_opt(&mut self, srs_name: Option<String>) {
91 self.abstract_geometry_mut()
92 .update_srs_reference_group(|group| group.set_srs_name_opt(srs_name));
93 }
94
95 fn clear_srs_name(&mut self) {
96 self.abstract_geometry_mut()
97 .update_srs_reference_group(SrsReferenceGroup::clear_srs_name);
98 }
99
100 fn set_srs_dimension(&mut self, srs_dimension: u32) {
101 self.abstract_geometry_mut()
102 .update_srs_reference_group(|group| group.set_srs_dimension(srs_dimension));
103 }
104
105 fn set_srs_dimension_opt(&mut self, srs_dimension: Option<u32>) {
106 self.abstract_geometry_mut()
107 .update_srs_reference_group(|group| group.set_srs_dimension_opt(srs_dimension));
108 }
109
110 fn clear_srs_dimension(&mut self) {
111 self.abstract_geometry_mut()
112 .update_srs_reference_group(SrsReferenceGroup::clear_srs_dimension);
113 }
114}
115
116impl AsAbstractGeometry for AbstractGeometry {
117 fn abstract_geometry(&self) -> &AbstractGeometry {
118 self
119 }
120}
121
122impl AsAbstractGeometryMut for AbstractGeometry {
123 fn abstract_geometry_mut(&mut self) -> &mut AbstractGeometry {
124 self
125 }
126}
127
128#[macro_export]
129macro_rules! impl_abstract_geometry_traits {
130 ($type:ty) => {
131 $crate::impl_abstract_gml_traits!($type);
132
133 impl $crate::model::base::AsAbstractGml for $type {
134 fn abstract_gml(&self) -> &$crate::model::base::AbstractGml {
135 &<$type as $crate::model::geometry::AsAbstractGeometry>::abstract_geometry(self)
136 .abstract_gml
137 }
138 }
139 };
140}
141
142#[macro_export]
143macro_rules! impl_abstract_geometry_mut_traits {
144 ($type:ty) => {
145 $crate::impl_abstract_gml_mut_traits!($type);
146
147 impl $crate::model::base::AsAbstractGmlMut for $type {
148 fn abstract_gml_mut(&mut self) -> &mut $crate::model::base::AbstractGml {
149 &mut <$type as $crate::model::geometry::AsAbstractGeometryMut>::abstract_geometry_mut(self)
150 .abstract_gml
151 }
152 }
153 };
154}
155
156impl_abstract_geometry_traits!(AbstractGeometry);
157impl_abstract_geometry_mut_traits!(AbstractGeometry);
158
159#[cfg(test)]
160mod tests {
161 use super::*;
162
163 #[test]
164 fn srs_attributes_are_not_allocated_by_default() {
165 let geometry = AbstractGeometry::new();
166 assert!(geometry.srs_reference_group().is_none());
167 assert_eq!(geometry.srs_name(), None);
168 assert_eq!(geometry.srs_dimension(), None);
169 }
170
171 #[test]
172 fn setting_srs_attributes_allocates_and_reads_back() {
173 let mut geometry = AbstractGeometry::new();
174 geometry.set_srs_name("EPSG:25832");
175 geometry.set_srs_dimension(3);
176
177 assert_eq!(geometry.srs_name(), Some("EPSG:25832"));
178 assert_eq!(geometry.srs_dimension(), Some(3));
179 }
180
181 #[test]
182 fn clearing_both_srs_attributes_drops_the_allocation() {
183 let mut geometry = AbstractGeometry::new();
184 geometry.set_srs_name("EPSG:25832");
185 geometry.set_srs_dimension(3);
186
187 geometry.clear_srs_name();
188 assert!(geometry.srs_reference_group().is_some());
189 assert_eq!(geometry.srs_dimension(), Some(3));
190
191 geometry.set_srs_dimension_opt(None);
192 assert!(geometry.srs_reference_group().is_none());
193 assert_eq!(geometry, AbstractGeometry::new());
194 }
195
196 #[test]
197 fn setting_an_empty_group_stores_none() {
198 let mut geometry = AbstractGeometry::new();
199 geometry.set_srs_name("EPSG:25832");
200
201 geometry.set_srs_reference_group(SrsReferenceGroup::new());
202
203 assert!(geometry.srs_reference_group().is_none());
204 assert_eq!(geometry, AbstractGeometry::new());
205 }
206
207 #[test]
208 fn clearing_unset_attributes_does_not_allocate() {
209 let mut geometry = AbstractGeometry::new();
210 geometry.clear_srs_name();
211 geometry.set_srs_name_opt(None);
212 assert!(geometry.srs_reference_group().is_none());
213 }
214}