instant_epp/host/
mod.rs

1//! Mapping for EPP host objects
2//!
3//! As described in [RFC 5732](https://tools.ietf.org/html/rfc5732).
4
5use std::borrow::Cow;
6use std::fmt;
7use std::net::IpAddr;
8
9use instant_xml::{Deserializer, FromXml, Serializer, ToXml};
10
11pub mod check;
12pub use check::HostCheck;
13
14pub mod create;
15pub use create::HostCreate;
16
17pub mod delete;
18pub use delete::HostDelete;
19
20pub mod info;
21pub use info::HostInfo;
22
23pub mod update;
24pub use update::HostUpdate;
25
26pub const XMLNS: &str = "urn:ietf:params:xml:ns:host-1.0";
27
28/// The `<status>` type on contact transactions
29#[derive(Clone, Copy, Debug, Eq, PartialEq)]
30pub enum Status {
31    ClientDeleteProhibited,
32    ServerDeleteProhibited,
33    ClientUpdateProhibited,
34    ServerUpdateProhibited,
35    Linked,
36    Ok,
37    PendingCreate,
38    PendingDelete,
39    PendingTransfer,
40    PendingUpdate,
41}
42
43impl Status {
44    pub fn as_str(&self) -> &'static str {
45        use Status::*;
46        match self {
47            ClientDeleteProhibited => "clientDeleteProhibited",
48            ServerDeleteProhibited => "serverDeleteProhibited",
49            ClientUpdateProhibited => "clientUpdateProhibited",
50            ServerUpdateProhibited => "serverUpdateProhibited",
51            Linked => "linked",
52            Ok => "ok",
53            PendingCreate => "pendingCreate",
54            PendingDelete => "pendingDelete",
55            PendingTransfer => "pendingTransfer",
56            PendingUpdate => "pendingUpdate",
57        }
58    }
59}
60
61impl ToXml for Status {
62    fn serialize<W: fmt::Write + ?Sized>(
63        &self,
64        _: Option<instant_xml::Id<'_>>,
65        serializer: &mut Serializer<W>,
66    ) -> Result<(), instant_xml::Error> {
67        serializer.write_start("status", XMLNS)?;
68        serializer.write_attr("s", XMLNS, &self.as_str())?;
69        serializer.end_empty()
70    }
71}
72
73impl<'xml> FromXml<'xml> for Status {
74    fn matches(id: instant_xml::Id<'_>, _: Option<instant_xml::Id<'_>>) -> bool {
75        id == instant_xml::Id {
76            ns: XMLNS,
77            name: "status",
78        }
79    }
80
81    fn deserialize<'cx>(
82        into: &mut Self::Accumulator,
83        field: &'static str,
84        deserializer: &mut Deserializer<'cx, 'xml>,
85    ) -> Result<(), instant_xml::Error> {
86        use instant_xml::de::Node;
87        use instant_xml::{Error, Id};
88
89        let node = match deserializer.next() {
90            Some(result) => result?,
91            None => return Err(Error::MissingValue(field)),
92        };
93
94        let attr = match node {
95            Node::Attribute(attr) => attr,
96            Node::Open(_) | Node::Text(_) => return Err(Error::MissingValue(field)),
97            node => return Err(Error::UnexpectedNode(format!("{node:?} in Status"))),
98        };
99
100        let id = deserializer.attribute_id(&attr)?;
101        let expected = Id { ns: "", name: "s" };
102        if id != expected {
103            return Err(Error::MissingValue(field));
104        }
105
106        *into = Some(match attr.value.as_ref() {
107            "clientDeleteProhibited" => Self::ClientDeleteProhibited,
108            "serverDeleteProhibited" => Self::ServerDeleteProhibited,
109            "clientUpdateProhibited" => Self::ClientUpdateProhibited,
110            "serverUpdateProhibited" => Self::ServerUpdateProhibited,
111            "linked" => Self::Linked,
112            "ok" => Self::Ok,
113            "pendingCreate" => Self::PendingCreate,
114            "pendingDelete" => Self::PendingDelete,
115            "pendingTransfer" => Self::PendingTransfer,
116            "pendingUpdate" => Self::PendingUpdate,
117            val => return Err(Error::UnexpectedValue(format!("invalid status {val:?}"))),
118        });
119
120        deserializer.ignore()?;
121        Ok(())
122    }
123
124    type Accumulator = Option<Self>;
125    const KIND: instant_xml::Kind = instant_xml::Kind::Element;
126}
127
128/// The `<hostAddr>` types domain or host transactions
129#[derive(Debug, FromXml, ToXml)]
130#[xml(rename = "addr", ns(XMLNS))]
131struct HostAddr<'a> {
132    #[xml(attribute, rename = "ip")]
133    ip_version: Option<Cow<'a, str>>,
134    #[xml(direct)]
135    address: Cow<'a, str>,
136}
137
138impl From<&IpAddr> for HostAddr<'static> {
139    fn from(addr: &IpAddr) -> Self {
140        Self {
141            ip_version: Some(match addr {
142                IpAddr::V4(_) => "v4".into(),
143                IpAddr::V6(_) => "v6".into(),
144            }),
145            address: addr.to_string().into(),
146        }
147    }
148}
149
150pub(crate) fn serialize_host_addrs_option<T: AsRef<[IpAddr]>, W: fmt::Write + ?Sized>(
151    addrs: &Option<T>,
152    serializer: &mut Serializer<'_, W>,
153) -> Result<(), instant_xml::Error> {
154    let addrs = match addrs {
155        Some(addrs) => addrs.as_ref(),
156        None => return Ok(()),
157    };
158
159    for addr in addrs {
160        HostAddr::from(addr).serialize(None, serializer)?;
161    }
162
163    Ok(())
164}