tempfile/
spooled.rs
1use crate::file::tempfile;
2use std::fs::File;
3use std::io::{self, Cursor, Read, Seek, SeekFrom, Write};
4
5#[derive(Debug)]
6enum SpooledInner {
7 InMemory(Cursor<Vec<u8>>),
8 OnDisk(File),
9}
10
11#[derive(Debug)]
16pub struct SpooledTempFile {
17 max_size: usize,
18 inner: SpooledInner,
19}
20
21#[inline]
61pub fn spooled_tempfile(max_size: usize) -> SpooledTempFile {
62 SpooledTempFile::new(max_size)
63}
64
65impl SpooledTempFile {
66 pub fn new(max_size: usize) -> SpooledTempFile {
67 SpooledTempFile {
68 max_size: max_size,
69 inner: SpooledInner::InMemory(Cursor::new(Vec::new())),
70 }
71 }
72
73 pub fn is_rolled(&self) -> bool {
75 match self.inner {
76 SpooledInner::InMemory(_) => false,
77 SpooledInner::OnDisk(_) => true,
78 }
79 }
80
81 pub fn roll(&mut self) -> io::Result<()> {
84 if !self.is_rolled() {
85 let mut file = tempfile()?;
86 if let SpooledInner::InMemory(ref mut cursor) = self.inner {
87 file.write_all(cursor.get_ref())?;
88 file.seek(SeekFrom::Start(cursor.position()))?;
89 }
90 self.inner = SpooledInner::OnDisk(file);
91 }
92 Ok(())
93 }
94
95 pub fn set_len(&mut self, size: u64) -> Result<(), io::Error> {
96 if size as usize > self.max_size {
97 self.roll()?; }
99 match self.inner {
100 SpooledInner::InMemory(ref mut cursor) => {
101 cursor.get_mut().resize(size as usize, 0);
102 Ok(())
103 }
104 SpooledInner::OnDisk(ref mut file) => file.set_len(size),
105 }
106 }
107}
108
109impl Read for SpooledTempFile {
110 fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
111 match self.inner {
112 SpooledInner::InMemory(ref mut cursor) => cursor.read(buf),
113 SpooledInner::OnDisk(ref mut file) => file.read(buf),
114 }
115 }
116}
117
118impl Write for SpooledTempFile {
119 fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
120 let mut rolling = false;
122 if let SpooledInner::InMemory(ref mut cursor) = self.inner {
123 rolling = cursor.position() as usize + buf.len() > self.max_size;
124 }
125 if rolling {
126 self.roll()?;
127 }
128
129 match self.inner {
131 SpooledInner::InMemory(ref mut cursor) => cursor.write(buf),
132 SpooledInner::OnDisk(ref mut file) => file.write(buf),
133 }
134 }
135
136 #[inline]
137 fn flush(&mut self) -> io::Result<()> {
138 match self.inner {
139 SpooledInner::InMemory(ref mut cursor) => cursor.flush(),
140 SpooledInner::OnDisk(ref mut file) => file.flush(),
141 }
142 }
143}
144
145impl Seek for SpooledTempFile {
146 fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
147 match self.inner {
148 SpooledInner::InMemory(ref mut cursor) => cursor.seek(pos),
149 SpooledInner::OnDisk(ref mut file) => file.seek(pos),
150 }
151 }
152}