1use crate::pb::PBNode;
4use alloc::borrow::Cow;
5use core::convert::TryFrom;
6use core::fmt;
7use core::ops::Range;
8
9pub fn node_data(block: &[u8]) -> Result<Option<&[u8]>, quick_protobuf::Error> {
11 let doc = PBNode::try_from(block)?;
12 Ok(match doc.Data {
13 Some(Cow::Borrowed(slice)) => Some(slice),
14 Some(Cow::Owned(_)) => unreachable!("never converted to owned"),
15 None => None,
16 })
17}
18
19pub fn wrap_node_data<T>(block: T) -> Result<NodeData<T>, quick_protobuf::Error>
22where
23 T: AsRef<[u8]>,
24{
25 let full = block.as_ref();
26 let range = node_data(full)?
27 .map(|data| subslice_to_range(full, data).expect("this has to be in range"));
28 Ok(NodeData {
29 inner: block,
30 range,
31 })
32}
33
34fn subslice_to_range(full: &[u8], sub: &[u8]) -> Option<Range<usize>> {
35 let max = full.len();
38 let amt = sub.len();
39
40 if max < amt {
41 return None;
43 }
44
45 let full = full.as_ptr() as usize;
46 let sub = sub.as_ptr() as usize;
47
48 sub.checked_sub(full)
49 .and_then(|start| if start >= max { None } else { Some(start) })
54 .map(|start| start..(start + amt))
55}
56
57#[derive(PartialEq, Eq)]
59pub struct NodeData<T> {
60 inner: T,
61 range: Option<Range<usize>>,
62}
63
64impl<T: AsRef<[u8]>> fmt::Debug for NodeData<T> {
65 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
66 write!(
67 fmt,
68 "NodeData<{}> {{ inner.len: {}, range: {:?} }}",
69 std::any::type_name::<T>(),
70 self.inner.as_ref().len(),
71 self.range
72 )
73 }
74}
75
76impl<T: AsRef<[u8]>> NodeData<T> {
77 pub fn node_data(&self) -> &[u8] {
79 if let Some(range) = self.range.as_ref() {
80 &self.inner.as_ref()[range.clone()]
81 } else {
82 &[][..]
83 }
84 }
85
86 pub fn get_ref(&self) -> &T {
88 &self.inner
89 }
90
91 pub fn into_inner(self) -> T {
93 self.inner
94 }
95}
96
97impl<T: AsRef<[u8]>, B: AsRef<[u8]>> PartialEq<B> for NodeData<T> {
98 fn eq(&self, other: &B) -> bool {
99 self.node_data() == other.as_ref()
100 }
101}
102
103#[cfg(test)]
104mod tests {
105 use super::subslice_to_range;
106
107 #[test]
108 fn subslice_ranges() {
109 let full = &b"01234"[..];
110
111 for start in 0..(full.len() - 1) {
112 for end in start..(full.len() - 1) {
113 let sub = &full[start..end];
114 assert_eq!(subslice_to_range(full, sub), Some(start..end));
115 }
116 }
117 }
118
119 #[test]
120 fn not_in_following_subslice() {
121 let full = &b"0123456789"[..];
126
127 let a = &full[0..4];
128 let b = &full[4..];
129
130 let a_sub = &a[1..3];
131 let b_sub = &b[0..2];
132
133 assert_eq!(subslice_to_range(a, a_sub), Some(1..3));
134 assert_eq!(subslice_to_range(b, b_sub), Some(0..2));
135
136 assert_eq!(subslice_to_range(a, b_sub), None);
137 assert_eq!(subslice_to_range(b, a_sub), None);
138 }
139}