xml: Differentiate between ValueSerialize and ValueDeserialize to prevent unwraps

This commit is contained in:
Lennart K
2025-01-15 11:05:57 +01:00
parent 4da975c6fb
commit 807335de17
9 changed files with 35 additions and 27 deletions

View File

@@ -9,7 +9,7 @@ use rustical_store::{
synctoken::{format_synctoken, parse_synctoken},
CalendarStore,
};
use rustical_xml::{Value, XmlDeserialize};
use rustical_xml::{ValueDeserialize, ValueSerialize, XmlDeserialize};
use crate::{
calendar_object::resource::{CalendarObjectProp, CalendarObjectResource},
@@ -22,7 +22,7 @@ pub(crate) enum SyncLevel {
Infinity,
}
impl Value for SyncLevel {
impl ValueDeserialize for SyncLevel {
fn deserialize(val: &str) -> Result<Self, rustical_xml::XmlDeError> {
Ok(match val {
"1" => Self::One,
@@ -34,6 +34,9 @@ impl Value for SyncLevel {
}
})
}
}
impl ValueSerialize for SyncLevel {
fn serialize(&self) -> String {
match self {
SyncLevel::One => "1",

View File

@@ -1,13 +1,13 @@
use derive_more::derive::From;
use rustical_xml::{XmlDeserialize, XmlSerialize};
use rustical_xml::XmlSerialize;
#[derive(Debug, Clone, XmlDeserialize, XmlSerialize, PartialEq, From)]
#[derive(Debug, Clone, XmlSerialize, PartialEq, From)]
pub struct SupportedCalendarComponent {
#[xml(ty = "attr")]
pub name: &'static str,
}
#[derive(Debug, Clone, XmlDeserialize, XmlSerialize, PartialEq)]
#[derive(Debug, Clone, XmlSerialize, PartialEq)]
pub struct SupportedCalendarComponentSet {
#[xml(ns = "rustical_dav::namespace::NS_CALDAV", flatten)]
pub comp: Vec<SupportedCalendarComponent>,

View File

@@ -29,7 +29,7 @@ pub enum PrincipalProp {
Displayname(String),
// Scheduling Extensions to CalDAV (RFC 6638)
#[xml(ns = "rustical_dav::namespace::NS_CALDAV")]
#[xml(ns = "rustical_dav::namespace::NS_CALDAV", skip_deserializing)]
CalendarUserType(&'static str),
#[xml(ns = "rustical_dav::namespace::NS_CALDAV")]
CalendarUserAddressSet(HrefElement),

View File

@@ -13,7 +13,7 @@ use rustical_store::{
synctoken::{format_synctoken, parse_synctoken},
AddressbookStore,
};
use rustical_xml::{Value, XmlDeserialize};
use rustical_xml::{ValueDeserialize, ValueSerialize, XmlDeserialize};
#[derive(Clone, Debug, PartialEq)]
pub(crate) enum SyncLevel {
@@ -21,7 +21,7 @@ pub(crate) enum SyncLevel {
Infinity,
}
impl Value for SyncLevel {
impl ValueDeserialize for SyncLevel {
fn deserialize(val: &str) -> Result<Self, rustical_xml::XmlDeError> {
Ok(match val {
"1" => Self::One,
@@ -33,6 +33,8 @@ impl Value for SyncLevel {
}
})
}
}
impl ValueSerialize for SyncLevel {
fn serialize(&self) -> String {
match self {
SyncLevel::One => "1",

View File

@@ -7,7 +7,7 @@ use ical::{
property::Property,
};
use lazy_static::lazy_static;
use rustical_xml::Value;
use rustical_xml::{ValueDeserialize, ValueSerialize};
use std::{collections::HashMap, ops::Add};
lazy_static! {
@@ -21,9 +21,9 @@ pub const LOCAL_DATE: &str = "%Y%m%d";
#[derive(Debug, Clone, Deref, PartialEq)]
pub struct UtcDateTime(DateTime<Utc>);
impl Value for UtcDateTime {
impl ValueDeserialize for UtcDateTime {
fn deserialize(val: &str) -> Result<Self, rustical_xml::XmlDeError> {
let input = <String as Value>::deserialize(val)?;
let input = <String as ValueDeserialize>::deserialize(val)?;
Ok(Self(
NaiveDateTime::parse_from_str(&input, UTC_DATE_TIME)
.map_err(|_| {
@@ -32,6 +32,8 @@ impl Value for UtcDateTime {
.and_utc(),
))
}
}
impl ValueSerialize for UtcDateTime {
fn serialize(&self) -> String {
format!("{}", self.0.format(UTC_DATE_TIME))
}

View File

@@ -232,7 +232,7 @@ impl Field {
let builder_field_ident = self.builder_field_ident();
let value = wrap_option_if_no_default(
quote! {
rustical_xml::Value::deserialize(text.as_ref())?
::rustical_xml::ValueDeserialize::deserialize(text.as_ref())?
},
self.attrs.default.is_some(),
);
@@ -250,8 +250,8 @@ impl Field {
let value = wrap_option_if_no_default(
quote! {
rustical_xml::Value::deserialize(attr.unescape_value()?.as_ref())?
},
::rustical_xml::ValueDeserialize::deserialize(attr.unescape_value()?.as_ref())?
},
self.attrs.default.is_some(),
);
@@ -270,7 +270,7 @@ impl Field {
let value = wrap_option_if_no_default(
quote! {
rustical_xml::Value::deserialize(&String::from_utf8_lossy(name.as_ref()))?
rustical_xml::ValueDeserialize::deserialize(&String::from_utf8_lossy(name.as_ref()))?
},
self.attrs.default.is_some(),
);

View File

@@ -239,7 +239,7 @@ impl NamedStruct {
quote! {
::quick_xml::events::attributes::Attribute {
key: ::quick_xml::name::QName(#field_name),
value: ::std::borrow::Cow::from(::rustical_xml::Value::serialize(&self.#field_index).into_bytes())
value: ::std::borrow::Cow::from(::rustical_xml::ValueSerialize::serialize(&self.#field_index).into_bytes())
}
}
});

View File

@@ -13,7 +13,7 @@ pub use de::XmlDocument;
pub use error::XmlDeError;
pub use se::XmlSerialize;
pub use se::XmlSerializeRoot;
pub use value::Value;
pub use value::{ParseValueError, ValueDeserialize, ValueSerialize};
pub use xml_derive::XmlRootTag;
impl XmlDeserialize for () {

View File

@@ -17,18 +17,23 @@ pub enum ParseValueError {
ParseFloatError(#[from] ParseFloatError),
}
pub trait Value: Sized {
pub trait ValueSerialize: Sized {
fn serialize(&self) -> String;
}
pub trait ValueDeserialize: Sized {
fn deserialize(val: &str) -> Result<Self, XmlDeError>;
}
macro_rules! impl_value_parse {
($t:ty) => {
impl Value for $t {
impl ValueSerialize for $t {
fn serialize(&self) -> String {
self.to_string()
}
}
impl ValueDeserialize for $t {
fn deserialize(val: &str) -> Result<Self, XmlDeError> {
val.parse()
.map_err(ParseValueError::from)
@@ -52,17 +57,13 @@ impl_value_parse!(u64);
impl_value_parse!(isize);
impl_value_parse!(usize);
impl Value for &str {
impl ValueSerialize for &str {
fn serialize(&self) -> String {
self.to_string()
}
fn deserialize(_val: &str) -> Result<Self, XmlDeError> {
Err(XmlDeError::Other("TODO: Handle this error".to_owned()))
}
}
impl<T: Value> XmlDeserialize for T {
impl<T: ValueDeserialize> XmlDeserialize for T {
fn deserialize<R: BufRead>(
reader: &mut quick_xml::NsReader<R>,
_start: &BytesStart,
@@ -88,11 +89,11 @@ impl<T: Value> XmlDeserialize for T {
}
}
Value::deserialize(&string)
ValueDeserialize::deserialize(&string)
}
}
impl<T: Value> XmlSerialize for T {
impl<T: ValueSerialize> XmlSerialize for T {
fn serialize<W: std::io::Write>(
&self,
ns: Option<Namespace>,