Migrate all deserialization business to rustical_xml

This commit is contained in:
Lennart
2024-12-25 10:21:36 +01:00
parent 5e2717e130
commit 80472289dc
15 changed files with 99 additions and 121 deletions

View File

@@ -1,20 +1,20 @@
use serde::{Deserialize, Serialize}; use serde::Serialize;
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq)] #[derive(Debug, Clone, Serialize, PartialEq)]
#[serde(rename_all = "kebab-case")] #[serde(rename_all = "kebab-case")]
pub struct SupportedCalendarComponent { pub struct SupportedCalendarComponent {
#[serde(rename = "@name")] #[serde(rename = "@name")]
pub name: String, pub name: String,
} }
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq)] #[derive(Debug, Clone, Serialize, PartialEq)]
#[serde(rename_all = "kebab-case")] #[serde(rename_all = "kebab-case")]
pub struct SupportedCalendarComponentSet { pub struct SupportedCalendarComponentSet {
#[serde(rename = "C:comp")] #[serde(rename = "C:comp")]
pub comp: Vec<SupportedCalendarComponent>, pub comp: Vec<SupportedCalendarComponent>,
} }
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq)] #[derive(Debug, Clone, Serialize, PartialEq)]
#[serde(rename_all = "kebab-case")] #[serde(rename_all = "kebab-case")]
pub struct CalendarData { pub struct CalendarData {
#[serde(rename = "@content-type")] #[serde(rename = "@content-type")]

View File

@@ -19,7 +19,8 @@ use rustical_dav::resource::{Resource, ResourceService};
use rustical_dav::xml::HrefElement; use rustical_dav::xml::HrefElement;
use rustical_store::auth::User; use rustical_store::auth::User;
use rustical_store::{Calendar, CalendarStore}; use rustical_store::{Calendar, CalendarStore};
use serde::{Deserialize, Serialize}; use rustical_xml::XmlDeserialize;
use serde::Serialize;
use sha2::{Digest, Sha256}; use sha2::{Digest, Sha256};
use std::str::FromStr; use std::str::FromStr;
use std::sync::Arc; use std::sync::Arc;
@@ -31,7 +32,7 @@ pub struct CalendarResourceService<C: CalendarStore + ?Sized> {
calendar_id: String, calendar_id: String,
} }
#[derive(Default, Deserialize, Serialize, PartialEq, EnumDiscriminants)] #[derive(Default, XmlDeserialize, Serialize, PartialEq, EnumDiscriminants)]
#[strum_discriminants( #[strum_discriminants(
name(CalendarPropName), name(CalendarPropName),
derive(EnumString, VariantNames), derive(EnumString, VariantNames),
@@ -48,6 +49,7 @@ pub enum CalendarProp {
// in DAVx5 yet // in DAVx5 yet
// https://github.com/bitfireAT/webdav-push/commit/461259a2f2174454b2b00033419b11fac52b79e3 // https://github.com/bitfireAT/webdav-push/commit/461259a2f2174454b2b00033419b11fac52b79e3
#[serde(skip_deserializing)] #[serde(skip_deserializing)]
#[xml(skip_deserializing)]
#[serde(rename = "P:push-transports", alias = "push-transports")] #[serde(rename = "P:push-transports", alias = "push-transports")]
Transports(Transports), Transports(Transports),
Topic(String), Topic(String),
@@ -65,15 +67,19 @@ pub enum CalendarProp {
rename = "C:supported-calendar-component-set", rename = "C:supported-calendar-component-set",
alias = "supported-calendar-component-set" alias = "supported-calendar-component-set"
)] )]
// TODO: Re-add
#[xml(skip_deserializing)]
SupportedCalendarComponentSet(SupportedCalendarComponentSet), SupportedCalendarComponentSet(SupportedCalendarComponentSet),
#[serde( #[serde(
rename = "C:supported-calendar-data", rename = "C:supported-calendar-data",
alias = "supported-calendar-data" alias = "supported-calendar-data"
)] )]
#[serde(skip_deserializing)] #[serde(skip_deserializing)]
#[xml(skip_deserializing)]
SupportedCalendarData(SupportedCalendarData), SupportedCalendarData(SupportedCalendarData),
MaxResourceSize(i64), MaxResourceSize(i64),
#[serde(skip_deserializing)] #[serde(skip_deserializing)]
#[xml(skip_deserializing)]
SupportedReportSet(SupportedReportSet), SupportedReportSet(SupportedReportSet),
// Collection Synchronization (RFC 6578) // Collection Synchronization (RFC 6578)

