Skip to main content

executable/
standard.rs

1use alloc::string::String;
2use core::time::Duration;
3use file_system::{AccessFlags, Path};
4use task::TaskIdentifier;
5use virtual_file_system::{File, VirtualFileSystem};
6
7use crate::ExecutableContext;
8use crate::Result;
9
10pub struct Standard<'a> {
11    pub context: &'static ExecutableContext,
12    pub standard_in: File<'a>,
13    pub standard_out: File<'a>,
14    pub standard_error: File<'a>,
15}
16
17impl<'a> Standard<'a> {
18    pub async fn open(
19        standard_in: &impl AsRef<Path>,
20        standard_out: &impl AsRef<Path>,
21        standard_error: &impl AsRef<Path>,
22        task: TaskIdentifier,
23        virtual_file_system: &'a VirtualFileSystem,
24        context: &'static ExecutableContext,
25    ) -> Result<Self> {
26        let standard_in = virtual_file_system
27            .open(standard_in, AccessFlags::Read.into(), task)
28            .await?;
29
30        let standard_out = virtual_file_system
31            .open(standard_out, AccessFlags::Write.into(), task)
32            .await?;
33
34        let standard_error = virtual_file_system
35            .open(standard_error, AccessFlags::Write.into(), task)
36            .await?;
37
38        Ok(Self::new(
39            context,
40            standard_in,
41            standard_out,
42            standard_error,
43        ))
44    }
45
46    pub fn new(
47        context: &'static ExecutableContext,
48        standard_in: File<'a>,
49        standard_out: File<'a>,
50        standard_error: File<'a>,
51    ) -> Self {
52        Self {
53            context,
54            standard_in,
55            standard_out,
56            standard_error,
57        }
58    }
59
60    pub fn input<'s>(&'s mut self) -> &'s mut File<'a> {
61        &mut self.standard_in
62    }
63
64    pub fn out<'s>(&'s mut self) -> &'s mut File<'a> {
65        &mut self.standard_out
66    }
67
68    pub fn error<'s>(&'s mut self) -> &'s mut File<'a> {
69        &mut self.standard_error
70    }
71
72    pub async fn read_line(&mut self, buffer: &mut String) -> virtual_file_system::Result<()> {
73        buffer.clear();
74
75        // This function read_until the source until the delimiter '\n' is found.
76        // If the delimiter is not found, expand the buffer
77
78        let mut temp_buffer = [0u8; 1];
79
80        loop {
81            let bytes_read = self.standard_in.read(&mut temp_buffer).await?;
82
83            if bytes_read == 0 {
84                task::sleep(Duration::from_millis(10)).await;
85                continue;
86            }
87
88            if temp_buffer[0] == b'\n' {
89                break;
90            } else {
91                buffer.push(temp_buffer[0] as char);
92            }
93        }
94
95        Ok(())
96    }
97
98    pub async fn duplicate(&self) -> virtual_file_system::Result<Self> {
99        Ok(Self {
100            context: self.context,
101            standard_in: self.standard_in.duplicate().await?,
102            standard_out: self.standard_out.duplicate().await?,
103            standard_error: self.standard_error.duplicate().await?,
104        })
105    }
106
107    pub fn split(self) -> (File<'a>, File<'a>, File<'a>) {
108        (self.standard_in, self.standard_out, self.standard_error)
109    }
110
111    pub async fn close(
112        self,
113        virtual_file_system: &VirtualFileSystem,
114    ) -> virtual_file_system::Result<()> {
115        self.standard_in.close(virtual_file_system).await?;
116        self.standard_out.close(virtual_file_system).await?;
117        self.standard_error.close(virtual_file_system).await?;
118
119        Ok(())
120    }
121}