kitsune_p2p_dht/spacetime/
segment.rs1use super::*;
2
3pub trait Offset: Sized + Copy + Clone + Deref<Target = u32> + From<u32> {
10 type Quantum: Quantum;
12
13 fn to_absolute(&self, dim: QDim<Self>, power: u8) -> QAbs<Self>;
15
16 fn to_quantum(&self, power: u8) -> Self::Quantum;
18
19 fn from_absolute_rounded(loc: Loc, dim: QDim<Self>, power: u8) -> Self;
21}
22
23pub(crate) type QAbs<O> = <<O as Offset>::Quantum as Quantum>::Absolute;
24pub(crate) type QDim<O> = <<O as Offset>::Quantum as Quantum>::Dim;
25
26#[derive(
28 Copy,
29 Clone,
30 Debug,
31 PartialEq,
32 Eq,
33 PartialOrd,
34 Ord,
35 Hash,
36 derive_more::Add,
37 derive_more::Sub,
38 derive_more::Mul,
39 derive_more::Div,
40 derive_more::Deref,
41 derive_more::DerefMut,
42 derive_more::From,
43 derive_more::Into,
44 serde::Serialize,
45 serde::Deserialize,
46)]
47#[cfg_attr(
48 feature = "fuzzing",
49 derive(arbitrary::Arbitrary, proptest_derive::Arbitrary)
50)]
51#[serde(transparent)]
52pub struct SpaceOffset(pub u32);
53
54#[derive(
56 Copy,
57 Clone,
58 Debug,
59 PartialEq,
60 Eq,
61 PartialOrd,
62 Ord,
63 Hash,
64 derive_more::Add,
65 derive_more::Sub,
66 derive_more::Mul,
67 derive_more::Div,
68 derive_more::Deref,
69 derive_more::DerefMut,
70 derive_more::From,
71 derive_more::Into,
72 serde::Serialize,
73 serde::Deserialize,
74)]
75#[cfg_attr(
76 feature = "fuzzing",
77 derive(arbitrary::Arbitrary, proptest_derive::Arbitrary)
78)]
79#[serde(transparent)]
80pub struct TimeOffset(pub u32);
81
82impl Offset for SpaceOffset {
83 type Quantum = SpaceQuantum;
84
85 fn to_absolute(&self, dim: SpaceDimension, power: u8) -> Loc {
87 self.wrapping_mul(dim.quantum)
88 .wrapping_mul(pow2(power))
89 .into()
90 }
91
92 fn to_quantum(&self, power: u8) -> Self::Quantum {
94 self.wrapping_mul(pow2(power)).into()
95 }
96
97 fn from_absolute_rounded(loc: Loc, dim: SpaceDimension, power: u8) -> Self {
99 (loc.as_u32() / dim.quantum / pow2(power)).into()
100 }
101}
102
103impl Offset for TimeOffset {
104 type Quantum = TimeQuantum;
105
106 fn to_absolute(&self, dim: TimeDimension, power: u8) -> Timestamp {
108 Timestamp::from_micros(self.wrapping_mul(dim.quantum).wrapping_mul(pow2(power)) as i64)
109 }
110
111 fn to_quantum(&self, power: u8) -> Self::Quantum {
113 self.wrapping_mul(pow2(power)).into()
114 }
115
116 fn from_absolute_rounded(loc: Loc, dim: TimeDimension, power: u8) -> Self {
118 (loc.as_u32() / dim.quantum / pow2(power)).into()
119 }
120}
121
122#[derive(
127 Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, serde::Deserialize, serde::Serialize,
128)]
129#[cfg_attr(
130 feature = "fuzzing",
131 derive(arbitrary::Arbitrary, proptest_derive::Arbitrary)
132)]
133pub struct Segment<O: Offset> {
134 pub power: u8,
136 pub offset: O,
138}
139
140impl<O: Offset> Segment<O> {
141 pub fn new<OO: Into<O>>(power: u8, offset: OO) -> Self {
143 Self {
144 power,
145 offset: offset.into(),
146 }
147 }
148
149 pub fn num_quanta(&self) -> u64 {
151 2u64.pow(self.power.into())
153 }
154
155 pub fn absolute_length(&self, dim: QDim<O>) -> u64 {
157 let q = dim.into().quantum as u64;
158 self.num_quanta() * q
160 }
161
162 pub fn quantum_bounds(&self, dim: QDim<O>) -> (O::Quantum, O::Quantum) {
164 let n = self.num_quanta();
165 let a = (n * u64::from(*self.offset)) as u32;
166 (
167 O::Quantum::from(a).normalized(dim),
168 O::Quantum::from(a.wrapping_add(n as u32).wrapping_sub(1)).normalized(dim),
169 )
170 }
171
172 pub fn contains_quantum(&self, dim: QDim<O>, coord: O::Quantum) -> bool {
174 let (lo, hi) = self.quantum_bounds(dim);
175 let coord = coord.normalized(dim);
176 if lo <= hi {
177 lo <= coord && coord <= hi
178 } else {
179 lo <= coord || coord <= hi
180 }
181 }
182
183 pub fn bisect(&self) -> Option<[Self; 2]> {
185 if self.power == 0 {
186 None
188 } else {
189 let power = self.power - 1;
190 Some([
191 Segment::new(power, O::from(self.offset.wrapping_mul(2))),
192 Segment::new(power, O::from(self.offset.wrapping_mul(2).wrapping_add(1))),
193 ])
194 }
195 }
196}
197
198impl SpaceSegment {
199 pub fn loc_bounds(&self, dim: impl SpaceDim) -> (Loc, Loc) {
201 let (a, b): (u32, u32) = space_bounds(dim.into().into(), self.power, self.offset, 1);
202 (Loc::from(a), Loc::from(b))
203 }
204}
205
206impl TimeSegment {
207 pub fn timestamp_bounds(&self, topo: &Topology) -> (Timestamp, Timestamp) {
209 let (a, b): (i64, i64) = time_bounds64(topo.time.into(), self.power, self.offset, 1);
210 let o = topo.time_origin.as_micros();
211 (Timestamp::from_micros(a + o), Timestamp::from_micros(b + o))
212 }
213}
214
215pub type SpaceSegment = Segment<SpaceOffset>;
217
218pub type TimeSegment = Segment<TimeOffset>;
220
221pub(super) fn space_bounds<N: From<u32>>(
233 dim: Dimension,
234 power: u8,
235 offset: SpaceOffset,
236 count: u32,
237) -> (N, N) {
238 debug_assert_ne!(dim.quantum, 0);
239 debug_assert_ne!(count, 0);
240 let q = dim.quantum.wrapping_mul(pow2(power));
241 let start = offset.wrapping_mul(q);
242 let len = count.wrapping_mul(q);
243 (start.into(), start.wrapping_add(len).wrapping_sub(1).into())
244}
245
246pub(super) fn time_bounds64<N: From<i64>>(
248 dim: Dimension,
249 power: u8,
250 offset: TimeOffset,
251 count: u32,
252) -> (N, N) {
253 debug_assert_ne!(dim.quantum, 0);
254 debug_assert_ne!(count, 0);
255 let q = dim.quantum as i64 * 2i64.pow(power.into());
256 let start = (*offset as i64).wrapping_mul(q);
257 let len = (count as i64).wrapping_mul(q);
258 (start.into(), start.wrapping_add(len).wrapping_sub(1).into())
259}
260
261#[cfg(test)]
262mod tests {
263 use super::*;
264
265 #[test]
266 fn simple_space_bounds() {
267 let dim = SpaceDimension::standard();
268 let (lower, upper) = space_bounds::<u32>(dim.into(), 0, 5.into(), 2);
269
270 assert_eq!(lower, dim.quantum * 5);
271 assert_eq!(upper, dim.quantum * 5 + dim.quantum * 2 - 1);
272 }
273
274 #[test]
275 fn simple_wrapping_space_bounds() {
276 let dim = SpaceDimension::standard();
277 let (lower, upper) = space_bounds::<u32>(
278 dim.into(),
279 0,
280 5.into(),
281 pow2(32 - dim.quantum_power) - 5 + 1,
282 );
283
284 assert!(upper < lower, "lower: {lower}, upper: {upper}");
285
286 assert_eq!(lower, dim.quantum * 5);
287 assert_eq!(upper, dim.quantum - 1);
288 }
289
290 #[test]
291 fn space_bounds_with_quantization() {
292 let dim = SpaceDimension::standard();
293
294 let (lower, upper) = space_bounds::<u32>(dim.into(), 2, 5.into(), 2);
297
298 let scaled_quantum = dim.quantum * pow2(2);
299 assert_eq!(lower, scaled_quantum * 5);
300 assert_eq!(upper, scaled_quantum * 5 + scaled_quantum * 2 - 1);
301 }
302
303 #[test]
304 fn simple_time_bounds() {
305 let dim = TimeDimension::standard();
306 let (lower, upper) = time_bounds64::<i64>(dim.into(), 0, 5.into(), 2);
307
308 assert_eq!(lower, dim.quantum as i64 * 5);
309 assert_eq!(upper, dim.quantum as i64 * 5 + dim.quantum as i64 * 2 - 1);
310 }
311
312 #[test]
313 fn time_bounds_with_quantization() {
314 let dim = TimeDimension::standard();
315
316 let (lower, upper) = time_bounds64::<i64>(dim.into(), 2, 5.into(), 2);
319
320 let scaled_quantum = (dim.quantum * pow2(2)) as i64;
321 assert_eq!(lower, scaled_quantum * 5);
322 assert_eq!(upper, scaled_quantum * 5 + scaled_quantum * 2 - 1);
323 }
324}