use super::DateTime;
use serde::{Deserialize, Serialize};
pub use crate::v1dot0::{MessageType, Scope, Severity, Urgency};
pub use crate::v1dot1::{Category, Certainty, Status};
mod map;
pub use map::Map;
mod response_type;
pub use response_type::ResponseType;
use crate::delimited_items::Items;
use crate::geo::{Circle, Polygon};
use crate::id::Id;
use crate::language::Language;
use crate::references::References;
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename = "{urn:oasis:names:tc:emergency:cap:1.2;}cap:alert")]
pub struct Alert {
#[serde(rename = "{urn:oasis:names:tc:emergency:cap:1.2;}cap:identifier")]
pub identifier: Id,
#[serde(rename = "{urn:oasis:names:tc:emergency:cap:1.2;}cap:sender")]
pub sender: Id,
#[serde(rename = "{urn:oasis:names:tc:emergency:cap:1.2;}cap:sent")]
pub sent: DateTime,
#[serde(rename = "{urn:oasis:names:tc:emergency:cap:1.2;}cap:status")]
pub status: Status,
#[serde(rename = "{urn:oasis:names:tc:emergency:cap:1.2;}cap:msgType")]
pub message_type: MessageType,
#[serde(
rename = "{urn:oasis:names:tc:emergency:cap:1.2;}cap:source",
skip_serializing_if = "Option::is_none"
)]
pub source: Option<String>,
#[serde(rename = "{urn:oasis:names:tc:emergency:cap:1.2;}cap:scope")]
pub scope: Scope,
#[serde(
rename = "{urn:oasis:names:tc:emergency:cap:1.2;}cap:restriction",
skip_serializing_if = "Option::is_none"
)]
pub restriction: Option<String>,
#[serde(
rename = "{urn:oasis:names:tc:emergency:cap:1.2;}cap:addresses",
skip_serializing_if = "Option::is_none"
)]
pub addresses: Option<Items>,
#[serde(
rename = "{urn:oasis:names:tc:emergency:cap:1.2;}cap:code",
default,
skip_serializing_if = "Vec::is_empty"
)]
pub codes: Vec<String>,
#[serde(
rename = "{urn:oasis:names:tc:emergency:cap:1.2;}cap:note",
skip_serializing_if = "Option::is_none"
)]
pub note: Option<String>,
#[serde(
rename = "{urn:oasis:names:tc:emergency:cap:1.2;}cap:references",
skip_serializing_if = "Option::is_none"
)]
pub references: Option<References>,
#[serde(
rename = "{urn:oasis:names:tc:emergency:cap:1.2;}cap:incidents",
skip_serializing_if = "Option::is_none"
)]
pub incidents: Option<Items>,
#[serde(
rename = "{urn:oasis:names:tc:emergency:cap:1.2;}cap:info",
default,
skip_serializing_if = "Vec::is_empty"
)]
pub info: Vec<Info>,
}
impl From<crate::v1dot1::Alert> for Alert {
fn from(prev: crate::v1dot1::Alert) -> Self {
Self {
identifier: prev.identifier,
sender: prev.sender,
sent: prev.sent,
status: prev.status,
message_type: prev.message_type,
source: prev.source,
scope: prev.scope,
restriction: prev.restriction,
addresses: prev.addresses,
codes: prev.codes,
note: prev.note,
references: prev.references,
incidents: prev.incidents,
info: prev.info.into_iter().map(Info::from).collect(),
}
}
}
impl From<crate::v1dot0::Alert> for Alert {
fn from(prev: crate::v1dot0::Alert) -> Self {
crate::v1dot1::Alert::from(prev).into()
}
}
#[derive(Serialize, Deserialize)]
struct AlertDocument {
#[serde(rename = "{urn:oasis:names:tc:emergency:cap:1.2;}cap:alert")]
alert: Alert,
}
impl std::str::FromStr for Alert {
type Err = xml_serde::Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
xml_serde::from_str::<AlertDocument>(s).map(|doc| doc.alert)
}
}
impl std::fmt::Display for Alert {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
xml_serde::to_string(self)
.map_err(|_| std::fmt::Error)
.and_then(|str| f.write_str(&str))
}
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename = "{urn:oasis:names:tc:emergency:cap:1.2;}cap:info")]
pub struct Info {
#[serde(
rename = "{urn:oasis:names:tc:emergency:cap:1.2;}cap:language",
skip_serializing_if = "Language::is_empty"
)]
pub language: Language,
#[serde(
rename = "{urn:oasis:names:tc:emergency:cap:1.2;}cap:category",
skip_serializing_if = "Vec::is_empty"
)]
pub categories: Vec<Category>,
#[serde(rename = "{urn:oasis:names:tc:emergency:cap:1.2;}cap:event")]
pub event: String,
#[serde(
rename = "{urn:oasis:names:tc:emergency:cap:1.2;}cap:responseType",
default,
skip_serializing_if = "Vec::is_empty"
)]
pub response_type: Vec<ResponseType>,
#[serde(rename = "{urn:oasis:names:tc:emergency:cap:1.2;}cap:urgency")]
pub urgency: Urgency,
#[serde(rename = "{urn:oasis:names:tc:emergency:cap:1.2;}cap:severity")]
pub severity: Severity,
#[serde(rename = "{urn:oasis:names:tc:emergency:cap:1.2;}cap:certainty")]
pub certainty: Certainty,
#[serde(
rename = "{urn:oasis:names:tc:emergency:cap:1.2;}cap:audience",
skip_serializing_if = "Option::is_none"
)]
pub audience: Option<String>,
#[serde(
rename = "{urn:oasis:names:tc:emergency:cap:1.2;}cap:eventCode",
default,
skip_serializing_if = "Map::is_empty"
)]
pub event_codes: Map,
#[serde(
rename = "{urn:oasis:names:tc:emergency:cap:1.2;}cap:effective",
skip_serializing_if = "Option::is_none"
)]
pub effective: Option<DateTime>,
#[serde(
rename = "{urn:oasis:names:tc:emergency:cap:1.2;}cap:onset",
skip_serializing_if = "Option::is_none"
)]
pub onset: Option<DateTime>,
#[serde(
rename = "{urn:oasis:names:tc:emergency:cap:1.2;}cap:expires",
skip_serializing_if = "Option::is_none"
)]
pub expires: Option<DateTime>,
#[serde(
rename = "{urn:oasis:names:tc:emergency:cap:1.2;}cap:senderName",
skip_serializing_if = "Option::is_none"
)]
pub sender_name: Option<String>,
#[serde(
rename = "{urn:oasis:names:tc:emergency:cap:1.2;}cap:headline",
skip_serializing_if = "Option::is_none"
)]
pub headline: Option<String>,
#[serde(
rename = "{urn:oasis:names:tc:emergency:cap:1.2;}cap:description",
skip_serializing_if = "Option::is_none"
)]
pub description: Option<String>,
#[serde(
rename = "{urn:oasis:names:tc:emergency:cap:1.2;}cap:instruction",
skip_serializing_if = "Option::is_none"
)]
pub instruction: Option<String>,
#[serde(
rename = "{urn:oasis:names:tc:emergency:cap:1.2;}cap:web",
deserialize_with = "crate::url::deserialize",
default,
skip_serializing_if = "Option::is_none"
)]
pub web: Option<url::Url>,
#[serde(
rename = "{urn:oasis:names:tc:emergency:cap:1.2;}cap:contact",
skip_serializing_if = "Option::is_none"
)]
pub contact: Option<String>,
#[serde(
rename = "{urn:oasis:names:tc:emergency:cap:1.2;}cap:parameter",
default,
skip_serializing_if = "Map::is_empty"
)]
pub parameters: Map,
#[serde(
rename = "{urn:oasis:names:tc:emergency:cap:1.2;}cap:resource",
default,
skip_serializing_if = "Vec::is_empty"
)]
pub resources: Vec<Resource>,
#[serde(
rename = "{urn:oasis:names:tc:emergency:cap:1.2;}cap:area",
default,
skip_serializing_if = "Vec::is_empty"
)]
pub areas: Vec<Area>,
}
impl From<crate::v1dot1::Info> for Info {
fn from(prev: crate::v1dot1::Info) -> Self {
Self {
language: prev.language,
categories: prev.categories,
event: prev.event,
response_type: prev
.response_type
.into_iter()
.map(ResponseType::from)
.collect(),
urgency: prev.urgency,
severity: prev.severity,
certainty: prev.certainty,
audience: prev.audience,
event_codes: prev.event_codes.into_iter().collect(),
effective: prev.effective,
onset: prev.onset,
expires: prev.expires,
sender_name: prev.sender_name,
headline: prev.headline,
description: prev.description,
instruction: prev.instruction,
web: prev.web,
contact: prev.contact,
parameters: prev.parameters.into_iter().collect(),
resources: prev.resources.into_iter().map(Resource::from).collect(),
areas: prev.areas.into_iter().map(Area::from).collect(),
}
}
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename = "{urn:oasis:names:tc:emergency:cap:1.2;}cap:resource")]
pub struct Resource {
#[serde(rename = "{urn:oasis:names:tc:emergency:cap:1.2;}cap:resourceDesc")]
pub description: String,
#[serde(rename = "{urn:oasis:names:tc:emergency:cap:1.2;}cap:mimeType")]
pub mime_type: String,
#[serde(
rename = "{urn:oasis:names:tc:emergency:cap:1.2;}cap:size",
skip_serializing_if = "Option::is_none"
)]
pub size: Option<u64>,
#[serde(
rename = "{urn:oasis:names:tc:emergency:cap:1.2;}cap:uri",
deserialize_with = "crate::url::deserialize",
default,
skip_serializing_if = "Option::is_none"
)]
pub uri: Option<url::Url>,
#[serde(
rename = "{urn:oasis:names:tc:emergency:cap:1.2;}cap:derefUri",
skip_serializing_if = "Option::is_none"
)]
pub embedded_content: Option<crate::EmbeddedContent>,
#[serde(
rename = "{urn:oasis:names:tc:emergency:cap:1.2;}cap:digest",
skip_serializing_if = "Option::is_none"
)]
pub digest: Option<crate::digest::Sha1>,
}
impl From<crate::v1dot1::Resource> for Resource {
fn from(prev: crate::v1dot1::Resource) -> Self {
Self {
description: prev.description,
mime_type: prev
.mime_type
.unwrap_or_else(|| String::from("application/octet-stream")),
size: prev.size,
uri: prev.uri,
embedded_content: prev.embedded_content,
digest: prev.digest,
}
}
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename = "{urn:oasis:names:tc:emergency:cap:1.2;}cap:area")]
pub struct Area {
#[serde(rename = "{urn:oasis:names:tc:emergency:cap:1.2;}cap:areaDesc")]
pub description: String,
#[serde(
rename = "{urn:oasis:names:tc:emergency:cap:1.2;}cap:polygon",
default,
deserialize_with = "Polygon::deserialize_optional",
skip_serializing_if = "Vec::is_empty"
)]
pub polygons: Vec<Polygon>,
#[serde(
rename = "{urn:oasis:names:tc:emergency:cap:1.2;}cap:circle",
default,
skip_serializing_if = "Vec::is_empty"
)]
pub circles: Vec<Circle>,
#[serde(
rename = "{urn:oasis:names:tc:emergency:cap:1.2;}cap:geocode",
default,
skip_serializing_if = "Map::is_empty"
)]
pub geocode: Map,
#[serde(
rename = "{urn:oasis:names:tc:emergency:cap:1.2;}cap:altitude",
skip_serializing_if = "Option::is_none"
)]
pub altitude: Option<f64>,
#[serde(
rename = "{urn:oasis:names:tc:emergency:cap:1.1;https://docs.oasis-open.org/emergency/cap/v1.1/errata/approved/cap.xsd}cap:ceiling",
skip_serializing_if = "Option::is_none"
)]
pub ceiling: Option<f64>,
}
impl From<crate::v1dot1::Area> for Area {
fn from(prev: crate::v1dot1::Area) -> Self {
Self {
description: prev.description,
polygons: prev.polygons,
circles: prev.circles,
geocode: prev.geocode.into_iter().collect(),
altitude: prev.altitude,
ceiling: prev.ceiling,
}
}
}
#[cfg(test)]
mod tests;