summaryrefslogtreecommitdiff
path: root/src/types/buffered_file.rs
blob: 5cdf0ea9fc833a1559a16b249e23f5457727ea2e (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
use std::fs::File;
use std::io::{BufReader, BufWriter, Read, Write};
use std::io::{ErrorKind, Seek, SeekFrom};


pub struct BufferedFile {
    file: AccessMode,
}

impl BufferedFile {
    pub fn new(file: File) -> Self {
        Self {
            file: AccessMode::Read(BufReader::new(file)),
        }
    }

    pub fn close(&mut self) {
        self.file = AccessMode::None;
    }

    pub fn read(&mut self) -> u8 {
        let mut buffer = [0u8; 1];

        let read_result = match &mut self.file {
            AccessMode::Read(reader) => reader.read_exact(&mut buffer),
            AccessMode::Write(writer) => {
                let address = writer.stream_position().unwrap();
                let file = std::mem::take(&mut self.file).unwrap();
                let mut reader = BufReader::new(file);
                reader.seek(SeekFrom::Start(address)).unwrap();
                let read_result = reader.read_exact(&mut buffer);
                self.file = AccessMode::Read(reader);
                read_result
            }
            AccessMode::None => unreachable!(),
        };

        match read_result {
            Ok(_) => buffer[0],
            Err(error) => match error.kind() {
                ErrorKind::UnexpectedEof => 0,
                _ => { log::error!("BufferedFile::read: {error:?}"); 0 },
            }
        }
    }

    pub fn write(&mut self, byte: u8) {
        let mut buffer = [byte; 1];

        let write_result = match &mut self.file {
            AccessMode::Write(writer) => writer.write_all(&mut buffer),
            AccessMode::Read(reader) => {
                let address = reader.stream_position().unwrap();
                let file = std::mem::take(&mut self.file).unwrap();
                let mut writer = BufWriter::new(file);
                writer.seek(SeekFrom::Start(address)).unwrap();
                let write_result = writer.write_all(&mut buffer);
                self.file = AccessMode::Write(writer);
                write_result
            }
            AccessMode::None => unreachable!(),
        };

        write_result.unwrap();
    }

    pub fn pointer(&mut self) -> u32 {
        let position = match &mut self.file {
            AccessMode::Read(reader) => reader.stream_position(),
            AccessMode::Write(writer) => writer.stream_position(),
            AccessMode::None => unreachable!(),
        };
        u32::try_from(position.unwrap()).unwrap_or(u32::MAX)
    }

    pub fn set_pointer(&mut self, pointer: u32) {
        let position = SeekFrom::Start(pointer as u64);
        match &mut self.file {
            AccessMode::Read(reader) => reader.seek(position).unwrap(),
            AccessMode::Write(writer) => writer.seek(position).unwrap(),
            AccessMode::None => unreachable!(),
        };
    }

    pub fn length(&mut self) -> u32 {
        let length = match &mut self.file {
            AccessMode::Read(reader) => reader.stream_len(),
            AccessMode::Write(writer) => writer.stream_len(),
            AccessMode::None => unreachable!(),
        };
        u32::try_from(length.unwrap()).unwrap_or(u32::MAX)
    }

    pub fn set_length(&mut self, length: u32) {
        match &mut self.file {
            AccessMode::Read(_) => {
                let file = std::mem::take(&mut self.file).unwrap();
                file.set_len(length as u64).unwrap();
                self.file = AccessMode::Read(BufReader::new(file));
            }
            AccessMode::Write(_) => {
                let file = std::mem::take(&mut self.file).unwrap();
                file.set_len(length as u64).unwrap();
                self.file = AccessMode::Read(BufReader::new(file));
            }
            AccessMode::None => unreachable!(),
        };
    }

    pub fn flush(&mut self) {
        if let AccessMode::Write(writer) = &mut self.file {
            let _ = writer.flush();
        }
    }
}

impl Drop for BufferedFile {
    fn drop(&mut self) {
        self.flush()
    }
}

enum AccessMode {
    Read(BufReader<File>),
    Write(BufWriter<File>),
    None,
}

impl AccessMode {
    pub fn unwrap(self) -> File {
        match self {
            Self::Read(reader) => reader.into_inner(),
            Self::Write(writer) => writer.into_inner().unwrap(),
            Self::None => unreachable!(),
        }
    }
}

impl Default for AccessMode {
    fn default() -> Self {
        Self::None
    }
}