xml: Strict namespace, some tests and restructuring

This commit is contained in:
Lennart
2025-01-15 19:12:54 +01:00
parent d021e7b8bf
commit 3e0571bb72
15 changed files with 176 additions and 157 deletions

View File

@@ -21,6 +21,7 @@ pub(crate) struct CalendarMultigetRequest {
#[xml(ty = "untagged")] #[xml(ty = "untagged")]
pub(crate) prop: PropfindType, pub(crate) prop: PropfindType,
#[xml(flatten)] #[xml(flatten)]
#[xml(ns = "rustical_dav::namespace::NS_DAV")]
pub(crate) href: Vec<String>, pub(crate) href: Vec<String>,
} }

View File

@@ -19,15 +19,19 @@ use crate::{
#[allow(dead_code)] #[allow(dead_code)]
pub(crate) struct TimeRangeElement { pub(crate) struct TimeRangeElement {
#[xml(ty = "attr")] #[xml(ty = "attr")]
#[xml(ns = "rustical_dav::namespace::NS_CALDAV")]
pub(crate) start: Option<UtcDateTime>, pub(crate) start: Option<UtcDateTime>,
#[xml(ty = "attr")] #[xml(ty = "attr")]
#[xml(ns = "rustical_dav::namespace::NS_CALDAV")]
pub(crate) end: Option<UtcDateTime>, pub(crate) end: Option<UtcDateTime>,
} }
#[derive(XmlDeserialize, Clone, Debug, PartialEq)] #[derive(XmlDeserialize, Clone, Debug, PartialEq)]
#[allow(dead_code)] #[allow(dead_code)]
struct ParamFilterElement { struct ParamFilterElement {
#[xml(ns = "rustical_dav::namespace::NS_CALDAV")]
is_not_defined: Option<()>, is_not_defined: Option<()>,
#[xml(ns = "rustical_dav::namespace::NS_CALDAV")]
text_match: Option<TextMatchElement>, text_match: Option<TextMatchElement>,
#[xml(ty = "attr")] #[xml(ty = "attr")]
@@ -38,18 +42,24 @@ struct ParamFilterElement {
#[allow(dead_code)] #[allow(dead_code)]
struct TextMatchElement { struct TextMatchElement {
#[xml(ty = "attr")] #[xml(ty = "attr")]
#[xml(ns = "rustical_dav::namespace::NS_CALDAV")]
collation: String, collation: String,
#[xml(ty = "attr")] #[xml(ty = "attr")]
#[xml(ns = "rustical_dav::namespace::NS_CALDAV")]
negate_collation: String, negate_collation: String,
} }
#[derive(XmlDeserialize, Clone, Debug, PartialEq)] #[derive(XmlDeserialize, Clone, Debug, PartialEq)]
#[allow(dead_code)] #[allow(dead_code)]
pub(crate) struct PropFilterElement { pub(crate) struct PropFilterElement {
#[xml(ns = "rustical_dav::namespace::NS_CALDAV")]
is_not_defined: Option<()>, is_not_defined: Option<()>,
#[xml(ns = "rustical_dav::namespace::NS_CALDAV")]
time_range: Option<TimeRangeElement>, time_range: Option<TimeRangeElement>,
#[xml(ns = "rustical_dav::namespace::NS_CALDAV")]
text_match: Option<TextMatchElement>, text_match: Option<TextMatchElement>,
#[xml(flatten)] #[xml(flatten)]
#[xml(ns = "rustical_dav::namespace::NS_CALDAV")]
param_filter: Vec<ParamFilterElement>, param_filter: Vec<ParamFilterElement>,
} }
@@ -57,14 +67,16 @@ pub(crate) struct PropFilterElement {
#[allow(dead_code)] #[allow(dead_code)]
// https://datatracker.ietf.org/doc/html/rfc4791#section-9.7.1 // https://datatracker.ietf.org/doc/html/rfc4791#section-9.7.1
pub(crate) struct CompFilterElement { pub(crate) struct CompFilterElement {
#[xml(ns = "rustical_dav::namespace::NS_CALDAV")]
pub(crate) is_not_defined: Option<()>, pub(crate) is_not_defined: Option<()>,
#[xml(ns = "rustical_dav::namespace::NS_CALDAV")]
pub(crate) time_range: Option<TimeRangeElement>, pub(crate) time_range: Option<TimeRangeElement>,
#[xml(flatten)] #[xml(ns = "rustical_dav::namespace::NS_CALDAV", flatten)]
pub(crate) prop_filter: Vec<PropFilterElement>, pub(crate) prop_filter: Vec<PropFilterElement>,
#[xml(flatten)] #[xml(ns = "rustical_dav::namespace::NS_CALDAV", flatten)]
pub(crate) comp_filter: Vec<CompFilterElement>, pub(crate) comp_filter: Vec<CompFilterElement>,
#[xml(ty = "attr")] #[xml(ns = "rustical_dav::namespace::NS_CALDAV", ty = "attr")]
pub(crate) name: String, pub(crate) name: String,
} }
@@ -155,6 +167,7 @@ impl CompFilterElement {
#[allow(dead_code)] #[allow(dead_code)]
// https://datatracker.ietf.org/doc/html/rfc4791#section-9.7 // https://datatracker.ietf.org/doc/html/rfc4791#section-9.7
pub(crate) struct FilterElement { pub(crate) struct FilterElement {
#[xml(ns = "rustical_dav::namespace::NS_CALDAV")]
pub(crate) comp_filter: CompFilterElement, pub(crate) comp_filter: CompFilterElement,
} }
@@ -170,8 +183,11 @@ impl FilterElement {
pub struct CalendarQueryRequest { pub struct CalendarQueryRequest {
#[xml(ty = "untagged")] #[xml(ty = "untagged")]
pub prop: PropfindType, pub prop: PropfindType,
#[xml(ns = "rustical_dav::namespace::NS_CALDAV")]
pub(crate) filter: Option<FilterElement>, pub(crate) filter: Option<FilterElement>,
#[xml(ns = "rustical_dav::namespace::NS_CALDAV")]
pub(crate) timezone: Option<String>, pub(crate) timezone: Option<String>,
#[xml(ns = "rustical_dav::namespace::NS_CALDAV")]
pub(crate) timezone_id: Option<String>, pub(crate) timezone_id: Option<String>,
} }

View File

@@ -5,9 +5,10 @@ use actix_web::{
}; };
use calendar_multiget::{handle_calendar_multiget, CalendarMultigetRequest}; use calendar_multiget::{handle_calendar_multiget, CalendarMultigetRequest};
use calendar_query::{handle_calendar_query, CalendarQueryRequest}; use calendar_query::{handle_calendar_query, CalendarQueryRequest};
use rustical_dav::xml::sync_collection::SyncCollectionRequest;
use rustical_store::{auth::User, CalendarStore}; use rustical_store::{auth::User, CalendarStore};
use rustical_xml::{XmlDeserialize, XmlDocument}; use rustical_xml::{XmlDeserialize, XmlDocument};
use sync_collection::{handle_sync_collection, SyncCollectionRequest}; use sync_collection::handle_sync_collection;
use tracing::instrument; use tracing::instrument;
mod calendar_multiget; mod calendar_multiget;
@@ -16,8 +17,11 @@ mod sync_collection;
#[derive(XmlDeserialize, XmlDocument, Clone, Debug, PartialEq)] #[derive(XmlDeserialize, XmlDocument, Clone, Debug, PartialEq)]
pub(crate) enum ReportRequest { pub(crate) enum ReportRequest {
#[xml(ns = "rustical_dav::namespace::NS_CALDAV")]
CalendarMultiget(CalendarMultigetRequest), CalendarMultiget(CalendarMultigetRequest),
#[xml(ns = "rustical_dav::namespace::NS_CALDAV")]
CalendarQuery(CalendarQueryRequest), CalendarQuery(CalendarQueryRequest),
#[xml(ns = "rustical_dav::namespace::NS_DAV")]
SyncCollection(SyncCollectionRequest), SyncCollection(SyncCollectionRequest),
} }
@@ -133,4 +137,31 @@ mod tests {
}) })
) )
} }
#[test]
fn test_xml_calendar_multiget() {
let report_request = ReportRequest::parse_str(r#"
<?xml version="1.0" encoding="UTF-8"?>
<calendar-multiget xmlns="urn:ietf:params:xml:ns:caldav" xmlns:D="DAV:">
<D:prop>
<D:getetag/>
<D:displayname/>
</D:prop>
<D:href>/caldav/user/user/6f787542-5256-401a-8db97003260da/ae7a998fdfd1d84a20391168962c62b</D:href>
</calendar-multiget>
"#).unwrap();
assert_eq!(
report_request,
ReportRequest::CalendarMultiget(CalendarMultigetRequest {
prop: rustical_dav::xml::PropfindType::Prop(PropElement(vec![
Propname("getetag".to_owned()),
Propname("displayname".to_owned())
])),
href: vec![
"/caldav/user/user/6f787542-5256-401a-8db97003260da/ae7a998fdfd1d84a20391168962c62b".to_owned()
]
})
)
}
} }

