Skip to content

Commit

Permalink
xml use tuple structs
Browse files Browse the repository at this point in the history
  • Loading branch information
lennart-k committed Jan 5, 2025
1 parent 2eb6b19 commit 9ea9beb
Show file tree
Hide file tree
Showing 17 changed files with 57 additions and 141 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -78,10 +78,9 @@ pub async fn handle_calendar_multiget<C: CalendarStore + ?Sized>(
PropfindType::Propname => {
vec!["propname".to_owned()]
}
PropfindType::Prop(PropElement { prop: prop_tags }) => prop_tags
.into_iter()
.map(|propname| propname.name)
.collect(),
PropfindType::Prop(PropElement(prop_tags)) => {
prop_tags.into_iter().map(|propname| propname.0).collect()
}
};
let props: Vec<&str> = props.iter().map(String::as_str).collect();

Expand Down
7 changes: 3 additions & 4 deletions crates/caldav/src/calendar/methods/report/calendar_query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -207,10 +207,9 @@ pub async fn handle_calendar_query<C: CalendarStore + ?Sized>(
PropfindType::Propname => {
vec!["propname".to_owned()]
}
PropfindType::Prop(PropElement { prop: prop_tags }) => prop_tags
.into_iter()
.map(|propname| propname.name)
.collect(),
PropfindType::Prop(PropElement(prop_tags)) => {
prop_tags.into_iter().map(|propname| propname.0).collect()
}
};
let props: Vec<&str> = props.iter().map(String::as_str).collect();

Expand Down
7 changes: 3 additions & 4 deletions crates/caldav/src/calendar/methods/report/sync_collection.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,10 +73,9 @@ pub async fn handle_sync_collection<C: CalendarStore + ?Sized>(
PropfindType::Propname => {
vec!["propname".to_owned()]
}
PropfindType::Prop(PropElement { prop: prop_tags }) => prop_tags
.into_iter()
.map(|propname| propname.name)
.collect(),
PropfindType::Prop(PropElement(prop_tags)) => {
prop_tags.into_iter().map(|propname| propname.0).collect()
}
};
let props: Vec<&str> = props.iter().map(String::as_str).collect();

