exocore_chain/
data.rs

1use std::ops::{Bound, Range, RangeBounds};
2
3use bytes::{Buf, Bytes};
4use exocore_core::framing::FrameReader;
5
6/// Abstraction for sources of data / bytes (in memory owned bytes, in memory
7/// data reference, mmap file, etc.)
8pub trait Data: FrameReader<OwnedType = Bytes> + Clone {
9    fn slice<R: RangeBounds<usize>>(&self, r: R) -> &[u8];
10
11    fn view<R: RangeBounds<usize>>(&self, r: R) -> Self;
12
13    fn len(&self) -> usize;
14
15    fn is_empty(&self) -> bool {
16        self.len() == 0
17    }
18}
19
20/// Data from in memory owned bytes.
21impl Data for Bytes {
22    fn slice<R: RangeBounds<usize>>(&self, r: R) -> &[u8] {
23        let r = translate_range(0, self.len(), r);
24        &self.chunk()[r]
25    }
26
27    fn view<R: RangeBounds<usize>>(&self, r: R) -> Self {
28        self.slice(r)
29    }
30
31    fn len(&self) -> usize {
32        self.len()
33    }
34}
35
36/// Data from a referenced sliced of bytes.
37#[derive(Clone)]
38pub struct RefData<'s> {
39    pub(crate) data: &'s [u8],
40    pub(crate) start: usize,
41    pub(crate) end: usize, // exclusive
42}
43
44impl<'s> RefData<'s> {
45    pub fn new(data: &[u8]) -> RefData {
46        RefData {
47            data,
48            start: 0,
49            end: data.len(),
50        }
51    }
52}
53
54impl<'s> Data for RefData<'s> {
55    fn slice<R: RangeBounds<usize>>(&self, r: R) -> &[u8] {
56        let r = translate_range(self.start, self.end, r);
57        &self.data[r]
58    }
59
60    fn view<R: RangeBounds<usize>>(&self, r: R) -> RefData<'s> {
61        let r = translate_range(self.start, self.end, r);
62        RefData {
63            data: self.data,
64            start: r.start,
65            end: r.end,
66        }
67    }
68
69    fn len(&self) -> usize {
70        self.end - self.start
71    }
72}
73
74impl<'s> FrameReader for RefData<'s> {
75    type OwnedType = Bytes;
76
77    fn exposed_data(&self) -> &[u8] {
78        self.slice(..)
79    }
80
81    fn whole_data(&self) -> &[u8] {
82        self.slice(..)
83    }
84
85    fn to_owned_frame(&self) -> Self::OwnedType {
86        panic!(
87            "Cannot call to_owned_frame since it could copy unbounded amount of referenced bytes"
88        )
89    }
90}
91
92/// Data from a memory mapped file.
93#[cfg(feature = "mmap")]
94pub use mmap::*;
95
96#[cfg(feature = "mmap")]
97mod mmap {
98    use std::{ops::RangeBounds, sync::Arc};
99
100    use bytes::Bytes;
101    use exocore_core::framing::FrameReader;
102
103    use super::{translate_range, Data};
104
105    #[derive(Clone)]
106    pub struct MmapData {
107        pub(crate) data: Arc<memmap2::Mmap>,
108        pub(crate) start: usize,
109        pub(crate) end: usize, // exclusive
110    }
111
112    impl MmapData {
113        pub fn from_mmap(data: Arc<memmap2::Mmap>, len: usize) -> MmapData {
114            MmapData {
115                data,
116                start: 0,
117                end: len,
118            }
119        }
120    }
121
122    impl Data for MmapData {
123        fn slice<R: RangeBounds<usize>>(&self, r: R) -> &[u8] {
124            let r = translate_range(self.start, self.end, r);
125            &self.data[r]
126        }
127
128        fn view<R: RangeBounds<usize>>(&self, r: R) -> MmapData {
129            let r = translate_range(self.start, self.end, r);
130            MmapData {
131                data: self.data.clone(),
132                start: r.start,
133                end: r.end,
134            }
135        }
136
137        fn len(&self) -> usize {
138            self.end - self.start
139        }
140    }
141
142    impl FrameReader for MmapData {
143        type OwnedType = Bytes;
144
145        fn exposed_data(&self) -> &[u8] {
146            self.slice(..)
147        }
148
149        fn whole_data(&self) -> &[u8] {
150            self.slice(..)
151        }
152
153        fn to_owned_frame(&self) -> Self::OwnedType {
154            panic!("Cannot call to_owned_frame since it could be a whole mmap file")
155        }
156    }
157}
158
159fn translate_range<R: RangeBounds<usize>>(start: usize, end: usize, range: R) -> Range<usize> {
160    let new_start = match range.start_bound() {
161        Bound::Included(s) => start + *s,
162        Bound::Excluded(s) => start + *s + 1,
163        Bound::Unbounded => start,
164    };
165    let new_end = match range.end_bound() {
166        Bound::Included(s) => (start + *s + 1).min(end),
167        Bound::Excluded(s) => (start + *s).min(end),
168        Bound::Unbounded => end,
169    };
170
171    Range {
172        start: new_start,
173        end: new_end,
174    }
175}
176
177#[cfg(test)]
178mod tests {
179    use super::*;
180
181    #[test]
182    fn test_translate_range() {
183        assert_eq!(translate_range(0, 99, ..), Range { start: 0, end: 99 });
184        assert_eq!(translate_range(2, 99, ..), Range { start: 2, end: 99 });
185        assert_eq!(translate_range(2, 99, ..120), Range { start: 2, end: 99 });
186        assert_eq!(translate_range(10, 99, 0..9), Range { start: 10, end: 19 });
187        assert_eq!(translate_range(10, 99, 0..=9), Range { start: 10, end: 20 });
188        assert_eq!(translate_range(10, 99, ..9), Range { start: 10, end: 19 });
189        assert_eq!(translate_range(10, 99, ..10), Range { start: 10, end: 20 });
190        assert_eq!(translate_range(10, 99, 80..), Range { start: 90, end: 99 });
191    }
192}