iroh_blobs/util/
mem_or_file.rs

1use std::{fs::File, io};
2
3use bao_tree::io::sync::{ReadAt, Size};
4use bytes::Bytes;
5
6/// This is a general purpose Either, just like Result, except that the two cases
7/// are Mem for something that is in memory, and File for something that is somewhere
8/// external and only available via io.
9#[derive(Debug)]
10pub enum MemOrFile<M, F> {
11    /// We got it all in memory
12    Mem(M),
13    /// A file
14    File(F),
15}
16
17/// Helper methods for a common way to use MemOrFile, where the memory part is something
18/// like a slice, and the file part is a tuple consisiting of path or file and size.
19impl<M, F> MemOrFile<M, (F, u64)>
20where
21    M: AsRef<[u8]>,
22{
23    /// Get the size of the MemOrFile
24    pub fn size(&self) -> u64 {
25        match self {
26            MemOrFile::Mem(mem) => mem.as_ref().len() as u64,
27            MemOrFile::File((_, size)) => *size,
28        }
29    }
30}
31
32impl ReadAt for MemOrFile<Bytes, File> {
33    fn read_at(&self, offset: u64, buf: &mut [u8]) -> io::Result<usize> {
34        match self {
35            MemOrFile::Mem(mem) => mem.as_ref().read_at(offset, buf),
36            MemOrFile::File(file) => file.read_at(offset, buf),
37        }
38    }
39}
40
41impl Size for MemOrFile<Bytes, File> {
42    fn size(&self) -> io::Result<Option<u64>> {
43        match self {
44            MemOrFile::Mem(mem) => Ok(Some(mem.len() as u64)),
45            MemOrFile::File(file) => file.size(),
46        }
47    }
48}
49
50impl<M: Default, F> Default for MemOrFile<M, F> {
51    fn default() -> Self {
52        MemOrFile::Mem(Default::default())
53    }
54}
55
56impl<M, F> MemOrFile<M, F> {
57    /// Turn a reference to a MemOrFile into a MemOrFile of references
58    pub fn as_ref(&self) -> MemOrFile<&M, &F> {
59        match self {
60            MemOrFile::Mem(mem) => MemOrFile::Mem(mem),
61            MemOrFile::File(file) => MemOrFile::File(file),
62        }
63    }
64
65    /// True if this is a Mem
66    pub fn is_mem(&self) -> bool {
67        matches!(self, MemOrFile::Mem(_))
68    }
69
70    /// Get the mem part
71    pub fn mem(&self) -> Option<&M> {
72        match self {
73            MemOrFile::Mem(mem) => Some(mem),
74            MemOrFile::File(_) => None,
75        }
76    }
77
78    /// Map the file part of this MemOrFile
79    pub fn map_file<F2>(self, f: impl FnOnce(F) -> F2) -> MemOrFile<M, F2> {
80        match self {
81            MemOrFile::Mem(mem) => MemOrFile::Mem(mem),
82            MemOrFile::File(file) => MemOrFile::File(f(file)),
83        }
84    }
85
86    /// Try to map the file part of this MemOrFile
87    pub fn try_map_file<F2, E>(
88        self,
89        f: impl FnOnce(F) -> Result<F2, E>,
90    ) -> Result<MemOrFile<M, F2>, E> {
91        match self {
92            MemOrFile::Mem(mem) => Ok(MemOrFile::Mem(mem)),
93            MemOrFile::File(file) => f(file).map(MemOrFile::File),
94        }
95    }
96
97    /// Map the memory part of this MemOrFile
98    pub fn map_mem<M2>(self, f: impl FnOnce(M) -> M2) -> MemOrFile<M2, F> {
99        match self {
100            MemOrFile::Mem(mem) => MemOrFile::Mem(f(mem)),
101            MemOrFile::File(file) => MemOrFile::File(file),
102        }
103    }
104}