1use std::{
7 fmt::{self, Debug, Formatter},
8 marker::PhantomData,
9};
10
11use data::{Flow, LinkReference, LinksConstants};
12
13use super::{
14 helpers,
15 macros::{decorator_struct, forward},
16};
17use crate::{
18 data::{ReadHandler, WriteHandler},
19 Doublets, Error, Fuse, Link, Links,
20};
21
22decorator_struct! {
23 UniquenessValidator
29}
30
31impl<T: LinkReference, L: Doublets<T>> Links<T> for UniquenessValidator<T, L> {
32 forward!(count_links, each_links, create_links, delete_links);
33
34 #[inline]
35 fn update_links(
36 &mut self,
37 query: &[T],
38 change: &[T],
39 handler: WriteHandler<'_, T>,
40 ) -> Result<Flow, Error<T>> {
41 let constants = self.links.constants();
42 let source = helpers::part(change, constants.source_part);
43 let target = helpers::part(change, constants.target_part);
44 helpers::ensure_does_not_exist(&self.links, source, target)?;
45 self.links.update_links(query, change, handler)
46 }
47}
48
49decorator_struct! {
50 UniquenessResolver
65}
66
67impl<T: LinkReference, L: Doublets<T>> UniquenessResolver<T, L> {
68 #[inline]
70 fn resolve_address_change_conflict(
71 &mut self,
72 old: T,
73 new: T,
74 handler: WriteHandler<'_, T>,
75 ) -> Result<Flow, Error<T>> {
76 resolve_address_change_conflict(self, old, new, handler)
77 }
78}
79
80impl<T: LinkReference, L: Doublets<T>> Links<T> for UniquenessResolver<T, L> {
81 forward!(count_links, each_links, create_links, delete_links);
82
83 #[inline]
84 fn update_links(
85 &mut self,
86 query: &[T],
87 change: &[T],
88 handler: WriteHandler<'_, T>,
89 ) -> Result<Flow, Error<T>> {
90 let constants = self.links.constants();
91 let source = helpers::part(change, constants.source_part);
92 let target = helpers::part(change, constants.target_part);
93 let old = helpers::part(query, constants.index_part);
94
95 let Some(new) = self.links.search(source, target) else {
96 return self.links.update_links(query, change, handler);
97 };
98 self.resolve_address_change_conflict(old, new, handler)
99 }
100}
101
102decorator_struct! {
103 CascadeUniquenessAndUsagesResolver
108}
109
110impl<T: LinkReference, L: Doublets<T>> CascadeUniquenessAndUsagesResolver<T, L> {
111 #[inline]
113 fn resolve_address_change_conflict(
114 &mut self,
115 old: T,
116 new: T,
117 handler: WriteHandler<'_, T>,
118 ) -> Result<Flow, Error<T>> {
119 let mut fuse = Fuse::new(&mut *handler);
120 helpers::merge_usages(self, old, new, |before, after| fuse.call(before, after))?;
123 resolve_address_change_conflict(self, old, new, &mut |before, after| {
124 fuse.call(before, after)
125 })
126 }
127}
128
129impl<T: LinkReference, L: Doublets<T>> Links<T> for CascadeUniquenessAndUsagesResolver<T, L> {
130 forward!(count_links, each_links, create_links, delete_links);
131
132 #[inline]
133 fn update_links(
134 &mut self,
135 query: &[T],
136 change: &[T],
137 handler: WriteHandler<'_, T>,
138 ) -> Result<Flow, Error<T>> {
139 let constants = self.links.constants();
140 let source = helpers::part(change, constants.source_part);
141 let target = helpers::part(change, constants.target_part);
142 let old = helpers::part(query, constants.index_part);
143
144 let Some(new) = self.links.search(source, target) else {
145 return self.links.update_links(query, change, handler);
146 };
147 self.resolve_address_change_conflict(old, new, handler)
148 }
149}
150
151#[inline]
156fn resolve_address_change_conflict<T, D>(
157 links: &mut D,
158 old: T,
159 new: T,
160 handler: WriteHandler<'_, T>,
161) -> Result<Flow, Error<T>>
162where
163 T: LinkReference,
164 D: Doublets<T>,
165{
166 let mut fuse = Fuse::new(&mut *handler);
167 if old != new && links.exist(old) {
168 links.delete_links(&[old], &mut |before, after| fuse.call(before, after))?;
169 }
170 let survivor = links.try_get_link(new)?;
171 Ok(fuse.call(survivor.clone(), survivor))
172}