From 8d1202234d88f5f737a20105174db8a1246d936d Mon Sep 17 00:00:00 2001 From: Lennart <18233294+lennart-k@users.noreply.github.com> Date: Sat, 18 Jan 2025 20:00:26 +0100 Subject: [PATCH] Generate everything strum does myself (no duplicate prop names) --- crates/caldav/Cargo.toml | 1 - crates/caldav/src/calendar/resource.rs | 11 ++----- crates/caldav/src/calendar_object/resource.rs | 11 ++----- crates/caldav/src/calendar_set/mod.rs | 12 ++----- crates/caldav/src/principal/mod.rs | 12 ++----- crates/carddav/Cargo.toml | 1 - crates/carddav/src/address_object/resource.rs | 11 ++----- crates/carddav/src/addressbook/resource.rs | 11 ++----- crates/carddav/src/principal/mod.rs | 12 ++----- crates/dav/src/resource/methods/proppatch.rs | 7 +++-- crates/dav/src/resource/mod.rs | 4 ++- crates/dav/src/resources/root.rs | 7 +++++ crates/xml/derive/src/attrs.rs | 2 +- crates/xml/derive/src/xml_enum.rs | 31 ++++++++++++++----- crates/xml/src/lib.rs | 3 ++ crates/xml/tests/enum_variants.rs | 7 ++++- 16 files changed, 69 insertions(+), 74 deletions(-) diff --git a/crates/caldav/Cargo.toml b/crates/caldav/Cargo.toml index 8a139eb..6ab381c 100644 --- a/crates/caldav/Cargo.toml +++ b/crates/caldav/Cargo.toml @@ -12,7 +12,6 @@ actix-web = { workspace = true } async-trait = { workspace = true } thiserror = { workspace = true } quick-xml = { workspace = true } -strum = { workspace = true } tracing = { workspace = true } tracing-actix-web = { workspace = true } futures-util = { workspace = true } diff --git a/crates/caldav/src/calendar/resource.rs b/crates/caldav/src/calendar/resource.rs index 12311e5..70e34a9 100644 --- a/crates/caldav/src/calendar/resource.rs +++ b/crates/caldav/src/calendar/resource.rs @@ -16,19 +16,14 @@ use rustical_dav::resource::{Resource, ResourceService}; use rustical_dav::xml::{HrefElement, Resourcetype, ResourcetypeInner}; use rustical_store::auth::User; use rustical_store::{Calendar, CalendarStore, SubscriptionStore}; -use rustical_xml::EnumVariants; +use rustical_xml::{EnumUnitVariants, EnumVariants}; use rustical_xml::{XmlDeserialize, XmlSerialize}; use std::marker::PhantomData; use std::str::FromStr; use std::sync::Arc; -use strum::{EnumDiscriminants, EnumString, IntoStaticStr}; -#[derive(XmlDeserialize, XmlSerialize, PartialEq, EnumDiscriminants, Clone, EnumVariants)] -#[strum_discriminants( - name(CalendarPropName), - derive(EnumString, IntoStaticStr), - strum(serialize_all = "kebab-case") -)] +#[derive(XmlDeserialize, XmlSerialize, PartialEq, Clone, EnumVariants, EnumUnitVariants)] +#[xml(unit_variants_ident = "CalendarPropName")] pub enum CalendarProp { // WebDAV (RFC 2518) #[xml(ns = "rustical_dav::namespace::NS_DAV")] diff --git a/crates/caldav/src/calendar_object/resource.rs b/crates/caldav/src/calendar_object/resource.rs index 6b77e64..c6cb54d 100644 --- a/crates/caldav/src/calendar_object/resource.rs +++ b/crates/caldav/src/calendar_object/resource.rs @@ -9,10 +9,9 @@ use rustical_dav::{ xml::Resourcetype, }; use rustical_store::{auth::User, CalendarObject, CalendarStore}; -use rustical_xml::{EnumVariants, XmlDeserialize, XmlSerialize}; +use rustical_xml::{EnumUnitVariants, EnumVariants, XmlDeserialize, XmlSerialize}; use serde::Deserialize; use std::sync::Arc; -use strum::{EnumDiscriminants, EnumString, IntoStaticStr}; pub struct CalendarObjectResourceService { cal_store: Arc, @@ -24,12 +23,8 @@ impl CalendarObjectResourceService { } } -#[derive(XmlDeserialize, XmlSerialize, PartialEq, EnumDiscriminants, Clone, EnumVariants)] -#[strum_discriminants( - name(CalendarObjectPropName), - derive(EnumString, IntoStaticStr), - strum(serialize_all = "kebab-case") -)] +#[derive(XmlDeserialize, XmlSerialize, PartialEq, Clone, EnumVariants, EnumUnitVariants)] +#[xml(unit_variants_ident = "CalendarObjectPropName")] pub enum CalendarObjectProp { // WebDAV (RFC 2518) #[xml(ns = "rustical_dav::namespace::NS_DAV")] diff --git a/crates/caldav/src/calendar_set/mod.rs b/crates/caldav/src/calendar_set/mod.rs index 6ebe467..893dd86 100644 --- a/crates/caldav/src/calendar_set/mod.rs +++ b/crates/caldav/src/calendar_set/mod.rs @@ -8,24 +8,18 @@ use rustical_dav::resource::{NamedRoute, Resource, ResourceService}; use rustical_dav::xml::{HrefElement, Resourcetype, ResourcetypeInner}; use rustical_store::auth::User; use rustical_store::CalendarStore; -use rustical_xml::{EnumVariants, XmlDeserialize, XmlSerialize}; +use rustical_xml::{EnumUnitVariants, EnumVariants, XmlDeserialize, XmlSerialize}; use std::sync::Arc; -use strum::{EnumDiscriminants, EnumString, IntoStaticStr}; #[derive(Clone)] pub struct CalendarSetResource { pub(crate) principal: String, } -#[derive(XmlDeserialize, XmlSerialize, PartialEq, EnumDiscriminants, Clone, EnumVariants)] -#[strum_discriminants( - name(PrincipalPropName), - derive(EnumString, IntoStaticStr), - strum(serialize_all = "kebab-case") -)] +#[derive(XmlDeserialize, XmlSerialize, PartialEq, Clone, EnumVariants, EnumUnitVariants)] +#[xml(unit_variants_ident = "PrincipalPropName")] pub enum PrincipalProp { // WebDAV Access Control (RFC 3744) - #[strum_discriminants(strum(serialize = "principal-URL"))] #[xml(ns = "rustical_dav::namespace::NS_DAV", rename = b"principal-URL")] PrincipalUrl(HrefElement), } diff --git a/crates/caldav/src/principal/mod.rs b/crates/caldav/src/principal/mod.rs index b28040d..5621ab4 100644 --- a/crates/caldav/src/principal/mod.rs +++ b/crates/caldav/src/principal/mod.rs @@ -6,8 +6,7 @@ use rustical_dav::privileges::UserPrivilegeSet; use rustical_dav::resource::{NamedRoute, Resource, ResourceService}; use rustical_dav::xml::{HrefElement, Resourcetype, ResourcetypeInner}; use rustical_store::auth::User; -use rustical_xml::{EnumVariants, XmlDeserialize, XmlSerialize}; -use strum::{EnumDiscriminants, EnumString, IntoStaticStr}; +use rustical_xml::{EnumUnitVariants, EnumVariants, XmlDeserialize, XmlSerialize}; #[derive(Clone)] pub struct PrincipalResource { @@ -18,12 +17,8 @@ pub struct PrincipalResource { #[derive(XmlDeserialize, XmlSerialize, PartialEq, Clone)] pub struct CalendarHomeSet(#[xml(ty = "untagged", flatten)] Vec); -#[derive(XmlDeserialize, XmlSerialize, PartialEq, EnumDiscriminants, Clone, EnumVariants)] -#[strum_discriminants( - name(PrincipalPropName), - derive(EnumString, IntoStaticStr), - strum(serialize_all = "kebab-case") -)] +#[derive(XmlDeserialize, XmlSerialize, PartialEq, Clone, EnumVariants, EnumUnitVariants)] +#[xml(unit_variants_ident = "PrincipalPropName")] pub enum PrincipalProp { #[xml(ns = "rustical_dav::namespace::NS_DAV")] Displayname(String), @@ -35,7 +30,6 @@ pub enum PrincipalProp { CalendarUserAddressSet(HrefElement), // WebDAV Access Control (RFC 3744) - #[strum_discriminants(strum(serialize = "principal-URL"))] #[xml(ns = "rustical_dav::namespace::NS_DAV", rename = b"principal-URL")] PrincipalUrl(HrefElement), diff --git a/crates/carddav/Cargo.toml b/crates/carddav/Cargo.toml index e4bf941..d78defd 100644 --- a/crates/carddav/Cargo.toml +++ b/crates/carddav/Cargo.toml @@ -12,7 +12,6 @@ actix-web = { workspace = true } async-trait = { workspace = true } thiserror = { workspace = true } quick-xml = { workspace = true } -strum = { workspace = true } tracing = { workspace = true } tracing-actix-web = { workspace = true } futures-util = { workspace = true } diff --git a/crates/carddav/src/address_object/resource.rs b/crates/carddav/src/address_object/resource.rs index aba63c6..957256a 100644 --- a/crates/carddav/src/address_object/resource.rs +++ b/crates/carddav/src/address_object/resource.rs @@ -8,10 +8,9 @@ use rustical_dav::{ xml::Resourcetype, }; use rustical_store::{auth::User, AddressObject, AddressbookStore}; -use rustical_xml::{EnumVariants, XmlDeserialize, XmlSerialize}; +use rustical_xml::{EnumUnitVariants, EnumVariants, XmlDeserialize, XmlSerialize}; use serde::Deserialize; use std::sync::Arc; -use strum::{EnumDiscriminants, EnumString, IntoStaticStr}; use super::methods::{get_object, put_object}; @@ -20,12 +19,8 @@ pub struct AddressObjectResourceService { addr_store: Arc, } -#[derive(XmlDeserialize, XmlSerialize, PartialEq, EnumDiscriminants, Clone, EnumVariants)] -#[strum_discriminants( - name(AddressObjectPropName), - derive(EnumString, IntoStaticStr), - strum(serialize_all = "kebab-case") -)] +#[derive(XmlDeserialize, XmlSerialize, PartialEq, Clone, EnumVariants, EnumUnitVariants)] +#[xml(unit_variants_ident = "AddressObjectPropName")] pub enum AddressObjectProp { // WebDAV (RFC 2518) #[xml(ns = "rustical_dav::namespace::NS_DAV")] diff --git a/crates/carddav/src/addressbook/resource.rs b/crates/carddav/src/addressbook/resource.rs index de2d3bd..0173925 100644 --- a/crates/carddav/src/addressbook/resource.rs +++ b/crates/carddav/src/addressbook/resource.rs @@ -16,11 +16,10 @@ use rustical_dav::resource::{Resource, ResourceService}; use rustical_dav::xml::{Resourcetype, ResourcetypeInner}; use rustical_store::auth::User; use rustical_store::{Addressbook, AddressbookStore, SubscriptionStore}; -use rustical_xml::{EnumVariants, XmlDeserialize, XmlSerialize}; +use rustical_xml::{EnumUnitVariants, EnumVariants, XmlDeserialize, XmlSerialize}; use std::marker::PhantomData; use std::str::FromStr; use std::sync::Arc; -use strum::{EnumDiscriminants, EnumString, IntoStaticStr}; pub struct AddressbookResourceService { addr_store: Arc, @@ -36,12 +35,8 @@ impl AddressbookResourceService } } -#[derive(XmlDeserialize, XmlSerialize, PartialEq, EnumDiscriminants, Clone, EnumVariants)] -#[strum_discriminants( - name(AddressbookPropName), - derive(EnumString, IntoStaticStr), - strum(serialize_all = "kebab-case") -)] +#[derive(XmlDeserialize, XmlSerialize, PartialEq, Clone, EnumVariants, EnumUnitVariants)] +#[xml(unit_variants_ident = "AddressbookPropName")] pub enum AddressbookProp { // WebDAV (RFC 2518) #[xml(ns = "rustical_dav::namespace::NS_DAV")] diff --git a/crates/carddav/src/principal/mod.rs b/crates/carddav/src/principal/mod.rs index ebfb275..f3adf3f 100644 --- a/crates/carddav/src/principal/mod.rs +++ b/crates/carddav/src/principal/mod.rs @@ -7,9 +7,8 @@ use rustical_dav::resource::{NamedRoute, Resource, ResourceService}; use rustical_dav::xml::{HrefElement, Resourcetype, ResourcetypeInner}; use rustical_store::auth::User; use rustical_store::AddressbookStore; -use rustical_xml::{EnumVariants, XmlDeserialize, XmlSerialize}; +use rustical_xml::{EnumUnitVariants, EnumVariants, XmlDeserialize, XmlSerialize}; use std::sync::Arc; -use strum::{EnumDiscriminants, EnumString, IntoStaticStr}; pub struct PrincipalResourceService { addr_store: Arc, @@ -26,18 +25,13 @@ pub struct PrincipalResource { principal: String, } -#[derive(XmlDeserialize, XmlSerialize, PartialEq, EnumDiscriminants, Clone, EnumVariants)] -#[strum_discriminants( - name(PrincipalPropName), - derive(EnumString, IntoStaticStr), - strum(serialize_all = "kebab-case") -)] +#[derive(XmlDeserialize, XmlSerialize, PartialEq, Clone, EnumVariants, EnumUnitVariants)] +#[xml(unit_variants_ident = "PrincipalPropName")] pub enum PrincipalProp { #[xml(ns = "rustical_dav::namespace::NS_DAV")] Displayname(String), // WebDAV Access Control (RFC 3744) - #[strum_discriminants(strum(serialize = "principal-URL"))] #[xml(rename = b"principal-URL")] #[xml(ns = "rustical_dav::namespace::NS_DAV")] PrincipalUrl(HrefElement), diff --git a/crates/dav/src/resource/methods/proppatch.rs b/crates/dav/src/resource/methods/proppatch.rs index 8613228..66fd75d 100644 --- a/crates/dav/src/resource/methods/proppatch.rs +++ b/crates/dav/src/resource/methods/proppatch.rs @@ -9,6 +9,7 @@ use actix_web::http::StatusCode; use actix_web::web::Data; use actix_web::{web::Path, HttpRequest}; use itertools::Itertools; +use quick_xml::name::Namespace; use rustical_store::auth::User; use rustical_xml::Unparsed; use rustical_xml::XmlDeserialize; @@ -97,11 +98,11 @@ pub(crate) async fn route_proppatch( match property { SetPropertyPropWrapper::Valid(prop) => { let propname: ::PropName = prop.clone().into(); - let propname: &str = propname.into(); + let (ns, propname): (Option, &str) = propname.into(); match resource.set_prop(prop) { - Ok(()) => props_ok.push((None, propname.to_owned())), + Ok(()) => props_ok.push((ns, propname.to_owned())), Err(Error::PropReadOnly) => { - props_conflict.push((None, propname.to_owned())) + props_conflict.push((ns, propname.to_owned())) } Err(err) => return Err(err.into()), }; diff --git a/crates/dav/src/resource/mod.rs b/crates/dav/src/resource/mod.rs index 7311381..f5f5a84 100644 --- a/crates/dav/src/resource/mod.rs +++ b/crates/dav/src/resource/mod.rs @@ -60,7 +60,9 @@ pub enum CommonPropertiesPropName { } pub trait Resource: Clone + 'static { - type PropName: ResourcePropName + From + Into<&'static str>; + type PropName: ResourcePropName + + From + + Into<(Option>, &'static str)>; type Prop: ResourceProp + PartialEq + Clone + EnumVariants; type Error: ResponseError + From; type PrincipalResource: Resource + NamedRoute; diff --git a/crates/dav/src/resources/root.rs b/crates/dav/src/resources/root.rs index f88f41e..9079b19 100644 --- a/crates/dav/src/resources/root.rs +++ b/crates/dav/src/resources/root.rs @@ -3,6 +3,7 @@ use crate::resource::{NamedRoute, Resource, ResourceService}; use crate::xml::{Resourcetype, ResourcetypeInner}; use actix_web::dev::ResourceMap; use async_trait::async_trait; +use quick_xml::name::Namespace; use rustical_store::auth::User; use rustical_xml::{EnumVariants, XmlDeserialize, XmlSerialize}; use serde::Serialize; @@ -22,6 +23,12 @@ impl Default for RootResource { #[strum(serialize_all = "kebab-case")] pub enum RootResourcePropName {} +impl From for (Option>, &'static str) { + fn from(_value: RootResourcePropName) -> Self { + (None, "unreachable") + } +} + #[derive(XmlDeserialize, XmlSerialize, Serialize, Clone, PartialEq, EnumVariants)] pub enum RootResourceProp {} diff --git a/crates/xml/derive/src/attrs.rs b/crates/xml/derive/src/attrs.rs index 6f34495..d0d8053 100644 --- a/crates/xml/derive/src/attrs.rs +++ b/crates/xml/derive/src/attrs.rs @@ -22,7 +22,7 @@ pub struct VariantAttrs { #[darling(attributes(xml))] pub struct EnumAttrs { pub untagged: Flag, - pub unit_variants_name: Option, + pub unit_variants_ident: Option, } #[derive(Default, FromDeriveInput, Clone)] diff --git a/crates/xml/derive/src/xml_enum.rs b/crates/xml/derive/src/xml_enum.rs index 0d0191b..0876e9b 100644 --- a/crates/xml/derive/src/xml_enum.rs +++ b/crates/xml/derive/src/xml_enum.rs @@ -2,7 +2,6 @@ use super::{attrs::EnumAttrs, Variant}; use crate::attrs::VariantAttrs; use core::panic; use darling::{FromDeriveInput, FromVariant}; -use proc_macro2::Span; use quote::quote; use syn::{DataEnum, DeriveInput}; @@ -245,11 +244,11 @@ impl Enum { if self.attrs.untagged.is_present() { panic!("EnumUnitVariants not implemented for untagged enums"); } - let unit_enum_ident = if let Some(name) = &self.attrs.unit_variants_name { - syn::Ident::new(name, Span::call_site()) - } else { - panic!("unit_variants_name not set"); - }; + let unit_enum_ident = self + .attrs + .unit_variants_ident + .as_ref() + .expect("unit_variants_ident no set"); let tagged_variants: Vec<_> = self .variants @@ -287,8 +286,15 @@ impl Enum { quote! { #ident::#variant_ident { .. } => #unit_enum_ident::#variant_ident } }); + let str_to_unit_branches = tagged_variants.iter().map(|variant| { + let variant_ident = &variant.variant.ident; + let b_xml_name = variant.xml_name().value(); + let xml_name = String::from_utf8_lossy(&b_xml_name); + quote! { #xml_name => Ok(#unit_enum_ident::#variant_ident) } + }); + quote! { - enum #unit_enum_ident { + pub enum #unit_enum_ident { #(#variant_idents),* } @@ -307,6 +313,17 @@ impl Enum { } } } + + impl ::std::str::FromStr for #unit_enum_ident { + type Err = ::rustical_xml::FromStrError; + + fn from_str(val: &str) -> Result { + match val { + #(#str_to_unit_branches),*, + _ => Err(::rustical_xml::FromStrError) + } + } + } } } } diff --git a/crates/xml/src/lib.rs b/crates/xml/src/lib.rs index e0d5428..a46e9b3 100644 --- a/crates/xml/src/lib.rs +++ b/crates/xml/src/lib.rs @@ -24,6 +24,9 @@ pub trait XmlRootTag { fn root_ns_prefixes() -> HashMap, &'static [u8]>; } +#[derive(Debug)] +pub struct FromStrError; + pub trait EnumVariants { const TAGGED_VARIANTS: &'static [(Option>, &'static str)]; diff --git a/crates/xml/tests/enum_variants.rs b/crates/xml/tests/enum_variants.rs index d8957a0..83d05ae 100644 --- a/crates/xml/tests/enum_variants.rs +++ b/crates/xml/tests/enum_variants.rs @@ -1,3 +1,5 @@ +use std::str::FromStr; + use quick_xml::name::Namespace; use rustical_xml::EnumVariants; use xml_derive::EnumUnitVariants; @@ -16,7 +18,7 @@ enum ExtensionProp { } #[derive(EnumVariants, EnumUnitVariants)] -#[xml(unit_variants_name = "CalendarPropName")] +#[xml(unit_variants_ident = "CalendarPropName")] enum CalendarProp { // WebDAV (RFC 2518) #[xml(ns = "NS_DAV")] @@ -73,4 +75,7 @@ fn test_enum_unit_variants() { let propname: CalendarPropName = CalendarProp::Displayname(None).into(); let displayname: (Option, &str) = propname.into(); assert_eq!(displayname, (Some(NS_DAV), "displayname")); + + let propname: CalendarPropName = FromStr::from_str("displayname").unwrap(); + assert_eq!(displayname, (Some(NS_DAV), "displayname")); }