osm_types/
lib.rs

1use chrono::NaiveDateTime;
2use fnv::FnvHashMap as HashMap;
3use kstring::KString;
4use rust_decimal::Decimal;
5
6/// Fundamental representation of geographical features in OpenStreetMap
7///
8/// <https://wiki.openstreetmap.org/wiki/Elements>
9#[derive(Debug, PartialEq, Eq, Clone)]
10#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
11pub enum Element {
12    Node(Node),
13    Way(Way),
14    Relation(Relation),
15}
16
17impl Element {
18    pub fn id(&self) -> Id {
19        match self {
20            Element::Node(Node { id, .. })
21            | Element::Way(Way { id, .. })
22            | Element::Relation(Relation { id, .. }) => *id,
23        }
24    }
25
26    pub fn tags(&self) -> &HashMap<KString, KString> {
27        match self {
28            Element::Node(Node { tags, .. })
29            | Element::Way(Way { tags, .. })
30            | Element::Relation(Relation { tags, .. }) => tags,
31        }
32    }
33
34    pub fn info(&self) -> Option<&Info> {
35        match self {
36            Element::Node(Node { info, .. })
37            | Element::Way(Way { info, .. })
38            | Element::Relation(Relation { info, .. }) => info.as_ref(),
39        }
40    }
41
42    /// Removes [Info] if present
43    pub fn strip_info(&mut self) {
44        let info = match self {
45            Element::Node(Node { info, .. })
46            | Element::Way(Way { info, .. })
47            | Element::Relation(Relation { info, .. }) => info,
48        };
49        *info = None;
50    }
51
52    pub fn as_node(&self) -> Option<&Node> {
53        if let Element::Node(n) = self {
54            Some(n)
55        } else {
56            None
57        }
58    }
59
60    pub fn as_way(&self) -> Option<&Way> {
61        if let Element::Way(w) = self {
62            Some(w)
63        } else {
64            None
65        }
66    }
67
68    pub fn as_relation(&self) -> Option<&Relation> {
69        if let Element::Relation(r) = self {
70            Some(r)
71        } else {
72            None
73        }
74    }
75}
76
77/// [Element] identifier
78#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Hash)]
79#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
80pub struct Id(pub i64);
81
82/// Single point in space
83///
84/// <https://wiki.openstreetmap.org/wiki/Node>
85#[derive(Debug, PartialEq, Eq, Clone)]
86#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
87pub struct Node {
88    pub id: Id,
89    pub tags: HashMap<KString, KString>,
90    pub info: Option<Info>,
91    /// [WGS 84](https://en.wikipedia.org/wiki/World_Geodetic_System#WGS84) latitude (y)
92    pub lat: Decimal,
93    /// [WGS 84](https://en.wikipedia.org/wiki/World_Geodetic_System#WGS84) longitude (x)
94    pub lon: Decimal,
95}
96
97impl Node {
98    /// Removes [Info] if present
99    pub fn strip_info(&mut self) {
100        self.info = None;
101    }
102}
103
104/// Ordered list of [Node]s
105///
106/// <https://wiki.openstreetmap.org/wiki/Way>
107#[derive(Debug, PartialEq, Eq, Clone)]
108#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
109pub struct Way {
110    pub id: Id,
111    pub tags: HashMap<KString, KString>,
112    pub info: Option<Info>,
113
114    /// Nodes in the way
115    ///
116    /// In an [open way](https://wiki.openstreetmap.org/wiki/Way#Open_way_%28open_polyline%29), the first and last nodes differ.
117    /// In a [closed way](https://wiki.openstreetmap.org/wiki/Way#Closed_way_%28closed_polyline%29), the first and last nodes are identical.
118    pub refs: Vec<Id>,
119}
120
121impl Way {
122    /// Removes [Info] if present
123    pub fn strip_info(&mut self) {
124        self.info = None;
125    }
126}
127
128/// Ordered list of [Element]s
129///
130/// This is a logical representation
131/// <https://wiki.openstreetmap.org/wiki/Relation>
132#[derive(Debug, PartialEq, Eq, Clone)]
133#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
134pub struct Relation {
135    pub id: Id,
136    pub tags: HashMap<KString, KString>,
137    pub info: Option<Info>,
138    /// There should be no more than 300 members per relation, with a hard limit of 32,000
139    ///
140    /// <https://wiki.openstreetmap.org/wiki/Relation#Size>
141    pub members: Vec<Member>,
142}
143
144impl Relation {
145    /// Removes [Info] if present
146    pub fn strip_info(&mut self) {
147        self.info = None;
148    }
149}
150
151/// [Element] in a [Relation]
152#[derive(Debug, PartialEq, Eq, Clone, Hash)]
153#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
154pub struct Member {
155    pub id: Id,
156    pub ty: MemberType,
157    /// Describes the function of this member in its relation
158    ///
159    /// <https://wiki.openstreetmap.org/wiki/Relation#Roles>
160    pub role: Option<KString>,
161}
162
163/// Type of [Element] represented by [Member]
164#[derive(Debug, PartialEq, Eq, Clone, Hash)]
165#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
166pub enum MemberType {
167    Node,
168    Way,
169    Relation,
170}
171
172/// Non-geographical information about a [Element]
173///
174/// <https://wiki.openstreetmap.org/wiki/Elements#Common_attributes>
175#[derive(Debug, PartialEq, Eq, Clone, Hash)]
176#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
177pub struct Info {
178    /// Version number of this revision of the [Element]
179    ///
180    /// Starts at 1 and incremented with each update
181    pub version: i32,
182    /// Time of last modification
183    pub timestamp: Option<NaiveDateTime>,
184    /// Group of edits that this version belongs to
185    ///
186    /// <https://wiki.openstreetmap.org/wiki/Changeset>
187    pub changeset: Option<i64>,
188    /// ID of user who performed the last modification
189    pub uid: Option<i32>,
190    /// Display name of the user
191    ///
192    /// This will change without a version increment if the user modifies their display name.
193    pub user: Option<KString>,
194    /// Whether a [Element] is visible or not
195    ///
196    /// Assume this to be true if it is [None]. If [Some(false)], the [Element] was deleted
197    /// and was returned by a history call.
198    pub visible: Option<bool>,
199}