1use 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#[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#[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}