View File

@@ -8,6 +8,7 @@ use rustical_dav::{
resource::{Resource, ResourceService}, resource::{Resource, ResourceService},
}; };
use rustical_store::{auth::User, CalendarObject, CalendarStore}; use rustical_store::{auth::User, CalendarObject, CalendarStore};
use rustical_xml::XmlDeserialize;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::sync::Arc; use std::sync::Arc;
use strum::{EnumDiscriminants, EnumString, VariantNames}; use strum::{EnumDiscriminants, EnumString, VariantNames};
@@ -19,7 +20,7 @@ pub struct CalendarObjectResourceService<C: CalendarStore + ?Sized> {
object_id: String, object_id: String,
} }
#[derive(Default, Deserialize, Serialize, PartialEq, EnumDiscriminants)] #[derive(Default, XmlDeserialize, Serialize, PartialEq, EnumDiscriminants)]
#[strum_discriminants( #[strum_discriminants(
name(CalendarObjectPropName), name(CalendarObjectPropName),
derive(EnumString, VariantNames), derive(EnumString, VariantNames),
@@ -36,6 +37,7 @@ pub enum CalendarObjectProp {
CalendarData(String), CalendarData(String),
#[serde(other)] #[serde(other)]
#[xml(other)]
#[strum_discriminants(strum(disabled))] #[strum_discriminants(strum(disabled))]
#[default] #[default]
Invalid, Invalid,

View File

@@ -9,7 +9,8 @@ use rustical_dav::resource::{Resource, ResourceService};
use rustical_dav::xml::HrefElement; use rustical_dav::xml::HrefElement;
use rustical_store::auth::User; use rustical_store::auth::User;
use rustical_store::CalendarStore; use rustical_store::CalendarStore;
use serde::{Deserialize, Serialize}; use rustical_xml::XmlDeserialize;
use serde::Serialize;
use std::sync::Arc; use std::sync::Arc;
use strum::{EnumDiscriminants, EnumString, VariantNames}; use strum::{EnumDiscriminants, EnumString, VariantNames};
@@ -23,7 +24,7 @@ pub struct PrincipalResource {
principal: String, principal: String,
} }
#[derive(Default, Deserialize, Serialize, PartialEq, EnumDiscriminants)] #[derive(Default, XmlDeserialize, Serialize, PartialEq, EnumDiscriminants)]
#[strum_discriminants( #[strum_discriminants(
name(PrincipalPropName), name(PrincipalPropName),
derive(EnumString, VariantNames), derive(EnumString, VariantNames),
@@ -43,6 +44,7 @@ pub enum PrincipalProp {
CalendarUserAddressSet(HrefElement), CalendarUserAddressSet(HrefElement),
#[serde(other)] #[serde(other)]
#[xml(other)]
#[strum_discriminants(strum(disabled))] #[strum_discriminants(strum(disabled))]
#[default] #[default]
Invalid, Invalid,

View File

@@ -7,6 +7,7 @@ use rustical_dav::{
resource::{Resource, ResourceService}, resource::{Resource, ResourceService},
}; };
use rustical_store::{auth::User, AddressObject, AddressbookStore}; use rustical_store::{auth::User, AddressObject, AddressbookStore};
use rustical_xml::XmlDeserialize;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::sync::Arc; use std::sync::Arc;
use strum::{EnumDiscriminants, EnumString, VariantNames}; use strum::{EnumDiscriminants, EnumString, VariantNames};
@@ -20,7 +21,7 @@ pub struct AddressObjectResourceService<AS: AddressbookStore + ?Sized> {
object_id: String, object_id: String,
} }
#[derive(Default, Deserialize, Serialize, PartialEq, EnumDiscriminants)] #[derive(Default, XmlDeserialize, Serialize, PartialEq, EnumDiscriminants)]
#[strum_discriminants( #[strum_discriminants(
name(AddressObjectPropName), name(AddressObjectPropName),
derive(EnumString, VariantNames), derive(EnumString, VariantNames),
@@ -37,6 +38,7 @@ pub enum AddressObjectProp {
AddressData(String), AddressData(String),
#[serde(other)] #[serde(other)]
#[xml(other)]
#[strum_discriminants(strum(disabled))] #[strum_discriminants(strum(disabled))]
#[default] #[default]
Invalid, Invalid,

View File

@@ -14,7 +14,8 @@ use rustical_dav::privileges::UserPrivilegeSet;
use rustical_dav::resource::{Resource, ResourceService}; use rustical_dav::resource::{Resource, ResourceService};
use rustical_store::auth::User; use rustical_store::auth::User;
use rustical_store::{Addressbook, AddressbookStore}; use rustical_store::{Addressbook, AddressbookStore};
use serde::{Deserialize, Serialize}; use rustical_xml::XmlDeserialize;
use serde::Serialize;
use std::str::FromStr; use std::str::FromStr;
use std::sync::Arc; use std::sync::Arc;
use strum::{EnumDiscriminants, EnumString, VariantNames}; use strum::{EnumDiscriminants, EnumString, VariantNames};
@@ -25,7 +26,7 @@ pub struct AddressbookResourceService<AS: AddressbookStore + ?Sized> {
addressbook_id: String, addressbook_id: String,
} }
#[derive(Default, Deserialize, Serialize, PartialEq, EnumDiscriminants)] #[derive(Default, XmlDeserialize, Serialize, PartialEq, EnumDiscriminants)]
#[serde(rename_all = "kebab-case")] #[serde(rename_all = "kebab-case")]
#[strum_discriminants( #[strum_discriminants(
name(AddressbookPropName), name(AddressbookPropName),
@@ -48,8 +49,10 @@ pub enum AddressbookProp {
alias = "supported-address-data" alias = "supported-address-data"
)] )]
#[serde(skip_deserializing)] #[serde(skip_deserializing)]
#[xml(skip_deserializing)]
SupportedAddressData(SupportedAddressData), SupportedAddressData(SupportedAddressData),
#[serde(skip_deserializing)] #[serde(skip_deserializing)]
#[xml(skip_deserializing)]
SupportedReportSet(SupportedReportSet), SupportedReportSet(SupportedReportSet),
MaxResourceSize(i64), MaxResourceSize(i64),
@@ -60,6 +63,7 @@ pub enum AddressbookProp {
Getctag(String), Getctag(String),
#[serde(other)] #[serde(other)]
#[xml(other)]
#[strum_discriminants(strum(disabled))] #[strum_discriminants(strum(disabled))]
#[default] #[default]
Invalid, Invalid,

View File

@@ -9,7 +9,8 @@ use rustical_dav::resource::{Resource, ResourceService};
use rustical_dav::xml::HrefElement; use rustical_dav::xml::HrefElement;
use rustical_store::auth::User; use rustical_store::auth::User;
use rustical_store::AddressbookStore; use rustical_store::AddressbookStore;
use serde::{Deserialize, Serialize}; use rustical_xml::XmlDeserialize;
use serde::Serialize;
use std::sync::Arc; use std::sync::Arc;
use strum::{EnumDiscriminants, EnumString, VariantNames}; use strum::{EnumDiscriminants, EnumString, VariantNames};
@@ -23,7 +24,7 @@ pub struct PrincipalResource {
principal: String, principal: String,
} }
#[derive(Default, Deserialize, Serialize, PartialEq, EnumDiscriminants)] #[derive(Default, XmlDeserialize, Serialize, PartialEq, EnumDiscriminants)]
#[strum_discriminants( #[strum_discriminants(
name(PrincipalPropName), name(PrincipalPropName),
derive(EnumString, VariantNames), derive(EnumString, VariantNames),
@@ -43,6 +44,7 @@ pub enum PrincipalProp {
PrincipalAddress(Option<HrefElement>), PrincipalAddress(Option<HrefElement>),
#[serde(other)] #[serde(other)]
#[xml(other)]
#[strum_discriminants(strum(disabled))] #[strum_discriminants(strum(disabled))]
#[default] #[default]
Invalid, Invalid,

View File

@@ -20,10 +20,7 @@ pub enum Error {
PropReadOnly, PropReadOnly,
#[error(transparent)] #[error(transparent)]
NewXmlDeserializationError(#[from] rustical_xml::XmlDeError), XmlDeserializationError(#[from] rustical_xml::XmlDeError),
#[error(transparent)]
XmlDeserializationError(#[from] quick_xml::DeError),
#[error(transparent)] #[error(transparent)]
XmlSerializationError(#[from] quick_xml::SeError), XmlSerializationError(#[from] quick_xml::SeError),
@@ -36,7 +33,6 @@ impl actix_web::error::ResponseError for Error {
Self::NotFound => StatusCode::NOT_FOUND, Self::NotFound => StatusCode::NOT_FOUND,
Self::BadRequest(_) => StatusCode::BAD_REQUEST, Self::BadRequest(_) => StatusCode::BAD_REQUEST,
Self::Unauthorized => StatusCode::UNAUTHORIZED, Self::Unauthorized => StatusCode::UNAUTHORIZED,
Self::NewXmlDeserializationError(_) => StatusCode::BAD_REQUEST,
Self::XmlDeserializationError(_) => StatusCode::BAD_REQUEST, Self::XmlDeserializationError(_) => StatusCode::BAD_REQUEST,
Self::XmlSerializationError(_) => StatusCode::BAD_REQUEST, Self::XmlSerializationError(_) => StatusCode::BAD_REQUEST,
Error::PropReadOnly => StatusCode::CONFLICT, Error::PropReadOnly => StatusCode::CONFLICT,

View File

@@ -1,8 +1,8 @@
use serde::{Deserialize, Serialize}; use rustical_xml::XmlDeserialize;
use serde::Serialize;
use std::collections::HashSet; use std::collections::HashSet;
#[derive(Debug, Clone, Serialize, Deserialize, Eq, Hash, PartialEq)] #[derive(Debug, Clone, Serialize, XmlDeserialize, Eq, Hash, PartialEq)]
#[serde(rename_all = "kebab-case")]
pub enum UserPrivilege { pub enum UserPrivilege {
Read, Read,
Write, Write,
@@ -42,10 +42,9 @@ impl Serialize for UserPrivilegeSet {
} }
} }
// TODO: implement Deserialize once we need it #[derive(Debug, Clone, XmlDeserialize, Default, PartialEq)]
#[derive(Debug, Clone, Deserialize, Default, PartialEq)]
#[serde(rename_all = "kebab-case")]
pub struct UserPrivilegeSet { pub struct UserPrivilegeSet {
#[xml(flatten)]
privileges: HashSet<UserPrivilege>, privileges: HashSet<UserPrivilege>,
} }

View File

@@ -42,7 +42,7 @@ pub(crate) async fn route_propfind<R: ResourceService>(
// A request body is optional. If empty we MUST return all props // A request body is optional. If empty we MUST return all props
let propfind: PropfindElement = if !body.is_empty() { let propfind: PropfindElement = if !body.is_empty() {
PropfindElement::parse_str(&body).map_err(Error::NewXmlDeserializationError)? PropfindElement::parse_str(&body).map_err(Error::XmlDeserializationError)?
} else { } else {
PropfindElement { PropfindElement {
prop: PropfindType::Allprop, prop: PropfindType::Allprop,

View File

@@ -5,47 +5,53 @@ use crate::resource::ResourceService;
use crate::xml::multistatus::{PropstatElement, PropstatWrapper, ResponseElement}; use crate::xml::multistatus::{PropstatElement, PropstatWrapper, ResponseElement};
use crate::xml::MultistatusElement; use crate::xml::MultistatusElement;
use crate::xml::TagList; use crate::xml::TagList;
use crate::xml::TagName;
use crate::Error; use crate::Error;
use actix_web::http::StatusCode; use actix_web::http::StatusCode;
use actix_web::{web::Path, HttpRequest}; use actix_web::{web::Path, HttpRequest};
use rustical_store::auth::User; use rustical_store::auth::User;
use serde::{Deserialize, Serialize}; use rustical_xml::XmlDeserialize;
use rustical_xml::XmlDocument;
use rustical_xml::XmlRootTag;
use std::str::FromStr; use std::str::FromStr;
use tracing::instrument; use tracing::instrument;
use tracing_actix_web::RootSpan; use tracing_actix_web::RootSpan;
// https://docs.rs/quick-xml/latest/quick_xml/de/index.html#normal-enum-variant #[derive(XmlDeserialize, Clone, Debug)]
#[derive(Deserialize, Serialize, Clone, Debug)] struct SetPropertyElement<T: XmlDeserialize> {
#[serde(rename_all = "kebab-case")]
struct PropertyElement<T> {
#[serde(rename = "$value")]
prop: T, prop: T,
} }
#[derive(Deserialize, Clone, Debug)] #[derive(XmlDeserialize, Clone, Debug)]
#[serde(rename_all = "kebab-case")] struct TagName {
struct SetPropertyElement<T> { #[xml(ty = "tag_name")]
prop: PropertyElement<T>, name: String,
} }
#[derive(Deserialize, Clone, Debug)] #[derive(XmlDeserialize, Clone, Debug)]
#[serde(rename_all = "kebab-case")] struct PropertyElement {
#[xml(ty = "untagged")]
property: TagName,
}
#[derive(XmlDeserialize, Clone, Debug)]
struct RemovePropertyElement { struct RemovePropertyElement {
prop: PropertyElement<TagName>, prop: PropertyElement,
} }
#[derive(Deserialize, Clone, Debug)] #[derive(XmlDeserialize, Clone, Debug)]
#[serde(rename_all = "kebab-case")] enum Operation<T: XmlDeserialize> {
enum Operation<PropType> { Set(SetPropertyElement<T>),
Set(SetPropertyElement<PropType>),
Remove(RemovePropertyElement), Remove(RemovePropertyElement),
} }
#[derive(Deserialize, Clone, Debug)] #[derive(XmlDeserialize, XmlRootTag, Clone, Debug)]
#[serde(rename_all = "kebab-case")] #[xml(root = b"propertyupdate")]
struct PropertyupdateElement<T> { struct PropertyupdateElement<T: XmlDeserialize> {
#[serde(rename = "$value", default = "Vec::new")] // #[xml(flatten)]
// set: Vec<T>,
// #[xml(flatten)]
// remove: Vec<TagName>,
#[xml(ty = "untagged", flatten)]
operations: Vec<Operation<T>>, operations: Vec<Operation<T>>,
} }
@@ -63,18 +69,18 @@ pub(crate) async fn route_proppatch<R: ResourceService>(
// Extract operations // Extract operations
let PropertyupdateElement::<<R::Resource as Resource>::Prop> { operations } = let PropertyupdateElement::<<R::Resource as Resource>::Prop> { operations } =
quick_xml::de::from_str(&body).map_err(Error::XmlDeserializationError)?; XmlDocument::parse_str(&body).map_err(Error::XmlDeserializationError)?;
// Extract all set property names without verification // Extract all set property names without verification
// Weird workaround because quick_xml doesn't allow untagged enums // Weird workaround because quick_xml doesn't allow untagged enums
let propnames: Vec<String> = quick_xml::de::from_str::<PropertyupdateElement<TagName>>(&body) let propnames: Vec<String> = PropertyupdateElement::<TagName>::parse_str(&body)
.map_err(Error::XmlDeserializationError)? .map_err(Error::XmlDeserializationError)?
.operations .operations
.into_iter() .into_iter()
.map(|op_el| match op_el { .map(|op_el| match op_el {
Operation::Set(set_el) => set_el.prop.prop.into(), Operation::Set(set_el) => set_el.prop.name,
// If we can't remove a nonexisting property then that's no big deal // If we can't remove a nonexisting property then that's no big deal
Operation::Remove(remove_el) => remove_el.prop.prop.into(), Operation::Remove(remove_el) => remove_el.prop.property.name,
}) })
.collect(); .collect();
@@ -90,9 +96,7 @@ pub(crate) async fn route_proppatch<R: ResourceService>(
for (operation, propname) in operations.into_iter().zip(propnames) { for (operation, propname) in operations.into_iter().zip(propnames) {
match operation { match operation {
Operation::Set(SetPropertyElement { Operation::Set(SetPropertyElement { prop }) => {
prop: PropertyElement { prop },
}) => {
if prop.invalid_property() { if prop.invalid_property() {
if <R::Resource as Resource>::list_props().contains(&propname.as_str()) { if <R::Resource as Resource>::list_props().contains(&propname.as_str()) {
// This happens in following cases: // This happens in following cases:

View File

@@ -11,7 +11,8 @@ pub use invalid_property::InvalidProperty;
use itertools::Itertools; use itertools::Itertools;
pub use resource_service::ResourceService; pub use resource_service::ResourceService;
use rustical_store::auth::User; use rustical_store::auth::User;
use serde::{Deserialize, Serialize}; use rustical_xml::XmlDeserialize;
use serde::Serialize;
use std::str::FromStr; use std::str::FromStr;
use strum::{EnumString, VariantNames}; use strum::{EnumString, VariantNames};
@@ -19,20 +20,21 @@ mod invalid_property;
mod methods; mod methods;
mod resource_service; mod resource_service;
pub trait ResourceProp: InvalidProperty + Serialize + for<'de> Deserialize<'de> {} pub trait ResourceProp: InvalidProperty + Serialize + XmlDeserialize {}
impl<T: InvalidProperty + Serialize + for<'de> Deserialize<'de>> ResourceProp for T {} impl<T: InvalidProperty + Serialize + XmlDeserialize> ResourceProp for T {}
pub trait ResourcePropName: FromStr + VariantNames {} pub trait ResourcePropName: FromStr + VariantNames {}
impl<T: FromStr + VariantNames> ResourcePropName for T {} impl<T: FromStr + VariantNames> ResourcePropName for T {}
pub trait ResourceType: Serialize + for<'de> Deserialize<'de> {} pub trait ResourceType: Serialize + XmlDeserialize {}
impl<T: Serialize + for<'de> Deserialize<'de>> ResourceType for T {} impl<T: Serialize + XmlDeserialize> ResourceType for T {}
#[derive(Deserialize, Serialize, PartialEq, Default)] #[derive(XmlDeserialize, Serialize, PartialEq, Default)]
#[serde(rename_all = "kebab-case")] #[serde(rename_all = "kebab-case")]
pub enum CommonPropertiesProp { pub enum CommonPropertiesProp {
// WebDAV (RFC 2518) // WebDAV (RFC 2518)
#[serde(skip_deserializing)] #[serde(skip_deserializing)]
#[xml(skip_deserializing)]
Resourcetype(Resourcetype), Resourcetype(Resourcetype),
// WebDAV Current Principal Extension (RFC 5397) // WebDAV Current Principal Extension (RFC 5397)
@@ -40,7 +42,7 @@ pub enum CommonPropertiesProp {
// WebDAV Access Control Protocol (RFC 3477) // WebDAV Access Control Protocol (RFC 3477)
CurrentUserPrivilegeSet(UserPrivilegeSet), CurrentUserPrivilegeSet(UserPrivilegeSet),
Owner(Option<HrefElement>), Owner(HrefElement),
#[serde(other)] #[serde(other)]
#[default] #[default]
@@ -97,11 +99,18 @@ pub trait Resource: Clone + 'static {
CommonPropertiesProp::CurrentUserPrivilegeSet(self.get_user_privileges(user)?) CommonPropertiesProp::CurrentUserPrivilegeSet(self.get_user_privileges(user)?)
} }
CommonPropertiesPropName::Owner => { CommonPropertiesPropName::Owner => {
CommonPropertiesProp::Owner(self.get_owner().map(|owner| { // TODO: Reintroduce optional owner field
let owner = self.get_owner().unwrap_or(&user.id);
CommonPropertiesProp::Owner(
Self::PrincipalResource::get_url(rmap, [owner]) Self::PrincipalResource::get_url(rmap, [owner])
.unwrap() .unwrap()
.into() .into(),
})) )
// CommonPropertiesProp::Owner(self.get_owner().map(|owner| {
// Self::PrincipalResource::get_url(rmap, [owner])
// .unwrap()
// .into()
// }))
} }
}) })
} }

View File

@@ -4,7 +4,8 @@ use actix_web::dev::ResourceMap;
use actix_web::HttpRequest; use actix_web::HttpRequest;
use async_trait::async_trait; use async_trait::async_trait;
use rustical_store::auth::User; use rustical_store::auth::User;
use serde::{Deserialize, Serialize}; use rustical_xml::XmlDeserialize;
use serde::Serialize;
use std::any::type_name; use std::any::type_name;
use std::marker::PhantomData; use std::marker::PhantomData;
use strum::{EnumString, VariantNames}; use strum::{EnumString, VariantNames};
@@ -22,7 +23,7 @@ impl<PR: Resource> Default for RootResource<PR> {
#[strum(serialize_all = "kebab-case")] #[strum(serialize_all = "kebab-case")]
pub enum RootResourcePropName {} pub enum RootResourcePropName {}
#[derive(Deserialize, Serialize, Default, Clone, PartialEq)] #[derive(XmlDeserialize, Serialize, Default, Clone, PartialEq)]
pub enum RootResourceProp { pub enum RootResourceProp {
#[serde(other)] #[serde(other)]
#[default] #[default]

View File

@@ -2,20 +2,15 @@ pub mod multistatus;
mod propfind; mod propfind;
mod resourcetype; mod resourcetype;
pub mod tag_list; pub mod tag_list;
pub mod tag_name;
pub use propfind::{PropElement, PropfindElement, PropfindType, Propname};
use derive_more::derive::From; use derive_more::derive::From;
pub use multistatus::MultistatusElement; pub use multistatus::MultistatusElement;
pub use tag_list::TagList; pub use propfind::{PropElement, PropfindElement, PropfindType, Propname};
pub use tag_name::TagName;
pub use resourcetype::Resourcetype; pub use resourcetype::Resourcetype;
use rustical_xml::XmlDeserialize;
use serde::Serialize;
pub use tag_list::TagList;
use serde::{Deserialize, Serialize}; #[derive(XmlDeserialize, Debug, Clone, Serialize, From, PartialEq)]
#[derive(Debug, Clone, Deserialize, Serialize, From, PartialEq)]
pub struct HrefElement { pub struct HrefElement {
pub href: String, pub href: String,
} }

View File

@@ -1,44 +0,0 @@
use serde::{
de::{VariantAccess, Visitor},
Deserialize,
};
#[derive(Debug, Clone, PartialEq)]
pub struct TagName(pub String);
impl From<TagName> for String {
fn from(value: TagName) -> Self {
value.0
}
}
impl From<String> for TagName {
fn from(value: String) -> Self {
Self(value)
}
}
impl<'de> Deserialize<'de> for TagName {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
struct __Visitor;
impl<'de> Visitor<'de> for __Visitor {
type Value = TagName;
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
formatter.write_str("tagname")
}
fn visit_enum<A>(self, data: A) -> Result<Self::Value, A::Error>
where
A: serde::de::EnumAccess<'de>,
{
let (name, variant): (String, _) = data.variant()?;
VariantAccess::unit_variant(variant)?;
Ok(TagName(name))
}
}
deserializer.deserialize_enum("doesn't matter", &[], __Visitor)
}
}