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}