1#![warn(explicit_outlives_requirements)]
6#![warn(missing_abi)]
7#![deny(non_ascii_idents)]
8#![warn(trivial_casts)]
9#![warn(unreachable_pub)]
10#![deny(unsafe_code)]
11#![deny(unsafe_op_in_unsafe_fn)]
12#![warn(unused_lifetimes)]
14#![warn(unused_qualifications)]
15#![warn(clippy::pedantic, clippy::cargo)]
17#![allow(clippy::missing_panics_doc)]
18#![allow(clippy::cargo_common_metadata)]
19#![warn(
20 clippy::allow_attributes_without_reason,
21 clippy::as_conversions,
22 clippy::clone_on_ref_ptr,
23 clippy::create_dir,
24 clippy::dbg_macro,
25 clippy::decimal_literal_representation,
26 clippy::default_numeric_fallback,
27 clippy::deref_by_slicing,
28 clippy::empty_structs_with_brackets,
29 clippy::float_cmp_const,
30 clippy::fn_to_numeric_cast_any,
31 clippy::if_then_some_else_none,
32 clippy::indexing_slicing,
33 clippy::let_underscore_must_use,
34 clippy::map_err_ignore,
35 clippy::print_stderr,
36 clippy::print_stdout,
37 clippy::single_char_lifetime_names,
38 clippy::str_to_string,
39 clippy::string_add,
40 clippy::string_slice,
41 clippy::string_to_string,
42 clippy::todo,
43 clippy::try_err,
44 clippy::unseparated_literal_suffix,
45 clippy::use_debug
46)]
47
48use std::borrow::Borrow;
49use std::collections::btree_map::Entry;
50use std::collections::BTreeMap;
51use std::hash::Hash;
52use std::str::FromStr;
53
54mod key;
55pub use key::TagKey;
56
57mod val;
58pub use val::TagVal;
59
60#[derive(Debug, Clone)]
61pub struct DuplicateKeyError(TagKey);
62
63impl From<String> for DuplicateKeyError {
64 fn from(string: String) -> Self {
65 DuplicateKeyError(TagKey::from(&string))
66 }
67}
68
69impl std::fmt::Display for DuplicateKeyError {
70 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
71 write!(f, "duplicate tag key {}", self.0.as_str())
72 }
73}
74
75impl std::error::Error for DuplicateKeyError {}
76
77#[derive(Clone, Debug, Default)]
85pub struct Tags {
86 map: BTreeMap<TagKey, TagVal>,
87}
88
89impl Tags {
90 pub fn from_pairs<I, K, V>(tags: I) -> Result<Self, DuplicateKeyError>
97 where
98 I: IntoIterator<Item = (K, V)>,
99 K: Into<TagKey>,
100 V: Into<TagVal>,
101 {
102 let mut map: BTreeMap<TagKey, TagVal> = BTreeMap::new();
103 for tag_pair in tags {
104 let key: TagKey = tag_pair.0.into();
105 let val: TagVal = tag_pair.1.into();
106 match map.entry(key) {
108 Entry::Vacant(entry) => entry.insert(val),
109 Entry::Occupied(entry) => return Err(DuplicateKeyError(entry.remove_entry().0)),
110 };
111 }
112 Ok(Self { map })
113 }
114
115 #[must_use]
117 pub fn from_pair<K, V>(key: K, val: V) -> Self
118 where
119 K: Into<TagKey>,
120 V: Into<TagVal>,
121 {
122 let mut map = BTreeMap::default();
123 let duplicate_val = map.insert(key.into(), val.into());
124 debug_assert!(duplicate_val.is_none());
125 Self { map }
126 }
127
128 #[must_use]
130 pub fn is_empty(&self) -> bool {
131 self.map.is_empty()
132 }
133
134 #[must_use]
136 pub fn to_str_pairs(&self) -> Vec<(&str, &str)> {
137 self.map
138 .iter()
139 .map(|(k, v)| (k.as_str(), v.as_str()))
140 .collect()
141 }
142
143 #[must_use]
145 pub fn to_vec(&self) -> Vec<String> {
146 let pairs = self.to_str_pairs();
147 pairs
148 .into_iter()
149 .map(|(key, val)| format!("{key}={val}"))
150 .collect()
151 }
152
153 pub fn get<Q>(&self, q: &Q) -> Option<&str>
155 where
156 TagKey: Borrow<Q>,
157 Q: Ord + Hash + Eq + ?Sized,
158 {
159 self.map.get(q).map(TagVal::as_str)
160 }
161
162 #[must_use]
165 pub fn is<Q>(&self, q: &Q, v: &str) -> bool
166 where
167 TagKey: Borrow<Q>,
168 Q: Ord + Hash + Eq + ?Sized,
169 {
170 self.get(q) == Some(v)
171 }
172
173 #[must_use]
176 pub fn is_any<Q>(&self, q: &Q, values: &[&str]) -> bool
177 where
178 TagKey: Borrow<Q>,
179 Q: Ord + Hash + Eq + ?Sized,
180 {
181 if let Some(v) = self.get(q) {
182 values.contains(&v)
183 } else {
184 false
185 }
186 }
187
188 #[must_use]
190 pub fn subset<'any, I, Q, O>(&self, keys: I) -> Self
191 where
192 I: IntoIterator<Item = &'any Q>,
193 TagKey: Borrow<Q>,
194 Q: 'any + Ord + Hash + Eq + ?Sized + ToOwned<Owned = O>,
195 O: Into<TagKey>,
196 {
197 let mut map = Self::default();
198 for key in keys {
199 if let Some(val) = self.get(key) {
200 let owned: O = key.to_owned();
201 let insert = map.checked_insert(owned.into(), TagVal::from(val));
202 debug_assert!(insert.is_ok());
203 }
204 }
205 map
206 }
207
208 pub fn pairs_with_stem<Q>(&self, q: &Q) -> Vec<(&str, &str)>
210 where
211 Q: AsRef<str> + ?Sized,
212 {
213 self.map
214 .iter()
215 .filter_map(|(key, val)| {
216 key.as_str()
217 .starts_with(q.as_ref())
218 .then(|| (key.as_str(), val.as_str()))
219 })
220 .collect()
221 }
222
223 pub fn checked_insert<K: Into<TagKey>, V: Into<TagVal>>(
228 &mut self,
229 key: K,
230 val: V,
231 ) -> Result<(), DuplicateKeyError> {
232 let key: TagKey = key.into();
233 match self.map.entry(key) {
235 Entry::Vacant(entry) => entry.insert(val.into()),
236 Entry::Occupied(entry) => return Err(DuplicateKeyError(entry.remove_entry().0)),
237 };
238 Ok(())
239 }
240}
241
242#[derive(Debug)]
243pub enum ParseTagsError {
244 MissingEquals(String),
245 DuplicateKey(DuplicateKeyError),
246}
247
248impl std::fmt::Display for ParseTagsError {
249 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
250 match self {
251 Self::MissingEquals(_val) => write!(f, "tag must be = separated"),
252 Self::DuplicateKey(duplicate_key_err) => duplicate_key_err.fmt(f),
253 }
254 }
255}
256
257impl std::error::Error for ParseTagsError {}
258
259impl FromStr for Tags {
260 type Err = ParseTagsError;
261
262 fn from_str(s: &str) -> Result<Self, Self::Err> {
271 let tags = s
272 .lines()
273 .map(|line| {
274 let (key, val) = line
275 .split_once('=')
276 .ok_or_else(|| ParseTagsError::MissingEquals(line.to_owned()))?;
277 Ok((key.to_owned(), val.to_owned()))
278 })
279 .collect::<Result<Vec<(String, String)>, Self::Err>>()?;
280 Self::from_pairs(tags).map_err(ParseTagsError::DuplicateKey)
281 }
282}
283
284impl ToString for Tags {
285 fn to_string(&self) -> String {
295 self.to_vec().as_slice().join("\n")
296 }
297}
298
299#[cfg(feature = "serde")]
301struct TagsVisitor {
302 marker: std::marker::PhantomData<fn() -> Tags>,
303}
304
305#[cfg(feature = "serde")]
306impl TagsVisitor {
307 fn new() -> Self {
308 TagsVisitor {
309 marker: std::marker::PhantomData,
310 }
311 }
312}
313
314#[cfg(feature = "serde")]
316impl<'de> serde::de::Visitor<'de> for TagsVisitor {
317 type Value = Tags;
318 fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
319 formatter.write_str("OSM Tags as Map")
320 }
321 fn visit_map<M>(self, mut access: M) -> Result<Self::Value, M::Error>
322 where
323 M: serde::de::MapAccess<'de>,
324 {
325 let mut tags = Tags::default();
326 while let Some((key, value)) = access.next_entry::<String, String>()? {
327 let _ignored = tags.checked_insert(&key, value);
329 }
330 Ok(tags)
331 }
332}
333
334#[cfg(feature = "serde")]
336impl<'de> serde::Deserialize<'de> for Tags {
337 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
338 where
339 D: serde::de::Deserializer<'de>,
340 {
341 deserializer.deserialize_map(TagsVisitor::new())
344 }
345}
346
347#[cfg(feature = "serde")]
348impl serde::Serialize for Tags {
349 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
350 where
351 S: serde::Serializer,
352 {
353 use serde::ser::SerializeMap;
354 let mut map = serializer.serialize_map(Some(self.map.len()))?;
355 for (k, v) in &self.map {
356 map.serialize_entry(k.as_str(), v.as_str())?;
357 }
358 map.end()
359 }
360}
361
362#[cfg(test)]
363mod tests {
364 use crate::{DuplicateKeyError, TagKey, Tags};
365
366 #[test]
367 fn test_tags() {
368 let tags = Tags::from_pairs([
369 ("foo", "bar"),
370 ("abra", "cadabra"),
371 ("foo:multi:key", "value"),
372 ("multivalue", "apple;banana;chocolate covered capybara"),
373 ])
374 .unwrap();
375 assert_eq!(
376 tags.to_vec(),
377 vec![
378 "abra=cadabra",
379 "foo=bar",
380 "foo:multi:key=value",
381 "multivalue=apple;banana;chocolate covered capybara"
382 ]
383 );
384
385 let tags_str = "{\"abra\":\"cadabra\",\"foo\":\"bar\",\"foo:multi:key\":\"value\",\"multivalue\":\"apple;banana;chocolate covered capybara\"}";
387 assert_eq!(serde_json::to_string(&tags).unwrap(), tags_str);
388 let de_tags: Tags = serde_json::from_str(tags_str).unwrap();
389 assert_eq!(de_tags.to_str_pairs(), tags.to_str_pairs());
390
391 let mut other_tags = tags.clone();
393 assert!(other_tags.checked_insert("new", "val").is_ok());
394 assert!(matches!(
395 other_tags.checked_insert("foo", "bar").unwrap_err(),
396 DuplicateKeyError(_),
397 ));
398 assert!(other_tags
399 .checked_insert(String::from("owned"), "val")
400 .is_ok());
401
402 assert_eq!(tags.get("foo"), Some("bar"));
404 assert_eq!(tags.get("bar"), None);
405 assert!(tags.is("foo", "bar"));
406 assert!(!tags.is("foo", "foo"));
407 assert!(!tags.is("bar", "foo"));
408 assert!(tags.is_any("foo", &["bar"]));
409 assert!(tags.is_any("foo", &["foo", "bar"]));
410 assert!(!tags.is_any("foo", &["foo"]));
411 assert!(!tags.is_any("bar", &["foo", "bar"]));
412 assert_eq!(tags.subset(["foo"]).to_vec(), vec!["foo=bar"]);
413 assert_eq!(
414 tags.subset(["foo", "abra"]).to_vec(),
415 vec!["abra=cadabra", "foo=bar"]
416 );
417 assert_eq!(tags.subset(["foo", "bar"]).to_vec(), vec!["foo=bar"]);
418 assert!(tags.subset(["bar"]).to_vec().is_empty());
419
420 const FOO_KEY: TagKey = TagKey::from_static("foo");
422 assert_eq!(tags.get(&FOO_KEY), Some("bar"));
423 assert_eq!(tags.get(&TagKey::from_static("bar")), None);
424 assert!(tags.is(&FOO_KEY, "bar"));
425 assert!(!tags.is(&FOO_KEY, "foo"));
426 assert_eq!(tags.subset(&[FOO_KEY]).to_vec(), vec!["foo=bar"]);
427 dbg!(&(FOO_KEY + "multi" + "key"));
428 assert!(tags.is(&(FOO_KEY + "multi" + "key"), "value"));
429 let foo_key = FOO_KEY + "multi" + "key";
430 assert!(tags.is(&foo_key, "value"));
431
432 assert_eq!(tags.pairs_with_stem(&FOO_KEY).len(), 2);
434 assert_eq!(tags.pairs_with_stem(&(FOO_KEY + "multi")).len(), 1);
435
436 }
438}