iroh_blobs/util/
sparse_mem_file.rs1use std::io;
2
3use bao_tree::io::sync::{ReadAt, Size, WriteAt};
4use derive_more::Deref;
5use range_collections::{range_set::RangeSetRange, RangeSet2};
6
7#[derive(derive_more::Debug)]
13pub struct SparseMemFile {
14 #[debug("{} bytes", data.len())]
16 data: Vec<u8>,
17 ranges: RangeSet2<usize>,
19}
20
21impl Default for SparseMemFile {
22 fn default() -> Self {
23 Self::new()
24 }
25}
26
27impl From<Vec<u8>> for SparseMemFile {
28 fn from(data: Vec<u8>) -> Self {
29 let ranges = RangeSet2::from(0..data.len());
30 Self { data, ranges }
31 }
32}
33
34impl TryInto<Vec<u8>> for SparseMemFile {
35 type Error = io::Error;
36
37 fn try_into(self) -> Result<Vec<u8>, Self::Error> {
38 let (data, ranges) = self.into_parts();
39 if ranges == RangeSet2::from(0..data.len()) {
40 Ok(data)
41 } else {
42 Err(io::Error::new(
43 io::ErrorKind::InvalidData,
44 "SparseMemFile has gaps",
45 ))
46 }
47 }
48}
49
50impl SparseMemFile {
51 pub fn new() -> Self {
53 Self {
54 data: Vec::new(),
55 ranges: RangeSet2::empty(),
56 }
57 }
58
59 pub fn into_parts(self) -> (Vec<u8>, RangeSet2<usize>) {
61 (self.data, self.ranges)
62 }
63
64 pub fn persist(&self, mut target: impl WriteAt) -> io::Result<()> {
68 let size = self.data.len();
69 for range in self.ranges.iter() {
70 let range = match range {
71 RangeSetRange::Range(range) => *range.start..*range.end,
72 RangeSetRange::RangeFrom(range) => *range.start..size,
73 };
74 let start = range.start.try_into().unwrap();
75 let buf = &self.data[range];
76 target.write_at(start, buf)?;
77 }
78 Ok(())
79 }
80}
81
82impl AsRef<[u8]> for SparseMemFile {
83 fn as_ref(&self) -> &[u8] {
84 &self.data
85 }
86}
87
88impl Deref for SparseMemFile {
89 type Target = [u8];
90
91 fn deref(&self) -> &Self::Target {
92 &self.data
93 }
94}
95
96impl ReadAt for SparseMemFile {
97 fn read_at(&self, offset: u64, buf: &mut [u8]) -> io::Result<usize> {
98 self.data.read_at(offset, buf)
99 }
100}
101
102impl WriteAt for SparseMemFile {
103 fn write_at(&mut self, offset: u64, buf: &[u8]) -> io::Result<usize> {
104 let start: usize = offset.try_into().map_err(|_| io::ErrorKind::InvalidInput)?;
105 let end = start
106 .checked_add(buf.len())
107 .ok_or(io::ErrorKind::InvalidInput)?;
108 let n = self.data.write_at(offset, buf)?;
109 self.ranges |= RangeSet2::from(start..end);
110 Ok(n)
111 }
112
113 fn flush(&mut self) -> io::Result<()> {
114 Ok(())
115 }
116}
117
118impl Size for SparseMemFile {
119 fn size(&self) -> io::Result<Option<u64>> {
120 Ok(Some(self.data.len() as u64))
121 }
122}