From f2194c818cde93513c7ccc20efc9f6d456cbad34 Mon Sep 17 00:00:00 2001 From: Dirkjan Ochtman Date: Thu, 2 Mar 2023 14:08:02 +0100 Subject: [PATCH] Use enum type to represent host::Status --- src/host/info.rs | 5 +- src/host/mod.rs | 105 ++++++++++++++++++++++-- src/host/update.rs | 10 +-- src/message/poll.rs | 3 +- tests/resources/request/host/update.xml | 2 +- 5 files changed, 107 insertions(+), 18 deletions(-) diff --git a/src/host/info.rs b/src/host/info.rs index ab69db0..0dcc036 100644 --- a/src/host/info.rs +++ b/src/host/info.rs @@ -56,7 +56,7 @@ pub struct InfoData { pub roid: String, /// The list of host statuses #[xml(rename = "status")] - pub statuses: Vec>, + pub statuses: Vec, /// The list of host IP addresses #[xml(rename = "addr", deserialize_with = "deserialize_host_addrs")] pub addresses: Vec, @@ -119,6 +119,7 @@ mod tests { use chrono::{TimeZone, Utc}; use super::{HostInfo, IpAddr}; + use crate::host::Status; use crate::response::ResultCode; use crate::tests::{assert_serialized, response_from_file, CLTRID, SUCCESS_MSG, SVTRID}; @@ -137,7 +138,7 @@ mod tests { assert_eq!(object.result.message, SUCCESS_MSG); assert_eq!(result.name, "host2.eppdev-1.com"); assert_eq!(result.roid, "UNDEF-ROID"); - assert_eq!(result.statuses[0].status, "ok".to_string()); + assert_eq!(result.statuses[0], Status::Ok); assert_eq!(result.addresses[0], IpAddr::from([29, 245, 122, 14])); assert_eq!( result.addresses[1], diff --git a/src/host/mod.rs b/src/host/mod.rs index 9564c3e..b39d873 100644 --- a/src/host/mod.rs +++ b/src/host/mod.rs @@ -6,7 +6,7 @@ use std::borrow::Cow; use std::fmt; use std::net::IpAddr; -use instant_xml::{FromXml, Serializer, ToXml}; +use instant_xml::{Deserializer, FromXml, Serializer, ToXml}; pub mod check; pub use check::HostCheck; @@ -26,12 +26,103 @@ pub use update::HostUpdate; pub const XMLNS: &str = "urn:ietf:params:xml:ns:host-1.0"; /// The `` type on contact transactions -#[derive(Debug, FromXml, ToXml)] -#[xml(rename = "status", ns(XMLNS))] -pub struct Status<'a> { - /// The status name, represented by the 's' attr on `` tags - #[xml(attribute, rename = "s")] - pub status: Cow<'a, str>, +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub enum Status { + ClientDeleteProhibited, + ServerDeleteProhibited, + ClientUpdateProhibited, + ServerUpdateProhibited, + Linked, + Ok, + PendingCreate, + PendingDelete, + PendingTransfer, + PendingUpdate, +} + +impl Status { + pub fn as_str(&self) -> &'static str { + use Status::*; + match self { + ClientDeleteProhibited => "clientDeleteProhibited", + ServerDeleteProhibited => "serverDeleteProhibited", + ClientUpdateProhibited => "clientUpdateProhibited", + ServerUpdateProhibited => "serverUpdateProhibited", + Linked => "linked", + Ok => "ok", + PendingCreate => "pendingCreate", + PendingDelete => "pendingDelete", + PendingTransfer => "pendingTransfer", + PendingUpdate => "pendingUpdate", + } + } +} + +impl ToXml for Status { + fn serialize( + &self, + _: Option>, + serializer: &mut Serializer, + ) -> Result<(), instant_xml::Error> { + serializer.write_start("status", XMLNS)?; + serializer.write_attr("s", XMLNS, &self.as_str())?; + serializer.end_empty() + } +} + +impl<'xml> FromXml<'xml> for Status { + fn matches(id: instant_xml::Id<'_>, _: Option>) -> bool { + id == instant_xml::Id { + ns: XMLNS, + name: "status", + } + } + + fn deserialize<'cx>( + into: &mut Self::Accumulator, + field: &'static str, + deserializer: &mut Deserializer<'cx, 'xml>, + ) -> Result<(), instant_xml::Error> { + use instant_xml::de::Node; + use instant_xml::{Error, Id}; + + let node = match deserializer.next() { + Some(result) => result?, + None => return Err(Error::MissingValue(field)), + }; + + let attr = match node { + Node::Attribute(attr) => attr, + Node::Open(_) | Node::Text(_) => return Err(Error::MissingValue(field)), + node => return Err(Error::UnexpectedNode(format!("{node:?} in Status"))), + }; + + let id = deserializer.attribute_id(&attr)?; + let expected = Id { ns: "", name: "s" }; + if id != expected { + return Err(Error::MissingValue(field)); + } + + *into = Some(match attr.value { + "clientDeleteProhibited" => Status::ClientDeleteProhibited, + "serverDeleteProhibited" => Status::ServerDeleteProhibited, + "clientUpdateProhibited" => Status::ClientUpdateProhibited, + "serverUpdateProhibited" => Status::ServerUpdateProhibited, + "linked" => Status::Linked, + "ok" => Status::Ok, + "pendingCreate" => Status::PendingCreate, + "pendingDelete" => Status::PendingDelete, + "pendingTransfer" => Status::PendingTransfer, + "pendingUpdate" => Status::PendingUpdate, + val => return Err(Error::UnexpectedValue(format!("invalid status {val:?}"))), + }); + + deserializer.ignore()?; + Ok(()) + } + + type Accumulator = Option; + const KIND: instant_xml::Kind = instant_xml::Kind::Element; } /// The `` types domain or host transactions diff --git a/src/host/update.rs b/src/host/update.rs index e72f2c9..5a301ae 100644 --- a/src/host/update.rs +++ b/src/host/update.rs @@ -60,7 +60,7 @@ pub struct HostAdd<'a> { pub addresses: Option<&'a [IpAddr]>, /// The statuses to be added to or removed from the host #[xml(rename = "host:status")] - pub statuses: Option<&'a [Status<'a>]>, + pub statuses: Option<&'a [Status]>, } /// Type for data under the `` and `` tags @@ -72,7 +72,7 @@ pub struct HostRemove<'a> { pub addresses: Option<&'a [IpAddr]>, /// The statuses to be added to or removed from the host #[xml(rename = "host:status")] - pub statuses: Option<&'a [Status<'a>]>, + pub statuses: Option<&'a [Status]>, } /// Type for data under the host `` tag @@ -118,13 +118,9 @@ mod tests { statuses: None, }; - let statuses = &[Status { - status: "clientDeleteProhibited".into(), - }]; - let remove = HostRemove { addresses: None, - statuses: Some(statuses), + statuses: Some(&[Status::ClientDeleteProhibited]), }; let mut object = HostUpdate::new("host1.eppdev-1.com"); diff --git a/src/message/poll.rs b/src/message/poll.rs index 795787c..4f3e624 100644 --- a/src/message/poll.rs +++ b/src/message/poll.rs @@ -48,6 +48,7 @@ pub enum MessagePollResponse { #[cfg(test)] mod tests { use super::{MessagePoll, MessagePollResponse}; + use crate::host::Status; use crate::response::ResultCode; use crate::tests::{assert_serialized, response_from_file, CLTRID, SVTRID}; @@ -133,7 +134,7 @@ mod tests { assert_eq!(host.name, "ns.test.com"); assert_eq!(host.roid, "1234"); - assert!(host.statuses.iter().any(|s| s.status == "ok")); + assert!(host.statuses.iter().any(|&s| s == Status::Ok)); assert!(host .addresses .iter() diff --git a/tests/resources/request/host/update.xml b/tests/resources/request/host/update.xml index fb48e2b..5a74f6f 100644 --- a/tests/resources/request/host/update.xml +++ b/tests/resources/request/host/update.xml @@ -8,7 +8,7 @@ 2404:6800:4001:801::200e - + host2.eppdev-1.com