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(self.file_system.read(descriptor.to_i64() as _).map_or_else(
54                    |_| memory.boolean(false).into(),
55                    |byte| Number::from_i64(byte as _).into(),
56                ))?;
57            }
58            Primitive::WRITE_FILE => {
59                let [descriptor, byte] = memory.pop_numbers();
60
61                self.file_system
62                    .write(descriptor.to_i64() as _, byte.to_i64() as _)
63                    .map_err(|_| FileError::Write)?;
64
65                memory.push(memory.boolean(false).into())?;
66            }
67            Primitive::DELETE_FILE => {
68                let [list] = memory.pop_many();
69                let path = T::decode_path(memory, list).map_err(|_| FileError::PathDecode)?;
70
71                self.file_system
72                    .delete(path.as_ref())
73                    .map_err(|_| FileError::Delete)?;
74
75                memory.push(memory.boolean(false).into())?;
76            }
77            Primitive::EXISTS_FILE => {
78                let [list] = memory.pop_many();
79                let path = T::decode_path(memory, list).map_err(|_| FileError::PathDecode)?;
80
81                memory.push(
82                    memory
83                        .boolean(
84                            self.file_system
85                                .exists(path.as_ref())
86                                .map_err(|_| FileError::Exists)?,
87                        )
88                        .into(),
89                )?;
90            }
91            _ => return Err(Error::IllegalPrimitive.into()),
92        }
93
94        Ok(())
95    }
96}