View File

@@ -1,65 +1,22 @@
use actix_web::{http::StatusCode, HttpRequest}; use actix_web::{http::StatusCode, HttpRequest};
use rustical_dav::{ use rustical_dav::{
resource::{CommonPropertiesProp, EitherProp, Resource}, resource::{CommonPropertiesProp, EitherProp, Resource},
xml::{multistatus::ResponseElement, MultistatusElement}, xml::{
xml::{PropElement, PropfindType}, multistatus::ResponseElement, sync_collection::SyncCollectionRequest, MultistatusElement,
PropElement, PropfindType,
},
}; };
use rustical_store::{ use rustical_store::{
auth::User, auth::User,
synctoken::{format_synctoken, parse_synctoken}, synctoken::{format_synctoken, parse_synctoken},
CalendarStore, CalendarStore,
}; };
use rustical_xml::{ValueDeserialize, ValueSerialize, XmlDeserialize};
use crate::{ use crate::{
calendar_object::resource::{CalendarObjectProp, CalendarObjectResource}, calendar_object::resource::{CalendarObjectProp, CalendarObjectResource},
Error, Error,
}; };
#[derive(Clone, Debug, PartialEq)]
pub(crate) enum SyncLevel {
One,
Infinity,
}
impl ValueDeserialize for SyncLevel {
fn deserialize(val: &str) -> Result<Self, rustical_xml::XmlError> {
Ok(match val {
"1" => Self::One,
"Infinity" => Self::Infinity,
_ => {
return Err(rustical_xml::XmlError::Other(
"Invalid sync-level".to_owned(),
))
}
})
}
}
impl ValueSerialize for SyncLevel {
fn serialize(&self) -> String {
match self {
SyncLevel::One => "1",
SyncLevel::Infinity => "Infinity",
}
.to_owned()
}
}
#[derive(XmlDeserialize, Clone, Debug, PartialEq)]
#[allow(dead_code)]
// <!ELEMENT sync-collection (sync-token, sync-level, limit?, prop)>
// <!-- DAV:limit defined in RFC 5323, Section 5.17 -->
// <!-- DAV:prop defined in RFC 4918, Section 14.18 -->
pub(crate) struct SyncCollectionRequest {
pub(crate) sync_token: String,
pub(crate) sync_level: SyncLevel,
pub(crate) timezone: Option<String>,
#[xml(ty = "untagged")]
pub prop: PropfindType,
pub(crate) limit: Option<u64>,
}
pub async fn handle_sync_collection<C: CalendarStore>( pub async fn handle_sync_collection<C: CalendarStore>(
sync_collection: SyncCollectionRequest, sync_collection: SyncCollectionRequest,
req: HttpRequest, req: HttpRequest,

View File

@@ -8,26 +8,34 @@ use tracing_actix_web::RootSpan;
#[derive(XmlDeserialize, Clone, Debug, PartialEq)] #[derive(XmlDeserialize, Clone, Debug, PartialEq)]
pub struct Resourcetype { pub struct Resourcetype {
#[xml(ns = "rustical_dav::namespace::NS_CARDDAV")]
addressbook: Option<()>, addressbook: Option<()>,
#[xml(ns = "rustical_dav::namespace::NS_DAV")]
collection: Option<()>, collection: Option<()>,
} }
#[derive(XmlDeserialize, Clone, Debug, PartialEq)] #[derive(XmlDeserialize, Clone, Debug, PartialEq)]
pub struct MkcolAddressbookProp { pub struct MkcolAddressbookProp {
#[xml(ns = "rustical_dav::namespace::NS_DAV")]
resourcetype: Option<Resourcetype>, resourcetype: Option<Resourcetype>,
#[xml(ns = "rustical_dav::namespace::NS_DAV")]
displayname: Option<String>, displayname: Option<String>,
#[xml(rename = b"addressbook-description")] #[xml(rename = b"addressbook-description")]
#[xml(ns = "rustical_dav::namespace::NS_CARDDAV")]
description: Option<String>, description: Option<String>,
} }
#[derive(XmlDeserialize, Clone, Debug, PartialEq)] #[derive(XmlDeserialize, Clone, Debug, PartialEq)]
pub struct PropElement<T: XmlDeserialize> { pub struct PropElement<T: XmlDeserialize> {
#[xml(ns = "rustical_dav::namespace::NS_DAV")]
prop: T, prop: T,
} }
#[derive(XmlDeserialize, XmlRootTag, Clone, Debug, PartialEq)] #[derive(XmlDeserialize, XmlRootTag, Clone, Debug, PartialEq)]
#[xml(root = b"mkcol")] #[xml(root = b"mkcol")]
#[xml(ns = "rustical_dav::namespace::NS_DAV")]
struct MkcolRequest { struct MkcolRequest {
#[xml(ns = "rustical_dav::namespace::NS_DAV")]
set: PropElement<MkcolAddressbookProp>, set: PropElement<MkcolAddressbookProp>,
} }

View File

@@ -16,11 +16,12 @@ use rustical_xml::XmlDeserialize;
#[derive(XmlDeserialize, Clone, Debug, PartialEq)] #[derive(XmlDeserialize, Clone, Debug, PartialEq)]
#[allow(dead_code)] #[allow(dead_code)]
#[xml(ns = "rustical_dav::namespace::NS_DAV")]
pub struct AddressbookMultigetRequest { pub struct AddressbookMultigetRequest {
#[xml(ty = "untagged")] #[xml(ns = "rustical_dav::namespace::NS_DAV", ty = "untagged")]
prop: PropfindType, pub(crate) prop: PropfindType,
#[xml(flatten)] #[xml(ns = "rustical_dav::namespace::NS_DAV", flatten)]
href: Vec<String>, pub(crate) href: Vec<String>,
} }
pub async fn get_objects_addressbook_multiget<AS: AddressbookStore>( pub async fn get_objects_addressbook_multiget<AS: AddressbookStore>(

View File

@@ -4,9 +4,10 @@ use actix_web::{
HttpRequest, Responder, HttpRequest, Responder,
}; };
use addressbook_multiget::{handle_addressbook_multiget, AddressbookMultigetRequest}; use addressbook_multiget::{handle_addressbook_multiget, AddressbookMultigetRequest};
use rustical_dav::xml::sync_collection::SyncCollectionRequest;
use rustical_store::{auth::User, AddressbookStore}; use rustical_store::{auth::User, AddressbookStore};
use rustical_xml::{XmlDeserialize, XmlDocument}; use rustical_xml::{XmlDeserialize, XmlDocument};
use sync_collection::{handle_sync_collection, SyncCollectionRequest}; use sync_collection::handle_sync_collection;
use tracing::instrument; use tracing::instrument;
mod addressbook_multiget; mod addressbook_multiget;
@@ -14,7 +15,9 @@ mod sync_collection;
#[derive(XmlDeserialize, XmlDocument, Clone, Debug, PartialEq)] #[derive(XmlDeserialize, XmlDocument, Clone, Debug, PartialEq)]
pub(crate) enum ReportRequest { pub(crate) enum ReportRequest {
#[xml(ns = "rustical_dav::namespace::NS_CARDDAV")]
AddressbookMultiget(AddressbookMultigetRequest), AddressbookMultiget(AddressbookMultigetRequest),
#[xml(ns = "rustical_dav::namespace::NS_DAV")]
SyncCollection(SyncCollectionRequest), SyncCollection(SyncCollectionRequest),
} }
@@ -61,8 +64,7 @@ pub async fn route_report_addressbook<AS: AddressbookStore>(
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use rustical_dav::xml::{PropElement, Propname}; use rustical_dav::xml::{sync_collection::SyncLevel, PropElement, Propname};
use sync_collection::SyncLevel;
use super::*; use super::*;
@@ -92,4 +94,31 @@ mod tests {
}) })
) )
} }
#[test]
fn test_xml_addressbook_multiget() {
let report_request = ReportRequest::parse_str(r#"
<?xml version="1.0" encoding="UTF-8"?>
<addressbook-multiget xmlns="urn:ietf:params:xml:ns:carddav" xmlns:D="DAV:">
<D:prop>
<D:getetag/>
<address-data/>
</D:prop>
<D:href>/carddav/user/user/6f787542-5256-401a-8db97003260da/ae7a998fdfd1d84a20391168962c62b</D:href>
</addressbook-multiget>
"#).unwrap();
assert_eq!(
report_request,
ReportRequest::AddressbookMultiget(AddressbookMultigetRequest {
prop: rustical_dav::xml::PropfindType::Prop(PropElement(vec![
Propname("getetag".to_owned()),
Propname("address-data".to_owned())
])),
href: vec![
"/carddav/user/user/6f787542-5256-401a-8db97003260da/ae7a998fdfd1d84a20391168962c62b".to_owned()
]
})
)
}
} }

