keramics_core/
fake_data_stream.rs

1/* Copyright 2024-2025 Joachim Metz <joachim.metz@gmail.com>
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License. You may
5 * obtain a copy of the License at https://www.apache.org/licenses/LICENSE-2.0
6 *
7 * Unless required by applicable law or agreed to in writing, software
8 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
9 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
10 * License for the specific language governing permissions and limitations
11 * under the License.
12 */
13
14use std::cmp::min;
15use std::io::SeekFrom;
16use std::sync::{Arc, RwLock};
17
18use super::data_stream::{DataStream, DataStreamReference};
19use super::errors::ErrorTrace;
20
21/// Fake (or virtual) data stream.
22pub struct FakeDataStream {
23    /// The data.
24    data: Vec<u8>,
25
26    /// The data size.
27    data_size: usize,
28
29    /// The current offset.
30    current_offset: u64,
31
32    /// The size.
33    pub size: u64,
34}
35
36impl FakeDataStream {
37    /// Creates a new data stream.
38    pub fn new(data: &[u8], size: u64) -> Self {
39        Self {
40            data: data.to_vec(),
41            data_size: data.len(),
42            current_offset: 0,
43            size: size,
44        }
45    }
46}
47
48impl DataStream for FakeDataStream {
49    /// Retrieves the size of the data.
50    fn get_size(&mut self) -> Result<u64, ErrorTrace> {
51        Ok(self.size)
52    }
53
54    /// Reads data at the current position.
55    fn read(&mut self, buf: &mut [u8]) -> Result<usize, ErrorTrace> {
56        if self.current_offset >= self.size {
57            return Ok(0);
58        }
59        let remaining_size: u64 = self.size - self.current_offset;
60        let mut read_size: usize = buf.len();
61
62        if (read_size as u64) > remaining_size {
63            read_size = remaining_size as usize;
64        }
65        let mut buf_offset: usize = 0;
66
67        while buf_offset < read_size {
68            let read_remainder_size: usize = read_size - buf_offset;
69
70            let read_count: usize = if self.current_offset < self.data_size as u64 {
71                let data_offset: usize = self.current_offset as usize;
72
73                let data_remainder_size: usize =
74                    min(read_remainder_size, self.data_size - data_offset);
75
76                let data_end_offset: usize = data_offset + data_remainder_size;
77                let buf_end_offset: usize = buf_offset + data_remainder_size;
78
79                buf[buf_offset..buf_end_offset]
80                    .copy_from_slice(&self.data[data_offset..data_end_offset]);
81
82                data_remainder_size
83            } else {
84                let buf_end_offset: usize = buf_offset + read_remainder_size;
85
86                buf[buf_offset..buf_end_offset].fill(0);
87
88                read_remainder_size
89            };
90            buf_offset += read_count;
91        }
92        self.current_offset += buf_offset as u64;
93
94        Ok(buf_offset)
95    }
96
97    /// Sets the current position of the data.
98    fn seek(&mut self, pos: SeekFrom) -> Result<u64, ErrorTrace> {
99        self.current_offset = match pos {
100            SeekFrom::Current(relative_offset) => {
101                let mut current_offset: i64 = self.current_offset as i64;
102                current_offset += relative_offset;
103                current_offset as u64
104            }
105            SeekFrom::End(relative_offset) => {
106                let mut end_offset: i64 = self.size as i64;
107                end_offset += relative_offset;
108                end_offset as u64
109            }
110            SeekFrom::Start(offset) => offset,
111        };
112        Ok(self.current_offset)
113    }
114}
115
116/// Opens a new fake data stream.
117pub fn open_fake_data_stream(data: Vec<u8>) -> DataStreamReference {
118    let data_size: u64 = data.len() as u64;
119    let fake_data_stream: FakeDataStream = FakeDataStream::new(&data, data_size);
120    Arc::new(RwLock::new(fake_data_stream))
121}
122
123#[cfg(test)]
124mod tests {
125    use super::*;
126
127    fn get_test_data() -> Vec<u8> {
128        return vec![
129            0x41, 0x20, 0x63, 0x65, 0x72, 0x61, 0x6d, 0x69, 0x63, 0x20, 0x69, 0x73, 0x20, 0x61,
130            0x6e, 0x79, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x76, 0x61, 0x72, 0x69,
131            0x6f, 0x75, 0x73, 0x20, 0x68, 0x61, 0x72, 0x64, 0x2c, 0x20, 0x62, 0x72, 0x69, 0x74,
132            0x74, 0x6c, 0x65, 0x2c, 0x20, 0x68, 0x65, 0x61, 0x74, 0x2d, 0x72, 0x65, 0x73, 0x69,
133            0x73, 0x74, 0x61, 0x6e, 0x74, 0x2c, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x63, 0x6f, 0x72,
134            0x72, 0x6f, 0x73, 0x69, 0x6f, 0x6e, 0x2d, 0x72, 0x65, 0x73, 0x69, 0x73, 0x74, 0x61,
135            0x6e, 0x74, 0x20, 0x6d, 0x61, 0x74, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x73, 0x20, 0x6d,
136            0x61, 0x64, 0x65, 0x20, 0x62, 0x79, 0x20, 0x73, 0x68, 0x61, 0x70, 0x69, 0x6e, 0x67,
137            0x20, 0x61, 0x6e, 0x64, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x20, 0x66, 0x69, 0x72, 0x69,
138            0x6e, 0x67, 0x20, 0x61, 0x6e, 0x20, 0x69, 0x6e, 0x6f, 0x72, 0x67, 0x61, 0x6e, 0x69,
139            0x63, 0x2c, 0x20, 0x6e, 0x6f, 0x6e, 0x6d, 0x65, 0x74, 0x61, 0x6c, 0x6c, 0x69, 0x63,
140            0x20, 0x6d, 0x61, 0x74, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x2c, 0x20, 0x73, 0x75, 0x63,
141            0x68, 0x20, 0x61, 0x73, 0x20, 0x63, 0x6c, 0x61, 0x79, 0x2c, 0x20, 0x61, 0x74, 0x20,
142            0x61, 0x20, 0x68, 0x69, 0x67, 0x68, 0x20, 0x74, 0x65, 0x6d, 0x70, 0x65, 0x72, 0x61,
143            0x74, 0x75, 0x72, 0x65, 0x2e, 0x0a,
144        ];
145    }
146
147    fn get_test_data_stream() -> FakeDataStream {
148        let test_data: Vec<u8> = get_test_data();
149        FakeDataStream::new(&test_data, 32768)
150    }
151
152    #[test]
153    fn test_seek_from_start() -> Result<(), ErrorTrace> {
154        let mut data_stream: FakeDataStream = get_test_data_stream();
155
156        let offset: u64 = data_stream.seek(SeekFrom::Start(1024))?;
157        assert_eq!(offset, 1024);
158
159        Ok(())
160    }
161
162    #[test]
163    fn test_seek_from_end() -> Result<(), ErrorTrace> {
164        let mut data_stream: FakeDataStream = get_test_data_stream();
165
166        let offset: u64 = data_stream.seek(SeekFrom::End(-512))?;
167        assert_eq!(offset, data_stream.size - 512);
168
169        Ok(())
170    }
171
172    #[test]
173    fn test_seek_from_current() -> Result<(), ErrorTrace> {
174        let mut data_stream: FakeDataStream = get_test_data_stream();
175
176        let offset = data_stream.seek(SeekFrom::Start(1024))?;
177        assert_eq!(offset, 1024);
178
179        let offset: u64 = data_stream.seek(SeekFrom::Current(-512))?;
180        assert_eq!(offset, 512);
181
182        Ok(())
183    }
184
185    #[test]
186    fn test_seek_beyond_size() -> Result<(), ErrorTrace> {
187        let mut data_stream: FakeDataStream = get_test_data_stream();
188
189        let offset: u64 = data_stream.seek(SeekFrom::End(512))?;
190        assert_eq!(offset, data_stream.size + 512);
191
192        Ok(())
193    }
194
195    #[test]
196    fn test_seek_and_read() -> Result<(), ErrorTrace> {
197        let mut data_stream: FakeDataStream = get_test_data_stream();
198        data_stream.seek(SeekFrom::Start(128))?;
199
200        let mut data: Vec<u8> = vec![0; 64];
201        let read_size: usize = data_stream.read(&mut data)?;
202        assert_eq!(read_size, 64);
203
204        let expected_data: String = [
205            "A ceramic is any of the various hard, brittle, heat-resistant, and ",
206            "corrosion-resistant materials made by shaping and then firing an inorganic, ",
207            "nonmetallic material, such as clay, at a high temperature.\n",
208        ]
209        .join("");
210
211        assert_eq!(data, expected_data.as_bytes()[128..192]);
212
213        Ok(())
214    }
215
216    #[test]
217    fn test_seek_and_read_beyond_size() -> Result<(), ErrorTrace> {
218        let mut data_stream: FakeDataStream = get_test_data_stream();
219        data_stream.seek(SeekFrom::End(512))?;
220
221        let mut data: Vec<u8> = vec![0; 512];
222        let read_size: usize = data_stream.read(&mut data)?;
223        assert_eq!(read_size, 0);
224
225        Ok(())
226    }
227
228    // TODO: add tests for get_size.
229}