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
use kitsune_p2p_dht_arc::DhtArcRange;
use crate::{spacetime::Topology, Loc};
use super::{Arq, ArqStart};
pub(crate) fn loc_upscale(len: usize, v: i32) -> u32 {
let max = 2f64.powi(32);
let lenf = len as f64;
let vf = v as f64;
(max / lenf * vf) as i64 as u32
}
pub(crate) fn loc_downscale(len: usize, d: Loc) -> usize {
let max = 2f64.powi(32);
let lenf = len as f64;
((lenf / max * (d.as_u32() as f64)) as usize) % len
}
pub fn add_location_ascii(mut s: String, locs: Vec<Loc>) -> String {
let len = s.len();
let mut buf = vec![0; len];
for loc in locs {
let loc = loc_downscale(len, loc);
buf[loc] += 1;
}
for (i, v) in buf.into_iter().enumerate() {
if v > 0 {
let c = format!("{:x}", v.min(0xf));
s.replace_range(i..i + 1, &c);
}
}
s
}
impl<S: ArqStart> Arq<S> {
pub fn to_ascii(&self, topo: &Topology, len: usize) -> String {
let empty = || " ".repeat(len);
let full = || "-".repeat(len);
let decide = |lo: &Loc, hi: &Loc| {
let mid = loc_upscale(len, (len / 2) as i32);
if lo < hi {
if hi.as_u32() - lo.as_u32() < mid {
empty()
} else {
full()
}
} else if lo.as_u32() - hi.as_u32() < mid {
full()
} else {
empty()
}
};
match self.to_dht_arc_range(topo) {
DhtArcRange::Full => full(),
DhtArcRange::Empty => empty(),
DhtArcRange::Bounded(lo0, hi0) => {
let lo = loc_downscale(len, lo0);
let hi = loc_downscale(len, hi0);
if lo0 <= hi0 {
if lo >= hi {
vec![decide(&lo0, &hi0)]
} else {
vec![
" ".repeat(lo),
"-".repeat(hi - lo + 1),
" ".repeat((len - hi).saturating_sub(1)),
]
}
} else if lo <= hi {
vec![decide(&lo0, &hi0)]
} else {
vec![
"-".repeat(hi + 1),
" ".repeat((lo - hi).saturating_sub(1)),
"-".repeat(len - lo),
]
}
.join("")
}
}
}
}