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
use crate::pb::PBNode;
use alloc::borrow::Cow;
use core::convert::TryFrom;
use core::fmt;
use core::ops::Range;
pub fn node_data(block: &[u8]) -> Result<Option<&[u8]>, quick_protobuf::Error> {
let doc = PBNode::try_from(block)?;
Ok(match doc.Data {
Some(Cow::Borrowed(slice)) => Some(slice),
Some(Cow::Owned(_)) => unreachable!("never converted to owned"),
None => None,
})
}
pub fn wrap_node_data<T>(block: T) -> Result<NodeData<T>, quick_protobuf::Error>
where
T: AsRef<[u8]>,
{
let full = block.as_ref();
let range = node_data(full)?
.map(|data| subslice_to_range(full, data).expect("this has to be in range"));
Ok(NodeData {
inner: block,
range,
})
}
fn subslice_to_range(full: &[u8], sub: &[u8]) -> Option<Range<usize>> {
let max = full.len();
let amt = sub.len();
if max < amt {
return None;
}
let full = full.as_ptr() as usize;
let sub = sub.as_ptr() as usize;
sub.checked_sub(full)
.and_then(|start| if start >= max { None } else { Some(start) })
.map(|start| start..(start + amt))
}
#[derive(PartialEq, Eq)]
pub struct NodeData<T> {
inner: T,
range: Option<Range<usize>>,
}
impl<T: AsRef<[u8]>> fmt::Debug for NodeData<T> {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
fmt,
"NodeData<{}> {{ inner.len: {}, range: {:?} }}",
std::any::type_name::<T>(),
self.inner.as_ref().len(),
self.range
)
}
}
impl<T: AsRef<[u8]>> NodeData<T> {
pub fn node_data(&self) -> &[u8] {
if let Some(range) = self.range.as_ref() {
&self.inner.as_ref()[range.clone()]
} else {
&[][..]
}
}
pub fn get_ref(&self) -> &T {
&self.inner
}
pub fn into_inner(self) -> T {
self.inner
}
}
impl<T: AsRef<[u8]>, B: AsRef<[u8]>> PartialEq<B> for NodeData<T> {
fn eq(&self, other: &B) -> bool {
self.node_data() == other.as_ref()
}
}
#[cfg(test)]
mod tests {
use super::subslice_to_range;
#[test]
fn subslice_ranges() {
let full = &b"01234"[..];
for start in 0..(full.len() - 1) {
for end in start..(full.len() - 1) {
let sub = &full[start..end];
assert_eq!(subslice_to_range(full, sub), Some(start..end));
}
}
}
#[test]
fn not_in_following_subslice() {
let full = &b"0123456789"[..];
let a = &full[0..4];
let b = &full[4..];
let a_sub = &a[1..3];
let b_sub = &b[0..2];
assert_eq!(subslice_to_range(a, a_sub), Some(1..3));
assert_eq!(subslice_to_range(b, b_sub), Some(0..2));
assert_eq!(subslice_to_range(a, b_sub), None);
assert_eq!(subslice_to_range(b, a_sub), None);
}
}