stak_file/
primitive_set.rs

1mod error;
2mod primitive;
3
4pub use self::primitive::Primitive;
5use crate::{FileError, FileSystem};
6pub use error::PrimitiveError;
7use stak_vm::{Error, Memory, Number, PrimitiveSet};
8use winter_maybe_async::maybe_async;
9
10/// A primitive set for a file system.
11pub struct FilePrimitiveSet<T: FileSystem> {
12    file_system: T,
13}
14
15impl<T: FileSystem> FilePrimitiveSet<T> {
16    /// Creates a primitive set.
17    pub const fn new(file_system: T) -> Self {
18        Self { file_system }
19    }
20}
21
22impl<T: FileSystem> PrimitiveSet for FilePrimitiveSet<T> {
23    type Error = PrimitiveError;
24
25    #[maybe_async]
26    fn operate(&mut self, memory: &mut Memory<'_>, primitive: usize) -> Result<(), Self::Error> {
27        match primitive {
28            Primitive::OPEN_FILE => {
29                let [list, output] = memory.pop_many()?;
30                let path = T::decode_path(memory, list).map_err(|_| FileError::PathDecode)?;
31
32                memory.push(
33                    Number::from_i64(
34                        self.file_system
35                            .open(path.as_ref(), output != memory.boolean(false)?.into())
36                            .map_err(|_| FileError::Open)? as _,
37                    )
38                    .into(),
39                )?;
40            }
41            Primitive::CLOSE_FILE => {
42                let [descriptor] = memory.pop_numbers()?;
43
44                self.file_system
45                    .close(descriptor.to_i64() as _)
46                    .map_err(|_| FileError::Close)?;
47
48                memory.push(memory.boolean(false)?.into())?;
49            }
50            Primitive::READ_FILE => {
51                let [descriptor] = memory.pop_numbers()?;
52
53                memory.push(
54                    if let Some(byte) = self
55                        .file_system
56                        .read(descriptor.to_i64() as _)
57                        .map_err(|_| FileError::Read)?
58                    {
59                        Number::from_i64(byte as _).into()
60                    } else {
61                        memory.boolean(false)?.into()
62                    },
63                )?;
64            }
65            Primitive::WRITE_FILE => {
66                let [descriptor, byte] = memory.pop_numbers()?;
67
68                self.file_system
69                    .write(descriptor.to_i64() as _, byte.to_i64() as _)
70                    .map_err(|_| FileError::Write)?;
71
72                memory.push(memory.boolean(false)?.into())?;
73            }
74            Primitive::DELETE_FILE => {
75                let [list] = memory.pop_many()?;
76                let path = T::decode_path(memory, list).map_err(|_| FileError::PathDecode)?;
77
78                self.file_system
79                    .delete(path.as_ref())
80                    .map_err(|_| FileError::Delete)?;
81
82                memory.push(memory.boolean(false)?.into())?;
83            }
84            Primitive::EXISTS_FILE => {
85                let [list] = memory.pop_many()?;
86                let path = T::decode_path(memory, list).map_err(|_| FileError::PathDecode)?;
87
88                memory.push(
89                    memory
90                        .boolean(
91                            self.file_system
92                                .exists(path.as_ref())
93                                .map_err(|_| FileError::Exists)?,
94                        )?
95                        .into(),
96                )?;
97            }
98            Primitive::FLUSH_FILE => {
99                let [descriptor] = memory.pop_numbers()?;
100
101                self.file_system
102                    .flush(descriptor.to_i64() as _)
103                    .map_err(|_| FileError::Flush)?;
104
105                memory.push(memory.boolean(false)?.into())?;
106            }
107            _ => return Err(Error::IllegalPrimitive.into()),
108        }
109
110        Ok(())
111    }
112}