Skip to main content

executable/
traits.rs

1use crate::Standard;
2use alloc::{boxed::Box, string::String, vec::Vec};
3use core::{num::NonZeroUsize, pin::Pin};
4use file_system::{
5    ControlCommand, ControlCommandIdentifier, DirectBaseOperations, DirectCharacterDevice,
6    MountOperations, define_command,
7};
8use shared::AnyByLayout;
9
10define_command!(GET_MAIN_FUNCTION, Read, b'E', 1, (), MainFunction);
11
12pub trait ExecutableTrait: 'static + Send + Sync {
13    fn main(standard: Standard<'static>, arguments: Vec<String>) -> MainFuture;
14}
15
16pub struct ExecutableContext {
17    pub task_manager: &'static task::Manager,
18    pub users_manager: &'static users::Manager,
19    pub virtual_file_system: &'static virtual_file_system::VirtualFileSystem,
20    #[cfg(feature = "graphics")]
21    pub graphics_manager: Option<&'static graphics::Manager>,
22    pub network_manager: Option<&'static network::Manager>,
23    pub time_manager: &'static time::Manager<'static>,
24}
25
26pub type MainFuture =
27    Pin<Box<dyn Future<Output = core::result::Result<(), NonZeroUsize>> + 'static>>;
28
29pub type MainFunction = Option<
30    Box<dyn Fn(&'static ExecutableContext, Standard<'static>, Vec<String>) -> MainFuture + 'static>,
31>;
32
33pub struct ExecutableWrapper<T: ExecutableTrait>(T, &'static ExecutableContext);
34
35impl<T: ExecutableTrait> ExecutableWrapper<T> {
36    pub fn new(executable: T, context: &'static ExecutableContext) -> Self {
37        Self(executable, context)
38    }
39}
40
41impl<T: ExecutableTrait> MountOperations for ExecutableWrapper<T> {}
42
43impl<T: ExecutableTrait> DirectBaseOperations for ExecutableWrapper<T> {
44    fn read(
45        &self,
46        _buffer: &mut [u8],
47        _absolute_position: file_system::Size,
48    ) -> file_system::Result<usize> {
49        Err(file_system::Error::UnsupportedOperation)
50    }
51
52    fn write(
53        &self,
54        _buffer: &[u8],
55        _absolute_position: file_system::Size,
56    ) -> file_system::Result<usize> {
57        Err(file_system::Error::UnsupportedOperation)
58    }
59
60    fn control(
61        &self,
62        command: ControlCommandIdentifier,
63        _: &AnyByLayout,
64        output: &mut AnyByLayout,
65    ) -> file_system::Result<()> {
66        log::debug!("ExecutableWrapper control command: {:?}", command);
67
68        match command {
69            GET_MAIN_FUNCTION::IDENTIFIER => {
70                let output = GET_MAIN_FUNCTION::cast_output(output)?;
71                let executable_context = self.1;
72                *output = Some(Box::new(move |context, standard, arguments| {
73                    let mut standard = standard;
74                    standard.context = context;
75                    debug_assert!(core::ptr::eq(context, executable_context));
76                    T::main(standard, arguments)
77                }));
78                Ok(())
79            }
80            _ => Err(file_system::Error::UnsupportedOperation),
81        }
82    }
83}
84
85impl<T: ExecutableTrait> DirectCharacterDevice for ExecutableWrapper<T> {}
86
87#[macro_export]
88macro_rules! mount_executables {
89
90    ( $context:expr, $virtual_file_system:expr, $task:expr, &[ $( ($path:expr, $executable:expr) ),* $(,)? ] ) => {
91
92    async || -> $crate::exported_virtual_file_system::Result<()>
93    {
94        use $crate::exported_file_system::{Permissions};
95        use $crate::exported_virtual_file_system::ItemStatic;
96
97        $(
98            let __executable = $crate::ExecutableWrapper::new($executable, $context);
99
100            let _ = $virtual_file_system.remove($task, $path).await;
101            $virtual_file_system.mount_character_device($task, $path, __executable).await?;
102            $virtual_file_system.set_permissions($task, $path, Permissions::EXECUTABLE).await?;
103        )*
104
105        Ok(())
106    }()
107};
108
109}