summaryrefslogtreecommitdiff
path: root/src/devices/file/buffered_file.rs
blob: 091b5d91343b31caf0a56840baa02533947ba3f2 (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
use std::fs::File;
use std::io::{BufReader, BufWriter};
use std::io::{Read, Write};
use std::io::{ErrorKind, Seek, SeekFrom};

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
    }
}

pub struct BufferedFile {
    file: AccessMode,
}

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

    pub fn read_byte(&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,
                _ => panic!("{error:?}"),
            }
        }
    }

    pub fn write_byte(&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!(),
        };
    }
}