1use crate::capability::DavResourceState;
4use crate::request::{DavMethod, DavMethodSet};
5
6#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
8pub enum DavExtensionPackage {
9 AccessControl,
10 VersionControl,
11 CheckoutInPlace,
12 VersionHistory,
13 Workspace,
14 Update,
15 Label,
16 WorkingResource,
17 Merge,
18 Baseline,
19 Activity,
20 VersionControlledCollection,
21 Search,
22 Quota,
23 CollectionSync,
24 ExtendedMkcol,
25 CurrentPrincipal,
26 OrderedCollections,
27 RedirectReferences,
28 Bindings,
29 AddMember,
30 Prefer,
31}
32
33impl DavExtensionPackage {
34 pub const ALL: [Self; 22] = [
36 Self::AccessControl,
37 Self::VersionControl,
38 Self::CheckoutInPlace,
39 Self::VersionHistory,
40 Self::Workspace,
41 Self::Update,
42 Self::Label,
43 Self::WorkingResource,
44 Self::Merge,
45 Self::Baseline,
46 Self::Activity,
47 Self::VersionControlledCollection,
48 Self::Search,
49 Self::Quota,
50 Self::CollectionSync,
51 Self::ExtendedMkcol,
52 Self::CurrentPrincipal,
53 Self::OrderedCollections,
54 Self::RedirectReferences,
55 Self::Bindings,
56 Self::AddMember,
57 Self::Prefer,
58 ];
59
60 const fn index(self) -> u32 {
61 match self {
62 Self::AccessControl => 0,
63 Self::VersionControl => 1,
64 Self::CheckoutInPlace => 2,
65 Self::VersionHistory => 3,
66 Self::Workspace => 4,
67 Self::Update => 5,
68 Self::Label => 6,
69 Self::WorkingResource => 7,
70 Self::Merge => 8,
71 Self::Baseline => 9,
72 Self::Activity => 10,
73 Self::VersionControlledCollection => 11,
74 Self::Search => 12,
75 Self::Quota => 13,
76 Self::CollectionSync => 14,
77 Self::ExtendedMkcol => 15,
78 Self::CurrentPrincipal => 16,
79 Self::OrderedCollections => 17,
80 Self::RedirectReferences => 18,
81 Self::Bindings => 19,
82 Self::AddMember => 20,
83 Self::Prefer => 21,
84 }
85 }
86
87 #[must_use]
89 pub const fn descriptor(self) -> &'static DavExtensionDescriptor {
90 &DESCRIPTORS[self.index() as usize]
91 }
92}
93
94#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
96pub struct DavExtensionSet(u32);
97
98impl DavExtensionSet {
99 #[must_use]
100 pub const fn empty() -> Self {
101 Self(0)
102 }
103
104 #[must_use]
105 pub const fn from_packages(packages: &[DavExtensionPackage]) -> Self {
106 let mut set = Self::empty();
107 let mut index = 0;
108 while index < packages.len() {
109 set = set.with(packages[index]);
110 index += 1;
111 }
112 set
113 }
114
115 #[must_use]
116 pub const fn with(self, package: DavExtensionPackage) -> Self {
117 Self(self.0 | (1u32 << package.index()))
118 }
119
120 #[must_use]
121 pub const fn union(self, other: Self) -> Self {
122 Self(self.0 | other.0)
123 }
124
125 #[must_use]
126 pub const fn contains(self, package: DavExtensionPackage) -> bool {
127 self.0 & (1u32 << package.index()) != 0
128 }
129
130 #[must_use]
131 pub const fn contains_all(self, required: Self) -> bool {
132 required.0 & !self.0 == 0
133 }
134
135 #[must_use]
136 pub const fn is_subset_of(self, maximum: Self) -> bool {
137 maximum.contains_all(self)
138 }
139
140 #[must_use]
141 pub const fn is_empty(self) -> bool {
142 self.0 == 0
143 }
144
145 #[must_use]
146 pub const fn iter(self) -> DavExtensionSetIter {
147 DavExtensionSetIter {
148 set: self,
149 index: 0,
150 }
151 }
152}
153
154#[derive(Debug, Clone)]
156pub struct DavExtensionSetIter {
157 set: DavExtensionSet,
158 index: usize,
159}
160
161impl Iterator for DavExtensionSetIter {
162 type Item = DavExtensionPackage;
163
164 fn next(&mut self) -> Option<Self::Item> {
165 while self.index < DavExtensionPackage::ALL.len() {
166 let package = DavExtensionPackage::ALL[self.index];
167 self.index += 1;
168 if self.set.contains(package) {
169 return Some(package);
170 }
171 }
172 None
173 }
174}
175
176#[derive(Debug, Clone, Copy, PartialEq, Eq)]
178pub struct DavResourceStateSet(u16);
179
180impl DavResourceStateSet {
181 #[must_use]
182 pub const fn from_states(states: &[DavResourceState]) -> Self {
183 let mut bits = 0u16;
184 let mut index = 0;
185 while index < states.len() {
186 bits |= 1u16 << resource_index(states[index]);
187 index += 1;
188 }
189 Self(bits)
190 }
191
192 #[must_use]
193 pub const fn contains(self, state: DavResourceState) -> bool {
194 self.0 & (1u16 << resource_index(state)) != 0
195 }
196
197 #[must_use]
198 pub const fn union(self, other: Self) -> Self {
199 Self(self.0 | other.0)
200 }
201}
202
203const fn resource_index(state: DavResourceState) -> u32 {
204 match state {
205 DavResourceState::Unmapped => 0,
206 DavResourceState::File => 1,
207 DavResourceState::Collection => 2,
208 DavResourceState::MountRoot => 3,
209 DavResourceState::Principal => 4,
210 DavResourceState::RedirectReference => 5,
211 DavResourceState::AddMemberEndpoint => 6,
212 }
213}
214
215#[derive(Debug, Clone, Copy, PartialEq, Eq)]
217pub enum DavExtensionBodyKind {
218 Xml,
219 Stream,
220}
221
222#[derive(Debug, Clone, Copy, PartialEq, Eq)]
224pub struct DavExtensionMethod {
225 pub method: DavMethod,
226 pub resources: DavResourceStateSet,
227 pub body: DavExtensionBodyKind,
228}
229
230macro_rules! protocol_enum {
231 (
232 $(#[$enum_meta:meta])*
233 pub enum $name:ident {
234 $($variant:ident => $local_name:literal),+ $(,)?
235 }
236 ) => {
237 $(#[$enum_meta])*
238 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
239 #[repr(u8)]
240 pub enum $name {
241 $($variant),+
242 }
243
244 impl $name {
245 pub const COUNT: usize = [$(Self::$variant),+].len();
247
248 pub const ALL: [Self; Self::COUNT] = [$(Self::$variant),+];
250
251 pub(crate) const fn index(self) -> usize {
252 self as usize
253 }
254
255 #[must_use]
257 pub const fn local_name(self) -> &'static str {
258 match self {
259 $(Self::$variant => $local_name),+
260 }
261 }
262 }
263 };
264}
265
266protocol_enum! {
267 pub enum DavLiveProperty {
269 CreationDate => "creationdate",
270 DisplayName => "displayname",
271 GetContentLanguage => "getcontentlanguage",
272 GetContentLength => "getcontentlength",
273 GetContentType => "getcontenttype",
274 GetEtag => "getetag",
275 GetLastModified => "getlastmodified",
276 LockDiscovery => "lockdiscovery",
277 ResourceType => "resourcetype",
278 SupportedLock => "supportedlock",
279 AlternateUriSet => "alternate-URI-set",
280 PrincipalUrl => "principal-URL",
281 GroupMemberSet => "group-member-set",
282 GroupMembership => "group-membership",
283 Owner => "owner",
284 Group => "group",
285 SupportedPrivilegeSet => "supported-privilege-set",
286 CurrentUserPrivilegeSet => "current-user-privilege-set",
287 Acl => "acl",
288 AclRestrictions => "acl-restrictions",
289 InheritedAclSet => "inherited-acl-set",
290 PrincipalCollectionSet => "principal-collection-set",
291 Comment => "comment",
292 CreatorDisplayName => "creator-displayname",
293 SupportedMethodSet => "supported-method-set",
294 SupportedLivePropertySet => "supported-live-property-set",
295 SupportedReportSet => "supported-report-set",
296 CheckedIn => "checked-in",
297 AutoVersion => "auto-version",
298 CheckedOut => "checked-out",
299 PredecessorSet => "predecessor-set",
300 SuccessorSet => "successor-set",
301 CheckoutSet => "checkout-set",
302 VersionName => "version-name",
303 CheckoutFork => "checkout-fork",
304 CheckinFork => "checkin-fork",
305 VersionSet => "version-set",
306 RootVersion => "root-version",
307 VersionHistory => "version-history",
308 WorkspaceCheckoutSet => "workspace-checkout-set",
309 Workspace => "workspace",
310 LabelNameSet => "label-name-set",
311 AutoUpdate => "auto-update",
312 MergeSet => "merge-set",
313 AutoMergeSet => "auto-merge-set",
314 BaselineControlledCollection => "baseline-controlled-collection",
315 SubbaselineSet => "subbaseline-set",
316 BaselineCollection => "baseline-collection",
317 VersionControlledConfiguration => "version-controlled-configuration",
318 BaselineControlledCollectionSet => "baseline-controlled-collection-set",
319 ActivityVersionSet => "activity-version-set",
320 ActivityCheckoutSet => "activity-checkout-set",
321 SubactivitySet => "subactivity-set",
322 CurrentWorkspaceSet => "current-workspace-set",
323 ActivitySet => "activity-set",
324 Unreserved => "unreserved",
325 CurrentActivitySet => "current-activity-set",
326 EclipsedSet => "eclipsed-set",
327 VersionControlledBindingSet => "version-controlled-binding-set",
328 SupportedQueryGrammarSet => "supported-query-grammar-set",
329 QuotaAvailableBytes => "quota-available-bytes",
330 QuotaUsedBytes => "quota-used-bytes",
331 SyncToken => "sync-token",
332 CurrentUserPrincipal => "current-user-principal",
333 OrderingType => "ordering-type",
334 RedirectLifetime => "redirect-lifetime",
335 RefTarget => "reftarget",
336 ResourceId => "resource-id",
337 ParentSet => "parent-set",
338 AddMember => "add-member",
339 }
340}
341
342protocol_enum! {
343 pub enum DavReportType {
345 VersionTree => "version-tree",
346 ExpandProperty => "expand-property",
347 LocateByHistory => "locate-by-history",
348 MergePreview => "merge-preview",
349 CompareBaseline => "compare-baseline",
350 LatestActivityVersion => "latest-activity-version",
351 AclPrincipalPropSet => "acl-principal-prop-set",
352 PrincipalMatch => "principal-match",
353 PrincipalPropertySearch => "principal-property-search",
354 PrincipalSearchPropertySet => "principal-search-property-set",
355 SyncCollection => "sync-collection",
356 }
357}
358
359#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
361pub struct DavPreferenceSet(u8);
362
363impl DavPreferenceSet {
364 pub const RETURN_MINIMAL: Self = Self(1);
365 pub const RETURN_REPRESENTATION: Self = Self(1 << 1);
366 pub const DEPTH_NO_ROOT: Self = Self(1 << 2);
367
368 #[must_use]
369 pub const fn empty() -> Self {
370 Self(0)
371 }
372
373 #[must_use]
374 pub const fn all() -> Self {
375 Self(Self::RETURN_MINIMAL.0 | Self::RETURN_REPRESENTATION.0 | Self::DEPTH_NO_ROOT.0)
376 }
377
378 #[must_use]
379 pub const fn union(self, other: Self) -> Self {
380 Self(self.0 | other.0)
381 }
382
383 #[must_use]
384 pub const fn contains(self, preference: Self) -> bool {
385 self.0 & preference.0 == preference.0
386 }
387}
388
389#[derive(Debug, Clone, Copy)]
391pub struct DavExtensionDescriptor {
392 pub package: DavExtensionPackage,
393 pub rfc: &'static str,
394 pub dav_token: Option<&'static str>,
395 pub prerequisites: DavExtensionSet,
396 pub resources: DavResourceStateSet,
397 pub methods: &'static [DavExtensionMethod],
398 pub live_properties: &'static [DavLiveProperty],
399 pub reports: &'static [DavReportType],
400 pub preferences: DavPreferenceSet,
401}
402
403const ALL_RESOURCES: DavResourceStateSet = DavResourceStateSet::from_states(&[
404 DavResourceState::Unmapped,
405 DavResourceState::File,
406 DavResourceState::Collection,
407 DavResourceState::MountRoot,
408 DavResourceState::Principal,
409 DavResourceState::RedirectReference,
410 DavResourceState::AddMemberEndpoint,
411]);
412const MAPPED_RESOURCES: DavResourceStateSet = DavResourceStateSet::from_states(&[
413 DavResourceState::File,
414 DavResourceState::Collection,
415 DavResourceState::MountRoot,
416 DavResourceState::Principal,
417 DavResourceState::RedirectReference,
418]);
419const CONTENT_RESOURCES: DavResourceStateSet = DavResourceStateSet::from_states(&[
420 DavResourceState::File,
421 DavResourceState::Collection,
422 DavResourceState::MountRoot,
423]);
424const COLLECTIONS: DavResourceStateSet =
425 DavResourceStateSet::from_states(&[DavResourceState::Collection, DavResourceState::MountRoot]);
426const UNMAPPED: DavResourceStateSet =
427 DavResourceStateSet::from_states(&[DavResourceState::Unmapped]);
428const ORDERABLE: DavResourceStateSet = DavResourceStateSet::from_states(&[
429 DavResourceState::Unmapped,
430 DavResourceState::Collection,
431 DavResourceState::MountRoot,
432]);
433const REDIRECT_TARGETS: DavResourceStateSet = DavResourceStateSet::from_states(&[
434 DavResourceState::Unmapped,
435 DavResourceState::File,
436 DavResourceState::Collection,
437 DavResourceState::MountRoot,
438 DavResourceState::Principal,
439 DavResourceState::RedirectReference,
440]);
441const ADD_MEMBER_TARGETS: DavResourceStateSet = DavResourceStateSet::from_states(&[
442 DavResourceState::Collection,
443 DavResourceState::MountRoot,
444 DavResourceState::AddMemberEndpoint,
445]);
446
447const XML: DavExtensionBodyKind = DavExtensionBodyKind::Xml;
448
449const ACL_METHODS: &[DavExtensionMethod] = &[
450 DavExtensionMethod {
451 method: DavMethod::Acl,
452 resources: MAPPED_RESOURCES,
453 body: XML,
454 },
455 DavExtensionMethod {
456 method: DavMethod::Report,
457 resources: MAPPED_RESOURCES,
458 body: XML,
459 },
460];
461const VERSION_CONTROL_METHODS: &[DavExtensionMethod] = &[
462 DavExtensionMethod {
463 method: DavMethod::VersionControl,
464 resources: CONTENT_RESOURCES.union(UNMAPPED),
465 body: XML,
466 },
467 DavExtensionMethod {
468 method: DavMethod::Report,
469 resources: CONTENT_RESOURCES,
470 body: XML,
471 },
472];
473const CHECKOUT_METHODS: &[DavExtensionMethod] = &[
474 DavExtensionMethod {
475 method: DavMethod::Checkout,
476 resources: CONTENT_RESOURCES,
477 body: XML,
478 },
479 DavExtensionMethod {
480 method: DavMethod::Checkin,
481 resources: CONTENT_RESOURCES,
482 body: XML,
483 },
484 DavExtensionMethod {
485 method: DavMethod::Uncheckout,
486 resources: CONTENT_RESOURCES,
487 body: XML,
488 },
489];
490const WORKSPACE_METHODS: &[DavExtensionMethod] = &[DavExtensionMethod {
491 method: DavMethod::Mkworkspace,
492 resources: UNMAPPED,
493 body: XML,
494}];
495const UPDATE_METHODS: &[DavExtensionMethod] = &[DavExtensionMethod {
496 method: DavMethod::Update,
497 resources: CONTENT_RESOURCES,
498 body: XML,
499}];
500const LABEL_METHODS: &[DavExtensionMethod] = &[DavExtensionMethod {
501 method: DavMethod::Label,
502 resources: CONTENT_RESOURCES,
503 body: XML,
504}];
505const WORKING_RESOURCE_METHODS: &[DavExtensionMethod] = CHECKOUT_METHODS;
506const MERGE_METHODS: &[DavExtensionMethod] = &[DavExtensionMethod {
507 method: DavMethod::Merge,
508 resources: CONTENT_RESOURCES,
509 body: XML,
510}];
511const BASELINE_METHODS: &[DavExtensionMethod] = &[DavExtensionMethod {
512 method: DavMethod::BaselineControl,
513 resources: COLLECTIONS,
514 body: XML,
515}];
516const ACTIVITY_METHODS: &[DavExtensionMethod] = &[DavExtensionMethod {
517 method: DavMethod::Mkactivity,
518 resources: UNMAPPED,
519 body: XML,
520}];
521const SEARCH_METHODS: &[DavExtensionMethod] = &[DavExtensionMethod {
522 method: DavMethod::Search,
523 resources: MAPPED_RESOURCES,
524 body: XML,
525}];
526const SYNC_METHODS: &[DavExtensionMethod] = &[DavExtensionMethod {
527 method: DavMethod::Report,
528 resources: COLLECTIONS,
529 body: XML,
530}];
531const EXTENDED_MKCOL_METHODS: &[DavExtensionMethod] = &[DavExtensionMethod {
532 method: DavMethod::Mkcol,
533 resources: UNMAPPED,
534 body: XML,
535}];
536const ORDERED_METHODS: &[DavExtensionMethod] = &[DavExtensionMethod {
537 method: DavMethod::Orderpatch,
538 resources: COLLECTIONS,
539 body: XML,
540}];
541const REDIRECT_METHODS: &[DavExtensionMethod] = &[
542 DavExtensionMethod {
543 method: DavMethod::Mkredirectref,
544 resources: UNMAPPED,
545 body: XML,
546 },
547 DavExtensionMethod {
548 method: DavMethod::Updateredirectref,
549 resources: DavResourceStateSet::from_states(&[DavResourceState::RedirectReference]),
550 body: XML,
551 },
552];
553const BIND_METHODS: &[DavExtensionMethod] = &[
554 DavExtensionMethod {
555 method: DavMethod::Bind,
556 resources: COLLECTIONS,
557 body: XML,
558 },
559 DavExtensionMethod {
560 method: DavMethod::Unbind,
561 resources: COLLECTIONS,
562 body: XML,
563 },
564 DavExtensionMethod {
565 method: DavMethod::Rebind,
566 resources: COLLECTIONS,
567 body: XML,
568 },
569];
570const ADD_MEMBER_METHODS: &[DavExtensionMethod] = &[DavExtensionMethod {
571 method: DavMethod::Post,
572 resources: DavResourceStateSet::from_states(&[DavResourceState::AddMemberEndpoint]),
573 body: DavExtensionBodyKind::Stream,
574}];
575
576const ACL_PROPERTIES: &[DavLiveProperty] = &[
577 DavLiveProperty::AlternateUriSet,
578 DavLiveProperty::PrincipalUrl,
579 DavLiveProperty::GroupMemberSet,
580 DavLiveProperty::GroupMembership,
581 DavLiveProperty::Owner,
582 DavLiveProperty::Group,
583 DavLiveProperty::SupportedPrivilegeSet,
584 DavLiveProperty::CurrentUserPrivilegeSet,
585 DavLiveProperty::Acl,
586 DavLiveProperty::AclRestrictions,
587 DavLiveProperty::InheritedAclSet,
588 DavLiveProperty::PrincipalCollectionSet,
589];
590const VERSION_CONTROL_PROPERTIES: &[DavLiveProperty] = &[
591 DavLiveProperty::Comment,
592 DavLiveProperty::CreatorDisplayName,
593 DavLiveProperty::SupportedMethodSet,
594 DavLiveProperty::SupportedLivePropertySet,
595 DavLiveProperty::SupportedReportSet,
596 DavLiveProperty::CheckedIn,
597 DavLiveProperty::AutoVersion,
598 DavLiveProperty::CheckedOut,
599 DavLiveProperty::PredecessorSet,
600 DavLiveProperty::SuccessorSet,
601 DavLiveProperty::CheckoutSet,
602 DavLiveProperty::VersionName,
603];
604const CHECKOUT_PROPERTIES: &[DavLiveProperty] =
605 &[DavLiveProperty::CheckoutFork, DavLiveProperty::CheckinFork];
606const VERSION_HISTORY_PROPERTIES: &[DavLiveProperty] = &[
607 DavLiveProperty::VersionSet,
608 DavLiveProperty::RootVersion,
609 DavLiveProperty::VersionHistory,
610];
611const WORKSPACE_PROPERTIES: &[DavLiveProperty] = &[
612 DavLiveProperty::WorkspaceCheckoutSet,
613 DavLiveProperty::Workspace,
614];
615const LABEL_PROPERTIES: &[DavLiveProperty] = &[DavLiveProperty::LabelNameSet];
616const WORKING_RESOURCE_PROPERTIES: &[DavLiveProperty] = &[DavLiveProperty::AutoUpdate];
617const MERGE_PROPERTIES: &[DavLiveProperty] =
618 &[DavLiveProperty::MergeSet, DavLiveProperty::AutoMergeSet];
619const BASELINE_PROPERTIES: &[DavLiveProperty] = &[
620 DavLiveProperty::BaselineControlledCollection,
621 DavLiveProperty::SubbaselineSet,
622 DavLiveProperty::BaselineCollection,
623 DavLiveProperty::VersionControlledConfiguration,
624 DavLiveProperty::BaselineControlledCollectionSet,
625];
626const ACTIVITY_PROPERTIES: &[DavLiveProperty] = &[
627 DavLiveProperty::ActivityVersionSet,
628 DavLiveProperty::ActivityCheckoutSet,
629 DavLiveProperty::SubactivitySet,
630 DavLiveProperty::CurrentWorkspaceSet,
631 DavLiveProperty::ActivitySet,
632 DavLiveProperty::Unreserved,
633 DavLiveProperty::CurrentActivitySet,
634];
635const VCC_PROPERTIES: &[DavLiveProperty] = &[
636 DavLiveProperty::EclipsedSet,
637 DavLiveProperty::VersionControlledBindingSet,
638];
639const SEARCH_PROPERTIES: &[DavLiveProperty] = &[DavLiveProperty::SupportedQueryGrammarSet];
640const QUOTA_PROPERTIES: &[DavLiveProperty] = &[
641 DavLiveProperty::QuotaAvailableBytes,
642 DavLiveProperty::QuotaUsedBytes,
643];
644const SYNC_PROPERTIES: &[DavLiveProperty] = &[DavLiveProperty::SyncToken];
645const CURRENT_PRINCIPAL_PROPERTIES: &[DavLiveProperty] = &[DavLiveProperty::CurrentUserPrincipal];
646const ORDERED_PROPERTIES: &[DavLiveProperty] = &[DavLiveProperty::OrderingType];
647const REDIRECT_PROPERTIES: &[DavLiveProperty] = &[
648 DavLiveProperty::RedirectLifetime,
649 DavLiveProperty::RefTarget,
650];
651const BIND_PROPERTIES: &[DavLiveProperty] =
652 &[DavLiveProperty::ResourceId, DavLiveProperty::ParentSet];
653const ADD_MEMBER_PROPERTIES: &[DavLiveProperty] = &[DavLiveProperty::AddMember];
654
655const ACL_REPORTS: &[DavReportType] = &[
656 DavReportType::AclPrincipalPropSet,
657 DavReportType::PrincipalMatch,
658 DavReportType::PrincipalPropertySearch,
659 DavReportType::PrincipalSearchPropertySet,
660];
661const VERSION_CONTROL_REPORTS: &[DavReportType] =
662 &[DavReportType::VersionTree, DavReportType::ExpandProperty];
663const VERSION_HISTORY_REPORTS: &[DavReportType] = &[DavReportType::LocateByHistory];
664const MERGE_REPORTS: &[DavReportType] = &[DavReportType::MergePreview];
665const BASELINE_REPORTS: &[DavReportType] = &[DavReportType::CompareBaseline];
666const ACTIVITY_REPORTS: &[DavReportType] = &[DavReportType::LatestActivityVersion];
667const SYNC_REPORTS: &[DavReportType] = &[DavReportType::SyncCollection];
668
669const EMPTY_METHODS: &[DavExtensionMethod] = &[];
670const EMPTY_PROPERTIES: &[DavLiveProperty] = &[];
671const EMPTY_REPORTS: &[DavReportType] = &[];
672const VERSION_CONTROL_REQUIRED: DavExtensionSet =
673 DavExtensionSet::from_packages(&[DavExtensionPackage::VersionControl]);
674const WORKSPACE_REQUIRED: DavExtensionSet = DavExtensionSet::from_packages(&[
675 DavExtensionPackage::VersionControl,
676 DavExtensionPackage::CheckoutInPlace,
677 DavExtensionPackage::VersionHistory,
678]);
679
680macro_rules! descriptor {
681 (
682 $package:expr,
683 $rfc:expr,
684 $dav_token:expr,
685 $prerequisites:expr,
686 $resources:expr,
687 $methods:expr,
688 $live_properties:expr,
689 $reports:expr $(,)?
690 ) => {
691 DavExtensionDescriptor {
692 package: $package,
693 rfc: $rfc,
694 dav_token: $dav_token,
695 prerequisites: $prerequisites,
696 resources: $resources,
697 methods: $methods,
698 live_properties: $live_properties,
699 reports: $reports,
700 preferences: DavPreferenceSet::empty(),
701 }
702 };
703}
704
705const DESCRIPTORS: [DavExtensionDescriptor; 22] = [
706 descriptor!(
707 DavExtensionPackage::AccessControl,
708 "RFC 3744",
709 Some("access-control"),
710 DavExtensionSet::empty(),
711 MAPPED_RESOURCES,
712 ACL_METHODS,
713 ACL_PROPERTIES,
714 ACL_REPORTS,
715 ),
716 descriptor!(
717 DavExtensionPackage::VersionControl,
718 "RFC 3253 section 3",
719 Some("version-control"),
720 DavExtensionSet::empty(),
721 ALL_RESOURCES,
722 VERSION_CONTROL_METHODS,
723 VERSION_CONTROL_PROPERTIES,
724 VERSION_CONTROL_REPORTS,
725 ),
726 descriptor!(
727 DavExtensionPackage::CheckoutInPlace,
728 "RFC 3253 section 4",
729 Some("checkout-in-place"),
730 VERSION_CONTROL_REQUIRED,
731 ALL_RESOURCES,
732 CHECKOUT_METHODS,
733 CHECKOUT_PROPERTIES,
734 EMPTY_REPORTS,
735 ),
736 descriptor!(
737 DavExtensionPackage::VersionHistory,
738 "RFC 3253 section 5",
739 Some("version-history"),
740 VERSION_CONTROL_REQUIRED,
741 ALL_RESOURCES,
742 EMPTY_METHODS,
743 VERSION_HISTORY_PROPERTIES,
744 VERSION_HISTORY_REPORTS,
745 ),
746 descriptor!(
747 DavExtensionPackage::Workspace,
748 "RFC 3253 section 6",
749 Some("workspace"),
750 WORKSPACE_REQUIRED,
751 ALL_RESOURCES,
752 WORKSPACE_METHODS,
753 WORKSPACE_PROPERTIES,
754 EMPTY_REPORTS,
755 ),
756 descriptor!(
757 DavExtensionPackage::Update,
758 "RFC 3253 section 7",
759 Some("update"),
760 VERSION_CONTROL_REQUIRED,
761 ALL_RESOURCES,
762 UPDATE_METHODS,
763 EMPTY_PROPERTIES,
764 EMPTY_REPORTS,
765 ),
766 descriptor!(
767 DavExtensionPackage::Label,
768 "RFC 3253 section 8",
769 Some("label"),
770 VERSION_CONTROL_REQUIRED,
771 ALL_RESOURCES,
772 LABEL_METHODS,
773 LABEL_PROPERTIES,
774 EMPTY_REPORTS,
775 ),
776 descriptor!(
777 DavExtensionPackage::WorkingResource,
778 "RFC 3253 section 9",
779 Some("working-resource"),
780 VERSION_CONTROL_REQUIRED,
781 ALL_RESOURCES,
782 WORKING_RESOURCE_METHODS,
783 WORKING_RESOURCE_PROPERTIES,
784 EMPTY_REPORTS,
785 ),
786 descriptor!(
787 DavExtensionPackage::Merge,
788 "RFC 3253 section 11",
789 Some("merge"),
790 VERSION_CONTROL_REQUIRED,
791 ALL_RESOURCES,
792 MERGE_METHODS,
793 MERGE_PROPERTIES,
794 MERGE_REPORTS,
795 ),
796 descriptor!(
797 DavExtensionPackage::Baseline,
798 "RFC 3253 section 12",
799 Some("baseline"),
800 VERSION_CONTROL_REQUIRED,
801 ALL_RESOURCES,
802 BASELINE_METHODS,
803 BASELINE_PROPERTIES,
804 BASELINE_REPORTS,
805 ),
806 descriptor!(
807 DavExtensionPackage::Activity,
808 "RFC 3253 section 13",
809 Some("activity"),
810 VERSION_CONTROL_REQUIRED,
811 ALL_RESOURCES,
812 ACTIVITY_METHODS,
813 ACTIVITY_PROPERTIES,
814 ACTIVITY_REPORTS,
815 ),
816 descriptor!(
817 DavExtensionPackage::VersionControlledCollection,
818 "RFC 3253 section 14",
819 Some("version-controlled-collection"),
820 VERSION_CONTROL_REQUIRED,
821 ALL_RESOURCES,
822 EMPTY_METHODS,
823 VCC_PROPERTIES,
824 EMPTY_REPORTS,
825 ),
826 descriptor!(
827 DavExtensionPackage::Search,
828 "RFC 5323",
829 None,
830 DavExtensionSet::empty(),
831 MAPPED_RESOURCES,
832 SEARCH_METHODS,
833 SEARCH_PROPERTIES,
834 EMPTY_REPORTS,
835 ),
836 descriptor!(
837 DavExtensionPackage::Quota,
838 "RFC 4331",
839 None,
840 DavExtensionSet::empty(),
841 CONTENT_RESOURCES,
842 EMPTY_METHODS,
843 QUOTA_PROPERTIES,
844 EMPTY_REPORTS,
845 ),
846 descriptor!(
847 DavExtensionPackage::CollectionSync,
848 "RFC 6578",
849 None,
850 DavExtensionSet::empty(),
851 COLLECTIONS,
852 SYNC_METHODS,
853 SYNC_PROPERTIES,
854 SYNC_REPORTS,
855 ),
856 descriptor!(
857 DavExtensionPackage::ExtendedMkcol,
858 "RFC 5689",
859 Some("extended-mkcol"),
860 DavExtensionSet::empty(),
861 UNMAPPED,
862 EXTENDED_MKCOL_METHODS,
863 EMPTY_PROPERTIES,
864 EMPTY_REPORTS,
865 ),
866 descriptor!(
867 DavExtensionPackage::CurrentPrincipal,
868 "RFC 5397",
869 None,
870 DavExtensionSet::empty(),
871 MAPPED_RESOURCES,
872 EMPTY_METHODS,
873 CURRENT_PRINCIPAL_PROPERTIES,
874 EMPTY_REPORTS,
875 ),
876 descriptor!(
877 DavExtensionPackage::OrderedCollections,
878 "RFC 3648",
879 Some("ordered-collections"),
880 DavExtensionSet::empty(),
881 ORDERABLE,
882 ORDERED_METHODS,
883 ORDERED_PROPERTIES,
884 EMPTY_REPORTS,
885 ),
886 descriptor!(
887 DavExtensionPackage::RedirectReferences,
888 "RFC 4437",
889 Some("redirectrefs"),
890 DavExtensionSet::empty(),
891 REDIRECT_TARGETS,
892 REDIRECT_METHODS,
893 REDIRECT_PROPERTIES,
894 EMPTY_REPORTS,
895 ),
896 descriptor!(
897 DavExtensionPackage::Bindings,
898 "RFC 5842",
899 Some("bind"),
900 DavExtensionSet::empty(),
901 MAPPED_RESOURCES,
902 BIND_METHODS,
903 BIND_PROPERTIES,
904 EMPTY_REPORTS,
905 ),
906 descriptor!(
907 DavExtensionPackage::AddMember,
908 "RFC 5995",
909 None,
910 DavExtensionSet::empty(),
911 ADD_MEMBER_TARGETS,
912 ADD_MEMBER_METHODS,
913 ADD_MEMBER_PROPERTIES,
914 EMPTY_REPORTS,
915 ),
916 DavExtensionDescriptor {
917 package: DavExtensionPackage::Prefer,
918 rfc: "RFC 8144",
919 dav_token: None,
920 prerequisites: DavExtensionSet::empty(),
921 resources: ALL_RESOURCES,
922 methods: EMPTY_METHODS,
923 live_properties: EMPTY_PROPERTIES,
924 reports: EMPTY_REPORTS,
925 preferences: DavPreferenceSet::all(),
926 },
927];
928
929#[must_use]
931pub fn extension_methods(packages: DavExtensionSet, resource: DavResourceState) -> DavMethodSet {
932 let mut methods = DavMethodSet::empty();
933 for package in packages.iter() {
934 for contribution in package.descriptor().methods {
935 if contribution.resources.contains(resource) {
936 methods = methods.with(contribution.method);
937 }
938 }
939 }
940 methods
941}
942
943#[must_use]
945pub fn extension_body_kind(
946 packages: DavExtensionSet,
947 resource: DavResourceState,
948 method: DavMethod,
949) -> Option<DavExtensionBodyKind> {
950 for package in packages.iter() {
951 for contribution in package.descriptor().methods {
952 if contribution.method == method && contribution.resources.contains(resource) {
953 return Some(contribution.body);
954 }
955 }
956 }
957 None
958}