View File

@@ -5,56 +5,16 @@ use crate::{
use actix_web::{http::StatusCode, HttpRequest}; use actix_web::{http::StatusCode, HttpRequest};
use rustical_dav::{ use rustical_dav::{
resource::{CommonPropertiesProp, EitherProp, Resource}, resource::{CommonPropertiesProp, EitherProp, Resource},
xml::{multistatus::ResponseElement, MultistatusElement}, xml::{
xml::{PropElement, PropfindType}, multistatus::ResponseElement, sync_collection::SyncCollectionRequest, MultistatusElement,
PropElement, PropfindType,
},
}; };
use rustical_store::{ use rustical_store::{
auth::User, auth::User,
synctoken::{format_synctoken, parse_synctoken}, synctoken::{format_synctoken, parse_synctoken},
AddressbookStore, AddressbookStore,
}; };
use rustical_xml::{ValueDeserialize, ValueSerialize, XmlDeserialize};
#[derive(Clone, Debug, PartialEq)]
pub(crate) enum SyncLevel {
One,
Infinity,
}
impl ValueDeserialize for SyncLevel {
fn deserialize(val: &str) -> Result<Self, rustical_xml::XmlError> {
Ok(match val {
"1" => Self::One,
"Infinity" => Self::Infinity,
_ => {
return Err(rustical_xml::XmlError::Other(
"Invalid sync-level".to_owned(),
))
}
})
}
}
impl ValueSerialize for SyncLevel {
fn serialize(&self) -> String {
match self {
SyncLevel::One => "1",
SyncLevel::Infinity => "Infinity",
}
.to_owned()
}
}
#[derive(XmlDeserialize, Clone, Debug, PartialEq)]
// <!ELEMENT sync-collection (sync-token, sync-level, limit?, prop)>
// <!-- DAV:limit defined in RFC 5323, Section 5.17 -->
// <!-- DAV:prop defined in RFC 4918, Section 14.18 -->
pub(crate) struct SyncCollectionRequest {
pub(crate) sync_token: String,
pub(crate) sync_level: SyncLevel,
#[xml(ty = "untagged")]
pub prop: PropfindType,
pub(crate) limit: Option<u64>,
}
pub async fn handle_sync_collection<AS: AddressbookStore>( pub async fn handle_sync_collection<AS: AddressbookStore>(
sync_collection: SyncCollectionRequest, sync_collection: SyncCollectionRequest,

View File

@@ -8,6 +8,7 @@ pub use propfind::{PropElement, PropfindElement, PropfindType, Propname};
pub use resourcetype::{Resourcetype, ResourcetypeInner}; pub use resourcetype::{Resourcetype, ResourcetypeInner};
use rustical_xml::{XmlDeserialize, XmlSerialize}; use rustical_xml::{XmlDeserialize, XmlSerialize};
pub use tag_list::TagList; pub use tag_list::TagList;
pub mod sync_collection;
#[derive(XmlDeserialize, XmlSerialize, Debug, Clone, From, PartialEq)] #[derive(XmlDeserialize, XmlSerialize, Debug, Clone, From, PartialEq)]
pub struct HrefElement { pub struct HrefElement {

View File

@@ -0,0 +1,49 @@
use rustical_xml::{ValueDeserialize, ValueSerialize, XmlDeserialize};
use super::PropfindType;
#[derive(Clone, Debug, PartialEq)]
pub enum SyncLevel {
One,
Infinity,
}
impl ValueDeserialize for SyncLevel {
fn deserialize(val: &str) -> Result<Self, rustical_xml::XmlError> {
Ok(match val {
"1" => Self::One,
"Infinity" => Self::Infinity,
_ => {
return Err(rustical_xml::XmlError::Other(
"Invalid sync-level".to_owned(),
))
}
})
}
}
impl ValueSerialize for SyncLevel {
fn serialize(&self) -> String {
match self {
SyncLevel::One => "1",
SyncLevel::Infinity => "Infinity",
}
.to_owned()
}
}
#[derive(XmlDeserialize, Clone, Debug, PartialEq)]
// <!ELEMENT sync-collection (sync-token, sync-level, limit?, prop)>
// <!-- DAV:limit defined in RFC 5323, Section 5.17 -->
// <!-- DAV:prop defined in RFC 4918, Section 14.18 -->
#[xml(ns = "crate::namespace::NS_DAV")]
pub struct SyncCollectionRequest {
#[xml(ns = "crate::namespace::NS_DAV")]
pub sync_token: String,
#[xml(ns = "crate::namespace::NS_DAV")]
pub sync_level: SyncLevel,
#[xml(ns = "crate::namespace::NS_DAV", ty = "untagged")]
pub prop: PropfindType,
#[xml(ns = "crate::namespace::NS_DAV")]
pub limit: Option<u64>,
}

View File

@@ -3,15 +3,9 @@ use std::collections::HashMap;
use darling::{util::Flag, FromDeriveInput, FromField, FromMeta, FromVariant}; use darling::{util::Flag, FromDeriveInput, FromField, FromMeta, FromVariant};
use syn::LitByteStr; use syn::LitByteStr;
#[derive(Default, FromMeta, Clone)]
pub struct ContainerAttrs {
pub ns_strict: Flag,
}
#[derive(Default, FromMeta, Clone)] #[derive(Default, FromMeta, Clone)]
pub struct TagAttrs { pub struct TagAttrs {
pub rename: Option<LitByteStr>, pub rename: Option<LitByteStr>,
pub ns_strict: Flag,
pub ns: Option<syn::Path>, pub ns: Option<syn::Path>,
} }
@@ -27,18 +21,12 @@ pub struct VariantAttrs {
#[derive(Default, FromDeriveInput, Clone)] #[derive(Default, FromDeriveInput, Clone)]
#[darling(attributes(xml))] #[darling(attributes(xml))]
pub struct EnumAttrs { pub struct EnumAttrs {
#[darling(flatten)]
// TODO: implement ns_strict
pub _container: ContainerAttrs,
pub untagged: Flag, pub untagged: Flag,
} }
#[derive(Default, FromDeriveInput, Clone)] #[derive(Default, FromDeriveInput, Clone)]
#[darling(attributes(xml))] #[darling(attributes(xml))]
pub struct StructAttrs { pub struct StructAttrs {
#[darling(flatten)]
pub container: ContainerAttrs,
pub root: Option<LitByteStr>, pub root: Option<LitByteStr>,
pub ns: Option<syn::Path>, pub ns: Option<syn::Path>,
#[darling(default)] #[darling(default)]

View File

@@ -1,5 +1,5 @@
use super::{ use super::{
attrs::{ContainerAttrs, FieldAttrs, FieldType}, attrs::{FieldAttrs, FieldType},
get_generic_type, get_generic_type,
}; };
use darling::FromField; use darling::FromField;
@@ -23,20 +23,14 @@ pub struct Field {
pub field: syn::Field, pub field: syn::Field,
pub field_num: usize, pub field_num: usize,
pub attrs: FieldAttrs, pub attrs: FieldAttrs,
pub container_attrs: ContainerAttrs,
} }
impl Field { impl Field {
pub fn from_syn_field( pub fn from_syn_field(field: syn::Field, field_num: usize) -> Self {
field: syn::Field,
field_num: usize,
container_attrs: ContainerAttrs,
) -> Self {
Self { Self {
attrs: FieldAttrs::from_field(&field).unwrap(), attrs: FieldAttrs::from_field(&field).unwrap(),
field, field,
field_num, field_num,
container_attrs,
} }
} }
@@ -51,11 +45,6 @@ impl Field {
}) })
} }
/// Whether to enforce the correct XML namespace
pub fn ns_strict(&self) -> bool {
self.attrs.common.ns_strict.is_present() || self.container_attrs.ns_strict.is_present()
}
/// Field identifier /// Field identifier
pub fn field_ident(&self) -> &Option<syn::Ident> { pub fn field_ident(&self) -> &Option<syn::Ident> {
&self.field.ident &self.field.ident
@@ -169,25 +158,18 @@ impl Field {
return None; return None;
} }
let namespace_match = if self.ns_strict() { let namespace_match = if self.attrs.common.ns.is_some() {
if self.attrs.common.ns.is_some() { quote! {quick_xml::name::ResolveResult::Bound(ns)}
quote! {quick_xml::name::ResolveResult::Bound(ns)}
} else {
quote! {quick_xml::name::ResolveResult::Unbound}
}
} else { } else {
quote! {_} quote! {quick_xml::name::ResolveResult::Unbound}
}; };
let namespace_condition = if self.ns_strict() { let namespace_condition = self
self.attrs .attrs
.common .common
.ns .ns
.as_ref() .as_ref()
.map(|ns| quote! { if ns == #ns }) .map(|ns| quote! { if ns == #ns });
} else {
None
};
let field_name = self.xml_name(); let field_name = self.xml_name();
let builder_field_ident = self.builder_field_ident(); let builder_field_ident = self.builder_field_ident();

View File

@@ -25,9 +25,7 @@ impl NamedStruct {
.named .named
.iter() .iter()
.enumerate() .enumerate()
.map(|(i, field)| { .map(|(i, field)| Field::from_syn_field(field.to_owned(), i))
Field::from_syn_field(field.to_owned(), i, attrs.container.clone())
})
.collect(), .collect(),
attrs, attrs,
ident: input.ident.to_owned(), ident: input.ident.to_owned(),
@@ -38,9 +36,7 @@ impl NamedStruct {
.unnamed .unnamed
.iter() .iter()
.enumerate() .enumerate()
.map(|(i, field)| { .map(|(i, field)| Field::from_syn_field(field.to_owned(), i))
Field::from_syn_field(field.to_owned(), i, attrs.container.clone())
})
.collect(), .collect(),
attrs, attrs,
ident: input.ident.to_owned(), ident: input.ident.to_owned(),

View File

@@ -81,7 +81,7 @@ fn test_tagged_enum_complex() {
nice: (), nice: (),
} }
let asd = Propfind::parse_str( let _ = Propfind::parse_str(
r#" r#"
<propfind> <propfind>
<prop> <prop>

View File

@@ -154,7 +154,7 @@ fn test_struct_ns() {
const NS_HELLO: Namespace = Namespace(b"hello"); const NS_HELLO: Namespace = Namespace(b"hello");
#[derive(Debug, XmlDeserialize, XmlRootTag, PartialEq)] #[derive(Debug, XmlDeserialize, XmlRootTag, PartialEq)]
#[xml(root = b"document", ns_strict)] #[xml(root = b"document")]
struct Document { struct Document {
#[xml(ns = "NS_HELLO")] #[xml(ns = "NS_HELLO")]
child: (), child: (),
@@ -169,7 +169,7 @@ fn test_struct_attr() {
const NS_HELLO: Namespace = Namespace(b"hello"); const NS_HELLO: Namespace = Namespace(b"hello");
#[derive(Debug, XmlDeserialize, XmlRootTag, PartialEq)] #[derive(Debug, XmlDeserialize, XmlRootTag, PartialEq)]
#[xml(root = b"document", ns_strict)] #[xml(root = b"document")]
struct Document { struct Document {
#[xml(ns = "NS_HELLO")] #[xml(ns = "NS_HELLO")]
child: (), child: (),
@@ -196,12 +196,12 @@ fn test_struct_attr() {
#[test] #[test]
fn test_struct_generics() { fn test_struct_generics() {
#[derive(XmlDeserialize, XmlRootTag)] #[derive(XmlDeserialize, XmlRootTag)]
#[xml(root = b"document", ns_strict)] #[xml(root = b"document")]
struct Document<T: XmlDeserialize> { struct Document<T: XmlDeserialize> {
child: T, child: T,
} }
let doc = Document::<Unparsed>::parse_str( let _ = Document::<Unparsed>::parse_str(
r#" r#"
<document> <document>
<child> <child>
@@ -216,12 +216,12 @@ fn test_struct_generics() {
#[test] #[test]
fn test_struct_unparsed() { fn test_struct_unparsed() {
#[derive(XmlDeserialize, XmlRootTag)] #[derive(XmlDeserialize, XmlRootTag)]
#[xml(root = b"document", ns_strict)] #[xml(root = b"document")]
struct Document { struct Document {
child: Unparsed, child: Unparsed,
} }
let doc = Document::parse_str( let _ = Document::parse_str(
r#" r#"
<document> <document>
<child> <child>
@@ -236,7 +236,7 @@ fn test_struct_unparsed() {
#[test] #[test]
fn test_xml_values() { fn test_xml_values() {
#[derive(XmlDeserialize, XmlRootTag, PartialEq, Debug)] #[derive(XmlDeserialize, XmlRootTag, PartialEq, Debug)]
#[xml(root = b"document", ns_strict)] #[xml(root = b"document")]
struct Document { struct Document {
href: String, href: String,
} }