use log::debug;
use std::str::FromStr;
use chrono::{DateTime, Utc};
use serde::{Deserialize, Deserializer, Serialize};
use serde_json::Value;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Node {
#[serde(rename = "@id")]
pub id: i64,
#[serde(rename = "@lat")]
pub lat: f64,
#[serde(rename = "@lon")]
pub lon: f64,
#[serde(rename = "tag", default)]
pub tags: Vec<Tag>,
#[serde(flatten)]
pub attributes: Attributes,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct NodeRef {
#[serde(rename = "@ref")]
pub reference: i64,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Way {
#[serde(rename = "@id")]
pub id: i64,
#[serde(rename = "nd", default)]
pub nodes: Vec<NodeRef>,
#[serde(rename = "tag", default)]
pub tags: Vec<Tag>,
#[serde(flatten)]
pub attributes: Attributes,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ElementRef {
#[serde(rename = "@type")]
element_type: ElementType,
#[serde(rename = "@ref")]
reference: i64,
#[serde(rename = "@role")]
role: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum ElementType {
Node,
Way,
Relation,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Relation {
#[serde(rename = "member", default)]
pub members: Vec<ElementRef>,
#[serde(rename = "tag", default)]
pub tags: Vec<Tag>,
#[serde(flatten)]
pub attributes: Attributes,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Tag {
#[serde(rename = "@k")]
pub key: String,
#[serde(rename = "@v")]
pub value: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Attributes {
#[serde(rename = "@user")]
pub user: String,
#[serde(rename = "@uid", deserialize_with = "de_from_str")]
pub uid: i64,
#[serde(rename = "@timestamp")]
pub timestamp: TimeStamp,
#[serde(rename = "@visible", deserialize_with = "de_from_str")]
pub visible: bool,
#[serde(rename = "@version", deserialize_with = "de_from_str")]
pub version: u8,
#[serde(rename = "@changeset", deserialize_with = "de_from_str")]
pub changeset: i64,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename = "osm")]
pub struct OSM {
#[serde(alias = "@version", default)]
pub version: String,
#[serde(alias = "@generator")]
pub generator: String,
#[serde(rename = "@timestamp")]
pub time_stamp_osm_base: Option<TimeStamp>,
#[serde(alias = "@copyright")]
pub copyright: String,
#[serde(alias = "@license")]
pub license: String,
#[serde(alias = "@attribution")]
pub attribution: String,
#[serde(rename = "@error")]
pub error: Option<String>,
#[serde(rename = "node", default)]
pub node: Vec<Node>,
#[serde(rename = "way", default)]
pub way: Vec<Way>,
#[serde(rename = "relation", default)]
pub relation: Vec<Relation>,
pub api: Option<Api>,
}
type TimeStamp = DateTime<Utc>;
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct Api {
#[serde(alias = "versions", deserialize_with = "de_inner_version")]
pub version: ApiVersion,
#[serde(alias = "area", deserialize_with = "de_inner_maximum", default)]
#[serde(skip_serializing_if = "Option::is_none")]
pub max_areas: Option<f64>,
#[serde(alias = "note_area", deserialize_with = "de_inner_maximum", default)]
#[serde(skip_serializing_if = "Option::is_none")]
pub max_note_areas: Option<i64>,
#[serde(alias = "tracepoints", deserialize_with = "de_inner_per_page", default)]
#[serde(skip_serializing_if = "Option::is_none")]
pub trackpoints_per_page: Option<i64>,
#[serde(alias = "waynodes", deserialize_with = "de_inner_maximum", default)]
#[serde(skip_serializing_if = "Option::is_none")]
pub max_way_nodes: Option<i64>,
#[serde(
alias = "relationmembers",
deserialize_with = "de_inner_maximum",
default
)]
#[serde(skip_serializing_if = "Option::is_none")]
pub max_relation_members: Option<i64>,
#[serde(alias = "changesets", default)]
#[serde(skip_serializing_if = "Option::is_none")]
pub changesets: Option<QueryLimit>,
#[serde(alias = "notes", default)]
#[serde(skip_serializing_if = "Option::is_none")]
pub notes: Option<QueryLimit>,
#[serde(alias = "timeout", deserialize_with = "de_inner_seconds", default)]
#[serde(skip_serializing_if = "Option::is_none")]
pub timeout: Option<i64>,
#[serde(alias = "status")]
#[serde(skip_serializing_if = "Option::is_none")]
pub status: Option<ApiStatus>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct VersionRange {
#[serde(alias = "@minimum")]
pub min: String,
#[serde(alias = "@maximum")]
pub max: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum Status {
Online,
#[serde(alias = "readonly")]
ReadOnly,
Offline,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ApiStatus {
#[serde(alias = "@database")]
pub database: Status,
#[serde(alias = "@api")]
pub api: Status,
#[serde(alias = "@gpx")]
pub gpx: Status,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct QueryLimit {
#[serde(alias = "@default_query_limit", alias = "default_query_limit")]
pub default: i64,
#[serde(alias = "@maximum_query_limit", alias = "maximum_query_limit")]
pub max: i64,
#[serde(alias = "@maximum_elements", alias = "maximum_elements")]
pub max_elements: Option<i64>,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub enum ApiVersion {
Versions(Vec<String>),
VersionRange(String, String),
#[default]
None,
}
fn de_inner_version<'de, D>(deserializer: D) -> Result<ApiVersion, D::Error>
where
D: Deserializer<'de>,
{
let value = Value::deserialize(deserializer)?;
debug!("value: {:?}", value);
match value {
Value::Array(versions) => Ok(ApiVersion::Versions(
versions
.iter()
.map(|v| v.as_str().expect("Not a valid string").to_string())
.collect(),
)),
Value::Object(obj) => {
if let Some(version) = obj.get("$text") {
return Ok(ApiVersion::Versions(vec![version.to_string()]));
}
let max = obj
.get("@maximum")
.or_else(|| obj.get("maximum"))
.expect("Missing maximum")
.as_str()
.expect("Not a valid string")
.to_string();
let min = obj
.get("@minimum")
.or_else(|| obj.get("minimum"))
.expect("Missing minimum")
.as_str()
.expect("Not a valid string")
.to_string();
Ok(ApiVersion::VersionRange(max, min))
}
_ => Err(serde::de::Error::custom("Invalid version")),
}
}
fn de_inner_maximum<'de, D, T>(deserializer: D) -> Result<Option<T>, D::Error>
where
D: Deserializer<'de>,
T: Deserialize<'de>,
{
#[derive(Deserialize)]
struct Helper<T> {
#[serde(alias = "@maximum")]
maximum: Option<T>,
}
Ok(Helper::<T>::deserialize(deserializer)?.maximum)
}
fn de_inner_seconds<'de, D, T>(deserializer: D) -> Result<Option<T>, D::Error>
where
D: Deserializer<'de>,
T: Deserialize<'de>,
{
#[derive(Deserialize)]
struct Helper<T> {
#[serde(alias = "@seconds")]
seconds: Option<T>,
}
Ok(Helper::<T>::deserialize(deserializer)?.seconds)
}
fn de_inner_per_page<'de, D, T>(deserializer: D) -> Result<Option<T>, D::Error>
where
D: Deserializer<'de>,
T: Deserialize<'de>,
{
#[derive(Deserialize)]
struct Helper<T> {
#[serde(alias = "@per_page")]
per_page: Option<T>,
}
Ok(Helper::<T>::deserialize(deserializer)?.per_page)
}
fn de_from_str<'de, D, T>(deserializer: D) -> Result<T, D::Error>
where
D: Deserializer<'de>,
T: FromStr,
T::Err: std::fmt::Display,
{
let s = String::deserialize(deserializer)?;
T::from_str(&s).map_err(serde::de::Error::custom)
}