1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
mod one;
mod three;
mod two;
use fast_stm::atomically_with_err;
use crate::cmap::{CMap3, DartIdType, LinkError};
use crate::geometry::CoordsFloat;
use crate::stm::{Transaction, TransactionClosureResult};
/// # **Link operations**
impl<T: CoordsFloat> CMap3<T> {
/// `I`-link operator.
///
/// # Description
///
/// This operation corresponds to coherently linking two darts via their *β* images. Unlike
/// sewing, this does not alter associated attributes. For a thorough explanation of this
/// operation, its hypothesis & consequences, refer to the [user guide][UG].
///
/// [UG]: https://lihpc-computational-geometry.github.io/honeycomb/user-guide/definitions/sew.html
///
/// # Arguments
///
/// - `const I: u8` -- Link dimension.
/// - `t: &mut Transaction` -- Transaction associated to the operation.
/// - `lhs_dart_id: DartIdType` -- First dart ID.
/// - `rhs_dart_id: DartIdType` -- Second dart ID.
///
/// # Errors
///
/// This method should be called in a transactional context. The `Result` is then used to
/// validate the transaction; Errors should not be processed manually, only processed via the
/// `?` operator. The policy in case of failure can be defined when creating the transaction,
/// using `Transaction::with_control`.
///
/// It may return an error if the transaction fails or if the link fails; See [`LinkError`] for
/// more detail about the latter.
///
/// # Panics
///
/// The method may panic if:
/// - `I >= 4` or `I == 0`,
/// - the two darts are not `I`-linkable.
pub fn link_tx<const I: u8>(
&self,
t: &mut Transaction,
lhs_dart_id: DartIdType,
rhs_dart_id: DartIdType,
) -> TransactionClosureResult<(), LinkError> {
// these assertions + match on a const are optimized away
assert!(I < 4);
assert_ne!(I, 0);
match I {
1 => self.one_link_tx(t, lhs_dart_id, rhs_dart_id),
2 => self.two_link_tx(t, lhs_dart_id, rhs_dart_id),
3 => self.three_link_tx(t, lhs_dart_id, rhs_dart_id),
_ => unreachable!(),
}
}
/// `I`-unlink operator.
///
/// # Description
///
/// This operation corresponds to unlinking two darts by resetting their *β* images. Unlike
/// unsewing, this does not alter associated attributes. For a thorough explanation of this
/// operation, its hypothesis & consequences, refer to the [user guide][UG].
///
/// [UG]: https://lihpc-computational-geometry.github.io/honeycomb/user-guide/definitions/sew.html
///
/// # Arguments
///
/// - `const I: u8` -- Unlink dimension.
/// - `t: &mut Transaction` -- Transaction associated to the operation.
/// - `lhs_dart_id: DartIdType` -- First dart ID.
///
/// The second dart ID is fetched using `I` and `lhs_dart_id`.
///
/// # Errors
///
/// This method should be called in a transactional context. The `Result` is then used to
/// validate the transaction; Errors should not be processed manually, only processed via the
/// `?` operator. The policy in case of failure can be defined when creating the transaction,
/// using `Transaction::with_control`.
///
/// # Panics
///
/// The method may panic if:
/// - `I >= 4` or `I == 0`,
/// - `lhs_dart_id` is already `I`-free.
pub fn unlink_tx<const I: u8>(
&self,
t: &mut Transaction,
lhs_dart_id: DartIdType,
) -> TransactionClosureResult<(), LinkError> {
// these assertions + match on a const are optimized away
assert!(I < 4);
assert_ne!(I, 0);
match I {
1 => self.one_unlink_tx(t, lhs_dart_id),
2 => self.two_unlink_tx(t, lhs_dart_id),
3 => self.three_unlink_tx(t, lhs_dart_id),
_ => unreachable!(),
}
}
/// `I`-link operator.
///
/// This variant is equivalent to [`link`][Self::link], but internally uses a transaction that
/// will be retried until validated.
///
/// # Errors
///
/// It may return an error if the transaction fails or if the link fails; See [`LinkError`] for
/// more detail about the latter.
///
/// # Panics
///
/// The method may panic if:
/// - `I >= 4` or `I == 0`,
/// - `lhs_dart_id` is already `I`-free.
pub fn link<const I: u8>(
&self,
lhs_dart_id: DartIdType,
rhs_dart_id: DartIdType,
) -> Result<(), LinkError> {
// these assertions + match on a const are optimized away
assert!(I < 4);
assert_ne!(I, 0);
match I {
1 => atomically_with_err(|t| self.one_link_tx(t, lhs_dart_id, rhs_dart_id)),
2 => atomically_with_err(|t| self.two_link_tx(t, lhs_dart_id, rhs_dart_id)),
3 => atomically_with_err(|t| self.three_link_tx(t, lhs_dart_id, rhs_dart_id)),
_ => unreachable!(),
}
}
/// `I`-unlink operator.
///
/// This variant is equivalent to [`unlink`][Self::unlink], but internally uses a transaction
/// that will be retried until validated.
///
/// # Errors
///
/// It may return an error if the transaction fails or if the link fails; See [`LinkError`] for
/// more detail about the latter.
///
/// # Panics
///
/// The method may panic if:
/// - `I >= 4` or `I == 0`,
/// - `lhs_dart_id` is already `I`-free.
pub fn unlink<const I: u8>(&self, lhs_dart_id: DartIdType) -> Result<(), LinkError> {
// these assertions + match on a const are optimized away
assert!(I < 4);
assert_ne!(I, 0);
match I {
1 => atomically_with_err(|t| self.one_unlink_tx(t, lhs_dart_id)),
2 => atomically_with_err(|t| self.two_unlink_tx(t, lhs_dart_id)),
3 => atomically_with_err(|t| self.three_unlink_tx(t, lhs_dart_id)),
_ => unreachable!(),
}
}
}