Expand Down
20 changes: 4 additions & 16 deletions crates/caldav/src/calendar/resource.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,25 +100,13 @@ impl Resource for CalendarResource {
fn get_resourcetype(&self) -> Resourcetype {
if self.0.subscription_url.is_none() {
Resourcetype(&[
ResourcetypeInner {
ns: rustical_dav::namespace::NS_DAV,
name: "collection",
},
ResourcetypeInner {
ns: rustical_dav::namespace::NS_CALDAV,
name: "calendar",
},
ResourcetypeInner(rustical_dav::namespace::NS_DAV, "collection"),
ResourcetypeInner(rustical_dav::namespace::NS_CALDAV, "calendar"),
])
} else {
Resourcetype(&[
ResourcetypeInner {
ns: rustical_dav::namespace::NS_DAV,
name: "collection",
},
ResourcetypeInner {
ns: rustical_dav::namespace::NS_CALENDARSERVER,
name: "subscribed",
},
ResourcetypeInner(rustical_dav::namespace::NS_DAV, "collection"),
ResourcetypeInner(rustical_dav::namespace::NS_CALENDARSERVER, "subscribed"),
])
}
}
Expand Down
10 changes: 2 additions & 8 deletions crates/caldav/src/principal/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,14 +59,8 @@ impl Resource for PrincipalResource {

fn get_resourcetype(&self) -> Resourcetype {
Resourcetype(&[
ResourcetypeInner {
ns: rustical_dav::namespace::NS_DAV,
name: "collection",
},
ResourcetypeInner {
ns: rustical_dav::namespace::NS_DAV,
name: "principal",
},
ResourcetypeInner(rustical_dav::namespace::NS_DAV, "collection"),
ResourcetypeInner(rustical_dav::namespace::NS_DAV, "principal"),
])
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,10 +84,9 @@ pub async fn handle_addressbook_multiget<AS: AddressbookStore + ?Sized>(
PropfindType::Propname => {
vec!["propname".to_owned()]
}
PropfindType::Prop(PropElement { prop: prop_tags }) => prop_tags
.into_iter()
.map(|propname| propname.name)
.collect(),
PropfindType::Prop(PropElement(prop_tags)) => {
prop_tags.into_iter().map(|propname| propname.0).collect()
}
};
let props: Vec<&str> = props.iter().map(String::as_str).collect();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,10 +70,9 @@ pub async fn handle_sync_collection<AS: AddressbookStore + ?Sized>(
PropfindType::Propname => {
vec!["propname".to_owned()]
}
PropfindType::Prop(PropElement { prop: prop_tags }) => prop_tags
.into_iter()
.map(|propname| propname.name)
.collect(),
PropfindType::Prop(PropElement(prop_tags)) => {
prop_tags.into_iter().map(|propname| propname.0).collect()
}
};
let props: Vec<&str> = props.iter().map(String::as_str).collect();

Expand Down
10 changes: 2 additions & 8 deletions crates/carddav/src/addressbook/resource.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,14 +72,8 @@ impl Resource for AddressbookResource {

fn get_resourcetype(&self) -> Resourcetype {
Resourcetype(&[
ResourcetypeInner {
ns: rustical_dav::namespace::NS_DAV,
name: "collection",
},
ResourcetypeInner {
ns: rustical_dav::namespace::NS_CARDDAV,
name: "addressbook",
},
ResourcetypeInner(rustical_dav::namespace::NS_DAV, "collection"),
ResourcetypeInner(rustical_dav::namespace::NS_CARDDAV, "addressbook"),
])
}

Expand Down
10 changes: 2 additions & 8 deletions crates/carddav/src/principal/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,14 +60,8 @@ impl Resource for PrincipalResource {

fn get_resourcetype(&self) -> Resourcetype {
Resourcetype(&[
ResourcetypeInner {
ns: rustical_dav::namespace::NS_DAV,
name: "collection",
},
ResourcetypeInner {
ns: rustical_dav::namespace::NS_DAV,
name: "principal",
},
ResourcetypeInner(rustical_dav::namespace::NS_DAV, "collection"),
ResourcetypeInner(rustical_dav::namespace::NS_DAV, "principal"),
])
}

Expand Down
6 changes: 3 additions & 3 deletions crates/dav/src/resource/methods/propfind.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use actix_web::web::Data;
use actix_web::web::Path;
use actix_web::HttpRequest;
use rustical_store::auth::User;
use rustical_xml::de::XmlDocument;
use rustical_xml::XmlDocument;
use tracing::instrument;
use tracing_actix_web::RootSpan;

Expand Down Expand Up @@ -53,9 +53,9 @@ pub(crate) async fn route_propfind<R: ResourceService>(
let props = match &propfind.prop {
PropfindType::Allprop => vec!["allprop"],
PropfindType::Propname => vec!["propname"],
PropfindType::Prop(PropElement { prop: prop_tags }) => prop_tags
PropfindType::Prop(PropElement(prop_tags)) => prop_tags
.iter()
.map(|propname| propname.name.as_str())
.map(|propname| propname.0.as_str())
.collect(),
};

Expand Down
34 changes: 13 additions & 21 deletions crates/dav/src/resource/methods/proppatch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,9 @@ enum SetPropertyPropWrapper<T: XmlDeserialize> {

// We are <prop>
#[derive(XmlDeserialize, Clone, Debug)]
struct SetPropertyPropWrapperWrapper<T: XmlDeserialize> {
#[xml(ty = "untagged")]
property: SetPropertyPropWrapper<T>,
}
struct SetPropertyPropWrapperWrapper<T: XmlDeserialize>(
#[xml(ty = "untagged")] SetPropertyPropWrapper<T>,
);

// We are <set>
#[derive(XmlDeserialize, Clone, Debug)]
Expand All @@ -39,16 +38,10 @@ struct SetPropertyElement<T: XmlDeserialize> {
}

#[derive(XmlDeserialize, Clone, Debug)]
struct TagName {
#[xml(ty = "tag_name")]
name: String,
}
struct TagName(#[xml(ty = "tag_name")] String);

#[derive(XmlDeserialize, Clone, Debug)]
struct PropertyElement {
#[xml(ty = "untagged")]
property: TagName,
}
struct PropertyElement(#[xml(ty = "untagged")] TagName);

#[derive(XmlDeserialize, Clone, Debug)]
struct RemovePropertyElement {
Expand All @@ -67,10 +60,7 @@ enum Operation<T: XmlDeserialize> {
#[derive(XmlDeserialize, XmlRootTag, Clone, Debug)]
#[xml(root = b"propertyupdate")]
#[xml(ns = "crate::namespace::NS_DAV")]
struct PropertyupdateElement<T: XmlDeserialize> {
#[xml(ty = "untagged", flatten)]
operations: Vec<Operation<T>>,
}
struct PropertyupdateElement<T: XmlDeserialize>(#[xml(ty = "untagged", flatten)] Vec<Operation<T>>);

#[instrument(parent = root_span.id(), skip(path, req, root_span, resource_service))]
pub(crate) async fn route_proppatch<R: ResourceService>(
Expand All @@ -84,9 +74,9 @@ pub(crate) async fn route_proppatch<R: ResourceService>(
let href = req.path().to_owned();

// Extract operations
let PropertyupdateElement::<SetPropertyPropWrapperWrapper<<R::Resource as Resource>::Prop>> {
let PropertyupdateElement::<SetPropertyPropWrapperWrapper<<R::Resource as Resource>::Prop>>(
operations,
} = XmlDocument::parse_str(&body).map_err(Error::XmlDeserializationError)?;
) = XmlDocument::parse_str(&body).map_err(Error::XmlDeserializationError)?;

let mut resource = resource_service.get_resource(&path).await?;
let privileges = resource.get_user_privileges(&user)?;
Expand All @@ -100,8 +90,10 @@ pub(crate) async fn route_proppatch<R: ResourceService>(

for operation in operations.into_iter() {
match operation {
Operation::Set(SetPropertyElement { prop }) => {
match prop.property {
Operation::Set(SetPropertyElement {
prop: SetPropertyPropWrapperWrapper(property),
}) => {
match property {
SetPropertyPropWrapper::Valid(prop) => {
let propname: <R::Resource as Resource>::PropName = prop.clone().into();
let propname: &str = propname.into();
Expand All @@ -125,7 +117,7 @@ pub(crate) async fn route_proppatch<R: ResourceService>(
}
}
Operation::Remove(remove_el) => {
let propname = remove_el.prop.property.name;
let propname = remove_el.prop.0 .0;
match <<R::Resource as Resource>::PropName as FromStr>::from_str(&propname) {
Ok(prop) => match resource.remove_prop(&prop) {
Ok(()) => props_ok.push(propname),
Expand Down
4 changes: 1 addition & 3 deletions crates/dav/src/resource/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -207,9 +207,7 @@ pub trait Resource: Clone + 'static {

let mut propstats = vec![PropstatWrapper::Normal(PropstatElement {
status: StatusCode::OK,
prop: PropTagWrapper {
prop: prop_responses,
},
prop: PropTagWrapper(prop_responses),
})];
if !invalid_props.is_empty() {
propstats.push(PropstatWrapper::TagList(PropstatElement {
Expand Down
5 changes: 1 addition & 4 deletions crates/dav/src/resources/root.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,7 @@ impl<PR: Resource> Resource for RootResource<PR> {
type PrincipalResource = PR;

fn get_resourcetype(&self) -> Resourcetype {
Resourcetype(&[ResourcetypeInner {
ns: crate::namespace::NS_DAV,
name: "collection",
}])
Resourcetype(&[ResourcetypeInner(crate::namespace::NS_DAV, "collection")])
}

fn get_prop(
Expand Down
7 changes: 1 addition & 6 deletions crates/dav/src/xml/multistatus.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,8 @@ use actix_web::{
use quick_xml::name::Namespace;
use rustical_xml::{XmlRootTag, XmlSerialize, XmlSerializeRoot};

// Intermediate struct because of a serde limitation, see following article:
// https://stackoverflow.com/questions/78444158/unsupportedcannot-serialize-enum-newtype-variant-exampledata
#[derive(XmlSerialize)]
pub struct PropTagWrapper<T: XmlSerialize> {
#[xml(flatten, ty = "untagged")]
pub prop: Vec<T>,
}
pub struct PropTagWrapper<T: XmlSerialize>(#[xml(flatten, ty = "untagged")] pub Vec<T>);

// RFC 2518
// <!ELEMENT propstat (prop, status, responsedescription?) >
Expand Down
12 changes: 3 additions & 9 deletions crates/dav/src/xml/propfind.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,15 @@ use rustical_xml::XmlRootTag;
#[derive(Debug, Clone, XmlDeserialize, XmlRootTag, PartialEq)]
#[xml(root = b"propfind", ns = "crate::namespace::NS_DAV")]
pub struct PropfindElement {
#[xml(ty = "untagged")]
#[xml(ns = "crate::namespace::NS_DAV")]
pub prop: PropfindType,
}

#[derive(Debug, Clone, XmlDeserialize, PartialEq)]
pub struct PropElement {
#[xml(ty = "untagged", flatten)]
pub prop: Vec<Propname>,
}
pub struct PropElement(#[xml(ty = "untagged", flatten)] pub Vec<Propname>);

#[derive(Debug, Clone, XmlDeserialize, PartialEq)]
pub struct Propname {
#[xml(ty = "tag_name")]
pub name: String,
}
pub struct Propname(#[xml(ty = "tag_name")] pub String);

#[derive(Debug, Clone, XmlDeserialize, PartialEq)]
pub enum PropfindType {
Expand Down
20 changes: 6 additions & 14 deletions crates/dav/src/xml/resourcetype.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,10 @@ use rustical_xml::XmlSerialize;
pub struct Resourcetype(#[xml(flatten, ty = "untagged")] pub &'static [ResourcetypeInner]);

#[derive(Debug, Clone, PartialEq, XmlSerialize)]
pub struct ResourcetypeInner {
#[xml(ty = "namespace")]
pub ns: quick_xml::name::Namespace<'static>,
#[xml(ty = "tag_name")]
pub name: &'static str,
}
pub struct ResourcetypeInner(
#[xml(ty = "namespace")] pub quick_xml::name::Namespace<'static>,
#[xml(ty = "tag_name")] pub &'static str,
);

#[cfg(test)]
mod tests {
Expand All @@ -29,14 +27,8 @@ mod tests {
let mut writer = quick_xml::Writer::new(&mut buf);
Document {
resourcetype: Resourcetype(&[
ResourcetypeInner {
ns: crate::namespace::NS_DAV,
name: "displayname",
},
ResourcetypeInner {
ns: crate::namespace::NS_CALENDARSERVER,
name: "calendar-color",
},
ResourcetypeInner(crate::namespace::NS_DAV, "displayname"),
ResourcetypeInner(crate::namespace::NS_CALENDARSERVER, "calendar-color"),
]),
}
.serialize_root(&mut writer)
Expand Down
25 changes: 4 additions & 21 deletions crates/dav/src/xml/tag_list.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,33 +15,16 @@ impl XmlSerialize for TagList {
writer: &mut quick_xml::Writer<W>,
) -> std::io::Result<()> {
#[derive(Debug, XmlSerialize, PartialEq)]
struct Inner {
#[xml(ty = "untagged", flatten)]
tags: Vec<Tag>,
}
struct Inner(#[xml(ty = "untagged", flatten)] Vec<Tag>);

#[derive(Debug, XmlSerialize, PartialEq)]
struct Tag {
#[xml(ty = "tag_name")]
name: String,
}
Inner {
tags: self.0.iter().map(|t| Tag { name: t.to_owned() }).collect(),
}
.serialize(ns, tag, namespaces, writer)
struct Tag(#[xml(ty = "tag_name")] String);
Inner(self.0.iter().map(|t| Tag(t.to_owned())).collect())
.serialize(ns, tag, namespaces, writer)
}

#[allow(refining_impl_trait)]
fn attributes<'a>(&self) -> Option<Vec<quick_xml::events::attributes::Attribute<'a>>> {
None
}
}

impl TagList {
pub fn inner(&self) -> &Vec<String> {
&self.0
}
pub fn into_inner(self) -> Vec<String> {
self.0
}
}

0 comments on commit 9ea9beb

Please sign in to comment.