use super::parse_error::ParseError;
use chrono::{DateTime, Utc};
use iri_string::types::IriString;
use oxilangtag::{LanguageTag, LanguageTagParseError};
use std::cmp::Ordering;
use valuable::{Valuable, Value, Visit};
macro_rules! IriStringImpl {
($structname:ident) => {
impl $structname {
pub(crate) fn new(uri: &str) -> Result<Self, ParseError> {
let uri = uri.trim().parse::<IriString>()?;
if uri.scheme_str() == "http" {
return Err(ParseError::InsecureHTTP);
}
let log_value = uri.as_str().to_string();
Ok(Self { uri, log_value })
}
}
impl Valuable for $structname {
fn as_value(&self) -> Value<'_> {
self.log_value.as_value()
}
fn visit(&self, _visit: &mut dyn Visit) {}
}
};
}
#[derive(Debug, PartialEq)]
pub struct AcknowledgmentsField {
pub uri: IriString,
log_value: String,
}
IriStringImpl!(AcknowledgmentsField);
#[derive(Debug, PartialEq)]
pub struct CanonicalField {
pub uri: IriString,
log_value: String,
}
IriStringImpl!(CanonicalField);
#[derive(Debug, PartialEq)]
pub struct ContactField {
pub uri: IriString,
log_value: String,
}
IriStringImpl!(ContactField);
#[derive(Debug, PartialEq)]
pub struct CsafField {
pub uri: IriString,
log_value: String,
}
IriStringImpl!(CsafField);
#[derive(Debug, PartialEq)]
pub struct EncryptionField {
pub uri: IriString,
log_value: String,
}
IriStringImpl!(EncryptionField);
#[derive(Debug, PartialEq)]
pub struct ExpiresField {
pub datetime: DateTime<Utc>,
log_value: String,
}
impl ExpiresField {
pub(crate) fn new(datetime: &str, now: DateTime<Utc>) -> Result<Self, ParseError> {
let datetime: DateTime<Utc> = datetime.trim().parse()?;
if datetime < now {
return Err(ParseError::ExpiresFieldExpired);
}
let log_value = datetime.to_rfc3339();
Ok(Self { datetime, log_value })
}
}
impl PartialOrd for ExpiresField {
#[inline]
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
self.datetime.partial_cmp(&other.datetime)
}
}
impl Valuable for ExpiresField {
fn as_value(&self) -> Value<'_> {
self.log_value.as_value()
}
fn visit(&self, _visit: &mut dyn Visit) {}
}
#[derive(Debug, PartialEq)]
pub struct HiringField {
pub uri: IriString,
log_value: String,
}
IriStringImpl!(HiringField);
#[derive(Debug, PartialEq)]
pub struct PolicyField {
pub uri: IriString,
log_value: String,
}
IriStringImpl!(PolicyField);
#[derive(Debug, PartialEq)]
pub struct PreferredLanguagesField {
pub languages: Vec<LanguageTag<String>>,
log_value: String,
}
impl PreferredLanguagesField {
pub(crate) fn new(languages: &str) -> Result<Self, ParseError> {
let languages = languages
.split(',')
.map(str::trim)
.map(LanguageTag::parse_and_normalize)
.collect::<Result<Vec<LanguageTag<String>>, LanguageTagParseError>>()?;
if languages.is_empty() {
return Err(ParseError::IllegalField);
}
let log_value = languages.join(", ");
Ok(Self { languages, log_value })
}
}
impl Valuable for PreferredLanguagesField {
fn as_value(&self) -> Value<'_> {
self.log_value.as_value()
}
fn visit(&self, _visit: &mut dyn Visit) {}
}
#[derive(Debug, PartialEq, Valuable)]
pub struct ExtensionField {
pub name: String,
pub value: String,
}
impl ExtensionField {
pub(crate) fn new(name: String, value: String) -> Result<Self, ParseError> {
Ok(Self { name, value })
}
}