mirror of
https://github.com/lennart-k/rustical.git
synced 2025-12-13 19:22:26 +00:00
xml: Strict namespace, some tests and restructuring
This commit is contained in:
@@ -21,6 +21,7 @@ pub(crate) struct CalendarMultigetRequest {
|
||||
#[xml(ty = "untagged")]
|
||||
pub(crate) prop: PropfindType,
|
||||
#[xml(flatten)]
|
||||
#[xml(ns = "rustical_dav::namespace::NS_DAV")]
|
||||
pub(crate) href: Vec<String>,
|
||||
}
|
||||
|
||||
|
||||
@@ -19,15 +19,19 @@ use crate::{
|
||||
#[allow(dead_code)]
|
||||
pub(crate) struct TimeRangeElement {
|
||||
#[xml(ty = "attr")]
|
||||
#[xml(ns = "rustical_dav::namespace::NS_CALDAV")]
|
||||
pub(crate) start: Option<UtcDateTime>,
|
||||
#[xml(ty = "attr")]
|
||||
#[xml(ns = "rustical_dav::namespace::NS_CALDAV")]
|
||||
pub(crate) end: Option<UtcDateTime>,
|
||||
}
|
||||
|
||||
#[derive(XmlDeserialize, Clone, Debug, PartialEq)]
|
||||
#[allow(dead_code)]
|
||||
struct ParamFilterElement {
|
||||
#[xml(ns = "rustical_dav::namespace::NS_CALDAV")]
|
||||
is_not_defined: Option<()>,
|
||||
#[xml(ns = "rustical_dav::namespace::NS_CALDAV")]
|
||||
text_match: Option<TextMatchElement>,
|
||||
|
||||
#[xml(ty = "attr")]
|
||||
@@ -38,18 +42,24 @@ struct ParamFilterElement {
|
||||
#[allow(dead_code)]
|
||||
struct TextMatchElement {
|
||||
#[xml(ty = "attr")]
|
||||
#[xml(ns = "rustical_dav::namespace::NS_CALDAV")]
|
||||
collation: String,
|
||||
#[xml(ty = "attr")]
|
||||
#[xml(ns = "rustical_dav::namespace::NS_CALDAV")]
|
||||
negate_collation: String,
|
||||
}
|
||||
|
||||
#[derive(XmlDeserialize, Clone, Debug, PartialEq)]
|
||||
#[allow(dead_code)]
|
||||
pub(crate) struct PropFilterElement {
|
||||
#[xml(ns = "rustical_dav::namespace::NS_CALDAV")]
|
||||
is_not_defined: Option<()>,
|
||||
#[xml(ns = "rustical_dav::namespace::NS_CALDAV")]
|
||||
time_range: Option<TimeRangeElement>,
|
||||
#[xml(ns = "rustical_dav::namespace::NS_CALDAV")]
|
||||
text_match: Option<TextMatchElement>,
|
||||
#[xml(flatten)]
|
||||
#[xml(ns = "rustical_dav::namespace::NS_CALDAV")]
|
||||
param_filter: Vec<ParamFilterElement>,
|
||||
}
|
||||
|
||||
@@ -57,14 +67,16 @@ pub(crate) struct PropFilterElement {
|
||||
#[allow(dead_code)]
|
||||
// https://datatracker.ietf.org/doc/html/rfc4791#section-9.7.1
|
||||
pub(crate) struct CompFilterElement {
|
||||
#[xml(ns = "rustical_dav::namespace::NS_CALDAV")]
|
||||
pub(crate) is_not_defined: Option<()>,
|
||||
#[xml(ns = "rustical_dav::namespace::NS_CALDAV")]
|
||||
pub(crate) time_range: Option<TimeRangeElement>,
|
||||
#[xml(flatten)]
|
||||
#[xml(ns = "rustical_dav::namespace::NS_CALDAV", flatten)]
|
||||
pub(crate) prop_filter: Vec<PropFilterElement>,
|
||||
#[xml(flatten)]
|
||||
#[xml(ns = "rustical_dav::namespace::NS_CALDAV", flatten)]
|
||||
pub(crate) comp_filter: Vec<CompFilterElement>,
|
||||
|
||||
#[xml(ty = "attr")]
|
||||
#[xml(ns = "rustical_dav::namespace::NS_CALDAV", ty = "attr")]
|
||||
pub(crate) name: String,
|
||||
}
|
||||
|
||||
@@ -155,6 +167,7 @@ impl CompFilterElement {
|
||||
#[allow(dead_code)]
|
||||
// https://datatracker.ietf.org/doc/html/rfc4791#section-9.7
|
||||
pub(crate) struct FilterElement {
|
||||
#[xml(ns = "rustical_dav::namespace::NS_CALDAV")]
|
||||
pub(crate) comp_filter: CompFilterElement,
|
||||
}
|
||||
|
||||
@@ -170,8 +183,11 @@ impl FilterElement {
|
||||
pub struct CalendarQueryRequest {
|
||||
#[xml(ty = "untagged")]
|
||||
pub prop: PropfindType,
|
||||
#[xml(ns = "rustical_dav::namespace::NS_CALDAV")]
|
||||
pub(crate) filter: Option<FilterElement>,
|
||||
#[xml(ns = "rustical_dav::namespace::NS_CALDAV")]
|
||||
pub(crate) timezone: Option<String>,
|
||||
#[xml(ns = "rustical_dav::namespace::NS_CALDAV")]
|
||||
pub(crate) timezone_id: Option<String>,
|
||||
}
|
||||
|
||||
|
||||
@@ -5,9 +5,10 @@ use actix_web::{
|
||||
};
|
||||
use calendar_multiget::{handle_calendar_multiget, CalendarMultigetRequest};
|
||||
use calendar_query::{handle_calendar_query, CalendarQueryRequest};
|
||||
use rustical_dav::xml::sync_collection::SyncCollectionRequest;
|
||||
use rustical_store::{auth::User, CalendarStore};
|
||||
use rustical_xml::{XmlDeserialize, XmlDocument};
|
||||
use sync_collection::{handle_sync_collection, SyncCollectionRequest};
|
||||
use sync_collection::handle_sync_collection;
|
||||
use tracing::instrument;
|
||||
|
||||
mod calendar_multiget;
|
||||
@@ -16,8 +17,11 @@ mod sync_collection;
|
||||
|
||||
#[derive(XmlDeserialize, XmlDocument, Clone, Debug, PartialEq)]
|
||||
pub(crate) enum ReportRequest {
|
||||
#[xml(ns = "rustical_dav::namespace::NS_CALDAV")]
|
||||
CalendarMultiget(CalendarMultigetRequest),
|
||||
#[xml(ns = "rustical_dav::namespace::NS_CALDAV")]
|
||||
CalendarQuery(CalendarQueryRequest),
|
||||
#[xml(ns = "rustical_dav::namespace::NS_DAV")]
|
||||
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()
|
||||
]
|
||||
})
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,65 +1,22 @@
|
||||
use actix_web::{http::StatusCode, HttpRequest};
|
||||
use rustical_dav::{
|
||||
resource::{CommonPropertiesProp, EitherProp, Resource},
|
||||
xml::{multistatus::ResponseElement, MultistatusElement},
|
||||
xml::{PropElement, PropfindType},
|
||||
xml::{
|
||||
multistatus::ResponseElement, sync_collection::SyncCollectionRequest, MultistatusElement,
|
||||
PropElement, PropfindType,
|
||||
},
|
||||
};
|
||||
use rustical_store::{
|
||||
auth::User,
|
||||
synctoken::{format_synctoken, parse_synctoken},
|
||||
CalendarStore,
|
||||
};
|
||||
use rustical_xml::{ValueDeserialize, ValueSerialize, XmlDeserialize};
|
||||
|
||||
use crate::{
|
||||
calendar_object::resource::{CalendarObjectProp, CalendarObjectResource},
|
||||
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>(
|
||||
sync_collection: SyncCollectionRequest,
|
||||
req: HttpRequest,
|
||||
|
||||
@@ -8,26 +8,34 @@ use tracing_actix_web::RootSpan;
|
||||
|
||||
#[derive(XmlDeserialize, Clone, Debug, PartialEq)]
|
||||
pub struct Resourcetype {
|
||||
#[xml(ns = "rustical_dav::namespace::NS_CARDDAV")]
|
||||
addressbook: Option<()>,
|
||||
#[xml(ns = "rustical_dav::namespace::NS_DAV")]
|
||||
collection: Option<()>,
|
||||
}
|
||||
|
||||
#[derive(XmlDeserialize, Clone, Debug, PartialEq)]
|
||||
pub struct MkcolAddressbookProp {
|
||||
#[xml(ns = "rustical_dav::namespace::NS_DAV")]
|
||||
resourcetype: Option<Resourcetype>,
|
||||
#[xml(ns = "rustical_dav::namespace::NS_DAV")]
|
||||
displayname: Option<String>,
|
||||
#[xml(rename = b"addressbook-description")]
|
||||
#[xml(ns = "rustical_dav::namespace::NS_CARDDAV")]
|
||||
description: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(XmlDeserialize, Clone, Debug, PartialEq)]
|
||||
pub struct PropElement<T: XmlDeserialize> {
|
||||
#[xml(ns = "rustical_dav::namespace::NS_DAV")]
|
||||
prop: T,
|
||||
}
|
||||
|
||||
#[derive(XmlDeserialize, XmlRootTag, Clone, Debug, PartialEq)]
|
||||
#[xml(root = b"mkcol")]
|
||||
#[xml(ns = "rustical_dav::namespace::NS_DAV")]
|
||||
struct MkcolRequest {
|
||||
#[xml(ns = "rustical_dav::namespace::NS_DAV")]
|
||||
set: PropElement<MkcolAddressbookProp>,
|
||||
}
|
||||
|
||||
|
||||
@@ -16,11 +16,12 @@ use rustical_xml::XmlDeserialize;
|
||||
|
||||
#[derive(XmlDeserialize, Clone, Debug, PartialEq)]
|
||||
#[allow(dead_code)]
|
||||
#[xml(ns = "rustical_dav::namespace::NS_DAV")]
|
||||
pub struct AddressbookMultigetRequest {
|
||||
#[xml(ty = "untagged")]
|
||||
prop: PropfindType,
|
||||
#[xml(flatten)]
|
||||
href: Vec<String>,
|
||||
#[xml(ns = "rustical_dav::namespace::NS_DAV", ty = "untagged")]
|
||||
pub(crate) prop: PropfindType,
|
||||
#[xml(ns = "rustical_dav::namespace::NS_DAV", flatten)]
|
||||
pub(crate) href: Vec<String>,
|
||||
}
|
||||
|
||||
pub async fn get_objects_addressbook_multiget<AS: AddressbookStore>(
|
||||
|
||||
@@ -4,9 +4,10 @@ use actix_web::{
|
||||
HttpRequest, Responder,
|
||||
};
|
||||
use addressbook_multiget::{handle_addressbook_multiget, AddressbookMultigetRequest};
|
||||
use rustical_dav::xml::sync_collection::SyncCollectionRequest;
|
||||
use rustical_store::{auth::User, AddressbookStore};
|
||||
use rustical_xml::{XmlDeserialize, XmlDocument};
|
||||
use sync_collection::{handle_sync_collection, SyncCollectionRequest};
|
||||
use sync_collection::handle_sync_collection;
|
||||
use tracing::instrument;
|
||||
|
||||
mod addressbook_multiget;
|
||||
@@ -14,7 +15,9 @@ mod sync_collection;
|
||||
|
||||
#[derive(XmlDeserialize, XmlDocument, Clone, Debug, PartialEq)]
|
||||
pub(crate) enum ReportRequest {
|
||||
#[xml(ns = "rustical_dav::namespace::NS_CARDDAV")]
|
||||
AddressbookMultiget(AddressbookMultigetRequest),
|
||||
#[xml(ns = "rustical_dav::namespace::NS_DAV")]
|
||||
SyncCollection(SyncCollectionRequest),
|
||||
}
|
||||
|
||||
@@ -61,8 +64,7 @@ pub async fn route_report_addressbook<AS: AddressbookStore>(
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use rustical_dav::xml::{PropElement, Propname};
|
||||
use sync_collection::SyncLevel;
|
||||
use rustical_dav::xml::{sync_collection::SyncLevel, PropElement, Propname};
|
||||
|
||||
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()
|
||||
]
|
||||
})
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,56 +5,16 @@ use crate::{
|
||||
use actix_web::{http::StatusCode, HttpRequest};
|
||||
use rustical_dav::{
|
||||
resource::{CommonPropertiesProp, EitherProp, Resource},
|
||||
xml::{multistatus::ResponseElement, MultistatusElement},
|
||||
xml::{PropElement, PropfindType},
|
||||
xml::{
|
||||
multistatus::ResponseElement, sync_collection::SyncCollectionRequest, MultistatusElement,
|
||||
PropElement, PropfindType,
|
||||
},
|
||||
};
|
||||
use rustical_store::{
|
||||
auth::User,
|
||||
synctoken::{format_synctoken, parse_synctoken},
|
||||
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>(
|
||||
sync_collection: SyncCollectionRequest,
|
||||
|
||||
@@ -8,6 +8,7 @@ pub use propfind::{PropElement, PropfindElement, PropfindType, Propname};
|
||||
pub use resourcetype::{Resourcetype, ResourcetypeInner};
|
||||
use rustical_xml::{XmlDeserialize, XmlSerialize};
|
||||
pub use tag_list::TagList;
|
||||
pub mod sync_collection;
|
||||
|
||||
#[derive(XmlDeserialize, XmlSerialize, Debug, Clone, From, PartialEq)]
|
||||
pub struct HrefElement {
|
||||
|
||||
49
crates/dav/src/xml/sync_collection.rs
Normal file
49
crates/dav/src/xml/sync_collection.rs
Normal 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>,
|
||||
}
|
||||
@@ -3,15 +3,9 @@ use std::collections::HashMap;
|
||||
use darling::{util::Flag, FromDeriveInput, FromField, FromMeta, FromVariant};
|
||||
use syn::LitByteStr;
|
||||
|
||||
#[derive(Default, FromMeta, Clone)]
|
||||
pub struct ContainerAttrs {
|
||||
pub ns_strict: Flag,
|
||||
}
|
||||
|
||||
#[derive(Default, FromMeta, Clone)]
|
||||
pub struct TagAttrs {
|
||||
pub rename: Option<LitByteStr>,
|
||||
pub ns_strict: Flag,
|
||||
pub ns: Option<syn::Path>,
|
||||
}
|
||||
|
||||
@@ -27,18 +21,12 @@ pub struct VariantAttrs {
|
||||
#[derive(Default, FromDeriveInput, Clone)]
|
||||
#[darling(attributes(xml))]
|
||||
pub struct EnumAttrs {
|
||||
#[darling(flatten)]
|
||||
// TODO: implement ns_strict
|
||||
pub _container: ContainerAttrs,
|
||||
pub untagged: Flag,
|
||||
}
|
||||
|
||||
#[derive(Default, FromDeriveInput, Clone)]
|
||||
#[darling(attributes(xml))]
|
||||
pub struct StructAttrs {
|
||||
#[darling(flatten)]
|
||||
pub container: ContainerAttrs,
|
||||
|
||||
pub root: Option<LitByteStr>,
|
||||
pub ns: Option<syn::Path>,
|
||||
#[darling(default)]
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use super::{
|
||||
attrs::{ContainerAttrs, FieldAttrs, FieldType},
|
||||
attrs::{FieldAttrs, FieldType},
|
||||
get_generic_type,
|
||||
};
|
||||
use darling::FromField;
|
||||
@@ -23,20 +23,14 @@ pub struct Field {
|
||||
pub field: syn::Field,
|
||||
pub field_num: usize,
|
||||
pub attrs: FieldAttrs,
|
||||
pub container_attrs: ContainerAttrs,
|
||||
}
|
||||
|
||||
impl Field {
|
||||
pub fn from_syn_field(
|
||||
field: syn::Field,
|
||||
field_num: usize,
|
||||
container_attrs: ContainerAttrs,
|
||||
) -> Self {
|
||||
pub fn from_syn_field(field: syn::Field, field_num: usize) -> Self {
|
||||
Self {
|
||||
attrs: FieldAttrs::from_field(&field).unwrap(),
|
||||
field,
|
||||
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
|
||||
pub fn field_ident(&self) -> &Option<syn::Ident> {
|
||||
&self.field.ident
|
||||
@@ -169,25 +158,18 @@ impl Field {
|
||||
return None;
|
||||
}
|
||||
|
||||
let namespace_match = if self.ns_strict() {
|
||||
if self.attrs.common.ns.is_some() {
|
||||
quote! {quick_xml::name::ResolveResult::Bound(ns)}
|
||||
} else {
|
||||
quote! {quick_xml::name::ResolveResult::Unbound}
|
||||
}
|
||||
let namespace_match = if self.attrs.common.ns.is_some() {
|
||||
quote! {quick_xml::name::ResolveResult::Bound(ns)}
|
||||
} else {
|
||||
quote! {_}
|
||||
quote! {quick_xml::name::ResolveResult::Unbound}
|
||||
};
|
||||
|
||||
let namespace_condition = if self.ns_strict() {
|
||||
self.attrs
|
||||
.common
|
||||
.ns
|
||||
.as_ref()
|
||||
.map(|ns| quote! { if ns == #ns })
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let namespace_condition = self
|
||||
.attrs
|
||||
.common
|
||||
.ns
|
||||
.as_ref()
|
||||
.map(|ns| quote! { if ns == #ns });
|
||||
|
||||
let field_name = self.xml_name();
|
||||
let builder_field_ident = self.builder_field_ident();
|
||||
|
||||
@@ -25,9 +25,7 @@ impl NamedStruct {
|
||||
.named
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(i, field)| {
|
||||
Field::from_syn_field(field.to_owned(), i, attrs.container.clone())
|
||||
})
|
||||
.map(|(i, field)| Field::from_syn_field(field.to_owned(), i))
|
||||
.collect(),
|
||||
attrs,
|
||||
ident: input.ident.to_owned(),
|
||||
@@ -38,9 +36,7 @@ impl NamedStruct {
|
||||
.unnamed
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(i, field)| {
|
||||
Field::from_syn_field(field.to_owned(), i, attrs.container.clone())
|
||||
})
|
||||
.map(|(i, field)| Field::from_syn_field(field.to_owned(), i))
|
||||
.collect(),
|
||||
attrs,
|
||||
ident: input.ident.to_owned(),
|
||||
|
||||
@@ -81,7 +81,7 @@ fn test_tagged_enum_complex() {
|
||||
nice: (),
|
||||
}
|
||||
|
||||
let asd = Propfind::parse_str(
|
||||
let _ = Propfind::parse_str(
|
||||
r#"
|
||||
<propfind>
|
||||
<prop>
|
||||
|
||||
@@ -154,7 +154,7 @@ fn test_struct_ns() {
|
||||
const NS_HELLO: Namespace = Namespace(b"hello");
|
||||
|
||||
#[derive(Debug, XmlDeserialize, XmlRootTag, PartialEq)]
|
||||
#[xml(root = b"document", ns_strict)]
|
||||
#[xml(root = b"document")]
|
||||
struct Document {
|
||||
#[xml(ns = "NS_HELLO")]
|
||||
child: (),
|
||||
@@ -169,7 +169,7 @@ fn test_struct_attr() {
|
||||
const NS_HELLO: Namespace = Namespace(b"hello");
|
||||
|
||||
#[derive(Debug, XmlDeserialize, XmlRootTag, PartialEq)]
|
||||
#[xml(root = b"document", ns_strict)]
|
||||
#[xml(root = b"document")]
|
||||
struct Document {
|
||||
#[xml(ns = "NS_HELLO")]
|
||||
child: (),
|
||||
@@ -196,12 +196,12 @@ fn test_struct_attr() {
|
||||
#[test]
|
||||
fn test_struct_generics() {
|
||||
#[derive(XmlDeserialize, XmlRootTag)]
|
||||
#[xml(root = b"document", ns_strict)]
|
||||
#[xml(root = b"document")]
|
||||
struct Document<T: XmlDeserialize> {
|
||||
child: T,
|
||||
}
|
||||
|
||||
let doc = Document::<Unparsed>::parse_str(
|
||||
let _ = Document::<Unparsed>::parse_str(
|
||||
r#"
|
||||
<document>
|
||||
<child>
|
||||
@@ -216,12 +216,12 @@ fn test_struct_generics() {
|
||||
#[test]
|
||||
fn test_struct_unparsed() {
|
||||
#[derive(XmlDeserialize, XmlRootTag)]
|
||||
#[xml(root = b"document", ns_strict)]
|
||||
#[xml(root = b"document")]
|
||||
struct Document {
|
||||
child: Unparsed,
|
||||
}
|
||||
|
||||
let doc = Document::parse_str(
|
||||
let _ = Document::parse_str(
|
||||
r#"
|
||||
<document>
|
||||
<child>
|
||||
@@ -236,7 +236,7 @@ fn test_struct_unparsed() {
|
||||
#[test]
|
||||
fn test_xml_values() {
|
||||
#[derive(XmlDeserialize, XmlRootTag, PartialEq, Debug)]
|
||||
#[xml(root = b"document", ns_strict)]
|
||||
#[xml(root = b"document")]
|
||||
struct Document {
|
||||
href: String,
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user