Skip to main content

overpass_lib/
osm.rs

1use std::collections::HashMap;
2use serde::{Deserialize, Deserializer, Serialize, de::Visitor};
3
4/// The basic component of OpenStreetMap's data model. Comes in three variants: [Node], [Way], and [Relation].
5///
6/// [wiki](https://wiki.openstreetmap.org/wiki/Elements)
7#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
8#[serde(rename_all="lowercase", tag="type")]
9pub enum Element {
10    Node(Node),
11    Way(Way),
12    Relation(Relation),
13}
14
15/// The identifier of an [Element], independent of the specific variant.
16#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
17#[serde(rename_all = "lowercase", tag = "type", content = "ref")]
18pub enum ElementId {
19    Node(i64),
20    Way(i64),
21    Relation(i64),
22}
23
24impl Element {
25    /// The [ElementId] of this element.
26    pub fn id(&self) -> ElementId {
27        match self {
28            Self::Node(n) => ElementId::Node(n.id),
29            Self::Way(w) => ElementId::Way(w.id),
30            Self::Relation(r) => ElementId::Relation(r.id),
31        }
32    }
33
34    /// The value of this element's tag with the given name, if one exists.
35    pub fn tag(&self, name: &str) -> Option<&str> {
36        let tags = match self {
37            Self::Node(n) => &n.tags,
38            Self::Way(w) => &w.tags,
39            Self::Relation(r) => &r.tags,
40        };
41        tags.get(name).map(|s| s.as_str())
42    }
43
44    /// An iterator of tag values on this element, composed of key/value tuples.
45    pub fn tags(&self) -> impl ExactSizeIterator<Item=(&str, &str)> {
46        let tags = match self {
47            Self::Node(n) => &n.tags,
48            Self::Way(w) => &w.tags,
49            Self::Relation(r) => &r.tags,
50        };
51        tags.iter().map(|(k,v)| (k.as_str(), v.as_str()))
52    }
53}
54
55/// A node is one of the core elements in the OpenStreetMap data model.
56///
57/// [wiki](https://wiki.openstreetmap.org/wiki/Node)
58#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
59pub struct Node {
60    pub id: i64,
61    pub lat: f64,
62    pub lon: f64,
63    pub tags: HashMap<String, String>,
64}
65
66/// A way is one of the fundamental elements of the map.
67///
68/// [wiki](https://wiki.openstreetmap.org/wiki/Way)
69#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
70pub struct Way {
71    pub id: i64,
72    pub tags: HashMap<String, String>,
73    pub nodes: Vec<i64>,
74}
75
76/// Relations are structured collections of objects - nodes, ways, and other relations.
77///
78/// [wiki](https://wiki.openstreetmap.org/wiki/Relation)
79#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
80pub struct Relation {
81    pub id: i64,
82    pub tags: HashMap<String, String>,
83    pub members: Vec<RelationMember>,
84}
85
86/// A reference to another [Node], [Way], or [Relation] from the owning relation, with an optional role.
87#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
88pub struct RelationMember {
89    #[serde(flatten)]
90    pub id: ElementId,
91    #[serde(deserialize_with = "skip_empty")]
92    pub role: Option<String>,
93}
94
95fn skip_empty<'de, D>(deserializer: D) -> Result<Option<String>, D::Error> where D: Deserializer<'de> {
96    deserializer.deserialize_string(OptionalStringVisitor)
97}
98
99struct OptionalStringVisitor;
100impl<'de> Visitor<'de> for OptionalStringVisitor {
101    type Value = Option<String>;
102
103    fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
104        write!(formatter, "a string")
105    }
106
107    fn visit_string<E>(self, v: String) -> Result<Self::Value, E> where E: serde::de::Error {
108        if v.is_empty() {
109            Ok(None)
110        } else {
111            Ok(Some(v))
112        }
113    }
114}
115
116#[cfg(test)]
117mod test {
118    use super::*;
119
120    #[test]
121    fn id() {
122        let a = ElementId::Node(123);
123        let str = serde_json::to_string(&a).unwrap();
124        assert_eq!(&str, r#"{"type":"node","ref":123}"#);
125        let b: ElementId = serde_json::from_str(&str).unwrap();
126        assert_eq!(a, b);
127    }
128}