use std::ops::Deref;
use std::{borrow::Cow, fmt::Display, net::IpAddr};
use serde::ser::SerializeSeq;
use serde::{Deserialize, Serialize};
use crate::request::Extension;
pub(crate) const EPP_XMLNS: &str = "urn:ietf:params:xml:ns:epp-1.0";
#[derive(Default, Serialize, Deserialize, Debug, Eq, PartialEq, Clone)]
pub struct StringValue<'a>(Cow<'a, str>);
impl Deref for StringValue<'_> {
type Target = str;
fn deref(&self) -> &Self::Target {
self.0.as_ref()
}
}
impl<'a> AsRef<str> for StringValue<'a> {
fn as_ref(&self) -> &str {
self.0.as_ref()
}
}
impl Display for StringValue<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.0)
}
}
impl<'a> From<&'a str> for StringValue<'a> {
fn from(s: &'a str) -> Self {
Self(s.into())
}
}
impl From<String> for StringValue<'static> {
fn from(s: String) -> Self {
Self(s.into())
}
}
#[derive(Serialize, Deserialize, Debug, Eq, PartialEq)]
pub struct NoExtension;
impl Extension for NoExtension {
type Response = NoExtension;
}
#[derive(Deserialize, Debug)]
struct Available {
#[serde(rename = "$value")]
pub id: StringValue<'static>,
#[serde(rename = "avail")]
pub available: bool,
}
#[derive(Deserialize, Debug)]
struct CheckResponseDataItem {
#[serde(rename = "name", alias = "id")]
pub resource: Available,
pub reason: Option<StringValue<'static>>,
}
#[derive(Deserialize, Debug)]
struct CheckData {
#[serde(rename = "cd")]
pub list: Vec<CheckResponseDataItem>,
}
#[derive(Deserialize, Debug)]
struct DeserializedCheckResponse {
#[serde(rename = "chkData")]
pub check_data: CheckData,
}
#[derive(Debug)]
pub struct Checked {
pub id: String,
pub available: bool,
pub reason: Option<String>,
}
#[derive(Deserialize, Debug)]
#[serde(from = "DeserializedCheckResponse")]
pub struct CheckResponse {
pub list: Vec<Checked>,
}
impl From<DeserializedCheckResponse> for CheckResponse {
fn from(rsp: DeserializedCheckResponse) -> Self {
Self {
list: rsp
.check_data
.list
.into_iter()
.map(|item| Checked {
id: item.resource.id.0.into_owned(),
available: item.resource.available,
reason: item.reason.map(|r| r.0.into_owned()),
})
.collect(),
}
}
}
#[derive(Serialize, Deserialize, Debug, Eq, PartialEq)]
#[serde(rename = "options")]
pub struct Options<'a> {
pub version: StringValue<'a>,
pub lang: StringValue<'a>,
}
impl<'a> Options<'a> {
pub fn build(version: &'a str, lang: &'a str) -> Self {
Self {
version: version.into(),
lang: lang.into(),
}
}
}
#[derive(Serialize, Deserialize, Debug, Eq, PartialEq)]
#[serde(rename = "svcExtension")]
pub struct ServiceExtension<'a> {
#[serde(rename = "extURI")]
pub ext_uris: Option<Vec<StringValue<'a>>>,
}
#[derive(Serialize, Deserialize, Debug, Eq, PartialEq)]
pub struct Services<'a> {
#[serde(rename = "objURI")]
pub obj_uris: Vec<StringValue<'a>>,
#[serde(rename = "svcExtension")]
pub svc_ext: Option<ServiceExtension<'a>>,
}
#[derive(Serialize, Deserialize, Debug)]
pub(crate) struct HostAddr<'a> {
#[serde(rename = "ip")]
pub ip_version: Option<Cow<'a, str>>,
#[serde(rename = "$value")]
pub address: Cow<'a, str>,
}
impl From<&IpAddr> for HostAddr<'static> {
fn from(addr: &IpAddr) -> Self {
Self {
ip_version: Some(match addr {
IpAddr::V4(_) => "v4".into(),
IpAddr::V6(_) => "v6".into(),
}),
address: addr.to_string().into(),
}
}
}
pub(crate) fn serialize_host_addrs_option<T: AsRef<[IpAddr]>, S>(
addrs: &Option<T>,
ser: S,
) -> Result<S::Ok, S::Error>
where
S: serde::ser::Serializer,
{
let addrs = match addrs {
Some(addrs) => addrs.as_ref(),
None => return ser.serialize_none(),
};
let mut seq = ser.serialize_seq(Some(addrs.len()))?;
for addr in addrs {
seq.serialize_element(&HostAddr::from(addr))?;
}
seq.end()
}
#[derive(Serialize, Deserialize, Debug)]
pub struct ObjectStatus<'a> {
#[serde(rename = "s")]
pub status: Cow<'a, str>,
}
pub struct Certificate(pub Vec<u8>);
pub struct PrivateKey(pub Vec<u8>);