diff --git a/Cargo.toml b/Cargo.toml index 1c65c02..72c9395 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,7 +5,7 @@ members = [ "Modules/Shared", "Modules/Virtual_machine", "Modules/Virtual_machine/Tests/WASM_test", - "Modules/Bindings/Tests/WASM_test", "Modules/Graphics", "Modules/Screen", "Modules/Task", + "Modules/Bindings/Tests/WASM_test", "Modules/Graphics", "Modules/Screen", "Modules/Task", "Modules/Users", ] [package] diff --git a/Modules/Bindings/Build.rs b/Modules/Bindings/Build.rs index 82f7e1a..93a3cd5 100644 --- a/Modules/Bindings/Build.rs +++ b/Modules/Bindings/Build.rs @@ -3,6 +3,8 @@ use std::{env, process::Command}; fn main() -> Result<(), ()> { println!("cargo:rerun-if-changed=Tests/WASM_test/src/main.rs"); + println!("cargo:rerun-if-changed=Tests/WASM_test/src/File_system.rs"); + println!("cargo:rerun-if-changed=Tests/WASM_test/src/Task.rs"); println!("cargo:rerun-if-changed=Tests/WASM_test/Cargo.toml"); // TODO : Add a check for test mode diff --git a/Modules/Bindings/Cargo.toml b/Modules/Bindings/Cargo.toml index 0e1f290..d11357f 100644 --- a/Modules/Bindings/Cargo.toml +++ b/Modules/Bindings/Cargo.toml @@ -9,7 +9,13 @@ File_system = { path = "../File_system" } Virtual_machine = { path = "../Virtual_machine" } Binding_tool = { path = "../../../Binding_tool", features = ["Native"] } Shared = { path = "../Shared" } +Users = { path = "../Users" } +Task = { path = "../Task" } [[test]] name = "File_system_bindings_tests" path = "Tests/File_system.rs" + +[[test]] +name = "Task_tests" +path = "Tests/Task.rs" diff --git a/Modules/Bindings/Tests/File_system.rs b/Modules/Bindings/Tests/File_system.rs index 4713ccd..0d10ff3 100644 --- a/Modules/Bindings/Tests/File_system.rs +++ b/Modules/Bindings/Tests/File_system.rs @@ -3,7 +3,10 @@ #![allow(non_upper_case_globals)] use Bindings::File_system_bindings; -use File_system::{Drivers::Native::File_system_type, Prelude::File_system_traits}; +use File_system::{ + Drivers::Native::File_system_type, + Prelude::{Path_type, Virtual_file_system_type}, +}; use Virtual_machine::{Data_type, Instantiate_test_environment, WasmValue}; #[test] @@ -12,14 +15,23 @@ fn Integration_test() { "../../../target/wasm32-unknown-unknown/release/File_system_bindings_WASM_test.wasm" ); - let mut Native_file_system = File_system_type::New(); + let Virtual_file_system = + Virtual_file_system_type::New(Task::Manager_type::New(), Users::Manager_type::New()); - Native_file_system.Initialize().unwrap(); + let Native_file_system = File_system_type::New().expect("Failed to create file system"); - let User_data = Data_type::New(&Native_file_system); + let _ = Virtual_file_system.Mount(Box::new(Native_file_system), Path_type::Get_root()); - let (_Runtime, _Module, Instance) = - Instantiate_test_environment(Binary_buffer, File_system_bindings {}, &User_data); + let (_Runtime, _Module, Instance) = Instantiate_test_environment( + Binary_buffer, + File_system_bindings::New(Virtual_file_system.clone()), + &Data_type::New(), + ); - assert_eq!(Instance.Call_main(&vec![]).unwrap(), WasmValue::I32(0)) + assert_eq!( + Instance + .Call_export_function("Test_file_system", &vec![]) + .unwrap(), + WasmValue::I32(0) + ) } diff --git a/Modules/Bindings/Tests/Task.rs b/Modules/Bindings/Tests/Task.rs new file mode 100644 index 0000000..606ddcc --- /dev/null +++ b/Modules/Bindings/Tests/Task.rs @@ -0,0 +1,30 @@ +#![allow(non_snake_case)] +#![allow(non_camel_case_types)] +#![allow(non_upper_case_globals)] + +use Bindings::{File_system_bindings, Task_bindings}; +use File_system::{ + Drivers::Native::File_system_type, + Prelude::{Path_type, Virtual_file_system_type}, +}; +use Virtual_machine::{Data_type, Instantiate_test_environment, WasmValue}; + +#[test] +fn Integration_test() { + let Binary_buffer = include_bytes!( + "../../../target/wasm32-unknown-unknown/release/File_system_bindings_WASM_test.wasm" + ); + + let Task_manager = Task::Manager_type::New(); + + let (_Runtime, _Module, Instance) = Instantiate_test_environment( + Binary_buffer, + Task_bindings::New(Task_manager.clone()), + &Data_type::New(), + ); + + assert_eq!( + Instance.Call_export_function("Test_task", &vec![]).unwrap(), + WasmValue::I32(42) + ) +} diff --git a/Modules/Bindings/Tests/WASM_test/.cargo/config.toml b/Modules/Bindings/Tests/WASM_test/.cargo/config.toml index d19f9ab..daa02a4 100644 --- a/Modules/Bindings/Tests/WASM_test/.cargo/config.toml +++ b/Modules/Bindings/Tests/WASM_test/.cargo/config.toml @@ -6,5 +6,4 @@ rustflags = [ "-C", "link-arg=--export=__heap_base", "-C", "link-arg=--export=__data_end", "-C", "link-arg=--strip-all", - "-C", "lto=yes", ] \ No newline at end of file diff --git a/Modules/Bindings/Tests/WASM_test/Cargo.toml b/Modules/Bindings/Tests/WASM_test/Cargo.toml index ca21884..8805a58 100644 --- a/Modules/Bindings/Tests/WASM_test/Cargo.toml +++ b/Modules/Bindings/Tests/WASM_test/Cargo.toml @@ -6,5 +6,4 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -Binding_tool = { path = "../../../../../Binding_tool", features = ["WASM"] } -wee_alloc = "0.4.5" +Binding_tool = { path = "../../../../../Binding_tool", features = ["WASM"] } \ No newline at end of file diff --git a/Modules/Bindings/Tests/WASM_test/src/File_system.rs b/Modules/Bindings/Tests/WASM_test/src/File_system.rs new file mode 100644 index 0000000..d7f68b8 --- /dev/null +++ b/Modules/Bindings/Tests/WASM_test/src/File_system.rs @@ -0,0 +1,98 @@ +use std::num::NonZeroU32; + +use Binding_tool::Bind_function_WASM; + +#[Bind_function_WASM] +fn Open(Path: &str, Flags: u32, File_identifier: &mut u32) -> Result<(), NonZeroU32> {} + +#[Bind_function_WASM] +fn Read(File_identifier: u32, Buffer: &mut [u8], Read_size: &mut u64) -> Result<(), NonZeroU32> {} + +#[Bind_function_WASM] +fn Create_file(Path: &str) -> Result<(), NonZeroU32> {} + +#[Bind_function_WASM] +fn Write(File_identifier: u32, Buffer: &[u8], Write_size: &mut u64) -> Result<(), NonZeroU32> {} + +#[Bind_function_WASM] +fn Exists(Path: &str, Exists: &mut bool) -> Result<(), NonZeroU32> {} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[repr(C)] +#[allow(dead_code)] +pub enum Position_type { + Start(u64), + Current(i64), + End(i64), +} + +#[Bind_function_WASM] +fn Set_position( + File_identifier: u32, + Position: &Position_type, + Result_value: &mut u64, +) -> Result<(), NonZeroU32> { +} + +#[Bind_function_WASM] +fn Delete(Path: &str, Recursive: bool) -> Result<(), NonZeroU32> {} + +#[no_mangle] +fn Test_file_system() -> u32 { + let mut File_identifier = 0; + + let mut File_exists: bool = true; + + Exists("/wasm.txt", &mut File_exists).expect("Failed to check if file exists"); + + if File_exists { + Delete("/wasm.txt", false).expect("Failed to delete file"); + } + + Create_file("/wasm.txt").expect("Failed to create file"); + + Exists("/wasm.txt", &mut File_exists).expect("Failed to check if file exists"); + + if !File_exists { + return 2; + } + + let Flags = 0b11 << 4; + + Open("/wasm.txt", Flags, &mut File_identifier).expect("Failed to open file"); + + let mut Write_size = 0; + + let Message = "Hello world from WASM !"; + + Write(File_identifier, Message.as_bytes(), &mut Write_size).expect("Failed to write file"); + + if Write_size != Message.len() as u64 { + return 4; + } + + let mut Result_position = 0; + + Set_position( + File_identifier, + &Position_type::Start(0), + &mut Result_position, + ) + .expect("Failed to set position"); + + let mut Buffer = [0; 64]; + + let mut Read_size = 0; + + Read(File_identifier, &mut Buffer, &mut Read_size).expect("Failed to read file"); + + let String = String::from_utf8_lossy(&Buffer[..Read_size as usize]); + + if String != Message { + return 6; + } + + Delete("/wasm.txt", false).expect("Failed to delete file"); + + 0 +} diff --git a/Modules/Bindings/Tests/WASM_test/src/Task.rs b/Modules/Bindings/Tests/WASM_test/src/Task.rs new file mode 100644 index 0000000..e06c5fc --- /dev/null +++ b/Modules/Bindings/Tests/WASM_test/src/Task.rs @@ -0,0 +1,26 @@ +#![allow(non_upper_case_globals)] + +use std::{num::NonZeroU32, sync::RwLock}; + +use Binding_tool::Bind_function_WASM; + +#[Bind_function_WASM] +fn New_task(Name: &str, Stack_size: u32, Function: u32) -> Result<(), NonZeroU32> {} + +#[Bind_function_WASM] +fn Sleep(Duration: u64) {} + +fn Test_function() { + *Test_variable.write().unwrap() = 42; +} + +static Test_variable: RwLock = RwLock::new(0); + +#[no_mangle] +fn Test_task() -> u32 { + let _ = New_task("Test", 4096, Test_function as usize as u32); + + Sleep(1); + + *Test_variable.read().unwrap() +} diff --git a/Modules/Bindings/Tests/WASM_test/src/main.rs b/Modules/Bindings/Tests/WASM_test/src/main.rs index 26d26ce..8624252 100644 --- a/Modules/Bindings/Tests/WASM_test/src/main.rs +++ b/Modules/Bindings/Tests/WASM_test/src/main.rs @@ -1,43 +1,7 @@ #![allow(non_snake_case)] +#![allow(non_camel_case_types)] +#![no_main] -use Binding_tool::Bind_function_WASM; +mod File_system; -#[Bind_function_WASM] -fn Open_file(Path: &str, Mode: u32, File_identifier: &mut u16) -> u32 {} - -#[Bind_function_WASM] -fn Read_file(File_identifier: u16, Buffer: &mut [u8], Read_size: &mut u32) -> u32 {} - -extern crate wee_alloc; - -// Use `wee_alloc` as the global allocator saving kilobytes of code size -#[global_allocator] -static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT; - -fn main() -> Result<(), ()> { - let mut File_identifier = 1; - - let Result = Open_file("test.txt", 1, &mut File_identifier); - - if Result != 0 { - return Err(()); - } - - let mut Buffer = [0; 1024]; - - let mut Read_size = 0; - - let Result = Read_file(File_identifier, &mut Buffer, &mut Read_size); - - if Result != 0 { - return Err(()); - } - - let String = String::from_utf8_lossy(&Buffer[..Read_size as usize]); - - if String != "Hello World!" { - return Err(()); - } - - Ok(()) -} +mod Task; diff --git a/Modules/Bindings/Xila/test.txt b/Modules/Bindings/Xila/test.txt deleted file mode 100644 index c57eff5..0000000 --- a/Modules/Bindings/Xila/test.txt +++ /dev/null @@ -1 +0,0 @@ -Hello World! \ No newline at end of file diff --git a/Modules/Bindings/src/File_system.rs b/Modules/Bindings/src/File_system.rs index 988cad0..0918385 100644 --- a/Modules/Bindings/src/File_system.rs +++ b/Modules/Bindings/src/File_system.rs @@ -2,7 +2,6 @@ use std::mem::MaybeUninit; use Binding_tool::Bind_function_native; use File_system::Prelude::*; -use Shared::{Discriminant_trait, From_result_to_u32}; use Virtual_machine::{Function_descriptor_type, Function_descriptors, Registrable_trait}; pub struct File_system_bindings {} @@ -13,199 +12,153 @@ impl Registrable_trait for File_system_bindings { } impl File_system_bindings { - pub fn New(File_system: &impl File_system_traits) -> Self { + pub fn New(File_system: Virtual_file_system_type) -> Self { unsafe { - Root_file_system.write(File_system); + Virtual_file_system.write(File_system); } Self {} } } -const File_system_bindings_functions: [Function_descriptor_type; 4] = Function_descriptors!( - Open_file_binding, - Close_file_binding, - Read_file_binding, - Write_file_binding -); - -// static Root_file_system = MaybeUninit::uninit(); - -#[Bind_function_native(Prefix = "File_system")] -fn Open_file(Path: &str, Mode: u32, File_identifier: &mut u16) -> u32 { - println!("Open_file {:?}", Path); - println!("Mode {:?}", Mode); - println!("File_identifier {:?}", File_identifier); - - let File_system = Environment.Get_user_data().Get_file_system(); - - let Path: Path_type = Path.into(); - - let Result = File_system.Open_file(&Path, Mode.into()); - - if let Ok(File) = &Result { - *File_identifier = File.Get_identifier(); - } else if let Err(Error) = &Result { - println!("Error {:?}", Error); - } - From_result_to_u32(&Result) +fn Get_virtual_file_system() -> &'static Virtual_file_system_type { + unsafe { Virtual_file_system.assume_init_ref() } } -#[Bind_function_native(Prefix = "File_system")] -fn Close_file(File_identifier: u16) -> u32 { - let File_system = Environment.Get_user_data().Get_file_system(); +const File_system_bindings_functions: [Function_descriptor_type; 8] = Function_descriptors!( + Open_binding, + Close_file_binding, + Read_binding, + Write_binding, + Create_file_binding, + Exists_binding, + Set_position_binding, + Delete_binding +); - let Result = File_system.Close_file(File_identifier); +static mut Virtual_file_system: MaybeUninit = MaybeUninit::uninit(); - From_result_to_u32(&Result) +fn New_path(Path: &str) -> Result<&Path_type> { + Path_type::New(Path).ok_or(Error_type::Invalid_path) } #[Bind_function_native(Prefix = "File_system")] -fn Read_file(File_identifier: u16, Buffer: &mut [u8], Read_size: &mut u32) -> u32 { - let File_system = Environment.Get_user_data().Get_file_system(); +fn Open( + Path: &str, + Flags: Flags_type, + File_identifier: &mut Unique_file_identifier_type, +) -> Result<()> { + let Path = New_path(Path)?; - let Result = File_system.Read_file(File_identifier, Buffer); + *File_identifier = Get_virtual_file_system().Open(Path, Flags)?; - if let Ok(Size) = &Result { - *Read_size = *Size as u32; - } - - From_result_to_u32(&Result) + Ok(()) } #[Bind_function_native(Prefix = "File_system")] -fn Write_file(File_identifier: u16, Buffer: &[u8], Write_size: &mut u32) -> u32 { - let File_system = Environment.Get_user_data().Get_file_system(); - - let Result = File_system.Write_file(File_identifier, Buffer); - - if let Ok(Size) = &Result { - *Write_size = *Size as u32; - } - - From_result_to_u32(&Result) +fn Close_file(File_identifier: Unique_file_identifier_type) -> Result<()> { + Get_virtual_file_system().Close(File_identifier) } #[Bind_function_native(Prefix = "File_system")] -fn Flush_file(File_identifier: u16) -> u32 { - let File_system = Environment.Get_user_data().Get_file_system(); - - let Result = File_system.Flush_file(File_identifier); +fn Read( + File_identifier: Unique_file_identifier_type, + Buffer: &mut [u8], + Read_size: &mut Size_type, +) -> Result<()> { + *Read_size = Get_virtual_file_system().Read(File_identifier, Buffer)?; - From_result_to_u32(&Result) + Ok(()) } #[Bind_function_native(Prefix = "File_system")] -fn Get_file_type(File_identifier: u16, Type_reference: &mut u32) -> u32 { - let File_system = Environment.Get_user_data().Get_file_system(); - - let Result = File_system.Get_file_type(File_identifier); - - if let Ok(Type) = &Result { - *Type_reference = Type.Get_discriminant(); - } +fn Write( + File_identifier: Unique_file_identifier_type, + Buffer: &[u8], + Write_size: &mut Size_type, +) -> Result<()> { + *Write_size = Get_virtual_file_system().Write(File_identifier, Buffer)?; - From_result_to_u32(&Result) + Ok(()) } #[Bind_function_native(Prefix = "File_system")] -fn Get_file_size(File_identifier: u16, Size_reference: &mut u64) -> u32 { - let File_system = Environment.Get_user_data().Get_file_system(); - - let Result = File_system.Get_file_size(File_identifier); - - if let Ok(Size) = &Result { - *Size_reference = Size.0; - } - - From_result_to_u32(&Result) +fn Flush(File_identifier: Unique_file_identifier_type) -> Result<()> { + Get_virtual_file_system().Flush(File_identifier) } #[Bind_function_native(Prefix = "File_system")] -fn Get_file_position(File_identifier: u16, Position_reference: &mut u64) -> u32 { - let File_system = Environment.Get_user_data().Get_file_system(); +fn Get_file_type(Path: &str, Type: &mut u32) -> Result<()> { + let Path = New_path(Path)?; - let Result = File_system.Get_file_position(File_identifier); + *Type = Get_virtual_file_system().Get_type(Path)? as u32; - if let Ok(Position) = &Result { - *Position_reference = Position.0; - } - - From_result_to_u32(&Result) + Ok(()) } #[Bind_function_native(Prefix = "File_system")] -fn Set_file_position(File_identifier: u16, Mode: u32, Value: u64) -> u32 { - let File_system = Environment.Get_user_data().Get_file_system(); +fn Get_file_size(Path: &str, Size: &mut Size_type) -> Result<()> { + let Path = New_path(Path)?; - let Result = File_system.Set_file_position(File_identifier, &Position_type::From(Mode, Value)); + *Size = Get_virtual_file_system().Get_size(Path)?; - From_result_to_u32(&Result) + Ok(()) } #[Bind_function_native(Prefix = "File_system")] -fn Delete_file(Path: &str) -> u32 { - let File_system = Environment.Get_user_data().Get_file_system(); - - let Path: Path_type = Path.into(); +fn Set_position( + File_identifier: Unique_file_identifier_type, + Position: &Position_type, + Result_value: &mut Size_type, +) -> Result<()> { + *Result_value = Get_virtual_file_system().Set_position(File_identifier, Position)?; - let Result = File_system.Delete_file(&Path); - - From_result_to_u32(&Result) + Ok(()) } #[Bind_function_native(Prefix = "File_system")] -fn Create_directory(Path: &str) -> u32 { - let File_system = Environment.Get_user_data().Get_file_system(); - - let Path: Path_type = Path.into(); +fn Delete_file(Path: &str, Recursive: bool) -> Result<()> { + let Path = New_path(Path)?; - let Result = File_system.Create_directory(&Path); + Get_virtual_file_system().Delete(Path, Recursive)?; - From_result_to_u32(&Result) + Ok(()) } #[Bind_function_native(Prefix = "File_system")] -fn Create_directory_recursive(Path: &str) -> u32 { - let File_system = Environment.Get_user_data().Get_file_system(); +fn Create_file(Path: &str) -> Result<()> { + let Path = New_path(Path)?; - let Path: Path_type = Path.into(); + Get_virtual_file_system() + .Create_file(Path) + .expect("Failed to create file"); - let Result = File_system.Create_directory_recursive(&Path); - - From_result_to_u32(&Result) + Ok(()) } #[Bind_function_native(Prefix = "File_system")] -fn Delete_directory(Path: &str) -> u32 { - let File_system = Environment.Get_user_data().Get_file_system(); - - let Path: Path_type = Path.into(); +fn Create_directory(Path: &str, Recursive: bool) -> Result<()> { + let Path = New_path(Path)?; - let Result = File_system.Delete_directory(&Path); + Get_virtual_file_system().Create_directory(Path, Recursive)?; - From_result_to_u32(&Result) + Ok(()) } #[Bind_function_native(Prefix = "File_system")] -fn Delete_directory_recursive(Path: &str) -> u32 { - let File_system = Environment.Get_user_data().Get_file_system(); +fn Delete(Path: &str, Recursive: bool) -> Result<()> { + let Path = New_path(Path)?; - let Path: Path_type = Path.into(); + Get_virtual_file_system().Delete(Path, Recursive)?; - let Result = File_system.Delete_directory_recursive(&Path); - - From_result_to_u32(&Result) + Ok(()) } #[Bind_function_native(Prefix = "File_system")] -fn Move(Path: &str, Destination: &str) -> u32 { - let File_system = Environment.Get_user_data().Get_file_system(); - - let Path: Path_type = Path.into(); - let Destination: Path_type = Destination.into(); +fn Exists(Path: &str, Exists: &mut bool) -> Result<()> { + let Path = New_path(Path)?; - let Result = File_system.Move(&Path, &Destination); + *Exists = Get_virtual_file_system().Exists(Path)?; - From_result_to_u32(&Result) + Ok(()) } diff --git a/Modules/Bindings/src/Task.rs b/Modules/Bindings/src/Task.rs new file mode 100644 index 0000000..b62610a --- /dev/null +++ b/Modules/Bindings/src/Task.rs @@ -0,0 +1,99 @@ +use std::mem::MaybeUninit; + +use Binding_tool::Bind_function_native; +use Task::{Error_type, Result_type, Task_identifier_type, Task_type}; +use Virtual_machine::{Function_descriptors, Registrable_trait, Runtime_type}; + +pub struct Task_bindings {} + +impl Registrable_trait for Task_bindings { + fn Get_functions(&self) -> &[Virtual_machine::Function_descriptor_type] { + &Task_bindings_functions + } +} + +impl Task_bindings { + pub fn New(Manager: Task::Manager_type) -> Self { + unsafe { + Task_manager.write(Manager); + } + + Self {} + } +} + +static mut Task_manager: MaybeUninit = MaybeUninit::uninit(); + +fn Get_task_manager() -> &'static Task::Manager_type { + unsafe { Task_manager.assume_init_ref() } +} + +const Task_bindings_functions: [Virtual_machine::Function_descriptor_type; 5] = Function_descriptors!( + New_task_binding, + Get_environment_variable_binding, + Set_environment_variable_binding, + Remove_environment_variable_binding, + Sleep_binding +); + +#[Bind_function_native(Prefix = "Task")] +fn Sleep(Duration: u64) { + Task_type::Sleep(std::time::Duration::from_millis(Duration)); +} + +#[Bind_function_native(Prefix = "Task")] +fn New_task(Name: &str, Stack_size: u32, Function: u32) -> Result_type<()> { + println!("New task: {}", Name); + println!("Function: {}", Function); + + let New_environment = Environment + .Create_environment(Stack_size as usize) + .map_err(|_| Error_type::Failed_to_spawn_thread) + .unwrap(); + + Get_task_manager().New_task(None, None, Name, Some(Stack_size as usize), move || { + Runtime_type::Initialize_thread_environment().unwrap(); + + let _ = New_environment.Call_indirect_function(Function, &vec![]); + + Runtime_type::Deinitialize_thread_environment(); + })?; + + Ok(()) +} + +#[Bind_function_native(Prefix = "Task")] +fn Get_environment_variable( + Task_identifier: Task_identifier_type, + Name: &str, + Value: &mut [u8], +) -> Result_type<()> { + Value.copy_from_slice( + Get_task_manager() + .Get_environment_variable(Task_identifier, Name)? + .as_bytes(), + ); + + Ok(()) +} + +#[Bind_function_native(Prefix = "Task")] +fn Set_environment_variable( + Task_identifier: Task_identifier_type, + Name: &str, + Value: &str, +) -> Result_type<()> { + Get_task_manager().Set_environment_variable(Task_identifier, Name, Value)?; + + Ok(()) +} + +#[Bind_function_native(Prefix = "Task")] +fn Remove_environment_variable( + Task_identifier: Task_identifier_type, + Name: &str, +) -> Result_type<()> { + Get_task_manager().Remove_environment_variable(Task_identifier, Name)?; + + Ok(()) +} diff --git a/Modules/Bindings/src/lib.rs b/Modules/Bindings/src/lib.rs index 29c81c1..94bbb24 100644 --- a/Modules/Bindings/src/lib.rs +++ b/Modules/Bindings/src/lib.rs @@ -3,5 +3,7 @@ #![allow(non_upper_case_globals)] mod File_system; - pub use File_system::*; + +mod Task; +pub use Task::*; diff --git a/Modules/File_system/Cargo.toml b/Modules/File_system/Cargo.toml index 06cb1d2..1590b58 100644 --- a/Modules/File_system/Cargo.toml +++ b/Modules/File_system/Cargo.toml @@ -4,4 +4,14 @@ version = "0.1.0" edition = "2021" [dependencies] -Shared = { path = "../Shared" } \ No newline at end of file +Task = { path = "../Task" } +Users = { path = "../Users" } +Shared = { path = "../Shared" } + +[features] +std = [] +default = ["std"] + +[[test]] +name = "Virtual_file_system" +path = "Tests/Virtual_file_system.rs" diff --git a/Modules/File_system/Tests/Virtual_file_system.rs b/Modules/File_system/Tests/Virtual_file_system.rs new file mode 100644 index 0000000..ea1763a --- /dev/null +++ b/Modules/File_system/Tests/Virtual_file_system.rs @@ -0,0 +1,116 @@ +#![allow(non_snake_case)] + +#[cfg(target_os = "linux")] +#[test] +fn Virtual_file_system_test() { + use File_system::{ + Drivers::Native::File_system_type, + Prelude::{ + File_type, Mode_type, Path_type, Position_type, Status_type, Virtual_file_system_type, + }, + }; + + let Task_manager = Task::Manager_type::New(); + + let Users_manager = Users::Manager_type::New(); + + let Virtual_file_system = Virtual_file_system_type::New(Task_manager, Users_manager); + + Virtual_file_system + .Mount( + Box::new(File_system_type::New().expect("Failed to create file system")), + Path_type::Get_root(), + ) + .expect("Failed to mount file system"); + + let File_path = Path_type::New("/test.txt").expect("Failed to create path"); + + if Virtual_file_system + .Exists(File_path) + .expect("Failed to check if file exists") + { + Virtual_file_system + .Delete(File_path, false) + .expect("Failed to delete file"); + } + + Virtual_file_system + .Create_file(File_path) + .expect("Failed to create file"); + + let File = File_type::Open( + &Virtual_file_system, + File_path, + Mode_type::Read_write().into(), + ) + .expect("Failed to open file"); + + let Data = b"Hello, world!"; + + File.Write(Data).expect("Failed to write data"); + + File.Set_position(&Position_type::Start(0_u64.into())) + .expect("Failed to set position"); + + let mut Buffer = [0; 13]; + + File.Read(&mut Buffer).expect("Failed to read data"); + + assert_eq!(Buffer, *Data); + + std::mem::drop(File); + + Virtual_file_system + .Delete(File_path, false) + .expect("Failed to delete file"); + + let (Pipe_read, Pipe_write) = + File_type::Create_unamed_pipe(&Virtual_file_system, 512, Status_type::default()) + .expect("Failed to create pipe"); + + Pipe_write.Write(Data).expect("Failed to write data"); + + let mut Buffer = [0; 13]; + + Pipe_read.Read(&mut Buffer).expect("Failed to read data"); + + assert_eq!(Buffer, *Data); + + let Pipe_path = Path_type::New("/pipe").expect("Failed to create path"); + + if Virtual_file_system + .Exists(Pipe_path) + .expect("Failed to check if pipe exists") + { + Virtual_file_system + .Delete(Pipe_path, false) + .expect("Failed to delete pipe"); + } + + /* + Virtual_file_system + .Create_named_pipe(&Pipe_path, 512) + .expect("Failed to create pipe"); + + let Pipe_read = File_type::Open( + &Virtual_file_system, + Pipe_path, + Mode_type::Read_only().into(), + ).expect("Failed to open pipe"); + + let mut Buffer = [0; 13]; + + Pipe_write.Write(Data).expect("Failed to write data"); + + Pipe_read.Read(&mut Buffer).expect("Failed to read data"); + + assert_eq!(Buffer, *Data); + + std::mem::drop(Pipe_read); + std::mem::drop(Pipe_write); + + Virtual_file_system + .Delete(Pipe_path, false) + .expect("Failed to delete pipe"); + */ +} diff --git a/Modules/File_system/src/Drivers/Native/mod.rs b/Modules/File_system/src/Drivers/Native/mod.rs index 529ef02..8d8968d 100644 --- a/Modules/File_system/src/Drivers/Native/mod.rs +++ b/Modules/File_system/src/Drivers/Native/mod.rs @@ -1,22 +1,25 @@ -use Shared::Task_identifier_type; - -use crate::Generics::{self, Error_type}; +use crate::Prelude::{ + Error_type, File_identifier_type, File_system_traits, Flags_type, Path_owned_type, Path_type, + Permissions_type, Position_type, Result, Size_type, Type_type, +}; use std::collections::HashMap; use std::env::{current_dir, var}; use std::fs::*; -use std::io::{Read, Seek, SeekFrom, Write}; -use std::path::Path; -use std::sync::{Arc, RwLock}; +use std::io::{ErrorKind, Read, Seek, Write}; + +use std::path::PathBuf; -impl From for Generics::Type_type { +use Task::Task_identifier_type; + +impl From for Type_type { fn from(value: FileType) -> Self { if value.is_dir() { - return Generics::Type_type::Directory; + return Type_type::Directory; } else if value.is_symlink() { - return Generics::Type_type::Symbolic_link; + return Type_type::Symbolic_link; } - Generics::Type_type::File + Type_type::File } } @@ -27,7 +30,7 @@ impl From for Error_type { match Error { ErrorKind::PermissionDenied => Error_type::Permission_denied, ErrorKind::NotFound => Error_type::Not_found, - ErrorKind::AlreadyExists => Error_type::File_already_exists, + ErrorKind::AlreadyExists => Error_type::Already_exists, ErrorKind::InvalidInput => Error_type::Invalid_path, ErrorKind::InvalidData => Error_type::Invalid_file, _ => Error_type::Unknown, @@ -35,363 +38,310 @@ impl From for Error_type { } } -pub struct File_system_type { - Virtual_root_path: Generics::Path_type, - Mount_points: Vec, - Open_files: Arc>>, +impl From for Error_type { + fn from(Error: std::io::Error) -> Self { + Error.kind().into() + } } -impl File_system_type { - pub fn New() -> Self { - File_system_type { - Virtual_root_path: Generics::Path_type::New(), - Mount_points: Vec::new(), - Open_files: Arc::new(RwLock::new(HashMap::new())), - } +impl Flags_type { + fn Into_open_options(self, Open_options: &mut OpenOptions) { + Open_options + .read(self.Get_mode().Get_read()) + .write(self.Get_mode().Get_write() || self.Get_status().Get_append()); } +} - pub fn Register_file(&self, File: File) -> Result { - let mut Open_files = self.Open_files.write().unwrap(); +impl From<&PathBuf> for Path_owned_type { + fn from(item: &PathBuf) -> Self { + Path_owned_type::New(item.to_str().unwrap().to_string()).unwrap() + } +} - let mut File_identifier: Generics::File_identifier_type = 0; - while Open_files.contains_key(&File_identifier) { - File_identifier += 1; - } +#[cfg(target_family = "unix")] +impl From<&Permissions_type> for std::fs::Permissions { + fn from(Permissions: &Permissions_type) -> Self { + use std::os::unix::fs::PermissionsExt; - if Open_files.insert(File_identifier, File).is_some() { - // If the file identifier is already used. - panic!("File identifier already used."); - } - Ok(File_identifier) + std::fs::Permissions::from_mode(Permissions.To_unix() as u32) } +} - pub fn Unregister_file( - &self, - File_identifier: Generics::File_identifier_type, - ) -> Result<(), Error_type> { - let mut Open_files = self.Open_files.write().unwrap(); - match Open_files.remove(&File_identifier) { - Some(_) => Ok(()), - None => Err(Error_type::Unknown), - } - } +pub struct File_system_type { + Virtual_root_path: Path_owned_type, + Open_files: HashMap, +} - pub fn Get_full_path(&self, Path: &Generics::Path_type) -> Generics::Path_type { - let Full_path = self.Virtual_root_path.clone(); - Full_path + Path +impl File_system_type { + pub fn New() -> Result { + Ok(File_system_type { + Virtual_root_path: Self::Get_root_path().ok_or(Error_type::Unknown)?, + Open_files: HashMap::new(), + }) } -} -impl Generics::File_system_traits for File_system_type { - fn Initialize(&mut self) -> Result<(), Error_type> { - match var("Xila_virtual_root_path") { - Ok(value) => { - self.Virtual_root_path = value.into(); - } + fn Get_root_path() -> Option { + let Root_path = match var("Xila_virtual_root_path") { + Ok(value) => value, Err(_) => match current_dir() { - Ok(value) => { - self.Virtual_root_path = value.to_str().unwrap().into(); - } + Ok(value) => value.to_str()?.to_string(), Err(_) => { - return Err(Error_type::Failed_to_initialize_file_system); + return None; } }, - } + }; - let mut Xila_directory = Generics::Path_type::New(); - Xila_directory.Append("Xila"); - self.Virtual_root_path += Xila_directory; + let Root_path = Path_owned_type::try_from(Root_path).ok()?.Append("Xila")?; - if !Path::new(&self.Virtual_root_path.As_str()).exists() { - match create_dir(self.Virtual_root_path.As_str()) { - Ok(_) => {} - Err(_) => { - return Err(Error_type::Failed_to_initialize_file_system); + match create_dir(Root_path.as_ref() as &Path_type) { + Ok(_) => {} + Err(Error) => { + if ErrorKind::AlreadyExists != Error.kind() { + return None; } } } - Ok(()) + Some(Root_path) } - fn Exists(&self, Path: &Generics::Path_type) -> Result { - Path::new(&self.Get_full_path(Path).As_str()) - .try_exists() - .map_err(|Error_type| Error_type.kind().into()) + fn Get_new_file_identifier( + &self, + Task_identifier: Task_identifier_type, + ) -> Option { + let Start = Self::Get_local_file_identifier(Task_identifier, File_identifier_type::from(0)); + let End = + Self::Get_local_file_identifier(Task_identifier, File_identifier_type::from(0xFFFF)); + + for i in Start..End { + if !self.Open_files.contains_key(&i) { + return Some(File_identifier_type::from(i as u16)); + } + } + + None } - fn Open_file( - &self, - Path: &Generics::Path_type, - Mode: Generics::Mode_type, - ) -> Result { - let Full_path = self.Get_full_path(Path); - let Full_path = Full_path.As_str(); - - let File = match Mode { - Generics::Mode_type::Read => File::open(Full_path).map_err(|Error| Error.kind())?, - Generics::Mode_type::Write => File::create(Full_path).map_err(|Error| Error.kind())?, - Generics::Mode_type::Read_write => OpenOptions::new() - .read(true) - .write(true) - .open(Full_path) - .map_err(|Error| Error.kind())?, - Generics::Mode_type::Append => OpenOptions::new() - .append(true) - .open(Full_path) - .map_err(|Error| Error.kind())?, - Generics::Mode_type::Read_append => OpenOptions::new() - .read(true) - .append(true) - .open(Full_path) - .map_err(|Error| Error.kind())?, - }; + pub fn Get_full_path(&self, Path: &dyn AsRef) -> Result { + self.Virtual_root_path + .clone() + .Join(Path) + .ok_or(Error_type::Invalid_path) + } +} + +impl File_system_traits for File_system_type { + fn Exists(&self, Path: &dyn AsRef) -> Result { + metadata(self.Get_full_path(&Path)?.as_ref() as &Path_type) + .map(|_| true) + .or_else(|Error| match Error.kind() { + ErrorKind::NotFound => Ok(false), + _ => Err(Error.kind().into()), + }) + } + + fn Open( + &mut self, + Task_identifier: Task_identifier_type, + Path: &dyn AsRef, + Flags: Flags_type, + ) -> Result { + let Full_path = self.Get_full_path(&Path)?; + + let mut Open_options = OpenOptions::new(); + + Flags.Into_open_options(&mut Open_options); - let File_identifier = self.Register_file(File)?; + let File = Open_options + .open(Full_path.as_ref() as &Path_type) + .map_err(|Error| Error.kind())?; - Ok(Generics::File_type::New(File_identifier, self)) + let File_identifier = self + .Get_new_file_identifier(Task_identifier) + .ok_or(Error_type::Too_many_open_files)?; + + let Local_file_identifier = + Self::Get_local_file_identifier(Task_identifier, File_identifier); + + if self + .Open_files + .insert(Local_file_identifier, File) + .is_some() + { + return Err(Error_type::Internal_error); + } + + Ok(File_identifier) } - fn Read_file( - &self, - File_identifier: Generics::File_identifier_type, + fn Read( + &mut self, + Task_identifier: Task_identifier_type, + File_identifier: File_identifier_type, Buffer: &mut [u8], - ) -> Result { - let mut Open_files = self.Open_files.write().unwrap(); - let File = match Open_files.get_mut(&File_identifier) { - Some(File) => File, - None => return Err(Error_type::Invalid_file_identifier), - }; - Ok(File.read(Buffer).map_err(|Error| Error.kind())?) + ) -> Result { + let Local_file_identifier = + Self::Get_local_file_identifier(Task_identifier, File_identifier); + + let File = self + .Open_files + .get_mut(&Local_file_identifier) + .ok_or(Error_type::Invalid_identifier)?; + + Ok(File.read(Buffer)?.into()) } - fn Write_file( - &self, - File_identifier: Generics::File_identifier_type, + fn Write( + &mut self, + Task_identifier: Task_identifier_type, + File_identifier: File_identifier_type, Buffer: &[u8], - ) -> Result { - let mut Open_files = self.Open_files.write().unwrap(); - let File = match Open_files.get_mut(&File_identifier) { - Some(File) => File, - None => return Err(Error_type::Invalid_file_identifier), - }; - File.write(Buffer).map_err(|Error| Error.kind().into()) + ) -> Result { + let Local_file_identifier = + Self::Get_local_file_identifier(Task_identifier, File_identifier); + + let File = self + .Open_files + .get_mut(&Local_file_identifier) + .ok_or(Error_type::Invalid_identifier)?; + + Ok(File.write(Buffer)?.into()) } - fn Flush_file( - &self, - File_identifier: Generics::File_identifier_type, - ) -> Result<(), Error_type> { - let mut Open_files = self.Open_files.write().unwrap(); - let File = match Open_files.get_mut(&File_identifier) { - Some(File) => File, - None => return Err(Error_type::Invalid_file_identifier), - }; + fn Flush(&mut self, Task: Task_identifier_type, File: File_identifier_type) -> Result<()> { + let Local_file_identifier = Self::Get_local_file_identifier(Task, File); + let File = self + .Open_files + .get_mut(&Local_file_identifier) + .ok_or(Error_type::Invalid_identifier)?; File.flush().map_err(|Error| Error.kind().into()) } - fn Close_file( - &self, - File_identifier: Generics::File_identifier_type, - ) -> Result<(), Error_type> { - self.Unregister_file(File_identifier) + fn Close(&mut self, Task: Task_identifier_type, File: File_identifier_type) -> Result<()> { + let Local_file_identifier = Self::Get_local_file_identifier(Task, File); + self.Open_files + .remove(&Local_file_identifier) + .ok_or(Error_type::Invalid_identifier)?; + Ok(()) } - fn Get_file_type( - &self, - File: Generics::File_identifier_type, - ) -> Result { - let mut Open_files = self.Open_files.write().unwrap(); - let File = match Open_files.get_mut(&File) { - Some(File) => File, - None => return Err(Error_type::Invalid_file_identifier), - }; - - Ok(File - .metadata() - .map_err(|Error| Error_type::from(Error.kind()))? - .file_type() - .into()) + fn Get_type(&self, _: Task_identifier_type, Path: &dyn AsRef) -> Result { + let Full_path = self.Get_full_path(&Path)?; + let Metadata = metadata(Full_path.as_ref() as &Path_type).map_err(|Error| Error.kind())?; + Ok(Metadata.file_type().into()) } - fn Get_file_size( - &self, - File_identifier: Generics::File_identifier_type, - ) -> Result { - let mut Open_files = self.Open_files.write().unwrap(); - let File = match Open_files.get_mut(&File_identifier) { - Some(File) => File, - None => return Err(Error_type::Invalid_file_identifier), - }; - Ok(File - .metadata() - .map_err(|Error| Error_type::from(Error.kind()))? - .len() - .into()) + fn Get_size(&self, _: Task_identifier_type, Path: &dyn AsRef) -> Result { + let Full_path = self.Get_full_path(&Path)?; + let Metadata = metadata(Full_path.as_ref() as &Path_type).map_err(|Error| Error.kind())?; + Ok(Metadata.len().into()) } - fn Get_file_position( - &self, - File: Generics::File_identifier_type, - ) -> Result { - let mut Open_files = self.Open_files.write().unwrap(); - let File = match Open_files.get_mut(&File) { + fn Set_position( + &mut self, + Task_identifier: Task_identifier_type, + File_identifier: File_identifier_type, + Position_type: &Position_type, + ) -> Result { + let Local_file_identifier = + Self::Get_local_file_identifier(Task_identifier, File_identifier); + let File = match self.Open_files.get_mut(&Local_file_identifier) { Some(File) => File, - None => return Err(Error_type::Invalid_file_identifier), + None => return Err(Error_type::Invalid_identifier), }; Ok(File - .stream_position() + .seek((*Position_type).into()) .map_err(|Error| Error_type::from(Error.kind()))? .into()) } - fn Set_file_position( - &self, - File: Generics::File_identifier_type, - Position_type: &Generics::Position_type, - ) -> Result { - let mut Open_files = self.Open_files.write().unwrap(); - let File = match Open_files.get_mut(&File) { - Some(File) => File, - None => return Err(Error_type::Invalid_file_identifier), - }; - - Ok(File - .seek(match Position_type { - Generics::Position_type::Start(Value) => SeekFrom::Start(Value.0), - Generics::Position_type::Current(Value) => SeekFrom::Current(*Value), - Generics::Position_type::End(Value) => SeekFrom::End(*Value), - }) - .map_err(|Error| Error_type::from(Error.kind()))? - .into()) - } + fn Delete(&mut self, Path: &dyn AsRef) -> Result<()> { + let Full_path = self.Get_full_path(&Path)?; - fn Delete_file(&self, Path: &Generics::Path_type) -> Result<(), Error_type> { - remove_file(self.Get_full_path(Path).As_str()).map_err(|Error| Error.kind().into()) + remove_file(Full_path.as_ref() as &Path_type).map_err(|Error| Error.kind().into()) } - fn Create_directory(&self, Path: &Generics::Path_type) -> Result<(), Error_type> { - create_dir(self.Get_full_path(Path).As_str()).map_err(|Error| Error.kind().into()) - } + fn Create_directory( + &mut self, + _: Task_identifier_type, + Path: &dyn AsRef, + ) -> Result<()> { + let Full_path = self.Get_full_path(&Path)?; - fn Create_directory_recursive(&self, Path: &Generics::Path_type) -> Result<(), Error_type> { - create_dir_all(self.Get_full_path(Path).As_str()).map_err(|Error| Error.kind().into()) + create_dir(Full_path.as_ref() as &Path_type).map_err(|Error| Error.kind().into()) } - fn Delete_directory(&self, Path: &Generics::Path_type) -> Result<(), Error_type> { - remove_dir(self.Get_full_path(Path).As_str()).map_err(|Error| Error.kind().into()) - } + fn Create_file(&mut self, _: Task_identifier_type, Path: &dyn AsRef) -> Result<()> { + let Full_path = self.Get_full_path(&Path)?; - fn Delete_directory_recursive(&self, Path: &Generics::Path_type) -> Result<(), Error_type> { - remove_dir_all(self.Get_full_path(Path).As_str()).map_err(|Error| Error.kind().into()) - } + OpenOptions::new() + .write(true) + .create_new(true) + .open(Full_path.as_ref() as &Path_type) + .map_err(|Error| Error.kind())?; - fn Move( - &self, - Path: &Generics::Path_type, - Destination: &Generics::Path_type, - ) -> Result<(), Error_type> { - rename( - self.Get_full_path(Path).As_str(), - self.Get_full_path(Destination).As_str(), - ) - .map_err(|Error| Error.kind().into()) + Ok(()) } -} - -// - Test -#[cfg(test)] -mod tests { - use crate::Prelude::Path_type; - use super::{Generics::*, *}; - use std::fs::File as STD_File; - use std::path::Path as STD_Path; + fn Close_all(&mut self, Task_identifier: Task_identifier_type) -> Result<()> { + let Start = Self::Get_local_file_identifier(Task_identifier, File_identifier_type::from(0)); + let End = + Self::Get_local_file_identifier(Task_identifier, File_identifier_type::from(0xFFFF)); - const Test_directory_path: &str = "Test"; + self.Open_files + .retain(|File_identifier, _| *File_identifier < Start || *File_identifier > End); - fn Get_path_in_test(Path: &Generics::Path_type) -> Generics::Path_type { - Generics::Path_type::from(Test_directory_path) + Path + Ok(()) } - fn Reset_test_directory(File_system: &File_system_type) { - let Test_directory_full_path = - File_system.Get_full_path(&Generics::Path_type::from(Test_directory_path)); - if !STD_Path::new(&Test_directory_full_path.As_str()).exists() { - create_dir(&Test_directory_full_path.As_str()).unwrap(); + fn Transfert_file_identifier( + &mut self, + Old_task: Task_identifier_type, + New_task: Task_identifier_type, + Old_file_identifier: File_identifier_type, + ) -> Result { + let Old_local_file_identifier = + Self::Get_local_file_identifier(Old_task, Old_file_identifier); + let New_file_identifier = self + .Get_new_file_identifier(New_task) + .ok_or(Error_type::Too_many_open_files)?; + let New_local_file_identifier = + Self::Get_local_file_identifier(New_task, New_file_identifier); + + let File = self + .Open_files + .remove(&Old_local_file_identifier) + .ok_or(Error_type::Invalid_identifier)?; + + if self + .Open_files + .insert(New_local_file_identifier, File) + .is_some() + { + return Err(Error_type::Internal_error); } - } - - #[test] - fn Exists() { - let mut File_system = File_system_type::New(); - assert!(File_system.Initialize().is_ok()); - Reset_test_directory(&File_system); - let File_path = Get_path_in_test(&Path_type::from("exists.txt")); - assert!(!File_system.Exists(&File_path).unwrap()); - let mut File = STD_File::create(File_system.Get_full_path(&File_path).As_str()).unwrap(); - assert!(File.write_all(b"Hello, world!").is_ok()); - assert!(File_system.Exists(&File_path).unwrap()); - assert!(remove_file(File_system.Get_full_path(&File_path).As_str()).is_ok()); - assert!(!File_system.Exists(&File_path).unwrap()); - } - #[test] - fn File_manipulation() { - let mut File_system = File_system_type::New(); - assert!(File_system.Initialize().is_ok()); - Reset_test_directory(&File_system); - - let File_path = Get_path_in_test(&Path_type::from("delete_file.txt")); - assert!(!File_system.Exists(&File_path).unwrap()); - assert!(File_system.Open_file(&File_path, Mode_type::Write).is_ok()); - assert!(File_system.Exists(&File_path).unwrap()); - assert!(File_system.Delete_file(&File_path).is_ok()); - assert!(!File_system.Exists(&File_path).unwrap()); + Ok(File_identifier_type::from(New_local_file_identifier as u16)) } - #[test] - fn Directory_operations() { - let mut File_system = File_system_type::New(); - assert!(File_system.Initialize().is_ok()); - - let Directory_path = Get_path_in_test(&Path_type::from("directory")); - assert!(!File_system.Exists(&Directory_path).unwrap()); - assert!(File_system.Create_directory(&Directory_path).is_ok()); - assert!(File_system.Exists(&Directory_path).unwrap()); - assert!(File_system.Delete_directory(&Directory_path).is_ok()); - assert!(!File_system.Exists(&Directory_path).unwrap()); - } - - #[test] - fn File_operations() { - let mut File_system = File_system_type::New(); - assert!(File_system.Initialize().is_ok()); - Reset_test_directory(&File_system); - - let File_path = Get_path_in_test(&Path_type::from("file_operations.txt")); - assert!(!File_system.Exists(&File_path).unwrap()); - let mut File = File_system.Open_file(&File_path, Mode_type::Write).unwrap(); - assert!(File.write_all(b"Hello, world!").is_ok()); - assert!(File_system.Exists(&File_path).unwrap()); - assert!(File_system.Delete_file(&File_path).is_ok()); - assert!(!File_system.Exists(&File_path).unwrap()); - } + fn Move( + &mut self, + _: Task_identifier_type, + Source: &dyn AsRef, + Destination: &dyn AsRef, + ) -> Result<()> { + let Source = self.Get_full_path(Source)?; + let Destination = self.Get_full_path(Destination)?; - #[test] - fn File_metadata() { - let mut File_system = File_system_type::New(); - assert!(File_system.Initialize().is_ok()); - Reset_test_directory(&File_system); - - let File_path = Get_path_in_test(&Path_type::from("file_metadata.txt")); - assert!(!File_system.Exists(&File_path).unwrap()); - let mut File = File_system.Open_file(&File_path, Mode_type::Write).unwrap(); - assert!(File.write_all(b"Hello, world!").is_ok()); - assert!(File_system.Exists(&File_path).unwrap()); - assert!(File.Get_size().unwrap() == Size_type(13)); - assert!(File_system.Delete_file(&File_path).is_ok()); - assert!(!File_system.Exists(&File_path).unwrap()); + rename( + Source.as_ref() as &Path_type, + Destination.as_ref() as &Path_type, + )?; + Ok(()) } } + +// - Test +#[cfg(test)] +mod Tests {} diff --git a/Modules/File_system/src/Drivers/mod.rs b/Modules/File_system/src/Drivers/mod.rs index 89b1fc1..53e3d7e 100644 --- a/Modules/File_system/src/Drivers/mod.rs +++ b/Modules/File_system/src/Drivers/mod.rs @@ -1 +1,2 @@ +#[cfg(any(target_os = "linux", target_os = "macos", target_os = "windows"))] pub mod Native; diff --git a/Modules/File_system/src/Generics/Error.rs b/Modules/File_system/src/Generics/Error.rs index 6672868..a5462c8 100644 --- a/Modules/File_system/src/Generics/Error.rs +++ b/Modules/File_system/src/Generics/Error.rs @@ -1,13 +1,14 @@ -use std::num::NonZeroU32; +use std::{num::NonZeroU32, sync::PoisonError}; -use Shared::Error_discriminant_trait; +pub type Result = std::result::Result; -#[derive(Debug, PartialEq, Copy, Clone)] +#[derive(Debug, PartialEq, Clone, Copy)] +#[repr(C)] pub enum Error_type { Failed_to_initialize_file_system = 1, Permission_denied, Not_found, - File_already_exists, + Already_exists, Directory_already_exists, File_system_full, File_system_error, @@ -16,15 +17,32 @@ pub enum Error_type { Invalid_directory, Invalid_symbolic_link, Unknown, - Invalid_file_identifier, + Invalid_identifier, + Failed_to_get_task_informations, + Too_many_mounted_file_systems, + Poisoned_lock, + Too_many_open_files, + Internal_error, + Invalid_mode, + Unsupported_operation, + Ressource_busy, + Other, } -impl Error_discriminant_trait for Error_type { - fn Get_discriminant(&self) -> NonZeroU32 { - NonZeroU32::new(*self as u32).unwrap() +impl From for Error_type { + fn from(_: Task::Error_type) -> Self { + Error_type::Failed_to_get_task_informations } +} + +impl From> for Error_type { + fn from(_: PoisonError) -> Self { + Error_type::Poisoned_lock + } +} - fn From_discriminant(Discriminant: NonZeroU32) -> Self { - unsafe { std::mem::transmute(Discriminant.get() as u8) } +impl From for NonZeroU32 { + fn from(Error: Error_type) -> Self { + unsafe { NonZeroU32::new_unchecked(Error as u32) } } } diff --git a/Modules/File_system/src/Generics/File.rs b/Modules/File_system/src/Generics/File.rs index adf3cd7..674ae22 100644 --- a/Modules/File_system/src/Generics/File.rs +++ b/Modules/File_system/src/Generics/File.rs @@ -1,168 +1,101 @@ -use Shared::Discriminant_trait; - -use super::*; - -#[derive(Debug, PartialEq, Eq, Clone, Copy)] -pub enum Mode_type { - Read = 1, - Write, - Read_write, - Append, - Read_append, -} - -impl Discriminant_trait for Mode_type { - fn Get_discriminant(&self) -> u32 { - *self as u32 - } - - fn From_discriminant(Discriminant: u32) -> Self { - unsafe { std::mem::transmute(Discriminant as u8) } - } -} - -impl From for Mode_type { - fn from(item: u32) -> Self { - Mode_type::From_discriminant(item) - } -} +use super::{ + Flags_type, Path_type, Position_type, Result, Size_type, Status_type, + Unique_file_identifier_type, Virtual_file_system::Virtual_file_system_type, +}; #[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[repr(C)] pub enum Type_type { File = 1, Directory, + Block_device, + Character_device, + Named_pipe, Symbolic_link, } -impl Discriminant_trait for Type_type { - fn Get_discriminant(&self) -> u32 { - *self as u32 - } - - fn From_discriminant(Discriminant: u32) -> Self { - unsafe { std::mem::transmute(Discriminant as u8) } - } +pub struct File_type { + File_identifier: Unique_file_identifier_type, + File_system: Virtual_file_system_type, } -pub type File_identifier_type = u16; - -pub struct File_type<'a> { - File_identifier: File_identifier_type, - File_system: &'a dyn File_system_traits, -} +impl File_type { + pub fn Open( + File_system: &Virtual_file_system_type, + Path: impl AsRef, + Flags: Flags_type, + ) -> Result { + let File_identifier = File_system.Open(Path, Flags)?; -impl<'a> File_type<'a> { - pub fn New( - File_identifier: File_identifier_type, - File_system: &'a dyn File_system_traits, - ) -> Self { - Self { + Ok(File_type { File_identifier, - File_system, - } + File_system: File_system.clone(), + }) + } + + pub fn Create_unamed_pipe( + File_system: &Virtual_file_system_type, + Size: usize, + Status: Status_type, + ) -> Result<(Self, Self)> { + let (File_identifier_read, File_identifier_write) = + File_system.Create_unnamed_pipe(Size, Status)?; + + Ok(( + File_type { + File_identifier: File_identifier_read, + File_system: File_system.clone(), + }, + File_type { + File_identifier: File_identifier_write, + File_system: File_system.clone(), + }, + )) + } + + // - Setters + pub fn Set_position(&self, Position: &Position_type) -> Result { + self.File_system + .Set_position(self.Get_file_identifier(), Position) } -} -impl<'a> File_type<'a> { - // - Operations - pub fn Get_identifier(&self) -> File_identifier_type { + // - Getters + pub const fn Get_file_identifier(&self) -> Unique_file_identifier_type { self.File_identifier } - pub fn Set_position(&mut self, Offset: Size_type) -> Result { - self.File_system - .Set_file_position(self.Get_identifier(), &Position_type::Start(Offset)) - } - pub fn Write(&self, Buffer: &[u8]) -> Result { - self.File_system.Write_file(self.Get_identifier(), Buffer) + // - Operations + + pub fn Write(&self, Buffer: &[u8]) -> Result { + self.File_system.Write(self.Get_file_identifier(), Buffer) } - pub fn Write_line(&self, Buffer: &[u8]) -> Result { - let Size = self.File_system.Write_file(self.Get_identifier(), Buffer)?; - Ok(Size + self.File_system.Write_file(self.Get_identifier(), b"\n")?) + + pub fn Write_line(&self, Buffer: &[u8]) -> Result { + let Size = self.Write(Buffer)? + self.Write(b"\n")?; + Ok(Size) } - pub fn Read(&self, Buffer: &mut [u8]) -> Result { - self.File_system.Read_file(self.Get_identifier(), Buffer) + + pub fn Read(&self, Buffer: &mut [u8]) -> Result { + self.File_system.Read(self.Get_file_identifier(), Buffer) } - pub fn Read_line(&self, Buffer: &mut [u8]) -> Result<(), Error_type> { - let mut Buffer = Buffer.iter_mut(); + pub fn Read_line(&self, Buffer: &mut [u8]) -> Result<()> { + let mut Index = 0; loop { - let Byte = self - .File_system - .Read_file(self.Get_identifier(), &mut [0; 1])?; - - if Byte == 0 { - return Ok(()); + let Size: usize = self.Read(&mut Buffer[Index..Index + 1])?.into(); + if Size == 0 { + break; } - let Byte = Buffer.next().unwrap(); - if *Byte == b'\n' { + if Buffer[Index] == b'\n' { break; } + Index += 1; } Ok(()) } - - pub fn Read_vector(&self) -> Result, Error_type> { - let Size = self.Get_size()?; - let mut Buffer = vec![0; Size.0 as usize]; - self.Read(&mut Buffer).map(|_| Buffer) - } - - pub fn Get_position(&self) -> Size_type { - self.File_system - .Get_file_position(self.Get_identifier()) - .unwrap() - } - - // - Metadata - pub fn Get_size(&self) -> Result { - self.File_system.Get_file_size(self.Get_identifier()) - } - - pub fn Get_type(&self) -> Result { - self.File_system.Get_file_type(self.Get_identifier()) - } } -impl std::io::Read for File_type<'_> { - fn read(&mut self, Buffer: &mut [u8]) -> Result { - self.File_system - .Read_file(self.File_identifier, Buffer) - .map_err(|_| std::io::Error::new(std::io::ErrorKind::Other, "Error")) - } -} - -impl std::io::Write for File_type<'_> { - fn write(&mut self, Buffer: &[u8]) -> Result { - self.File_system - .Write_file(self.File_identifier, Buffer) - .map_err(|_| std::io::Error::new(std::io::ErrorKind::Other, "Error")) - } - - fn flush(&mut self) -> Result<(), std::io::Error> { - self.File_system - .Flush_file(self.File_identifier) - .map_err(|_| std::io::Error::new(std::io::ErrorKind::Other, "Error")) - } -} - -impl std::io::Seek for File_type<'_> { - fn seek(&mut self, Position: std::io::SeekFrom) -> Result { - match Position { - std::io::SeekFrom::Start(Offset) => self - .File_system - .Set_file_position(self.File_identifier, &Position_type::Start(Offset.into())) - .map(|x| x.0) - .map_err(|_| std::io::Error::new(std::io::ErrorKind::Other, "Error")), - std::io::SeekFrom::End(Offset) => self - .File_system - .Set_file_position(self.File_identifier, &Position_type::End(Offset)) - .map(|x| x.0) - .map_err(|_| std::io::Error::new(std::io::ErrorKind::Other, "Error")), - std::io::SeekFrom::Current(Offset) => self - .File_system - .Set_file_position(self.File_identifier, &Position_type::Current(Offset)) - .map(|x| x.0) - .map_err(|_| std::io::Error::new(std::io::ErrorKind::Other, "Error")), - } +impl Drop for File_type { + fn drop(&mut self) { + let _ = self.File_system.Close(self.Get_file_identifier()); } } diff --git a/Modules/File_system/src/Generics/File_system.rs b/Modules/File_system/src/Generics/File_system.rs index a02e673..6c85fe7 100644 --- a/Modules/File_system/src/Generics/File_system.rs +++ b/Modules/File_system/src/Generics/File_system.rs @@ -1,37 +1,372 @@ -use super::*; +use crate::Prelude::Mode_type; -pub trait File_system_traits { - fn Initialize(&mut self) -> Result<(), Error_type>; +use super::{ + File_identifier_type, Flags_type, Path_owned_type, Path_type, Permissions_type, Position_type, + Result, Size_type, Type_type, +}; - // - Status - fn Exists(&self, Path: &Path_type) -> Result; +use Task::Task_identifier_type; +use Users::{Group_identifier_type, User_identifier_type}; - // - Mount points - //fn Mount(&mut self, File_system: &mut Self, Mount_point: &Path_type) -> Result<(), ()>; - //fn Unmount(&mut self, Mount_point: &Path_type) -> Result<(), ()>; +pub trait File_system_traits: Send + Sync { + // - Status + fn Exists(&self, Path: &dyn AsRef) -> Result; // - Manipulation + // - - Open/close/delete + + /// Create a file. + /// + /// # Errors + /// Returns an error if the file already exists. + /// Returns an error if the user / group doesn't have the permission to create the file (no write permission on parent directory). + fn Create_file( + &mut self, + Task: Task_identifier_type, + Path: &dyn AsRef, + ) -> Result<()>; + + /// Open a file. + /// + /// # Errors + /// Returns an error if the file doesn't exists. + /// Returns an error if the user / group doesn't have the permission to open the file (mode is not compatible with the file permissions). + fn Open( + &mut self, + Task: Task_identifier_type, + Path: &dyn AsRef, + Mode: Flags_type, + ) -> Result; + + /// Close a file. + /// + /// # Errors + /// Returns an error if the file is not opened by the task (invalid file identifier). + /// Returns an error if the task identifier is invalid. + fn Close(&mut self, Task: Task_identifier_type, File: File_identifier_type) -> Result<()>; + + /// Close all files opened by the task. + fn Close_all(&mut self, Task: Task_identifier_type) -> Result<()>; + + /// Transfer a file identifier from a task to another. + fn Transfert_file_identifier( + &mut self, + Old_task: Task_identifier_type, + New_task: Task_identifier_type, + File: File_identifier_type, + ) -> Result; + + /// Delete a file. + /// + /// # Errors + /// Returns an error if the file doesn't exists. + /// Returns an error if the user / group doesn't have the permission to delete the file (no write permission on parent directory). + fn Delete(&mut self, Path: &dyn AsRef) -> Result<()>; // - - File operations - fn Open_file(&self, Path: &Path_type, Mode: Mode_type) -> Result; - fn Close_file(&self, File: File_identifier_type) -> Result<(), Error_type>; - fn Read_file(&self, File: File_identifier_type, Buffer: &mut [u8]) - -> Result; - fn Write_file(&self, File: File_identifier_type, Buffer: &[u8]) -> Result; - fn Flush_file(&self, File: File_identifier_type) -> Result<(), Error_type>; - fn Get_file_type(&self, File: File_identifier_type) -> Result; - fn Get_file_size(&self, File: File_identifier_type) -> Result; - fn Get_file_position(&self, File: File_identifier_type) -> Result; - fn Set_file_position( - &self, + + /// Read a file. + /// + /// # Errors + /// - If the file is not opened. + /// - If the file is not opened in read mode. + fn Read( + &mut self, + Task: Task_identifier_type, + File: File_identifier_type, + Buffer: &mut [u8], + ) -> Result; + + /// Write a file. + /// + /// # Errors + /// - If the file is not opened (invalid file identifier). + /// - If the file is not opened in write mode (invalid mode). + fn Write( + &mut self, + Task: Task_identifier_type, + File: File_identifier_type, + Buffer: &[u8], + ) -> Result; + + fn Move( + &mut self, + Task: Task_identifier_type, + Source: &dyn AsRef, + Destination: &dyn AsRef, + ) -> Result<()>; + + /// Set the position of the file. + /// + /// # Errors + /// - If the file is not opened (invalid file identifier). + fn Set_position( + &mut self, + Task: Task_identifier_type, File: File_identifier_type, Position: &Position_type, - ) -> Result; - - fn Delete_file(&self, Path: &Path_type) -> Result<(), Error_type>; - // - - Directory - fn Create_directory(&self, Path: &Path_type) -> Result<(), Error_type>; - fn Create_directory_recursive(&self, Path: &Path_type) -> Result<(), Error_type>; - fn Delete_directory(&self, Path: &Path_type) -> Result<(), Error_type>; - fn Delete_directory_recursive(&self, Path: &Path_type) -> Result<(), Error_type>; - fn Move(&self, Path: &Path_type, Destination: &Path_type) -> Result<(), Error_type>; + ) -> Result; + fn Flush(&mut self, Task: Task_identifier_type, File: File_identifier_type) -> Result<()>; + + // - Metadata + // - - Size + + /// Get the type of the file. + /// + /// # Errors + /// - If the file doesn't exists. + fn Get_type( + &self, + Task: Task_identifier_type, + Path_type: &dyn AsRef, + ) -> Result; + + /// Get the size of the file. + /// + /// # Errors + /// - If the file doesn't exists. + /// - If the user / group doesn't have the permission to get the size (no execute permission on parent directory). + fn Get_size( + &self, + Task: Task_identifier_type, + Path: &dyn AsRef, + ) -> Result; + + // - - Security + + /// Set the owner of the file. + /// If `User` is `None`, the owner is not changed. + /// If `Group` is `None`, the group is not changed. + /// If both are `None`, the owner and group are not changed. + /// + /// # Errors + /// Returns an error if the file doesn't exists. + /// Returns an error if the user / group doesn't have the permission to change the owner (not the current owner or not the root user). + fn Set_owner( + &mut self, + _: Task_identifier_type, + _: &dyn AsRef, + _: Option, + _: Option, + ) -> Result<()> { + Ok(()) // TODO : Implement with permission file + } + + /// Get the owner of the file. + /// + /// # Errors + /// Returns an error if the file doesn't exists. + /// Returns an error if the user / group doesn't have the permission to get the owner (no execute permission on parent directory). + fn Get_owner( + &self, + _: Task_identifier_type, + _: &dyn AsRef, + ) -> Result<(User_identifier_type, Group_identifier_type)> { + Ok((0, 0)) // TODO : Implement with permission file + } + + /// Set the permissions of the file. + /// + /// # Errors + /// Returns an error if the file doesn't exists. + /// Returns an error if the user / group doesn't have the permission to set the permissions (no execute permission on parent directory). + fn Set_permissions( + &mut self, + _: Task_identifier_type, + _: &Permissions_type, + _: &dyn AsRef, + ) -> Result<()> { + Ok(()) // TODO : Implement with permission file + } + + /// Get the permissions of the file. + /// + /// # Errors + /// Returns an error if the file doesn't exists. + /// Returns an error if the user / group doesn't have the permission to get the permissions (no execute permission on parent directory). + fn Get_permissions( + &self, + _: Task_identifier_type, + _: &dyn AsRef, + ) -> Result { + Ok(Permissions_type::New_all_full()) // TODO : Implement with permission file + } + + // - Directory + + /// Create a directory. + /// + /// # Errors + /// + /// Returns an error if the directory / file already exists. + /// Returns an error if the user / group doesn't have the permission to create the directory (no write permission on parent directory). + fn Create_directory( + &mut self, + Task: Task_identifier_type, + Path: &dyn AsRef, + ) -> Result<()>; + + /// Combine task identifier and file identifier to get a unique file identifier. + fn Get_local_file_identifier( + Task_identifier: Task_identifier_type, + File_identifier: File_identifier_type, + ) -> u32 + where + Self: Sized, // ? : Makes the compiler happy + { + let File_identifier: u16 = File_identifier.into(); + let Task_identifier: u32 = Task_identifier.into(); + (Task_identifier) << 16 | File_identifier as u32 + } + + // - Tests + + /// Test the existence of a file. + /// + /// # Before running the tests + /// + /// - `Test_path` should be an existing directory + /// - Create file `exists` in the `Test_path` directory + /// - Ensure `not_exists` doesn't exists in the `Test_path` directory + fn Test_existence(&self) { + assert_eq!(self.Exists(&Get_test_path()), Ok(true)); + assert_eq!( + self.Exists(&Get_test_path().Append("exists").unwrap()), + Ok(true) + ); + assert_eq!( + self.Exists(&Get_test_path().Append("not_exists").unwrap()), + Ok(false) + ); + } + + /// Test opening and closing a file. + /// + /// # Before running the tests + /// + /// - Create file `read_only`, `write_only` and `read_write` in the directory + /// - Ensure `not_exists` doesn't exists in the `Test_path` directory + /// - Ensure `read_only`, `write_only` and `read_write` are closed + fn Test_open_close_file(&mut self) { + let Task_identifier = Task_identifier_type::from(1); + + let Read_only = self + .Open( + Task_identifier, + &Get_test_path().Append("read_only").unwrap(), + Mode_type::Read_only().into(), + ) + .unwrap(); + assert!(self + .Open( + Task_identifier, + &Get_test_path().Append("read_only").unwrap(), + Mode_type::Read_only().into(), + ) + .is_err()); + + let Write_only = self + .Open( + Task_identifier, + &Get_test_path().Append("write_only").unwrap(), + Mode_type::Write_only().into(), + ) + .unwrap(); + + let Read_write = self + .Open( + Task_identifier, + &Get_test_path().Append("read_write").unwrap(), + Mode_type::Read_write().into(), + ) + .unwrap(); + + self.Close(Task_identifier, Read_only).unwrap(); + + self.Close(Task_identifier, Write_only).unwrap(); + + self.Close(Task_identifier, Read_write).unwrap(); + } + + /// Test creating a directory and verifying its existence. + /// + /// # Before running the tests + /// + /// - Ensure `test_dir` doesn't exists in the `Test_path` directory + /// - Ensure `already_exists` exists in the `Test_path` directory + fn Test_create_directory_exists(&mut self) { + let New_path = Get_test_path().Append("test_dir").unwrap(); + let Task_identifier = Task_identifier_type::from(1); + + assert_eq!(self.Exists(&New_path), Ok(false)); + self.Create_directory(Task_identifier, &New_path).unwrap(); + assert_eq!(self.Exists(&New_path), Ok(true)); + } + + /// Test read file operation. + /// + /// # Before running the tests + /// + /// - Create file `read` in the `Test_path` directory containing `0123456789\n` (10 bytes) + /// - Create file `empty_read` in the `Test_path` directory + fn Test_file_read(&mut self) { + let Task_identifier = Task_identifier_type::from(1); + + let Read_file = Get_test_path().Append("read").unwrap(); + let Read_file_identifier = self + .Open(Task_identifier, &Read_file, Mode_type::Read_only().into()) + .unwrap(); + let mut Buffer = [0; 11]; + let Size = self + .Read(Task_identifier, Read_file_identifier, &mut Buffer) + .unwrap(); + assert_eq!(Size, 11); + assert_eq!(&Buffer, b"0123456789\n"); + assert_eq!(self.Get_size(Task_identifier, &Read_file).unwrap(), 11); + + let Empty_file = Get_test_path().Append("empty_read").unwrap(); + let Empty_file_identifier = self + .Open(Task_identifier, &Empty_file, Mode_type::Read_only().into()) + .unwrap(); + + let mut Buffer = [0; 1]; + let Size = self + .Read(Task_identifier, Empty_file_identifier, &mut Buffer) + .unwrap(); + assert_eq!(Size, 0); + assert_eq!(self.Get_size(Task_identifier, &Empty_file).unwrap(), 0); + } + + /// Test write file operation. + /// + /// # Before running the tests + /// + /// - Create file `write` in the `Test_path` directory + fn Test_file_write(&mut self) { + let Task_identifier = Task_identifier_type::from(1); + + let File = Get_test_path().Append("write").unwrap(); + let File_identifier = self + .Open(Task_identifier, &File, Mode_type::Write_only().into()) + .unwrap(); + let Buffer = b"0123456789\n"; + let Size = self + .Write(Task_identifier, File_identifier, Buffer) + .unwrap(); + assert_eq!(Size, 11); + assert_eq!(self.Get_size(Task_identifier, &File).unwrap(), 11); + } + + /// Run before the tests. + fn Reset_test_directory(&mut self) { + let _ = self.Delete(&Get_test_path()); + assert_eq!(self.Exists(&Get_test_path()), Ok(false)); + + self.Create_directory(Task_identifier_type::from(1), &Get_test_path()) + .unwrap(); + assert_eq!(self.Exists(&Get_test_path()), Ok(true)); + } +} + +pub fn Get_test_path() -> Path_owned_type { + Path_type::Get_root().Append("test").unwrap() } diff --git a/Modules/File_system/src/Generics/Fundamentals/Flags.rs b/Modules/File_system/src/Generics/Fundamentals/Flags.rs new file mode 100644 index 0000000..267e71c --- /dev/null +++ b/Modules/File_system/src/Generics/Fundamentals/Flags.rs @@ -0,0 +1,119 @@ +use super::Permission_type; + +#[inline] +fn Set_bit(Data: &mut u32, Position: u8, Value: bool) { + if Value { + *Data |= 1 << Position; + } else { + *Data &= !(1 << Position); + } +} + +#[inline] +fn Get_bit(Data: &u32, Bit: u8) -> bool { + (Data & (1 << Bit)) != 0 +} + +#[derive(Debug, PartialEq, Eq, Clone, Copy)] +#[repr(transparent)] +pub struct Mode_type(u32); + +impl Mode_type { + const Read_bit: u8 = 0; + const Write_bit: u8 = 1; + + pub fn Read_only() -> Self { + Self(1 << Self::Read_bit) + } + + pub fn Write_only() -> Self { + Self(1 << Self::Write_bit) + } + + pub fn Read_write() -> Self { + Self((1 << Self::Read_bit) | (1 << Self::Write_bit)) + } + + pub fn Get_read(&self) -> bool { + Get_bit(&self.0, Self::Read_bit) + } + + pub fn Get_write(&self) -> bool { + Get_bit(&self.0, Self::Write_bit) + } +} + +#[derive(Debug, PartialEq, Eq, Clone, Copy)] +#[repr(transparent)] +pub struct Status_type(u32); + +impl Default for Status_type { + fn default() -> Self { + Self(0).Set_append(false).Set_non_blocking(false) + } +} + +impl Status_type { + const Append_bit: u8 = 0; + const Non_blocking_bit: u8 = 1; + + pub fn Set_non_blocking(mut self, Value: bool) -> Self { + Set_bit(&mut self.0, Self::Non_blocking_bit, Value); + self + } + + pub fn Get_non_blocking(&self) -> bool { + Get_bit(&self.0, Self::Non_blocking_bit) + } + + pub fn Set_append(mut self, Value: bool) -> Self { + Set_bit(&mut self.0, Self::Append_bit, Value); + self + } + + pub fn Get_append(&self) -> bool { + Get_bit(&self.0, Self::Append_bit) + } +} + +#[derive(Debug, PartialEq, Eq, Clone, Copy)] +#[repr(transparent)] +pub struct Flags_type(u32); + +impl Flags_type { + pub fn New(Mode: Mode_type, Status: Option) -> Self { + Self(Mode.0 << 4 | Status.unwrap_or_default().0) + } + + pub fn Get_mode(&self) -> Mode_type { + Mode_type(self.0 >> 4) + } + + pub fn Get_status(&self) -> Status_type { + Status_type(self.0 & 0b00001111) + } + + pub fn Set_status(&mut self, Status: Status_type) { + self.0 = (self.0 & 0b11110000) | Status.0; + } + + pub fn Is_permission_granted(&self, Permission: &Permission_type) -> bool { + let Mode = self.Get_mode(); + + (Permission.Get_read() && Mode.Get_read()) // Read permission + || (Permission.Get_write() && (Mode.Get_write() || self.Get_status().Get_append())) + // Write permission + } +} + +impl From for Flags_type { + fn from(Mode: Mode_type) -> Self { + Self::New(Mode, None) + } +} + +impl From for u32 { + fn from(Flags: Flags_type) -> Self { + Flags.0 as u32 + } +} diff --git a/Modules/File_system/src/Generics/Fundamentals/Identifiers.rs b/Modules/File_system/src/Generics/Fundamentals/Identifiers.rs new file mode 100644 index 0000000..c92fc1d --- /dev/null +++ b/Modules/File_system/src/Generics/Fundamentals/Identifiers.rs @@ -0,0 +1,76 @@ +use std::ops::{Add, AddAssign}; + +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +#[repr(transparent)] +pub struct File_identifier_type(u16); + +impl From for File_identifier_type { + fn from(Internal_file_identifier: u16) -> Self { + File_identifier_type(Internal_file_identifier) + } +} + +impl From for u16 { + fn from(Internal_file_identifier: File_identifier_type) -> Self { + Internal_file_identifier.0 + } +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +#[repr(transparent)] +pub struct File_system_identifier_type(u8); + +impl File_system_identifier_type { + pub fn New() -> Self { + Self(0) + } + + pub const fn New_from(Identifier: u8) -> Self { + Self(Identifier) + } +} + +impl AddAssign for File_system_identifier_type { + fn add_assign(&mut self, rhs: u8) { + self.0 += rhs; + } +} + +impl Add for File_system_identifier_type { + type Output = Self; + + fn add(self, rhs: u8) -> Self::Output { + Self(self.0 + rhs) + } +} + +impl From for File_system_identifier_type { + fn from(Internal_file_system_identifier: u8) -> Self { + File_system_identifier_type(Internal_file_system_identifier) + } +} + +impl From for u8 { + fn from(Internal_file_system_identifier: File_system_identifier_type) -> Self { + Internal_file_system_identifier.0 + } +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +#[repr(transparent)] +pub struct Unique_file_identifier_type(u32); + +impl Unique_file_identifier_type { + pub fn New( + File_system_identifier: File_system_identifier_type, + File_identifier: File_identifier_type, + ) -> Self { + Self((File_system_identifier.0 as u32) << 16 | File_identifier.0 as u32) + } + + pub fn Split(self) -> (File_system_identifier_type, File_identifier_type) { + let File_system_identifier = File_system_identifier_type::New_from((self.0 >> 16) as u8); + let File_identifier = File_identifier_type((self.0 & 0xFFFF) as u16); + (File_system_identifier, File_identifier) + } +} diff --git a/Modules/File_system/src/Generics/Fundamentals/Path.rs b/Modules/File_system/src/Generics/Fundamentals/Path.rs deleted file mode 100644 index 76263a2..0000000 --- a/Modules/File_system/src/Generics/Fundamentals/Path.rs +++ /dev/null @@ -1,182 +0,0 @@ -use std::{ - fmt::{Display, Formatter}, - ops::{Add, AddAssign}, -}; - -#[derive(Clone, Eq, Hash)] -pub struct Path_type(String); - -impl From<&str> for Path_type { - fn from(item: &str) -> Self { - item.to_string().into() - } -} - -impl From for Path_type { - fn from(item: String) -> Self { - Path_type(item) - } -} - -impl Display for Path_type { - fn fmt(&self, Formatter: &mut Formatter) -> Result<(), std::fmt::Error> { - write!(Formatter, "{}", self.0) - } -} - -impl Add for Path_type { - type Output = Path_type; - - fn add(mut self, rhs: Path_type) -> Self::Output { - self.Append(rhs.0.as_str()); - self - } -} - -impl Add<&Path_type> for Path_type { - type Output = Path_type; - - fn add(mut self, rhs: &Path_type) -> Self::Output { - self.Append(rhs.0.as_str()); - self - } -} - -impl AddAssign for Path_type { - fn add_assign(&mut self, rhs: Path_type) { - self.Append(rhs.0.as_str()); - } -} - -impl AddAssign<&Path_type> for Path_type { - fn add_assign(&mut self, rhs: &Path_type) { - self.Append(rhs.0.as_str()); - } -} - -impl PartialEq for Path_type { - fn eq(&self, other: &Self) -> bool { - self.0 == other.0 - } -} - -impl Path_type { - const Separator: char = '/'; - const Extension_separator: char = '.'; - - pub fn New() -> Path_type { - Path_type("".to_string()) - } - - pub fn Root() -> Path_type { - Path_type("/".to_string()) - } - - pub fn As_str(&self) -> &str { - &self.0 - } - - pub fn Append(&mut self, File: &str) -> &mut Self { - if !self.0.ends_with(Self::Separator) { - self.0.push(Self::Separator); - } - self.0.push_str(File); - self - } - - pub fn Revert_parent_directory(&mut self) -> &mut Self { - let mut Last_index = 0; - for (i, c) in self.0.chars().enumerate() { - if c == Self::Separator { - Last_index = i; - } - } - if Last_index == 0 { - self.0.clear(); - return self; - } - - self.0.truncate(Last_index); - self - } - - pub fn Get_extension(&self) -> Option<&str> { - let mut extension = None; - - for (i, c) in self.0.chars().enumerate() { - if c == Self::Extension_separator { - extension = Some(&self.0[i..]); - } - } - extension - } - - pub fn Get_file_name(&self) -> &str { - let mut Last_index = 0; - for (i, c) in self.0.chars().enumerate() { - if c == Self::Separator { - Last_index = i; - } - } - if Last_index >= self.0.len() { - return &self.0[Last_index..]; - } - &self.0[Last_index + 1..] - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn Test_path_file_and_directory() { - let mut Path = Path_type::Root(); - assert_eq!(Path.As_str(), "/"); - Path.Append("Directory"); - assert_eq!(Path.As_str(), "/Directory"); - Path.Append("File"); - assert_eq!(Path.to_string(), "/Directory/File"); - Path.Revert_parent_directory(); - assert_eq!(Path.to_string(), "/Directory"); - } - - #[test] - fn Test_path_extension() { - let Path = Path_type::Root(); - assert_eq!(Path.Get_extension(), None); - let Path = Path_type::from("File"); - assert_eq!(Path.Get_extension(), None); - let Path = Path_type::from("File.txt"); - assert_eq!(Path.Get_extension(), Some(".txt")); - let Path = Path_type::from("/Directory/File.txt"); - assert_eq!(Path.Get_extension(), Some(".txt")); - let Path = Path_type::from("/Directory/File"); - assert_eq!(Path.Get_extension(), None); - } - - #[test] - fn Test_path_file_name() { - let Path = Path_type::from(""); - assert_eq!(Path.Get_file_name(), ""); - let Path = Path_type::from("/File"); - assert_eq!(Path.Get_file_name(), "File"); - let Path = Path_type::from("/File.txt"); - assert_eq!(Path.Get_file_name(), "File.txt"); - let Path = Path_type::from("/Directory/File.txt"); - assert_eq!(Path.Get_file_name(), "File.txt"); - let Path = Path_type::from("/Directory/File"); - assert_eq!(Path.Get_file_name(), "File"); - let Path = Path_type::from("/Directory"); - assert_eq!(Path.Get_file_name(), "Directory"); - } - - #[test] - fn Test_path_addition() { - let mut Path = Path_type::from("/"); - Path += Path_type::from("Folder"); - assert_eq!(Path.As_str(), "/Folder"); - Path += Path_type::from("File"); - assert_eq!(Path.As_str(), "/Folder/File"); - } -} diff --git a/Modules/File_system/src/Generics/Fundamentals/Path/Components.rs b/Modules/File_system/src/Generics/Fundamentals/Path/Components.rs new file mode 100644 index 0000000..23aceb2 --- /dev/null +++ b/Modules/File_system/src/Generics/Fundamentals/Path/Components.rs @@ -0,0 +1,64 @@ +use super::{Path_type, Separator}; + +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum Component_type<'a> { + Root, + Current, + Parent, + Normal(&'a str), +} + +impl<'a> From<&'a str> for Component_type<'a> { + fn from(item: &'a str) -> Self { + match item { + "/" => Component_type::Root, + "." => Component_type::Current, + ".." => Component_type::Parent, + _ => Component_type::Normal(item), + } + } +} + +pub struct Components_type<'a> { + Components: Vec>, + Front: usize, + Back: usize, +} + +impl<'a> Components_type<'a> { + pub fn New<'b>(Path: &'b Path_type) -> Components_type<'b> { + let mut Components: Vec> = Path + .As_str() + .split(Separator) + .map(Component_type::from) + .collect(); + + if Path.Is_absolute() { + Components.insert(0, Component_type::Root); // TODO : Find a way to avoid this relocation. + } + + let Components_length = Components.len(); + + Components_type { + Components, + Front: 0, + Back: Components_length, + } + } +} + +impl<'a> Iterator for Components_type<'a> { + type Item = Component_type<'a>; + + fn next(&mut self) -> Option { + self.Front += 1; + self.Components.get(self.Front - 1).cloned() + } +} + +impl<'a> DoubleEndedIterator for Components_type<'a> { + fn next_back(&mut self) -> Option { + self.Back -= 1; + self.Components.get(self.Back).cloned() + } +} diff --git a/Modules/File_system/src/Generics/Fundamentals/Path/Path_owned.rs b/Modules/File_system/src/Generics/Fundamentals/Path/Path_owned.rs new file mode 100644 index 0000000..c9d756c --- /dev/null +++ b/Modules/File_system/src/Generics/Fundamentals/Path/Path_owned.rs @@ -0,0 +1,244 @@ +use std::{ + fmt::{Display, Formatter}, + ops::Deref, +}; + +use super::{Extension_separator, Path_type, Separator}; + +#[derive(Clone, Eq, Debug)] +pub struct Path_owned_type(String); + +impl Path_owned_type { + /// # Safety + /// The caller must ensure that the string is valid path string. + pub unsafe fn New_unchecked(Path: String) -> Self { + Path_owned_type(Path) + } + + pub fn New(Path: String) -> Option { + let Path = if Path.ends_with(Separator) && Path.len() > 1 { + Path[..Path.len() - 1].to_string() + } else { + Path + }; + + if Is_valid_string(&Path) { + Some(Path_owned_type(Path)) + } else { + None + } + } + + pub fn Root() -> Path_owned_type { + Path_owned_type("/".to_string()) + } + + pub fn Join(mut self, Path: impl AsRef) -> Option { + if Path.as_ref().Is_absolute() { + return None; + } + + if !self.0.ends_with(Separator) { + self.0.push(Separator); + } + self.0.push_str(Path.as_ref().As_str()); + + Some(self) + } + + pub fn Append(self, Path: &str) -> Option { + self.Join(Path_type::New(Path)?) + } + + pub fn Revert_parent_directory(&mut self) -> &mut Self { + let mut Last_index = 0; + for (i, c) in self.0.chars().enumerate() { + if c == Separator { + Last_index = i; + } + } + if Last_index == 0 { + self.0.clear(); + return self; + } + + self.0.truncate(Last_index); + self + } + + pub fn Get_extension(&self) -> Option<&str> { + let mut extension = None; + + for (i, c) in self.0.chars().enumerate() { + if c == Extension_separator { + extension = Some(&self.0[i..]); + } + } + extension + } + + pub fn Get_file_name(&self) -> &str { + let mut Last_index = 0; + for (i, c) in self.0.chars().enumerate() { + if c == Separator { + Last_index = i; + } + } + if Last_index >= self.0.len() { + return &self.0[Last_index..]; + } + &self.0[Last_index + 1..] + } + + pub fn Get_relative_to(&self, Path: &Path_owned_type) -> Option { + if !self.0.starts_with(Path.0.as_str()) { + return None; + } + + Some(Path_owned_type(self.0[Path.0.len()..].to_string())) + } + + pub fn Canonicalize(mut self) -> Self { + let mut Stack: Vec<&str> = Vec::new(); + + if self.Is_absolute() { + Stack.push(""); + } + + for Component in self.0.split('/') { + match Component { + ".." => { + Stack.pop(); + } + "." | "" => continue, + _ => Stack.push(Component), + } + } + + self.0 = Stack.join("/"); + + self + } +} + +pub fn Is_valid_string(String: &str) -> bool { + let Invalid = ['\0', ':', '*', '?', '"', '<', '>', '|', ' ']; + + if String.is_empty() { + // Empty string is not valid. + return false; + } + + for Character in String.chars() { + // Check if the string contains invalid characters. + if Invalid.contains(&Character) { + return false; + } + } + + if String.ends_with(Separator) && String.len() > 1 { + // Check if the string ends with a separator and is not the root directory. + return false; + } + + true +} + +impl TryFrom<&str> for Path_owned_type { + type Error = (); + + fn try_from(item: &str) -> Result { + if Is_valid_string(item) { + Ok(Path_owned_type(item.to_string())) + } else { + Err(()) + } + } +} + +impl TryFrom for Path_owned_type { + type Error = (); + + fn try_from(item: String) -> Result { + if Is_valid_string(&item) { + Ok(Path_owned_type(item)) + } else { + Err(()) + } + } +} + +impl Display for Path_owned_type { + fn fmt(&self, Formatter: &mut Formatter) -> Result<(), std::fmt::Error> { + write!(Formatter, "{}", self.0) + } +} + +impl AsRef for Path_owned_type { + fn as_ref(&self) -> &str { + self.0.as_str() + } +} + +impl PartialEq for Path_owned_type { + fn eq(&self, other: &Self) -> bool { + self.0 == other.0 + } +} + +impl Deref for Path_owned_type { + type Target = Path_type; + + fn deref(&self) -> &Self::Target { + unsafe { Path_type::New_unchecked(self.0.as_str()) } + } +} + +impl AsRef for Path_owned_type { + fn as_ref(&self) -> &Path_type { + self + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn Test_path_addition() { + let Path = Path_owned_type::try_from("/").unwrap(); + assert_eq!(Path.As_str(), "/"); + let Path = Path.Append("Folder").unwrap(); + assert_eq!(Path.As_str(), "/Folder"); + let Path = Path.Append("File").unwrap(); + assert_eq!(Path.As_str(), "/Folder/File"); + } + + #[test] + fn Test_valid_string() { + assert!(Is_valid_string("Hello")); + assert!(Is_valid_string("Hello/World")); + assert!(Is_valid_string("Hello/World.txt")); + assert!(!Is_valid_string("Hello/World.txt/")); + assert!(!Is_valid_string("Hello/World.txt:")); + assert!(!Is_valid_string("Hello/World.txt*")); + assert!(!Is_valid_string("Hello/World.txt?")); + assert!(!Is_valid_string("Hello/World.txt\"")); + assert!(!Is_valid_string("Hello/World.txt<")); + assert!(!Is_valid_string("Hello/World.txt>")); + assert!(!Is_valid_string("Hello/World.txt|")); + assert!(!Is_valid_string("Hello/World.txt ")); + assert!(!Is_valid_string("Hello/World.txt\0")); + assert!(!Is_valid_string("")); + assert!(!Is_valid_string("Hello/Wo rld.txt/")); + } + + #[test] + fn Test_canonicalize() { + let Path = Path_owned_type::try_from("/home/../home/user/./file.txt").unwrap(); + assert_eq!(Path.Canonicalize().As_str(), "/home/user/file.txt"); + + let Path = Path_owned_type::try_from("./home/../home/user/./file.txt").unwrap(); + assert_eq!(Path.Canonicalize().As_str(), "home/user/file.txt"); + } +} diff --git a/Modules/File_system/src/Generics/Fundamentals/Path/Path_reference.rs b/Modules/File_system/src/Generics/Fundamentals/Path/Path_reference.rs new file mode 100644 index 0000000..d59f747 --- /dev/null +++ b/Modules/File_system/src/Generics/Fundamentals/Path/Path_reference.rs @@ -0,0 +1,290 @@ +use std::borrow::Borrow; + +use super::*; + +/// A borrowed path type. +/// The implementation is very similar to the standard library's `std::path::Path`. +/// However, this implementation is more lightweight and allows for std-less usage. +#[derive(Debug, PartialEq, Eq, Hash)] +#[repr(transparent)] +pub struct Path_type(str); + +impl Path_type { + pub fn Get_root() -> &'static Path_type { + unsafe { Self::New_unchecked("/") } + } + + pub fn Get_empty() -> &'static Path_type { + unsafe { Self::New_unchecked("") } + } + + /// # Safety + /// The caller must ensure that the string is a valid path string. + pub unsafe fn New_unchecked + ?Sized>(Path: &S) -> &Path_type { + unsafe { &*(Path.as_ref() as *const str as *const Path_type) } + } + + pub fn New + ?Sized>(Path: &S) -> Option<&Path_type> { + let Path = if Path.as_ref().ends_with(Separator) && Path.as_ref().len() > 1 { + &Path.as_ref()[..Path.as_ref().len() - 1] + } else { + Path.as_ref() + }; + + if Is_valid_string(Path) { + Some(unsafe { Self::New_unchecked(Path) }) + } else { + None + } + } + + pub fn Is_absolute(&self) -> bool { + self.0.starts_with('/') + } + + pub fn Is_root(&self) -> bool { + &self.0 == "/" + } + + pub fn Go_parent(&self) -> Option<&Path_type> { + let Characters_to_remove = match self.0.rfind(Separator) { + Some(index) => index, + None => { + // If there is no separator, the path is either empty or relative to the current directory. + if self.Get_length() > 0 { + // Relative to the current directory. + return Some(Self::Get_empty()); + } else { + return None; + } + } + }; + + if Characters_to_remove == 0 { + if self.Get_length() == 1 { + return None; + } + + if self.Is_absolute() { + return Some(Self::Get_root()); + } else { + return Some(unsafe { Self::New_unchecked("") }); + } + } + + Some(unsafe { Self::New_unchecked(&self.0[..Characters_to_remove]) }) + } + + pub fn Get_file_prefix(&self) -> Option<&str> { + let Extension_start = self + .0 + .rfind(Extension_separator) + .or_else(|| Some(self.Get_length()))?; // Find the extension separator. + let File_prefix_start = self.0.rfind(Separator).map(|i| i + 1).unwrap_or(0); // Find the file prefix start. + + if Extension_start <= File_prefix_start { + return None; + } + + Some(&self.0[File_prefix_start..Extension_start]) + } + + pub fn Get_file_name(&self) -> Option<&str> { + let File_prefix_start = self.0.rfind(Separator).map(|i| i + 1).unwrap_or(0); // Find the file prefix start. + + if File_prefix_start >= self.Get_length() { + return None; + } + + Some(&self.0[File_prefix_start..]) + } + + pub fn Get_extension(&self) -> Option<&str> { + let Extension_start = self.0.rfind(Extension_separator)?; + + Some(&self.0[Extension_start..]) + } + + pub fn Set_extension(&self, Extension: &str) -> Option { + let Extension_start = self + .0 + .rfind(Extension_separator) + .unwrap_or(self.Get_length()); + + Some(unsafe { + Path_owned_type::New_unchecked(format!("{}{}", &self.0[..Extension_start], Extension)) + }) + } + + pub fn Strip_prefix<'b>(&'b self, Path_prefix: &Path_type) -> Option<&'b Path_type> { + let mut Stripped_prefix = self.0.strip_prefix(&Path_prefix.0)?; + + if Stripped_prefix.starts_with(Separator) { + Stripped_prefix = &Stripped_prefix[1..]; + } + + Self::New(Stripped_prefix) + } + + pub fn Strip_suffix<'b>(&'b self, Path_suffix: &Path_type) -> Option<&'b Path_type> { + Self::New(self.0.strip_suffix(&Path_suffix.0)?) + } + + pub fn Get_components(&self) -> Components_type { + Components_type::New(self) + } + + pub fn Join(&self, Path: &Path_type) -> Option { + self.to_owned().Join(Path) + } + + pub fn Append(&self, Path: &str) -> Option { + self.to_owned().Append(Path) + } + + pub fn Get_length(&self) -> usize { + self.0.len() + } + + pub fn As_str(&self) -> &str { + &self.0 + } +} + +#[cfg(feature = "std")] +impl AsRef for Path_type { + fn as_ref(&self) -> &std::path::Path { + std::path::Path::new(&self.0) + } +} + +impl ToOwned for Path_type { + type Owned = Path_owned_type; + + fn to_owned(&self) -> Self::Owned { + unsafe { Path_owned_type::New_unchecked(self.0.to_string()) } + } + + fn clone_into(&self, target: &mut Self::Owned) { + *target = self.to_owned(); + } +} + +impl Borrow for Path_owned_type { + fn borrow(&self) -> &Path_type { + unsafe { Path_type::New_unchecked(&self.0) } + } +} + +impl AsRef for &Path_type { + fn as_ref(&self) -> &str { + &self.0 + } +} + +impl AsRef for Path_type { + fn as_ref(&self) -> &Path_type { + self + } +} + +#[cfg(test)] +mod Tests { + use super::*; + + #[test] + fn Test_strip_prefix() { + let Path = Path_type::New("/home/user/file.txt").unwrap(); + let Prefix = Path_type::New("/home/user").unwrap(); + assert_eq!(Path.Strip_prefix(Prefix).unwrap().As_str(), "file.txt"); + + let Invalid_prefix = Path_type::New("/home/invalid/").unwrap(); + assert_eq!(Path.Strip_prefix(Invalid_prefix), None); + } + + #[test] + fn Test_strip_suffix() { + let Path = Path_type::New("/home/user/file.txt").unwrap(); + let Suffix = Path_type::New("user/file.txt").unwrap(); + assert_eq!(Path.Strip_suffix(Suffix).unwrap().As_str(), "/home"); + + let Invalid_suffix = Path_type::New("user/invalid.txt").unwrap(); + assert_eq!(Path.Strip_suffix(Invalid_suffix), None); + } + + #[test] + fn Test_go_parent() { + let Path = Path_type::New("/home/user/file.txt").unwrap(); + assert_eq!(&Path.Go_parent().unwrap().0, "/home/user"); + assert_eq!(&Path.Go_parent().unwrap().Go_parent().unwrap().0, "/home"); + assert_eq!( + &Path + .Go_parent() + .unwrap() + .Go_parent() + .unwrap() + .Go_parent() + .unwrap() + .0, + "/" + ); + assert_eq!( + Path.Go_parent() + .unwrap() + .Go_parent() + .unwrap() + .Go_parent() + .unwrap() + .Go_parent(), + None + ); + + let Path = Path_type::New("home/user/file.txt").unwrap(); + assert_eq!(&Path.Go_parent().unwrap().0, "home/user"); + assert_eq!(&Path.Go_parent().unwrap().Go_parent().unwrap().0, "home"); + assert_eq!( + &Path + .Go_parent() + .unwrap() + .Go_parent() + .unwrap() + .Go_parent() + .unwrap() + .0, + "" + ); + } + + #[test] + fn Test_path_file() { + // Regular case + let Path = Path_type::New("/Directory/File.txt").unwrap(); + assert_eq!(Path.Get_extension(), Some(".txt")); + assert_eq!(Path.Get_file_prefix(), Some("File")); + assert_eq!(Path.Get_file_name(), Some("File.txt")); + + // No extension + let Path = Path_type::New("/Directory/File").unwrap(); + assert_eq!(Path.Get_extension(), None); + assert_eq!(Path.Get_file_prefix(), Some("File")); + assert_eq!(Path.Get_file_name(), Some("File")); + + // No file prefix + let Path = Path_type::New("File.txt").unwrap(); + assert_eq!(Path.Get_extension(), Some(".txt")); + assert_eq!(Path.Get_file_prefix(), Some("File")); + assert_eq!(Path.Get_file_name(), Some("File.txt")); + + // No file prefix or extension + let Path = Path_type::New("/").unwrap(); + assert_eq!(Path.Get_extension(), None); + assert_eq!(Path.Get_file_prefix(), None); + assert_eq!(Path.Get_file_name(), None); + + // No file prefix or extension + let Path = Path_type::New("File").unwrap(); + assert_eq!(Path.Get_extension(), None); + assert_eq!(Path.Get_file_prefix(), Some("File")); + assert_eq!(Path.Get_file_name(), Some("File")); + } +} diff --git a/Modules/File_system/src/Generics/Fundamentals/Path/mod.rs b/Modules/File_system/src/Generics/Fundamentals/Path/mod.rs new file mode 100644 index 0000000..fdcb15c --- /dev/null +++ b/Modules/File_system/src/Generics/Fundamentals/Path/mod.rs @@ -0,0 +1,10 @@ +mod Components; +mod Path_owned; +mod Path_reference; + +pub use Components::*; +pub use Path_owned::*; +pub use Path_reference::*; + +pub const Separator: char = '/'; +pub const Extension_separator: char = '.'; diff --git a/Modules/File_system/src/Generics/Fundamentals/Permission.rs b/Modules/File_system/src/Generics/Fundamentals/Permission.rs new file mode 100644 index 0000000..ef906f2 --- /dev/null +++ b/Modules/File_system/src/Generics/Fundamentals/Permission.rs @@ -0,0 +1,259 @@ +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct Permissions_type(u16); + +impl Permissions_type { + /// Creates a new permission. + pub fn New(User: &Permission_type, Group: &Permission_type, Others: &Permission_type) -> Self { + Self(0).Set_user(User).Set_group(Group).Set_others(Others) + } + + /// Creates a new permission with full access (read, write, execute) for all (user, group, others). + pub fn New_all_full() -> Self { + Self::New( + &Permission_type::New_full(), + &Permission_type::New_full(), + &Permission_type::New_full(), + ) + } + + /// Creates a new permission with full access (read, write, execute) for user. No access for group and others. + pub fn New_user_full() -> Self { + Self::New( + &Permission_type::New_full(), + &Permission_type::New_none(), + &Permission_type::New_none(), + ) + } + + /// Creates a new permission with read write access for user. No access for group and others. + pub fn New_user_read_write() -> Self { + Self::New( + &Permission_type::New_read_write(), + &Permission_type::New_none(), + &Permission_type::New_none(), + ) + } + + /// Creates a new permission with read access for user. No access for group and others. + pub fn New_standard_directory() -> Self { + Self::New( + &Permission_type::New_full(), + &Permission_type::New_write(), + &Permission_type::New_execute(), + ) + } + + /// Creates a new permission with read access for user. No access for group and others. + pub fn New_standard_file() -> Self { + Self::New( + &Permission_type::New_full(), + &Permission_type::New_read(), + &Permission_type::New_none(), + ) + } + + /// Sets the permission for the user. + pub fn Set_user(mut self, User: &Permission_type) -> Self { + self.0 = (self.0 & 0o077) | (User.To_unix() as u16) << 6; + self + } + + /// Sets the permission for the group. + pub fn Set_group(mut self, Group: &Permission_type) -> Self { + self.0 = (self.0 & 0o707) | (Group.To_unix() as u16) << 3; + self + } + + /// Sets the permission for others. + pub fn Set_others(mut self, Others: &Permission_type) -> Self { + self.0 = (self.0 & 0o770) | Others.To_unix() as u16; + self + } + + /// Gets the permission for the user. + pub fn Get_user(&self) -> Permission_type { + Permission_type::From_unix((self.0 >> 6) as u8).unwrap() + } + + /// Gets the permission for the group. + pub fn Get_group(&self) -> Permission_type { + Permission_type::From_unix(((self.0 >> 3) & 0b111) as u8).unwrap() + } + + /// Gets the permission for others. + pub fn Get_others(&self) -> Permission_type { + Permission_type::From_unix((self.0 & 0b111) as u8).unwrap() + } + + /// Converts the permission to a Unix permission. + pub fn From_unix(Unix: u16) -> Option { + if Unix > 0o777 { + return None; + } + + Some(Self(Unix)) + } + + /// Converts the permission to a Unix permission. + pub fn To_unix(&self) -> u16 { + self.0 + } +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct Permission_type(u8); + +impl Permission_type { + /// Creates a new permission. + pub fn New(Read: bool, Write: bool, Execute: bool) -> Self { + Self((Read as u8) << 2 | (Write as u8) << 1 | Execute as u8) + } + + /// Creates a new permission with read access (equivalent to Unix permission 4). + pub fn New_read() -> Self { + Self::New(true, false, false) + } + + /// Creates a new permission with write access (equivalent to Unix permission 2). + pub fn New_write() -> Self { + Self::New(false, true, false) + } + + /// Creates a new permission with execute access (equivalent to Unix permission 1). + pub fn New_execute() -> Self { + Self::New(false, false, true) + } + + /// Creates a new permission with full access (equivalent to Unix permission 7). + pub fn New_full() -> Self { + Self::New(true, true, true) + } + + /// Creates a new permission with no access (equivalent to Unix permission 0). + pub fn New_read_write() -> Self { + Self::New(true, true, false) + } + + /// Creates a new permission with no access (equivalent to Unix permission 0). + pub fn New_none() -> Self { + Self::New(false, false, false) + } + + /// Sets the read permission. + pub fn Set_read(mut self, Read: bool) -> Self { + self.0 = (self.0 & 0b011) | (Read as u8) << 2; + self + } + + /// Sets the write permission. + pub fn Set_write(mut self, Write: bool) -> Self { + self.0 = (self.0 & 0b101) | (Write as u8) << 1; + self + } + + /// Sets the execute permission. + pub fn Set_execute(mut self, Execute: bool) -> Self { + self.0 = (self.0 & 0b110) | Execute as u8; + self + } + + /// Gets the read permission. + pub fn Get_read(&self) -> bool { + self.0 & 0b100 != 0 + } + + /// Gets the write permission. + pub fn Get_write(&self) -> bool { + self.0 & 0b010 != 0 + } + + /// Gets the execute permission. + pub fn Get_execute(&self) -> bool { + self.0 & 0b001 != 0 + } + + /// Converts the permission to a Unix permission. + pub fn To_unix(&self) -> u8 { + self.0 + } + + /// Creates a permission from a Unix permission. + pub fn From_unix(Unix: u8) -> Option { + if Unix > 0b111 { + return None; + } + + Some(Self(Unix)) + } +} + +#[cfg(test)] +mod Tests { + use super::*; + + #[test] + fn Test_new_permissions() { + let user = Permission_type::New(true, false, false); // Read only + let group = Permission_type::New(false, true, false); // Write only + let others = Permission_type::New(false, false, true); // Execute only + let permissions = Permissions_type::New(&user, &group, &others); + assert_eq!(permissions.0, 0b100_010_001); + } + + #[test] + fn Test_new_permission() { + let permissions = Permissions_type::New_all_full(); + assert_eq!(permissions.0, 0b111_111_111); + + let permissions = Permissions_type::New_user_full(); + assert_eq!(permissions.0, 0b111_000_000); + + let permissions = Permissions_type::New_user_read_write(); + assert_eq!(permissions.0, 0b110_000_000); + } + + #[test] + fn Test_permission_type_to_unix() { + let read = Permission_type::New_read(); + assert_eq!(read.To_unix(), 4); + let write = Permission_type::New_write(); + assert_eq!(write.To_unix(), 2); + let execute = Permission_type::New_execute(); + assert_eq!(execute.To_unix(), 1); + let full = Permission_type::New_full(); + assert_eq!(full.To_unix(), 7); + let none = Permission_type::New_none(); + assert_eq!(none.To_unix(), 0); + } + + #[test] + fn Test_permission_type_from_unix() { + let Read = Permission_type::From_unix(4).unwrap(); + assert!(Read.Get_read() && !Read.Get_write() && !Read.Get_execute()); + let Write = Permission_type::From_unix(2).unwrap(); + assert!(!Write.Get_read() && Write.Get_write() && !Write.Get_execute()); + let Execute = Permission_type::From_unix(1).unwrap(); + assert!(!Execute.Get_read() && !Execute.Get_write() && Execute.Get_execute()); + let Full = Permission_type::From_unix(7).unwrap(); + assert!(Full.Get_read() && Full.Get_write() && Full.Get_execute()); + let No = Permission_type::From_unix(0).unwrap(); + assert!(!No.Get_read() && !No.Get_write() && !No.Get_execute()); + } + + #[test] + fn Test_permissions_type_from_unix() { + let Permissions = Permissions_type::From_unix(0b101_101_101).unwrap(); + assert_eq!(Permissions.Get_user().To_unix(), 5); + assert_eq!(Permissions.Get_group().To_unix(), 5); + assert_eq!(Permissions.Get_others().To_unix(), 5); + } + + #[test] + fn Test_permissions_type_to_unix() { + let User = Permission_type::New(true, false, true); // Read and execute + let Group = Permission_type::New(true, true, false); // Read and write + let Others = Permission_type::New(false, true, true); // Write and execute + let Permissions = Permissions_type::New(&User, &Group, &Others); + assert_eq!(Permissions.To_unix(), 0b101_110_011); + } +} diff --git a/Modules/File_system/src/Generics/Fundamentals/mod.rs b/Modules/File_system/src/Generics/Fundamentals/mod.rs index 10d829a..71af961 100644 --- a/Modules/File_system/src/Generics/Fundamentals/mod.rs +++ b/Modules/File_system/src/Generics/Fundamentals/mod.rs @@ -1,46 +1,64 @@ -use std::{ops, u64}; +use std::ops; -pub mod Path; +mod Flags; +mod Identifiers; +mod Path; +mod Permission; + +pub use Flags::*; +pub use Identifiers::*; pub use Path::*; -use Shared::Discriminant_trait; +pub use Permission::*; #[derive(Default, PartialOrd, PartialEq, Eq, Ord, Clone, Copy, Debug)] #[repr(transparent)] -pub struct Size_type(pub u64); -pub type Signed_size_type = i64; +pub struct Size_type(u64); -pub enum Position_type { - Start(Size_type), - Current(Signed_size_type), - End(Signed_size_type), +impl PartialEq for Size_type { + fn eq(&self, other: &usize) -> bool { + self.0 == *other as u64 + } } -impl Position_type { - pub fn From(Discriminant: u32, Value: u64) -> Self { - match Discriminant { - 0 => Position_type::Start(Size_type(Value)), - 1 => Position_type::Current(Value as i64), - 2 => Position_type::End(Value as i64), - _ => panic!("Invalid discriminant"), - } +impl From for Size_type { + fn from(item: usize) -> Self { + Size_type(item as u64) } } -impl Discriminant_trait for Position_type { - fn Get_discriminant(&self) -> u32 { - match self { - Position_type::Start(_) => 0, - Position_type::Current(_) => 1, - Position_type::End(_) => 2, - } +impl From for Size_type { + fn from(item: u64) -> Self { + Size_type(item) + } +} + +impl From for usize { + fn from(item: Size_type) -> Self { + item.0 as usize } +} - fn From_discriminant(Discriminant: u32) -> Self { - match Discriminant { - 0 => Position_type::Start(Size_type::default()), - 1 => Position_type::Current(0), - 2 => Position_type::End(0), - _ => panic!("Invalid discriminant"), +impl From for u64 { + fn from(item: Size_type) -> Self { + item.0 + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[repr(C)] +pub enum Position_type { + Start(u64), + Current(i64), + End(i64), +} + +#[cfg(feature = "std")] +impl From for std::io::SeekFrom { + fn from(Position: Position_type) -> Self { + match Position { + Position_type::Start(Item) => std::io::SeekFrom::Start(Item), + Position_type::Current(Item) => std::io::SeekFrom::Current(Item), + Position_type::End(Item) => std::io::SeekFrom::End(Item), } } } @@ -61,15 +79,3 @@ impl ops::Add for Size_type { Size_type(self.0 + rhs.0) } } - -impl From for Size_type { - fn from(item: u64) -> Self { - Size_type(item) - } -} - -impl From for Size_type { - fn from(item: usize) -> Self { - Size_type(item as u64) - } -} diff --git a/Modules/File_system/src/Generics/Pipe/File_system.rs b/Modules/File_system/src/Generics/Pipe/File_system.rs new file mode 100644 index 0000000..ea94207 --- /dev/null +++ b/Modules/File_system/src/Generics/Pipe/File_system.rs @@ -0,0 +1,399 @@ +use std::{collections::HashMap, time::Duration}; + +use Task::{Task_identifier_type, Task_type}; + +use crate::Prelude::{ + Error_type, File_identifier_type, Flags_type, Mode_type, Result, Size_type, Status_type, +}; + +#[derive(Eq, PartialEq, Hash, Clone, Copy)] +#[repr(transparent)] +pub struct Named_pipe_identifier_type(u32); + +impl Named_pipe_identifier_type { + pub const MAX: u32 = 0xFFFF_FFFF; +} + +impl From for Named_pipe_identifier_type { + fn from(Identifier: u32) -> Self { + Named_pipe_identifier_type(Identifier) + } +} + +impl From for u32 { + fn from(Identifier: Named_pipe_identifier_type) -> Self { + Identifier.0 + } +} + +impl From<[u8; 4]> for Named_pipe_identifier_type { + fn from(Identifier: [u8; 4]) -> Self { + Named_pipe_identifier_type(u32::from_ne_bytes(Identifier)) + } +} + +impl From for [u8; 4] { + fn from(Identifier: Named_pipe_identifier_type) -> Self { + Identifier.0.to_ne_bytes() + } +} + +use super::Pipe_type; + +pub struct Pipes_file_system_type { + Named_pipes: HashMap, + Opened_pipes: HashMap, +} + +impl Pipes_file_system_type { + pub fn New() -> Self { + Self { + Named_pipes: HashMap::new(), + Opened_pipes: HashMap::new(), + } + } + + fn Get_named_pipe_identifier(&self) -> Option { + (0..=Named_pipe_identifier_type::MAX) + .find(|&Identifier| !self.Named_pipes.contains_key(&Identifier.into())) + .map(|Identifier| Identifier.into()) + } + + fn Get_local_file_identifier( + Task_identifier: Task_identifier_type, + File_identifier: File_identifier_type, + ) -> u32 { + let File_identifier: u16 = File_identifier.into(); + let Task_identifier: u32 = Task_identifier.into(); + Task_identifier << 16 | File_identifier as u32 + } + + fn Get_new_file_identifier( + &self, + Task_identifier: Task_identifier_type, + ) -> Option { + let Start = Self::Get_local_file_identifier(Task_identifier, File_identifier_type::from(0)); + let End = + Self::Get_local_file_identifier(Task_identifier, File_identifier_type::from(0xFFFF)); + + for File_identifier in Start..=End { + if !self.Opened_pipes.contains_key(&File_identifier) { + return Some(File_identifier_type::from(File_identifier as u16)); + // Remove the task identifier and keep the file identifier. + } + } + + None + } + + pub fn Create_named_pipe(&mut self, Size: usize) -> Result { + let Identifier = self + .Get_named_pipe_identifier() + .ok_or(Error_type::Too_many_open_files)?; + + self.Named_pipes.insert(Identifier, Pipe_type::New(Size)); + + Ok(Identifier) + } + + pub fn Create_unnamed_pipe( + &mut self, + Task_identifier: Task_identifier_type, + Status: Status_type, + Size: usize, + ) -> Result<(File_identifier_type, File_identifier_type)> { + let Pipe = Pipe_type::New(Size); + + let New_file_identifier_read = self + .Get_new_file_identifier(Task_identifier) + .ok_or(Error_type::Too_many_open_files)?; + + self.Opened_pipes.insert( + Self::Get_local_file_identifier(Task_identifier, New_file_identifier_read), + ( + Pipe.clone(), + Flags_type::New(Mode_type::Read_only(), Some(Status)), + ), + ); + + let New_file_identifier_write = self + .Get_new_file_identifier(Task_identifier) + .ok_or(Error_type::Too_many_open_files)?; + + self.Opened_pipes.insert( + Self::Get_local_file_identifier(Task_identifier, New_file_identifier_write), + (Pipe, Flags_type::New(Mode_type::Write_only(), Some(Status))), + ); + + Ok((New_file_identifier_read, New_file_identifier_write)) + } + + pub fn Open( + &mut self, + Task_identifier: Task_identifier_type, + Identifier: Named_pipe_identifier_type, + Flags: Flags_type, + ) -> Result { + let Named_pipe = self + .Named_pipes + .get(&Identifier) + .ok_or(Error_type::Not_found)?; + + let File_identifier = self + .Get_new_file_identifier(Task_identifier) + .ok_or(Error_type::Too_many_open_files)?; + + let Local_file_identifier = + Self::Get_local_file_identifier(Task_identifier, File_identifier); + + self.Opened_pipes + .insert(Local_file_identifier, (Named_pipe.clone(), Flags)); + + Ok(File_identifier) + } + + pub fn Close( + &mut self, + Task: Task::Task_identifier_type, + File: File_identifier_type, + ) -> Result<()> { + let Local_file_identifier = Self::Get_local_file_identifier(Task, File); + + self.Opened_pipes + .remove(&Local_file_identifier) + .ok_or(Error_type::Invalid_identifier)?; + + Ok(()) + } + + pub fn Close_all(&mut self, Task: Task::Task_identifier_type) -> Result<()> { + let Start = Self::Get_local_file_identifier(Task, File_identifier_type::from(0)); + let End = Self::Get_local_file_identifier(Task, File_identifier_type::from(0xFFFF)); + + self.Opened_pipes.retain(|Key, _| { + if *Key >= Start && *Key <= End { + return false; + } + true + }); + + Ok(()) + } + + pub fn Delete(&mut self, Identifier: Named_pipe_identifier_type) -> Result<()> { + self.Named_pipes + .remove(&Identifier) + .ok_or(Error_type::Not_found)?; + + // The pipe is still opened by some tasks until they close it. + // The pipe will be deleted when the last task closes it. + + Ok(()) + } + + pub fn Read( + &mut self, + Task: Task::Task_identifier_type, + File: File_identifier_type, + Buffer: &mut [u8], + ) -> Result { + let Local_file_identifier = Self::Get_local_file_identifier(Task, File); + + let (Pipe, Flags) = self + .Opened_pipes + .get(&Local_file_identifier) + .ok_or(Error_type::Invalid_identifier)?; + + if !Flags.Get_mode().Get_read() { + return Err(Error_type::Invalid_mode); + } + + while let Err(Error) = Pipe.Read(Buffer) { + if let Error_type::File_system_full = Error { + if Flags.Get_status().Get_non_blocking() { + return Err(Error_type::Ressource_busy); + } else { + Task_type::Sleep(Duration::from_millis(5)); + } + } else { + return Err(Error); + } + } + + Ok(Buffer.len().into()) + } + + pub fn Write( + &mut self, + Task: Task::Task_identifier_type, + File: File_identifier_type, + Buffer: &[u8], + ) -> Result { + let Local_file_identifier = Self::Get_local_file_identifier(Task, File); + + let (Pipe, Mode) = self + .Opened_pipes + .get(&Local_file_identifier) + .ok_or(Error_type::Invalid_identifier)?; + + if !Mode.Get_mode().Get_write() { + return Err(Error_type::Invalid_mode); + } + + while let Err(Error) = Pipe.Write(Buffer) { + if let Error_type::File_system_full = Error { + if Mode.Get_status().Get_non_blocking() { + return Err(Error_type::Ressource_busy); + } else { + Task_type::Sleep(Duration::from_millis(5)); + } + } else { + return Err(Error); + } + } + + Ok(Buffer.len().into()) + } + + pub fn Get_size(&self, Identifier: Named_pipe_identifier_type) -> Result { + self.Named_pipes + .get(&Identifier) + .ok_or(Error_type::Not_found)? + .Get_size() + } + + pub fn Transfert_file_identifier( + &mut self, + Old_task: Task_identifier_type, + New_task: Task_identifier_type, + File: File_identifier_type, + ) -> Result { + let Local_file_identifier = Self::Get_local_file_identifier(Old_task, File); + + let (Pipe, Mode) = self + .Opened_pipes + .remove(&Local_file_identifier) + .ok_or(Error_type::Invalid_identifier)?; + + let New_file_identifier = self + .Get_new_file_identifier(New_task) + .ok_or(Error_type::Too_many_open_files)?; + + let Local_file_identifier = Self::Get_local_file_identifier(New_task, New_file_identifier); + + self.Opened_pipes + .insert(Local_file_identifier, (Pipe, Mode)); + + Ok(New_file_identifier) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn Test_new() { + let File_system = Pipes_file_system_type::New(); + assert!(File_system.Named_pipes.is_empty()); + assert!(File_system.Opened_pipes.is_empty()); + } + + #[test] + fn Test_get_local_file_identifier() { + let Task_identifier = Task_identifier_type::from(1); + let File_identifier = File_identifier_type::from(0); + let local_file_id = + Pipes_file_system_type::Get_local_file_identifier(Task_identifier, File_identifier); + assert_eq!(local_file_id, 65536); // 1 << 16 | 0 + } + + #[test] + fn Test_new_unnamed_pipe() { + let mut File_system = Pipes_file_system_type::New(); + let Task_identifier = Task_identifier_type::from(1); + let Size = 1024; + let (Read_identifier, Write_identifier) = File_system + .Create_unnamed_pipe( + Task_identifier, + Status_type::default().Set_non_blocking(true), + Size, + ) + .unwrap(); + assert_ne!(Read_identifier, Write_identifier); + assert!(File_system.Opened_pipes.contains_key( + &Pipes_file_system_type::Get_local_file_identifier(Task_identifier, Read_identifier) + )); + assert!(File_system.Opened_pipes.contains_key( + &Pipes_file_system_type::Get_local_file_identifier(Task_identifier, Write_identifier) + )); + } + + #[test] + fn Test_close_all() { + let mut File_system = Pipes_file_system_type::New(); + let Task_identifier = Task_identifier_type::from(1); + let Size = 1024; + File_system + .Create_unnamed_pipe( + Task_identifier, + Status_type::default().Set_non_blocking(true), + Size, + ) + .unwrap(); + File_system + .Create_unnamed_pipe( + Task_identifier, + Status_type::default().Set_non_blocking(true), + Size, + ) + .unwrap(); + File_system + .Create_unnamed_pipe( + Task_identifier, + Status_type::default().Set_non_blocking(true), + Size, + ) + .unwrap(); + File_system.Close_all(Task_identifier).unwrap(); + assert!(File_system.Opened_pipes.is_empty()); + } + + #[test] + fn Test_delete_named_pipe() { + let mut File_system = Pipes_file_system_type::New(); + + let Size = 1024; + + let Identifier = File_system.Create_named_pipe(Size).unwrap(); + assert!(File_system.Delete(Identifier).is_ok()); + assert!(File_system.Named_pipes.is_empty()); + assert!(File_system.Delete(Identifier).is_err()); + } + + #[test] + fn Test_read_write_unnamed_pipe() { + let mut File_system = Pipes_file_system_type::New(); + let Task_identifier = Task_identifier_type::from(1); + let Size = 1024; + let (Read_identifier, Write_identifier) = File_system + .Create_unnamed_pipe( + Task_identifier, + Status_type::default().Set_non_blocking(true), + Size, + ) + .unwrap(); + + let Write_data = b"Hello, pipe!"; + File_system + .Write(Task_identifier, Write_identifier, Write_data) + .unwrap(); + + let mut Buffer = [0; 12]; + + let Read_data = File_system + .Read(Task_identifier, Read_identifier, &mut Buffer) + .unwrap(); + assert_eq!(Write_data, &Buffer[..Read_data.into()]); + } +} diff --git a/Modules/File_system/src/Generics/Pipe/Pipe.rs b/Modules/File_system/src/Generics/Pipe/Pipe.rs new file mode 100644 index 0000000..7852e15 --- /dev/null +++ b/Modules/File_system/src/Generics/Pipe/Pipe.rs @@ -0,0 +1,49 @@ +use std::sync::{Arc, RwLock}; + +use Shared::Ring_buffer_type; + +use crate::Prelude::{Error_type, Result, Size_type}; + +/// A pipe is a FIFO (ring) buffer that can be used to communicate between tasks. +#[derive(Clone)] +pub struct Pipe_type(Arc>>); + +impl Pipe_type { + /// Create a new pipe with a buffer of the specified size. + pub fn New(Buffer_size: usize) -> Self { + Self(Arc::new(RwLock::new(Ring_buffer_type::New(Buffer_size)))) + } + + pub fn Write(&self, Data: &[u8]) -> Result<()> { + let mut Inner = self.0.write()?; + + if Data.len() > Inner.Get_free_space() { + return Err(Error_type::File_system_full); + } + + for Byte in Data { + if !Inner.Push(*Byte) { + return Err(Error_type::File_system_full); + } + } + Ok(()) + } + + pub fn Read(&self, Data: &mut [u8]) -> Result<()> { + let mut Inner = self.0.write()?; + let Length = Data.len(); + + if Length > Inner.Get_used_space() { + return Err(Error_type::File_system_full); + } + + for Byte in Data { + *Byte = Inner.Pop().unwrap(); + } + Ok(()) + } + + pub fn Get_size(&self) -> Result { + Ok(self.0.read()?.Get_capacity().into()) + } +} diff --git a/Modules/File_system/src/Generics/Pipe/mod.rs b/Modules/File_system/src/Generics/Pipe/mod.rs new file mode 100644 index 0000000..b5ee399 --- /dev/null +++ b/Modules/File_system/src/Generics/Pipe/mod.rs @@ -0,0 +1,6 @@ +mod File_system; +#[allow(clippy::module_inception)] +mod Pipe; + +pub use File_system::*; +pub use Pipe::*; diff --git a/Modules/File_system/src/Generics/Virtual_file_system.rs b/Modules/File_system/src/Generics/Virtual_file_system.rs new file mode 100644 index 0000000..fe3f6f6 --- /dev/null +++ b/Modules/File_system/src/Generics/Virtual_file_system.rs @@ -0,0 +1,679 @@ +use std::{ + collections::HashMap, + sync::{Arc, RwLock, RwLockWriteGuard}, +}; + +use Task::Task_identifier_type; +use Users::{Group_identifier_type, Manager_type, User_identifier_type}; + +use super::{ + Error_type, File_system_identifier_type, File_system_traits, Flags_type, Mode_type, + Path_owned_type, Path_type, Permissions_type, + Pipe::{Named_pipe_identifier_type, Pipes_file_system_type}, + Position_type, Result, Size_type, Status_type, Type_type, Unique_file_identifier_type, +}; + +struct Internal_file_system_type { + pub Mount_point: Path_owned_type, + pub Inner: Box, +} + +#[derive(Clone)] +pub struct Virtual_file_system_type { + /// A reference to the task manager. + Task_manager: Task::Manager_type, + /// User manager. + User_manager: Users::Manager_type, + /// Mounted file systems. + File_systems: + Arc>>>, + /// Pipe file system + Pipes_file_system: Arc>, +} + +impl Virtual_file_system_type { + const Pipe_file_system_identifier: File_system_identifier_type = + File_system_identifier_type::New_from(0xFF); + + const Named_pipe_extension: &'static str = ".Xila_pipe"; + + pub fn New(Task_manager: Task::Manager_type, User_manager: Users::Manager_type) -> Self { + Virtual_file_system_type { + Task_manager, + User_manager, + File_systems: Arc::new(RwLock::new(HashMap::new())), + Pipes_file_system: Arc::new(RwLock::new(Pipes_file_system_type::New())), + } + } + + fn Get_new_file_system_identifier(&self) -> Option { + let File_systems = self.File_systems.read().ok()?; + + let mut File_system_identifier = File_system_identifier_type::New(); + + while File_systems.contains_key(&File_system_identifier) + || File_system_identifier == Self::Pipe_file_system_identifier + { + File_system_identifier += 1; + } + + Some(File_system_identifier) + } + + /// Mount a file system at a given mount point. + pub fn Mount( + &self, + File_system: Box, + Mount_point: impl AsRef, + ) -> Result { + if self.Exists(Mount_point.as_ref())? { + return Err(Error_type::Already_exists); + } + + let File_system_identifier = self + .Get_new_file_system_identifier() + .ok_or(Error_type::Too_many_mounted_file_systems)?; + + if !Mount_point.as_ref().Is_absolute() { + return Err(Error_type::Invalid_path); + } + + let mut File_systems = self.File_systems.write()?; + File_systems.insert( + File_system_identifier, + RwLock::new(Internal_file_system_type { + Mount_point: Mount_point.as_ref().to_owned(), + Inner: File_system, + }), + ); + + Ok(File_system_identifier) + } + + pub fn Unmount(&self, File_system_identifier: File_system_identifier_type) -> Result<()> { + let mut File_systems = self.File_systems.write()?; + File_systems + .remove(&File_system_identifier) + .ok_or(Error_type::Invalid_identifier)?; + + Ok(()) + } + + fn Get_file_system<'b>( + File_systems: &'b HashMap>, + Path: &'b dyn AsRef, + ) -> Result<(File_system_identifier_type, &'b Path_type)> { + let mut Result_score = 0; + let mut Result: Option<(File_system_identifier_type, &'b Path_type)> = None; + + for (File_system_identifier, File_system) in File_systems.iter() { + let File_system = File_system.read()?; + + if let Some(Relative_path) = Path.as_ref().Strip_prefix(&File_system.Mount_point) { + let Score = Relative_path.Get_length(); + if Score > Result_score { + Result_score = Score; + Result = Some((*File_system_identifier, Relative_path)); + } + } + } + + Result.ok_or(Error_type::Invalid_path) + } + + pub fn Open( + &self, + Path: impl AsRef, + Flags: Flags_type, + ) -> Result { + let File_systems = self.File_systems.read()?; // Get the file systems + + let (File_system_identifier, Relative_path) = Self::Get_file_system(&File_systems, &Path)?; // Get the file system identifier and the relative path + + let File_systems = self.File_systems.read()?; // Get the file systems + + let File_system = File_systems + .get(&File_system_identifier) + .ok_or(Error_type::Invalid_path)?; + + let Task_identifier = self.Task_manager.Get_current_task_identifier()?; + + let mut File_system = File_system.write()?; // Get the file system + + // - Check permissions + + self.Check_permissions(&File_system, Task_identifier, Relative_path, Flags)?; + + // - Open file + + match File_system + .Inner + .Open(Task_identifier, &Relative_path, Flags) + { + Ok(File_identifier) => Ok(Unique_file_identifier_type::New( + File_system_identifier, + File_identifier, + )), + Err(Error_type::Invalid_path) => { + if let Some(Self::Named_pipe_extension) = Relative_path.Get_extension() { + return Err(Error_type::Invalid_path); + } + + self.Open_named_pipe(Relative_path, Flags) + } + + Err(e) => Err(e), + } + } + + fn Check_permissions( + &self, + File_system: &RwLockWriteGuard, + Task_identifier: Task_identifier_type, + Relative_path: impl AsRef, + Flags: Flags_type, + ) -> Result<()> { + // - Check permissions + + let Permissions = File_system + .Inner + .Get_permissions(Task_identifier, &Relative_path)?; + + let (Owner_user, Owner_group) = File_system + .Inner + .Get_owner(Task_identifier, &Relative_path)?; + + let Task_user = self.Task_manager.Get_owner(Task_identifier)?; + + let Permission = if Task_user == Owner_user { + Permissions.Get_user() + } else if self.User_manager.Is_in_group(Task_user, Owner_group) { + Permissions.Get_group() + } else { + Permissions.Get_others() + }; + + if !Flags.Is_permission_granted(&Permission) { + return Err(Error_type::Permission_denied); + } + + Ok(()) + } + + fn Open_named_pipe( + &self, + Relative_path: impl AsRef, + Flags: Flags_type, + ) -> Result { + let Path = Relative_path + .as_ref() + .Set_extension(Self::Named_pipe_extension) + .ok_or(Error_type::Invalid_path)?; // Append the pipe extension + + let File = self.Open(Path, Mode_type::Read_only().into())?; // Open the file + + let mut Pipe_identifier = [0; 4]; + + let Bytes_read = self.Read(File, &mut Pipe_identifier)?; + + if Bytes_read != Pipe_identifier.len() { + return Err(Error_type::Invalid_path); + } + + let Pipe_identifier = Named_pipe_identifier_type::from(Pipe_identifier); + + let File_identifier = self.Pipes_file_system.write()?.Open( + self.Task_manager.Get_current_task_identifier()?, + Pipe_identifier, + Flags, + )?; + + Ok(Unique_file_identifier_type::New( + Self::Pipe_file_system_identifier, + File_identifier, + )) + } + + pub fn Close(&self, File: Unique_file_identifier_type) -> Result<()> { + let (File_system_identifier, File_identifier) = File.Split(); + + if File_system_identifier == Self::Pipe_file_system_identifier { + return self.Pipes_file_system.write()?.Close( + self.Task_manager.Get_current_task_identifier()?, + File_identifier, + ); + } + + let File_systems = self.File_systems.read()?; // Get the file systems + + let mut File_system = File_systems + .get(&File_system_identifier) + .ok_or(Error_type::Invalid_identifier)? + .write()?; // Get the file system + + let Task_identifier = self.Task_manager.Get_current_task_identifier()?; + + File_system.Inner.Close(Task_identifier, File_identifier) + } + + pub fn Read( + &self, + File_identifier: Unique_file_identifier_type, + Buffer: &mut [u8], + ) -> Result { + let (File_system_identifier, File_identifier) = File_identifier.Split(); + + if File_system_identifier == Self::Pipe_file_system_identifier { + return self.Pipes_file_system.write()?.Read( + self.Task_manager.Get_current_task_identifier()?, + File_identifier, + Buffer, + ); + } + + let Task_identifier = self.Task_manager.Get_current_task_identifier()?; + + let File_systems = self.File_systems.read()?; // Get the file systems + + let mut File_system = File_systems + .get(&File_system_identifier) + .ok_or(Error_type::Invalid_identifier)? + .write()?; // Get the file system + + File_system + .Inner + .Read(Task_identifier, File_identifier, Buffer) + } + + pub fn Write(&self, File: Unique_file_identifier_type, Buffer: &[u8]) -> Result { + let (File_system_identifier, File_identifier) = File.Split(); + + if File_system_identifier == Self::Pipe_file_system_identifier { + return self.Pipes_file_system.write()?.Write( + self.Task_manager.Get_current_task_identifier()?, + File_identifier, + Buffer, + ); + } + + let Task_identifier = self.Task_manager.Get_current_task_identifier()?; + + let File_systems = self.File_systems.read()?; // Get the file systems + + let File_system = File_systems + .get(&File_system_identifier) + .ok_or(Error_type::Invalid_identifier)?; + + let mut File_system = File_system.write()?; // Get the file system + + File_system + .Inner + .Write(Task_identifier, File_identifier, Buffer) + } + + pub fn Set_position( + &self, + File_identifier: Unique_file_identifier_type, + Position: &Position_type, + ) -> Result { + let Task_identifier = self.Task_manager.Get_current_task_identifier()?; + + let File_systems = self.File_systems.read()?; // Get the file systems + + let (File_system_identifier, File_identifier) = File_identifier.Split(); + + let mut File_system = File_systems + .get(&File_system_identifier) + .ok_or(Error_type::Invalid_identifier)? + .write()?; // Get the file system + + File_system + .Inner + .Set_position(Task_identifier, File_identifier, Position) + } + + pub fn Exists(&self, Path: impl AsRef) -> Result { + let File_systems = self.File_systems.read()?; // Get the file systems + + if File_systems.is_empty() { + return Ok(false); + } + + let (File_system_identifier, Relative_path) = Self::Get_file_system(&File_systems, &Path)?; // Get the file system identifier and the relative path + + let File_system = File_systems + .get(&File_system_identifier) + .ok_or(Error_type::Invalid_path)? + .read()?; // Get the file system + + File_system.Inner.Exists(&Relative_path) + } + + pub fn Get_size(&self, Path: impl AsRef) -> Result { + let File_systems = self.File_systems.read()?; // Get the file system + + let (File_system_identifier, Relative_path) = Self::Get_file_system(&File_systems, &Path)?; // Get the file system identifier and the relative path + + let File_system = File_systems + .get(&File_system_identifier) + .ok_or(Error_type::Invalid_path)? + .read()?; // Get the file system + + let Task_identifier = self.Task_manager.Get_current_task_identifier()?; + + File_system.Inner.Get_size(Task_identifier, &Relative_path) + } + + pub fn Get_type(&self, Path: impl AsRef) -> Result { + let File_systems = self.File_systems.read()?; // Get the file systems + + let (File_system_identifier, Relative_path) = Self::Get_file_system(&File_systems, &Path)?; // Get the file system identifier and the relative path + + let File_system = File_systems + .get(&File_system_identifier) + .ok_or(Error_type::Invalid_path)? + .read()?; // Get the file system + + let Task_identifier = self.Task_manager.Get_current_task_identifier()?; + + File_system.Inner.Get_type(Task_identifier, &Relative_path) + } + + pub fn Get_permissions(&self, Path: impl AsRef) -> Result { + if Path.as_ref().Is_root() { + return Ok(Permissions_type::New_all_full()); + } + + let File_systems = self.File_systems.read()?; // Get the file systems + + let (File_system_identifier, Relative_path) = Self::Get_file_system(&File_systems, &Path)?; // Get the file system identifier and the relative path + + let File_system = File_systems + .get(&File_system_identifier) + .ok_or(Error_type::Invalid_path)? + .read()?; // Get the file system + + let Task_identifier = self.Task_manager.Get_current_task_identifier()?; + + File_system + .Inner + .Get_permissions(Task_identifier, &Relative_path) + } + + pub fn Get_owner( + &self, + Path: impl AsRef, + ) -> Result<(User_identifier_type, Group_identifier_type)> { + let File_systems = self.File_systems.read()?; // Get the file systems + + let (File_system_identifier, Relative_path) = Self::Get_file_system(&File_systems, &Path)?; // Get the file system identifier and the relative path + + let File_system = File_systems + .get(&File_system_identifier) + .ok_or(Error_type::Invalid_path)? + .read()?; // Get the file system + + let Task_identifier = self.Task_manager.Get_current_task_identifier()?; + + File_system.Inner.Get_owner(Task_identifier, &Relative_path) + } + + pub fn Set_owner( + &self, + Path: impl AsRef, + User: Option, + Group: Option, + ) -> Result<()> { + let Task_identifier = self.Task_manager.Get_current_task_identifier()?; + + let Task_user = self.Task_manager.Get_owner(Task_identifier)?; + + if !Manager_type::Is_root(Task_user) { + return Err(Error_type::Permission_denied); + } + + let File_systems = self.File_systems.read()?; + + let (File_system_identifier, Relative_path) = Self::Get_file_system(&File_systems, &Path)?; // Get the file system identifier and the relative path + + let File_systems = self.File_systems.read()?; // Get the file systems + + let mut File_system = File_systems + .get(&File_system_identifier) + .ok_or(Error_type::Invalid_path)? + .write()?; + + File_system + .Inner + .Set_owner(Task_identifier, &Relative_path, User, Group) + } + + pub fn Set_permissions( + &self, + Path: impl AsRef, + Permissions: &Permissions_type, + ) -> Result<()> { + if Path.as_ref().Is_root() { + return Err(Error_type::Permission_denied); + } + + let File_systems = self.File_systems.read()?; + + let (File_system_identifier, Relative_path) = Self::Get_file_system(&File_systems, &Path)?; // Get the file system identifier and the relative path + + let File_systems = self.File_systems.read()?; // Get the file systems + + let File_system = File_systems + .get(&File_system_identifier) + .ok_or(Error_type::Invalid_path)?; + + let mut File_system = File_system.write()?; // Get the file system + + // - Check permissions + + let Task_identifier = self.Task_manager.Get_current_task_identifier()?; + + let Task_user = self.Task_manager.Get_owner(Task_identifier)?; + + let Owner = if Manager_type::Is_root(Task_user) { + true + } else { + let (Owner_user, _) = File_system + .Inner + .Get_owner(Task_identifier, &Relative_path)?; + + Task_user == Owner_user + }; + + if !Owner { + return Err(Error_type::Permission_denied); + } + + File_system + .Inner + .Set_permissions(Task_identifier, Permissions, &Relative_path) + } + + pub fn Close_all(&self, Task_identifier: Task_identifier_type) -> Result<()> { + let File_systems = self.File_systems.read()?; // Get the file systems + + for File_system in File_systems.values() { + File_system.write()?.Inner.Close_all(Task_identifier)?; + } + + self.Pipes_file_system.write()?.Close_all(Task_identifier)?; + + Ok(()) + } + + pub fn Create_named_pipe(&self, Path: &impl AsRef, Size: usize) -> Result<()> { + let Path = Path + .as_ref() + .Set_extension(Self::Named_pipe_extension) + .ok_or(Error_type::Invalid_path)?; // Append the pipe extension + + self.Create_file(&Path)?; // Create the special file + + let File = self.Open(&Path, Mode_type::Write_only().into())?; // Open the file + + let Pipe_identifier = self.Pipes_file_system.write()?.Create_named_pipe(Size)?; // Create the named pipe + + let Pipe_identifier: [u8; 4] = Pipe_identifier.into(); + + self.Write(File, &Pipe_identifier)?; // Write the pipe identifier + + Ok(()) + } + + pub fn Create_unnamed_pipe( + &self, + Size: usize, + Status: Status_type, + ) -> Result<(Unique_file_identifier_type, Unique_file_identifier_type)> { + let Task_identifier = self.Task_manager.Get_current_task_identifier()?; + + let (File_identifier_read, File_identifier_write) = self + .Pipes_file_system + .write()? + .Create_unnamed_pipe(Task_identifier, Status, Size)?; // Create the unnamed pipe + + Ok(( + Unique_file_identifier_type::New( + Self::Pipe_file_system_identifier, + File_identifier_read, + ), + Unique_file_identifier_type::New( + Self::Pipe_file_system_identifier, + File_identifier_write, + ), + )) + } + + pub fn Create_file(&self, Path: impl AsRef) -> Result<()> { + let Task_identifier = self.Task_manager.Get_current_task_identifier()?; + + let File_systems = self.File_systems.read()?; // Get the file systems + + let (File_system_identifier, Relative_path) = Self::Get_file_system(&File_systems, &Path)?; // Get the file system identifier and the relative path + + let mut File_system = File_systems + .get(&File_system_identifier) + .ok_or(Error_type::Invalid_path)? + .write()?; // Get the file system + + File_system + .Inner + .Create_file(Task_identifier, &Relative_path) + } + + pub fn Create_directory(&self, Path: impl AsRef, Recursive: bool) -> Result<()> { + if Recursive { + // If the directory already exists, return Ok(()) (only if recursive is true). + if self.Exists(Path.as_ref())? { + return Ok(()); + } + + // Create the parent directory recursively. + self.Create_directory( + Path.as_ref().Go_parent().ok_or(Error_type::Invalid_path)?, + true, + )? + } + + // Create current directory. + let Task_identifier = self.Task_manager.Get_current_task_identifier()?; + + let File_systems = self.File_systems.read()?; // Get the file systems + + let (File_system_identifier, Relative_path) = Self::Get_file_system(&File_systems, &Path)?; // Get the file system identifier and the relative path + + let mut File_system = File_systems + .get(&File_system_identifier) + .ok_or(Error_type::Invalid_path)? + .write()?; // Get the file system + + File_system + .Inner + .Create_directory(Task_identifier, &Relative_path) + } + + pub fn Delete(&self, Path: impl AsRef, Recursive: bool) -> Result<()> { + if Recursive { + todo!() + } + + // Delete current directory. + let Task_identifier = self.Task_manager.Get_current_task_identifier()?; + + let File_systems = self.File_systems.read()?; // Get the file systems + + let (File_system_identifier, Relative_path) = Self::Get_file_system(&File_systems, &Path)?; // Get the file system identifier and the relative path + + let mut File_system = File_systems + .get(&File_system_identifier) + .ok_or(Error_type::Invalid_path)? + .write()?; // Get the file system + + // Check if the user has the right to delete the file (write permission on the parent directory) + self.Check_permissions( + &File_system, + Task_identifier, + Relative_path.Go_parent().ok_or(Error_type::Invalid_path)?, + Mode_type::Write_only().into(), + )?; + + File_system.Inner.Delete(&Relative_path) + } + + pub fn Transfert_file( + &self, + File: Unique_file_identifier_type, + New_task: Task_identifier_type, + ) -> Result { + let Task_identifier = self.Task_manager.Get_current_task_identifier()?; + + let File_systems = self.File_systems.read()?; // Get the file systems + + let (File_system_identifier, File_identifier) = File.Split(); + + let New_file_identifier = if File_system_identifier == Self::Pipe_file_system_identifier { + self.Pipes_file_system.write()?.Transfert_file_identifier( + Task_identifier, + New_task, + File_identifier, + )? + } else { + File_systems + .get(&File_system_identifier) + .ok_or(Error_type::Invalid_identifier)? + .write()? + .Inner + .Transfert_file_identifier(Task_identifier, New_task, File_identifier)? + }; + + Ok(Unique_file_identifier_type::New( + File_system_identifier, + New_file_identifier, + )) + } + + pub fn Flush(&self, File: Unique_file_identifier_type) -> Result<()> { + let (File_system_identifier, File_identifier) = File.Split(); + + if File_system_identifier == Self::Pipe_file_system_identifier { + return Ok(()); // No need to flush a pipe. + // ? : Maybe we should return an error. + } + + let Task_identifier = self.Task_manager.Get_current_task_identifier()?; + + let File_systems = self.File_systems.read()?; // Get the file systems + + let mut File_system = File_systems + .get(&File_system_identifier) + .ok_or(Error_type::Invalid_identifier)? + .write()?; // Get the file system + + File_system.Inner.Flush(Task_identifier, File_identifier) + } +} diff --git a/Modules/File_system/src/Generics/mod.rs b/Modules/File_system/src/Generics/mod.rs index 3db6ceb..fe4b76d 100644 --- a/Modules/File_system/src/Generics/mod.rs +++ b/Modules/File_system/src/Generics/mod.rs @@ -1,9 +1,12 @@ -pub mod Error; -pub mod File; -pub mod File_system; -pub mod Fundamentals; +mod Error; +mod File; +mod File_system; +mod Fundamentals; +mod Pipe; +mod Virtual_file_system; pub use Error::*; pub use File::*; pub use File_system::*; pub use Fundamentals::*; +pub use Virtual_file_system::*; diff --git a/Modules/File_system/src/Prelude.rs b/Modules/File_system/src/Prelude.rs index 45cd3bf..1f5cac5 100644 --- a/Modules/File_system/src/Prelude.rs +++ b/Modules/File_system/src/Prelude.rs @@ -1,5 +1 @@ -pub use super::Generics::Fundamentals::*; - -pub use super::Generics::File::*; - -pub use super::Generics::File_system::*; +pub use crate::Generics::*; diff --git a/Modules/Graphics/Cargo.toml b/Modules/Graphics/Cargo.toml index d1e7008..a4a2a45 100644 --- a/Modules/Graphics/Cargo.toml +++ b/Modules/Graphics/Cargo.toml @@ -5,6 +5,7 @@ edition = "2021" [dependencies] cstr_core = "0.2.6" +Task = { path = "../Task" } [target.'cfg( target_os = "espidf" )'.dependencies] lvgl = { git = "https://github.com/lvgl/lv_binding_rust.git", default-features = false, features = [ diff --git a/Modules/Graphics/src/Window.rs b/Modules/Graphics/src/Window.rs index 85b940d..c7e6eb9 100644 --- a/Modules/Graphics/src/Window.rs +++ b/Modules/Graphics/src/Window.rs @@ -4,7 +4,7 @@ use lvgl::{ widgets::Label, LvError, NativeObject, Obj, Widget, }; -use Shared::Task_identifier_type; +use Task::Task_identifier_type; pub type Windows_indentifier_type = u16; diff --git a/Modules/Shared/src/Discriminant.rs b/Modules/Shared/src/Discriminant.rs deleted file mode 100644 index e90729a..0000000 --- a/Modules/Shared/src/Discriminant.rs +++ /dev/null @@ -1,18 +0,0 @@ -use std::num::NonZeroU32; - -pub trait Error_discriminant_trait: Clone { - fn Get_discriminant(&self) -> NonZeroU32; - fn From_discriminant(Discriminant: NonZeroU32) -> Self; -} - -pub trait Discriminant_trait { - fn Get_discriminant(&self) -> u32; - fn From_discriminant(Discriminant: u32) -> Self; -} - -pub fn From_result_to_u32(Result: &Result) -> u32 { - match Result { - Ok(_) => 0, - Err(Error) => Error.Get_discriminant().get(), - } -} diff --git a/Modules/Shared/src/Ring_buffer.rs b/Modules/Shared/src/Ring_buffer.rs new file mode 100644 index 0000000..fb68da8 --- /dev/null +++ b/Modules/Shared/src/Ring_buffer.rs @@ -0,0 +1,205 @@ +/// Lightweight ring buffer implementation. +pub struct Ring_buffer_type { + Buffer: Vec, + Head: usize, + Tail: usize, + Full: bool, +} + +impl Ring_buffer_type { + /// Create a new ring buffer with the specified capacity. + pub fn New(Capacity: usize) -> Self { + Ring_buffer_type { + Buffer: Vec::with_capacity(Capacity), + Head: 0, + Tail: 0, + Full: false, + } + } + + /// Add an element to the buffer. + pub fn Push(&mut self, Item: T) -> bool { + if self.Is_full() { + return false; + } + + if self.Buffer.len() < self.Buffer.capacity() { + self.Buffer.push(Item); + } else { + self.Buffer[self.Tail] = Item; + } + + self.Tail = (self.Tail + 1) % self.Get_capacity(); + + if self.Tail == self.Head { + self.Full = true; + } + + true + } + + /// Remove an element from the buffer. + pub fn Pop(&mut self) -> Option { + if self.Is_empty() { + return None; + } + let Item = self.Buffer[self.Head]; // The `Copy` trait is required here + self.Head = (self.Head + 1) % self.Buffer.capacity(); + self.Full = false; + Some(Item) + } + + /// Check if the buffer is empty. + pub fn Is_empty(&self) -> bool { + !self.Full && (self.Head == self.Tail) + } + + /// Check if the buffer is full. + pub fn Is_full(&self) -> bool { + self.Full + } + + /// Get the capacity of the buffer. + pub fn Get_capacity(&self) -> usize { + self.Buffer.capacity() + } + + /// Get the number of elements that are currently in the buffer. + pub fn Get_used_space(&self) -> usize { + if self.Full { + self.Get_capacity() + } else if self.Tail >= self.Head { + self.Tail - self.Head + } else { + self.Get_capacity() - self.Head + self.Tail + } + } + + /// Get the number of free elements in the buffer. + pub fn Get_free_space(&self) -> usize { + self.Get_capacity() - self.Get_used_space() + } +} + +#[cfg(test)] +mod Tests { + use super::*; + + #[test] + fn Test_ring_buffer() { + let mut Ring_buffer = Ring_buffer_type::New(3); + assert!(Ring_buffer.Is_empty()); + assert!(!Ring_buffer.Is_full()); + assert_eq!(Ring_buffer.Get_capacity(), 3); + assert_eq!(Ring_buffer.Get_used_space(), 0); + assert_eq!(Ring_buffer.Head, 0); + assert_eq!(Ring_buffer.Tail, 0); + + assert!(Ring_buffer.Push(1)); + assert!(!Ring_buffer.Is_empty()); + assert!(!Ring_buffer.Is_full()); + assert_eq!(Ring_buffer.Get_used_space(), 1); + assert_eq!(Ring_buffer.Head, 0); + assert_eq!(Ring_buffer.Tail, 1); + + assert!(Ring_buffer.Push(2)); + assert!(!Ring_buffer.Is_empty()); + assert!(!Ring_buffer.Is_full()); + assert_eq!(Ring_buffer.Get_used_space(), 2); + assert_eq!(Ring_buffer.Head, 0); + assert_eq!(Ring_buffer.Tail, 2); + + assert!(Ring_buffer.Push(3)); + assert!(!Ring_buffer.Is_empty()); + assert!(Ring_buffer.Is_full()); + assert_eq!(Ring_buffer.Get_used_space(), 3); + assert_eq!(Ring_buffer.Head, 0); + assert_eq!(Ring_buffer.Tail, 0); + + assert!(!Ring_buffer.Push(4)); + assert!(!Ring_buffer.Is_empty()); + assert!(Ring_buffer.Is_full()); + assert_eq!(Ring_buffer.Get_used_space(), 3); + assert_eq!(Ring_buffer.Head, 0); + assert_eq!(Ring_buffer.Tail, 0); + + assert_eq!(Ring_buffer.Pop(), Some(1)); + assert!(!Ring_buffer.Is_empty()); + assert!(!Ring_buffer.Is_full()); + assert_eq!(Ring_buffer.Get_used_space(), 2); + assert_eq!(Ring_buffer.Head, 1); + assert_eq!(Ring_buffer.Tail, 0); + + assert_eq!(Ring_buffer.Pop(), Some(2)); + assert!(!Ring_buffer.Is_empty()); + assert!(!Ring_buffer.Is_full()); + assert_eq!(Ring_buffer.Get_used_space(), 1); + assert_eq!(Ring_buffer.Head, 2); + assert_eq!(Ring_buffer.Tail, 0); + + assert_eq!(Ring_buffer.Pop(), Some(3)); + assert!(Ring_buffer.Is_empty()); + assert!(!Ring_buffer.Is_full()); + assert_eq!(Ring_buffer.Get_used_space(), 0); + assert_eq!(Ring_buffer.Head, 0); + assert_eq!(Ring_buffer.Tail, 0); + + assert_eq!(Ring_buffer.Pop(), None); + assert!(Ring_buffer.Is_empty()); + assert!(!Ring_buffer.Is_full()); + assert_eq!(Ring_buffer.Get_capacity(), 3); + assert_eq!(Ring_buffer.Get_used_space(), 0); + assert_eq!(Ring_buffer.Head, 0); + assert_eq!(Ring_buffer.Tail, 0); + + Ring_buffer.Push(4); + assert!(!Ring_buffer.Is_empty()); + assert!(!Ring_buffer.Is_full()); + assert_eq!(Ring_buffer.Get_used_space(), 1); + assert_eq!(Ring_buffer.Head, 0); + assert_eq!(Ring_buffer.Tail, 1); + + Ring_buffer.Push(5); + assert!(!Ring_buffer.Is_empty()); + assert!(!Ring_buffer.Is_full()); + assert_eq!(Ring_buffer.Get_used_space(), 2); + assert_eq!(Ring_buffer.Head, 0); + assert_eq!(Ring_buffer.Tail, 2); + + Ring_buffer.Push(6); + assert!(!Ring_buffer.Is_empty()); + assert!(Ring_buffer.Is_full()); + assert_eq!(Ring_buffer.Get_used_space(), 3); + assert_eq!(Ring_buffer.Head, 0); + assert_eq!(Ring_buffer.Tail, 0); + + assert_eq!(Ring_buffer.Pop(), Some(4)); + assert!(!Ring_buffer.Is_empty()); + assert!(!Ring_buffer.Is_full()); + assert_eq!(Ring_buffer.Get_used_space(), 2); + assert_eq!(Ring_buffer.Head, 1); + assert_eq!(Ring_buffer.Tail, 0); + + assert_eq!(Ring_buffer.Pop(), Some(5)); + assert!(!Ring_buffer.Is_empty()); + assert!(!Ring_buffer.Is_full()); + assert_eq!(Ring_buffer.Get_used_space(), 1); + assert_eq!(Ring_buffer.Head, 2); + assert_eq!(Ring_buffer.Tail, 0); + + assert_eq!(Ring_buffer.Pop(), Some(6)); + assert!(Ring_buffer.Is_empty()); + assert!(!Ring_buffer.Is_full()); + assert_eq!(Ring_buffer.Get_used_space(), 0); + assert_eq!(Ring_buffer.Head, 0); + assert_eq!(Ring_buffer.Tail, 0); + + assert_eq!(Ring_buffer.Pop(), None); + assert!(Ring_buffer.Is_empty()); + assert!(!Ring_buffer.Is_full()); + assert_eq!(Ring_buffer.Get_capacity(), 3); + assert_eq!(Ring_buffer.Get_used_space(), 0); + assert_eq!(Ring_buffer.Head, 0); + assert_eq!(Ring_buffer.Tail, 0); + } +} diff --git a/Modules/Shared/src/lib.rs b/Modules/Shared/src/lib.rs index 0552b69..4aaeede 100644 --- a/Modules/Shared/src/lib.rs +++ b/Modules/Shared/src/lib.rs @@ -1,16 +1,14 @@ #![allow(non_snake_case)] #![allow(non_camel_case_types)] -mod Discriminant; mod Error; mod Mutable_slice; mod Mutable_string; +mod Ring_buffer; mod Size; -pub use Discriminant::*; pub use Error::*; pub use Mutable_slice::*; pub use Mutable_string::*; +pub use Ring_buffer::*; pub use Size::*; - -pub type Task_identifier_type = u16; diff --git a/Modules/Task/Cargo.toml b/Modules/Task/Cargo.toml index 18e0803..e7330eb 100644 --- a/Modules/Task/Cargo.toml +++ b/Modules/Task/Cargo.toml @@ -4,3 +4,4 @@ version = "0.1.0" edition = "2021" [dependencies] +Users = { path = "../Users" } \ No newline at end of file diff --git a/Modules/Task/src/Error.rs b/Modules/Task/src/Error.rs new file mode 100644 index 0000000..0e86f87 --- /dev/null +++ b/Modules/Task/src/Error.rs @@ -0,0 +1,29 @@ +#![allow(non_camel_case_types)] + +use std::{num::NonZeroU32, sync::PoisonError}; + +pub type Result_type = std::result::Result; + +#[derive(Debug, Clone)] +#[repr(C)] +pub enum Error_type { + Invalid_task_identifier, + Failed_to_create_thread, + No_thread_for_task, + Failed_to_spawn_thread, + Poisoned_lock, + Invalid_environment_variable, + Too_many_tasks, +} + +impl From> for Error_type { + fn from(_: PoisonError) -> Self { + Error_type::Poisoned_lock + } +} + +impl From for NonZeroU32 { + fn from(Error: Error_type) -> Self { + unsafe { NonZeroU32::new_unchecked(Error as u32) } + } +} diff --git a/Modules/Task/src/Manager.rs b/Modules/Task/src/Manager.rs index 5fdf1a2..39083d2 100644 --- a/Modules/Task/src/Manager.rs +++ b/Modules/Task/src/Manager.rs @@ -4,9 +4,11 @@ use super::*; // - - External // - - - Standard library use std::{ + borrow::Cow, collections::HashMap, sync::{Arc, RwLock}, }; +use Users::{Root_user_identifier, User_identifier_type}; /// Internal representation of a task. struct Task_internal_type { @@ -14,6 +16,10 @@ struct Task_internal_type { Thread: Thread_wrapper_type, /// The identifiers of the children of the task. Children: Vec, + /// The identifier of the user that owns the task. + Owner: User_identifier_type, + /// Environment variables of the task. + Environment_variables: HashMap, Cow<'static, str>>, } /// A manager for tasks. @@ -24,169 +30,404 @@ pub struct Manager_type { } impl Manager_type { - /// The identifier of the root task (the task that is created when the manager is created). - const Root_task_identifier: Task_identifier_type = 0; - pub fn New() -> Self { - let Manager = Manager_type { - Tasks: Arc::new(RwLock::new(HashMap::new())), + // Add current thread to tasks as root task + let Task_internal = Task_internal_type { + Thread: Thread_wrapper_type::Get_current(), + Children: Vec::new(), + Owner: Root_user_identifier, + Environment_variables: HashMap::new(), }; - Manager - } + let mut Tasks_map = HashMap::new(); - fn Get_new_task_identifier(&self) -> Task_identifier_type { - if self.Tasks.read().unwrap().len() == 0 { - return Self::Root_task_identifier; - } + Tasks_map.insert(Task_identifier_type::from(0), Task_internal); - for Process_identifier in 0..std::usize::MAX - 1 { - if !self.Tasks.read().unwrap().contains_key(&Process_identifier) { - return Process_identifier; - } + Manager_type { + Tasks: Arc::new(RwLock::new(Tasks_map)), } - panic!("No more process identifier available."); // Should never happen since the maximum number of tasks is usize::MAX - 1 which is a lot. } - pub fn Get_task_name(&self, Process_identifier: Task_identifier_type) -> Result { - match self.Tasks.read().unwrap().get(&Process_identifier) { + fn Get_new_task_identifier(&self) -> Option { + (0..Task_identifier_type::Maximum) + .find(|Identifier| { + !self + .Tasks + .read() + .unwrap() + .contains_key(&(*Identifier).into()) + }) + .map(|Identifier| Identifier.into()) + } + + pub fn Get_task_name(&self, Task_identifier: Task_identifier_type) -> Result_type { + match self.Tasks.read().unwrap().get(&Task_identifier) { Some(Task) => match Task.Thread.Get_name() { Some(Name) => Ok(Name.to_string()), - None => Err(()), + None => Err(Error_type::Invalid_task_identifier), }, - None => Err(()), + None => Err(Error_type::Invalid_task_identifier), } } - pub fn New_root_task(&self, Stack_size: Option, Function: F) - where - F: FnOnce() + Send + 'static, - { - let Thread_wrapper = match Thread_wrapper_type::New("Xila", Stack_size, Function) { - Ok(Thread_wrapper) => Thread_wrapper, - Err(()) => panic!(), - }; - - let mut Tasks = self.Tasks.write().unwrap(); // Acquire lock - - Tasks.insert( - Self::Root_task_identifier, - Task_internal_type { - Thread: Thread_wrapper, - Children: Vec::new(), - }, - ); - } - /// Create a new child task, returns the identifier of the child task. /// # Arguments - /// * `Parent_task_identifier` - The identifier of the parent task. + /// * `Parent_task_identifier` - The identifier of the parent task, if None, the current task is used. /// * `Name` - The human readable name of the task. /// * `Stack_size` - The size of the stack of the task. /// * `Function` - The function that the task will execute. /// - pub fn New_task( + pub fn New_task( &self, - Parent_task_identifier: Task_identifier_type, + Parent_task_identifier: Option, + User_identifier: Option, Name: &str, Stack_size: Option, Function: F, - ) -> Result + ) -> Result_type<(Task_identifier_type, Join_handle_type)> where - F: FnOnce() + Send + 'static, + T: Send + 'static, + F: FnOnce() -> T + Send + 'static, { - let Child_task_identifier = self.Get_new_task_identifier(); - - let mut Tasks = self.Tasks.write().unwrap(); // Acquire lock - - let Parent_task = match Tasks.get_mut(&Parent_task_identifier) { - Some(Parent_task) => Parent_task, - None => return Err(()), + let Child_task_identifier = self + .Get_new_task_identifier() + .ok_or(Error_type::Too_many_tasks)?; + + let Parent_task_identifier = if let Some(Parent_task_identifier) = Parent_task_identifier { + Parent_task_identifier + } else { + self.Get_current_task_identifier()? }; - let Thread_wrapper = match Thread_wrapper_type::New(Name, Stack_size, Function) { - Ok(Thread_wrapper) => Thread_wrapper, - Err(()) => return Err(()), + let Owner = match User_identifier { + Some(Identifier) => Identifier, + None => self.Get_owner(Parent_task_identifier)?, }; + let mut Tasks = self.Tasks.write()?; + + let Parent_task = Tasks + .get_mut(&Parent_task_identifier) + .ok_or(Error_type::Invalid_task_identifier)?; + Parent_task.Children.push(Child_task_identifier); - std::mem::drop(Tasks); // Force Release lock // TODO : Find a better way to do this - self.Tasks.write().unwrap().insert( + let Environment_variables = Parent_task.Environment_variables.clone(); + + let Manager = self.clone(); + + let Function = move || { + let Result = Function(); + let _ = Manager.Delete_task(Child_task_identifier); + Result + }; + + let Join_handle = Thread_wrapper_type::New(Name, Stack_size, Function)?; + + let Thread = Join_handle.Get_thread_wrapper(); + + Tasks.insert( Child_task_identifier, Task_internal_type { - Thread: Thread_wrapper, + Thread, Children: Vec::new(), + Owner, + Environment_variables, }, ); - Ok(Child_task_identifier) + Ok((Child_task_identifier, Join_handle)) } - fn Delete_task(&self, Task_identifier: Task_identifier_type) -> Result<(), ()> { - let mut Tasks = self.Tasks.write().unwrap(); // Acquire lock + pub fn Get_owner( + &self, + Task_identifier: Task_identifier_type, + ) -> Result_type { + let Tasks = self.Tasks.read().unwrap(); + + Ok(Tasks + .get(&Task_identifier) + .ok_or(Error_type::Invalid_task_identifier)? + .Owner) + } - // - Remove task from hashmap and take ownership of it - let Task = match Tasks.remove(&Task_identifier) { - Some(Task) => Task, - None => return Err(()), - }; + fn Delete_task(&self, Task_identifier: Task_identifier_type) -> Result_type<()> { + // - Wait for all children to terminate + while !self + .Tasks + .read()? + .get(&Task_identifier) + .ok_or(Error_type::Invalid_task_identifier)? + .Children + .is_empty() + { + Task_type::Sleep(std::time::Duration::from_millis(10)); + } - std::mem::drop(Tasks); // Force Release lock // TODO : Find a better way to do this + self.Tasks + .write()? + .remove(&Task_identifier) + .ok_or(Error_type::Invalid_task_identifier)?; - // - Waiting for thread to terminate - Task.Thread.Join().unwrap(); + Ok(()) + } - let mut R = Ok(()); + pub fn Get_current_task_identifier(&self) -> Result_type { + let Tasks = self.Tasks.read().unwrap(); // Acquire lock - for Child_task_identifier in Task.Children.iter() { - if self.Delete_task(*Child_task_identifier).is_err() { - R = Err(()); + for (Task_identifier, Task) in Tasks.iter() { + if Task.Thread.Get_identifier() == std::thread::current().id() { + return Ok(*Task_identifier); } } - R + Err(Error_type::No_thread_for_task) + } + + pub fn Get_current_task(&self) -> Result_type { + Ok(Task_type::New( + self.Get_current_task_identifier()?, + self.clone(), + )) } - pub fn Get_current_task_identifier(&self) -> Result { + pub fn Get_environment_variable( + &self, + Task_identifier: Task_identifier_type, + Name: &str, + ) -> Result_type> { let Tasks = self.Tasks.read().unwrap(); // Acquire lock - for (Task_identifier, Task) in Tasks.iter() { - if Task.Thread.Get_name().unwrap() == std::thread::current().name().unwrap() { - return Ok(*Task_identifier); - } - } + Ok(Tasks + .get(&Task_identifier) + .ok_or(Error_type::Invalid_task_identifier)? + .Environment_variables + .get(Name) + .ok_or(Error_type::Invalid_environment_variable)? + .clone()) + } + + pub fn Get_environment_variables( + &self, + Task_identifier: Task_identifier_type, + ) -> Result_type, Cow<'static, str>>> { + let Tasks = self.Tasks.read().unwrap(); // Acquire lock - Err(()) + Ok(Tasks + .get(&Task_identifier) + .ok_or(Error_type::Invalid_task_identifier)? + .Environment_variables + .clone()) + } + + pub fn Set_environment_variable( + &self, + Task_identifier: Task_identifier_type, + Name: &str, + Value: &str, + ) -> Result_type<()> { + let mut Tasks = self.Tasks.write().unwrap(); // Acquire lock + + Tasks + .get_mut(&Task_identifier) + .ok_or(Error_type::Invalid_task_identifier)? + .Environment_variables + .insert(Cow::Owned(Name.to_string()), Cow::Owned(Value.to_string())); + + Ok(()) + } + + pub fn Remove_environment_variable( + &self, + Task_identifier: Task_identifier_type, + Name: &str, + ) -> Result_type<()> { + let mut Tasks = self.Tasks.write().unwrap(); // Acquire lock + + Tasks + .get_mut(&Task_identifier) + .ok_or(Error_type::Invalid_task_identifier)? + .Environment_variables + .remove(Name); + + Ok(()) } } #[cfg(test)] mod tests { use super::*; - use std::time::Duration; #[test] - fn Test() { + fn Test_get_task_name() { + let Manager = Manager_type::New(); + let Task_name = "Test Task"; + let (Task_identifier, _) = Manager + .New_task(None, None, Task_name, None, || {}) + .unwrap(); + assert_eq!(Manager.Get_task_name(Task_identifier).unwrap(), Task_name); + } + + #[test] + fn Test_new_task() { let Manager = Manager_type::New(); + let Task_name = "Child Task"; + let (Task_identifier, _) = Manager + .New_task(None, None, Task_name, None, || {}) + .unwrap(); + assert!(Manager.Get_task_name(Task_identifier).is_ok()); + } - Manager.New_root_task(None, || { - Task_type::Sleep(Duration::from_millis(100)); - }); + #[test] + fn Test_delete_task() { + let Manager = Manager_type::New(); + let (Task_identifier, _) = Manager + .New_task(None, None, "Task to delete", None, || {}) + .unwrap(); + assert!(Manager.Delete_task(Task_identifier).is_ok()); + assert!(Manager.Get_task_name(Task_identifier).is_err()); + } - let _ = Manager - .New_task( - Manager_type::Root_task_identifier, - "Child task", - None, - || { - Task_type::Sleep(Duration::from_millis(100)); - }, - ) + #[test] + fn Test_get_owner() { + let Manager = Manager_type::New(); + let User_identifier = 123; // Assuming User_identifier_type is i32 for example + let (Task_identifier, _) = Manager + .New_task(None, Some(User_identifier), "Task with owner", None, || {}) .unwrap(); + assert_eq!(Manager.Get_owner(Task_identifier).unwrap(), User_identifier); + } + #[test] + fn Test_get_current_task_identifier() { + // This test might be tricky to implement due to the nature of comparing thread IDs. + // Assuming there's a way to simulate or mock the thread ID comparison. + let Manager = Manager_type::New(); + let Manager_copy = Manager.clone(); + let (Task_identifier, Join_handle) = Manager + .New_task(None, None, "Current Task", None, move || { + let _ = Manager_copy.Get_current_task_identifier().unwrap(); + }) + .unwrap(); + let _ = Manager.Get_task_name(Task_identifier); // Just to use Task_identifier and avoid unused variable warning. + Join_handle.Join().unwrap(); + } + + #[test] + fn Test_multiple_tasks_with_same_owner() { + let Manager = Manager_type::New(); + let Manager_copy = Manager.clone(); + let User_identifier = 123; // Assuming User_identifier_type is i32 for example + let (Task_identifier_1, _) = Manager + .New_task(None, Some(User_identifier), "Task 1", None, move || { + let Manager = Manager_copy.clone(); + let Manager_copy = Manager.clone(); + + let (Task_identifier_2, _) = Manager + .New_task(None, None, "Task 2", None, move || { + let Manager = Manager_copy.clone(); + assert_eq!( + Manager.Get_current_task().unwrap().Get_owner().unwrap(), + User_identifier + ); + assert_eq!( + Manager.Get_current_task().unwrap().Get_name().unwrap(), + "Task 2" + ); + + Task_type::Sleep(std::time::Duration::from_secs(1)); + }) + .unwrap(); + + assert_eq!( + Manager.Get_owner(Task_identifier_2).unwrap(), + User_identifier + ); + + let Manager_copy = Manager.clone(); + + let _ = Manager + .New_task(None, Some(6969), "Task 3", None, move || { + let Manager = Manager_copy.clone(); + assert_eq!( + Manager.Get_current_task().unwrap().Get_owner().unwrap(), + 6969 + ); + assert_eq!( + Manager.Get_current_task().unwrap().Get_name().unwrap(), + "Task 3" + ); + }) + .unwrap(); + }) + .unwrap(); + + assert_eq!( + Manager.Get_owner(Task_identifier_1).unwrap(), + User_identifier + ); + } + + #[test] + fn Test_environment_variables() { + let Manager = Manager_type::New(); + let (Task_identifier, _) = Manager + .New_task(None, None, "Task with environment variables", None, || {}) + .unwrap(); + let Name = "Key"; + let Value = "Value"; Manager - .Delete_task(Manager_type::Root_task_identifier) + .Set_environment_variable(Task_identifier, Name, Value) + .unwrap(); + assert_eq!( + Manager + .Get_environment_variable(Task_identifier, Name) + .unwrap(), + Value + ); + Manager + .Remove_environment_variable(Task_identifier, Name) + .unwrap(); + assert!(Manager + .Get_environment_variable(Task_identifier, Name) + .is_err()); + } + + #[test] + fn Test_environment_variable_inheritance() { + let Manager = Manager_type::New(); + let Manager_copy = Manager.clone(); + let _ = Manager + .New_task(None, None, "Parent Task", None, || { + let Manager = Manager_copy; + let Manager_copy = Manager.clone(); + + let (Task_identifier_2, _) = Manager + .New_task(None, None, "Child Task", None, move || { + let Manager = Manager_copy; + + let Current_task = Manager.Get_current_task().unwrap(); + + assert_eq!( + Current_task.Get_environment_variable("Key").unwrap(), + "Value" + ); + }) + .unwrap(); + Manager + .Set_environment_variable(Task_identifier_2, "Key", "Value") + .unwrap(); + }) + .unwrap(); + } + + #[test] + fn Test_join_handle() { + let Manager = Manager_type::New(); + let (_, Join_handle) = Manager + .New_task(None, None, "Task with join handle", None, || 42) .unwrap(); + let Result = Join_handle.Join(); + assert_eq!(Result.unwrap(), 42); } } diff --git a/Modules/Task/src/Pipe.rs b/Modules/Task/src/Pipe.rs deleted file mode 100644 index 48da69b..0000000 --- a/Modules/Task/src/Pipe.rs +++ /dev/null @@ -1,59 +0,0 @@ -use std::sync::{Arc, RwLock}; - -struct Pipe_internal_type { - Buffer: [u8; Buffer_size], - Read_index: usize, - Write_index: usize, -} - -pub struct Pipe_type(Arc>>); - -impl Pipe_type { - pub fn New() -> Self { - Self(Arc::new(RwLock::new(Pipe_internal_type { - Buffer: [0; Buffer_size], - Read_index: 0, - Write_index: 0, - }))) - } - - pub fn Write(&self, Data: &[u8]) -> Result<(), ()> { - if Data.len() > Buffer_size { - return Err(()); - } - - let mut Pipe = self.0.write().unwrap(); - - for Byte in Data { - // ? : Probably not the most efficient way to do this. - let Write_index = Pipe.Write_index; // * Make the borrow checker happy. - Pipe.Buffer[Write_index] = *Byte; - Pipe.Write_index += 1; - - if Pipe.Write_index == Buffer_size { - Pipe.Write_index = 0; - } - } - - Ok(()) - } - - pub fn Read(&self, Data: &mut [u8]) -> Result<(), ()> { - if Data.len() > Buffer_size { - return Err(()); - } - - let mut Pipe = self.0.write().unwrap(); - - for Byte in Data { - *Byte = Pipe.Buffer[Pipe.Read_index]; - Pipe.Read_index += 1; - - if Pipe.Read_index == Buffer_size { - Pipe.Read_index = 0; - } - } - - Ok(()) - } -} diff --git a/Modules/Task/src/Task.rs b/Modules/Task/src/Task.rs index 5d8f350..521d778 100644 --- a/Modules/Task/src/Task.rs +++ b/Modules/Task/src/Task.rs @@ -1,18 +1,40 @@ -use super::*; +use std::borrow::Cow; -pub type Task_identifier_type = usize; +use Users::User_identifier_type; + +use crate::{Join_handle_type, Manager_type, Result_type, Thread_wrapper_type}; + +#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)] +#[repr(transparent)] +pub struct Task_identifier_type(u32); + +impl Task_identifier_type { + pub const Maximum: u32 = u32::MAX; +} + +impl From for Task_identifier_type { + fn from(Value: u32) -> Self { + Self(Value) + } +} + +impl From for u32 { + fn from(Value: Task_identifier_type) -> Self { + Value.0 + } +} /// A wrapper for individual tasks that are managed by [Manager_type]. -pub struct Task_type<'a> { +pub struct Task_type { /// The identifier of the task. Identifier: Task_identifier_type, /// A reference to the [Manager_type] that manages the task. - Manager: &'a Manager_type, + Manager: Manager_type, } -impl<'a> Task_type<'a> { +impl Task_type { /// Internal method to create a new task. - fn New(Identifier: Task_identifier_type, Manager: &'a Manager_type) -> Self { + pub(crate) fn New(Identifier: Task_identifier_type, Manager: Manager_type) -> Self { Self { Identifier, Manager, @@ -20,25 +42,28 @@ impl<'a> Task_type<'a> { } /// Create a new child task. - pub fn New_child_task( + pub fn New_child_task( &self, Name: &str, + Owner: Option, Stack_size: Option, Function: F, - ) -> Result + ) -> Result_type<(Task_type, Join_handle_type)> where - F: FnOnce() + Send + 'static, + T: Send + 'static, + F: FnOnce() -> T + Send + 'static, { - match self - .Manager - .New_task(self.Identifier, Name, Stack_size, Function) - { - Ok(Child_task_identifier) => Ok(Self::New(Child_task_identifier, self.Manager)), - Err(()) => Err(()), - } + let (Task_identifier, Join_handle) = + self.Manager + .New_task(Some(self.Identifier), Owner, Name, Stack_size, Function)?; + + Ok(( + Task_type::New(Task_identifier, self.Manager.clone()), + Join_handle, + )) } - pub fn Get_name(&self) -> Result { + pub fn Get_name(&self) -> Result_type { self.Manager.Get_task_name(self.Identifier) } @@ -46,38 +71,25 @@ impl<'a> Task_type<'a> { self.Identifier } - pub fn Get_manager(&self) -> &'a Manager_type { - self.Manager - } - - pub fn Get_current_task(Manager: &'a Manager_type) -> Result { - let Current_task_identifier = Manager.Get_current_task_identifier()?; - Ok(Self::New(Current_task_identifier, Manager)) + pub fn Get_owner(&self) -> Result_type { + self.Manager.Get_owner(self.Identifier) } pub fn Sleep(Duration: std::time::Duration) { Thread_wrapper_type::Sleep(Duration) } -} - -#[cfg(test)] -mod tests { - use super::*; - #[test] - fn Test() { - let Manager = Manager_type::New(); - - let Manager_copy = Manager.clone(); + pub fn Get_environment_variable(&self, Name: &str) -> Result_type> { + self.Manager.Get_environment_variable(self.Identifier, Name) + } - let _ = Manager.New_root_task(None, move || { - let Task = Task_type::Get_current_task(&Manager_copy).unwrap(); + pub fn Set_environment_variable(&self, Name: &str, Value: &str) -> Result_type<()> { + self.Manager + .Set_environment_variable(self.Identifier, Name, Value) + } - let _ = Task - .New_child_task("Child task", None, || { - Task_type::Sleep(std::time::Duration::from_millis(100)); - }) - .unwrap(); - }); + pub fn Remove_environment_variable(&self, Name: &str) -> Result_type<()> { + self.Manager + .Remove_environment_variable(self.Identifier, Name) } } diff --git a/Modules/Task/src/Thread.rs b/Modules/Task/src/Thread.rs index 48dc4e1..4c7a86a 100644 --- a/Modules/Task/src/Thread.rs +++ b/Modules/Task/src/Thread.rs @@ -1,13 +1,34 @@ -use std::thread; +use super::*; +use std::{ + any::Any, + thread::{self, ThreadId}, +}; + +pub struct Join_handle_type(thread::JoinHandle); + +impl Join_handle_type { + pub fn Join(self) -> std::result::Result> { + self.0.join() + } + + pub(crate) fn Get_thread_wrapper(&self) -> Thread_wrapper_type { + Thread_wrapper_type(self.0.thread().clone()) + } +} /// A wrapper around [std::thread::Thread]. -pub struct Thread_wrapper_type(thread::JoinHandle<()>); +pub struct Thread_wrapper_type(thread::Thread); impl Thread_wrapper_type { /// Creates a new thread with a given name, stack size and function. - pub fn New(Name: &str, Stack_size: Option, Function: F) -> Result + pub fn New( + Name: &str, + Stack_size: Option, + Function: F, + ) -> Result_type> where - F: FnOnce() + Send + 'static, + T: Send + 'static, + F: FnOnce() -> T + Send + 'static, { let Thread_builder = thread::Builder::new().name(Name.to_string()); @@ -16,28 +37,27 @@ impl Thread_wrapper_type { None => Thread_builder, }; - let Join_handle = match Thread_builder.spawn(Function) { - Ok(Join_handle) => Join_handle, - Err(_) => return Err(()), - }; + let Join_handle = Thread_builder + .spawn(Function) + .map_err(|_| Error_type::Failed_to_spawn_thread)?; - Ok(Self(Join_handle)) - } - - /// Block the current thread until the thread terminates. - pub fn Join(self) -> Result<(), ()> { - match self.0.join() { - Ok(_) => Ok(()), - Err(_) => Err(()), - } + Ok(Join_handle_type(Join_handle)) } /// Gets the name of the thread. pub fn Get_name(&self) -> Option<&str> { - self.0.thread().name() + self.0.name() } pub fn Sleep(Duration: std::time::Duration) { std::thread::sleep(Duration); } + + pub fn Get_identifier(&self) -> ThreadId { + self.0.id() + } + + pub fn Get_current() -> Thread_wrapper_type { + Thread_wrapper_type(thread::current()) + } } diff --git a/Modules/Task/src/lib.rs b/Modules/Task/src/lib.rs index 71a3bad..67be9ec 100644 --- a/Modules/Task/src/lib.rs +++ b/Modules/Task/src/lib.rs @@ -2,6 +2,9 @@ #![allow(non_camel_case_types)] #![allow(non_upper_case_globals)] +mod Error; +pub use Error::*; + mod Manager; pub use Manager::*; @@ -9,8 +12,6 @@ mod Task; pub use Task::*; mod Thread; -pub use Thread::*; - -mod Pipe; +use Thread::*; pub mod Prelude; diff --git a/Modules/Users/Cargo.toml b/Modules/Users/Cargo.toml new file mode 100644 index 0000000..7e2c004 --- /dev/null +++ b/Modules/Users/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "Users" +version = "0.1.0" +edition = "2021" + +[dependencies] diff --git a/Modules/Users/src/Error.rs b/Modules/Users/src/Error.rs new file mode 100644 index 0000000..399ae03 --- /dev/null +++ b/Modules/Users/src/Error.rs @@ -0,0 +1,21 @@ +use std::sync::PoisonError; + +pub type Result = std::result::Result; + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[repr(C)] +pub enum Error_type { + Duplicate_group_identifier, + Duplicate_user_identifier, + Invalid_group_identifier, + Invalid_user_identifier, + Too_many_groups, + Too_many_users, + Poisoned_lock, +} + +impl From> for Error_type { + fn from(_: PoisonError) -> Self { + Error_type::Poisoned_lock + } +} diff --git a/Modules/Users/src/Manager.rs b/Modules/Users/src/Manager.rs new file mode 100644 index 0000000..1063b76 --- /dev/null +++ b/Modules/Users/src/Manager.rs @@ -0,0 +1,296 @@ +use super::*; +use std::{ + collections::{HashMap, HashSet}, + sync::{Arc, RwLock}, + vec::Vec, +}; + +struct Internal_user_type { + pub Name: String, +} + +struct Internal_group_type { + pub Name: String, + pub Users: HashSet, +} + +struct Internal_manager_type { + pub Users: HashMap, + pub Groups: HashMap, +} + +#[derive(Clone)] +pub struct Manager_type(Arc>); + +impl Manager_type { + pub fn New() -> Self { + Self(Arc::new(RwLock::new(Internal_manager_type { + Users: HashMap::new(), + Groups: HashMap::new(), + }))) + } + + fn Get_new_group_identifier(&self) -> Option { + let Inner = self.0.read().ok()?; + + (0..Group_identifier_type::MAX).find(|Identifier| !Inner.Groups.contains_key(Identifier)) + } + + fn Get_new_user_identifier(&self) -> Option { + let Inner = self.0.read().ok()?; + + (0..User_identifier_type::MAX).find(|Identifier| !Inner.Users.contains_key(Identifier)) + } + + pub fn Create_user(&self, Name: &str) -> Result { + let Identifier = match self.Get_new_user_identifier() { + Some(Identifier) => Identifier, + None => return Err(Error_type::Too_many_users), + }; + + let User = Internal_user_type { + Name: Name.to_string(), + }; + + if self.Exists_user(Identifier)? { + return Err(Error_type::Duplicate_user_identifier); + } + + let mut Inner = self.0.write().unwrap(); + + if Inner.Users.insert(Identifier, User).is_some() { + return Err(Error_type::Duplicate_user_identifier); // Shouldn't happen + } + Ok(Identifier) + } + + pub fn Create_group( + &self, + Name: &str, + Identifier: Option, + ) -> Result { + let Identifier = match Identifier { + Some(Identifier) => Identifier, + None => self + .Get_new_group_identifier() + .ok_or(Error_type::Too_many_groups)?, + }; + + let Group = Internal_group_type { + Name: Name.to_string(), + Users: HashSet::new(), + }; + + if self.Exists_group(Identifier)? { + return Err(Error_type::Duplicate_group_identifier); + } + + let mut Inner = self.0.write().unwrap(); + + if Inner.Groups.insert(Identifier, Group).is_some() { + return Err(Error_type::Duplicate_group_identifier); // Shouldn't happen + } + Ok(Identifier) + } + + pub fn Is_root(Identifier: User_identifier_type) -> bool { + crate::Root_user_identifier == Identifier + } + + pub fn Is_in_group( + &self, + User_identifier: User_identifier_type, + Group_identifier: Group_identifier_type, + ) -> bool { + let Inner = self.0.read().unwrap(); + Inner + .Groups + .get(&Group_identifier) + .unwrap() + .Users + .contains(&User_identifier) + } + + pub fn Get_user_groups( + &self, + Identifier: User_identifier_type, + ) -> Option> { + let Inner = self.0.read().unwrap(); + Some( + Inner + .Groups + .iter() + .filter(|(_, Group)| Group.Users.contains(&Identifier)) + .map(|(Identifier, _)| *Identifier) + .collect(), + ) + } + + pub fn Exists_group(&self, Identifier: Group_identifier_type) -> Result { + Ok(self.0.read()?.Groups.contains_key(&Identifier)) + } + + pub fn Exists_user(&self, Identifier: User_identifier_type) -> Result { + Ok(self.0.read()?.Users.contains_key(&Identifier)) + } + + pub fn Add_to_group( + &self, + User_identifier: User_identifier_type, + Group_identifier: Group_identifier_type, + ) -> Result<()> { + if !self.Exists_group(Group_identifier)? { + return Err(Error_type::Invalid_group_identifier); + } + let mut Inner = self.0.write()?; + if !Inner + .Groups + .get_mut(&Group_identifier) + .unwrap() + .Users + .insert(User_identifier) + { + return Err(Error_type::Duplicate_group_identifier); + } + Ok(()) + } + + pub fn Get_group_name(&self, Identifier: Group_identifier_type) -> Result { + Ok(self.0.read()?.Groups.get(&Identifier).unwrap().Name.clone()) + } + + pub fn Get_group_users( + &self, + Identifier: Group_identifier_type, + ) -> Result> { + Ok(self + .0 + .read()? + .Groups + .get(&Identifier) + .ok_or(Error_type::Invalid_group_identifier)? + .Users + .clone() + .into_iter() + .collect()) + } + + pub fn Get_user_name(&self, Identifier: User_identifier_type) -> Result { + Ok(self + .0 + .read()? + .Users + .get(&Identifier) + .ok_or(Error_type::Invalid_user_identifier)? + .Name + .clone()) + } + + pub fn Check_credentials(&self, _User_name: &str, _Password: &str) -> bool { + true + } +} + +#[cfg(test)] +mod Tests { + use super::*; + + #[test] + fn New() { + let Manager = Manager_type::New(); + assert!(Manager.0.read().unwrap().Groups.is_empty()); + } + + #[test] + fn Create_user() { + let Manager = Manager_type::New(); + let User_name = "Alice"; + let Result = Manager.Create_user(User_name); + assert!(Result.is_ok()); + let User_id = Result.unwrap(); + assert!(Manager.Exists_user(User_id).unwrap()); + } + + #[test] + fn Create_group() { + let Manager = Manager_type::New(); + let Group_name = "Developers"; + let Result = Manager.Create_group(Group_name, None); + assert!(Result.is_ok()); + let Group_id = Result.unwrap(); + assert!(Manager.Exists_group(Group_id).unwrap()); + } + + #[test] + fn Is_root() { + let Root_id = crate::Root_user_identifier; + assert!(Manager_type::Is_root(Root_id)); + } + + #[test] + fn Is_in_group() { + let Manager = Manager_type::New(); + let User_name = "Bob"; + let User_id = Manager.Create_user(User_name).unwrap(); + let Group_name = "Admins"; + let Group_id = Manager.Create_group(Group_name, None).unwrap(); + Manager.Add_to_group(User_id, Group_id).unwrap(); + assert!(Manager.Is_in_group(User_id, Group_id)); + } + + #[test] + fn Get_user_groups() { + let Manager = Manager_type::New(); + + let User_name = "Charlie"; + let User_id = Manager.Create_user(User_name).unwrap(); + let Group_name1 = "TeamA"; + let Group_id1 = Manager.Create_group(Group_name1, None).unwrap(); + let Group_name2 = "TeamB"; + let Group_id2 = Manager.Create_group(Group_name2, None).unwrap(); + Manager.Add_to_group(User_id, Group_id1).unwrap(); + Manager.Add_to_group(User_id, Group_id2).unwrap(); + let Groups = Manager.Get_user_groups(User_id).unwrap(); + assert_eq!(Groups.len(), 2); + assert!(Groups.contains(&Group_id1) && Groups.contains(&Group_id2)); + } + + #[test] + fn Get_group_name() { + let Manager = Manager_type::New(); + let Group_name = "QA"; + let Group_id = Manager.Create_group(Group_name, None).unwrap(); + let Retrieved_name = Manager.Get_group_name(Group_id).unwrap(); + assert_eq!(Group_name, Retrieved_name); + } + + #[test] + fn Get_group_users() { + let Manager = Manager_type::New(); + let User_name = "Dave"; + let User_id = Manager.Create_user(User_name).unwrap(); + let Group_name = "Engineers"; + let Group_id = Manager.Create_group(Group_name, None).unwrap(); + Manager.Add_to_group(User_id, Group_id).unwrap(); + let Users = Manager.Get_group_users(Group_id).unwrap(); + assert_eq!(Users.len(), 1); + assert!(Users.contains(&User_id)); + } + + #[test] + fn Get_user_name() { + let Manager = Manager_type::New(); + let User_name = "Eve"; + let User_id = Manager.Create_user(User_name).unwrap(); + let Retrieved_name = Manager.Get_user_name(User_id).unwrap(); + assert_eq!(User_name, Retrieved_name); + } + + #[test] + fn Check_credentials() { + let Manager = Manager_type::New(); + let User_name = "Frank"; + let Password = "password123"; + assert!(Manager.Check_credentials(User_name, Password)); + } +} diff --git a/Modules/Users/src/lib.rs b/Modules/Users/src/lib.rs new file mode 100644 index 0000000..d53a9c7 --- /dev/null +++ b/Modules/Users/src/lib.rs @@ -0,0 +1,14 @@ +#![allow(non_camel_case_types)] +#![allow(non_snake_case)] +#![allow(non_upper_case_globals)] + +pub type User_identifier_type = u16; +pub type Group_identifier_type = u16; +pub const Root_user_identifier: User_identifier_type = 0; +pub const Root_group_identifier: Group_identifier_type = 0; + +mod Manager; +pub use Manager::*; + +mod Error; +pub use Error::*; diff --git a/Modules/Virtual_machine/Cargo.toml b/Modules/Virtual_machine/Cargo.toml index d585961..bad634c 100644 --- a/Modules/Virtual_machine/Cargo.toml +++ b/Modules/Virtual_machine/Cargo.toml @@ -8,7 +8,6 @@ build = "Build.rs" [dependencies] wamr-rust-sdk = { git = "https://github.com/AlixANNERAUD/wamr-rust-sdk.git" } Shared = { version = "0.1.0", path = "../Shared" } -File_system = { path = "../File_system" } [[test]] name = "Virtual_machine_test" diff --git a/Modules/Virtual_machine/Tests/Test.rs b/Modules/Virtual_machine/Tests/Test.rs index b675207..dd32556 100644 --- a/Modules/Virtual_machine/Tests/Test.rs +++ b/Modules/Virtual_machine/Tests/Test.rs @@ -4,7 +4,6 @@ use wamr_rust_sdk::value::WasmValue; -use File_system::Drivers::Native::File_system_type; use Virtual_machine::{ Data_type, Environment_pointer_type, Environment_type, Function_descriptor_type, Function_descriptors, Instantiate_test_environment, Registrable_trait, WASM_pointer, @@ -101,9 +100,7 @@ fn Integration_test() { Test_string }; - let File_system = File_system_type::New(); - - let User_data = Data_type::New(&File_system); + let User_data = Data_type::New(); let (_Runtime, _Module, Instance) = Instantiate_test_environment(Binary_buffer, Registrable {}, &User_data); diff --git a/Modules/Virtual_machine/Tests/WASM_test/src/main.rs b/Modules/Virtual_machine/Tests/WASM_test/src/main.rs index 7ddbe2f..3079fe6 100644 --- a/Modules/Virtual_machine/Tests/WASM_test/src/main.rs +++ b/Modules/Virtual_machine/Tests/WASM_test/src/main.rs @@ -1,6 +1,8 @@ #![allow(non_snake_case)] +#![allow(non_camel_case_types)] +#![allow(non_upper_case_globals)] -use std::{collections::HashMap, fmt::Pointer, os::raw::c_void}; +use std::collections::HashMap; #[link(wasm_import_module = "host")] extern "C" { diff --git a/Modules/Virtual_machine/src/Data.rs b/Modules/Virtual_machine/src/Data.rs index 8d1e9ce..15eef93 100644 --- a/Modules/Virtual_machine/src/Data.rs +++ b/Modules/Virtual_machine/src/Data.rs @@ -1,15 +1,7 @@ -use File_system::Prelude::File_system_traits; +pub struct Data_type(); -pub struct Data_type<'a> { - File_system: &'a dyn File_system_traits, -} - -impl Data_type<'_> { - pub fn New(File_system: &dyn File_system_traits) -> Data_type<'_> { - Data_type { File_system } - } - - pub fn Get_file_system(&self) -> &dyn File_system_traits { - self.File_system +impl Data_type { + pub fn New() -> Self { + Self {} } } diff --git a/Modules/Virtual_machine/src/Environment.rs b/Modules/Virtual_machine/src/Environment.rs index 1ea12af..d30de03 100644 --- a/Modules/Virtual_machine/src/Environment.rs +++ b/Modules/Virtual_machine/src/Environment.rs @@ -1,27 +1,38 @@ +#![allow(non_camel_case_types)] + use std::{ + ffi::CStr, marker::PhantomData, mem::size_of, os::raw::c_void, ptr::{null_mut, NonNull}, }; -use wamr_rust_sdk::sys::{ - wasm_exec_env_t, wasm_module_inst_t, wasm_runtime_addr_app_to_native, - wasm_runtime_addr_native_to_app, wasm_runtime_get_exec_env_singleton, - wasm_runtime_get_module_inst, wasm_runtime_get_user_data, wasm_runtime_module_free, - wasm_runtime_module_malloc, wasm_runtime_set_user_data, wasm_runtime_validate_app_addr, - wasm_runtime_validate_native_addr, +use wamr_rust_sdk::{ + sys::{ + wasm_exec_env_t, wasm_module_inst_t, wasm_runtime_addr_app_to_native, + wasm_runtime_addr_native_to_app, wasm_runtime_call_indirect, wasm_runtime_create_exec_env, + wasm_runtime_get_exception, wasm_runtime_get_exec_env_singleton, + wasm_runtime_get_module_inst, wasm_runtime_get_user_data, wasm_runtime_module_free, + wasm_runtime_module_malloc, wasm_runtime_set_user_data, wasm_runtime_validate_app_addr, + wasm_runtime_validate_native_addr, + }, + value::WasmValue, }; use Shared::Mutable_string_type; -use crate::{Data::Data_type, Error_type, Instance_type, WASM_pointer, WASM_usize}; +use crate::{Data::Data_type, Error_type, Instance_type, Result_type, WASM_pointer, WASM_usize}; pub type Environment_pointer_type = wasm_exec_env_t; pub struct Environment_type<'a>(Environment_pointer_type, PhantomData<&'a ()>); +unsafe impl Send for Environment_type<'_> {} + +unsafe impl Sync for Environment_type<'_> {} + impl<'a> Environment_type<'a> { - pub fn From_raw_pointer(Raw_pointer: Environment_pointer_type) -> Result { + pub fn From_raw_pointer(Raw_pointer: Environment_pointer_type) -> Result_type { if Raw_pointer.is_null() { return Err(Error_type::Invalid_pointer); } @@ -29,7 +40,7 @@ impl<'a> Environment_type<'a> { Ok(Self(Raw_pointer as Environment_pointer_type, PhantomData)) } - pub fn From_instance(Instance: &Instance_type) -> Result { + pub fn From_instance(Instance: &Instance_type) -> Result_type { let Instance_pointer = Instance.Get_inner_reference().get_inner_instance(); if Instance_pointer.is_null() { @@ -105,7 +116,7 @@ impl<'a> Environment_type<'a> { &self, Address: WASM_pointer, Size: WASM_usize, - ) -> Result<&str, Error_type> { + ) -> Result_type<&str> { if !self.Validate_WASM_pointer(Address, Size) { return Err(Error_type::Invalid_pointer); } @@ -127,7 +138,7 @@ impl<'a> Environment_type<'a> { String: WASM_pointer, Length: WASM_pointer, Size: WASM_usize, - ) -> Result, Error_type> { + ) -> Result_type> { if !self.Validate_WASM_pointer(String, Size) { return Err(Error_type::Invalid_pointer); } @@ -149,7 +160,7 @@ impl<'a> Environment_type<'a> { &self, Address: WASM_pointer, Length: WASM_usize, - ) -> Result<&[T], Error_type> { + ) -> Result_type<&[T]> { if !self.Validate_WASM_pointer(Address, Length) { return Err(Error_type::Invalid_pointer); } @@ -165,7 +176,7 @@ impl<'a> Environment_type<'a> { &self, Slice: WASM_pointer, Size: WASM_usize, - ) -> Result<&'a mut [T], Error_type> { + ) -> Result_type<&'a mut [T]> { if !self.Validate_WASM_pointer(Slice, Size) { return Err(Error_type::Invalid_pointer); } @@ -178,10 +189,7 @@ impl<'a> Environment_type<'a> { Ok(Slice) } - pub fn Convert_to_native_reference( - &self, - Address: WASM_pointer, - ) -> Result<&'a T, Error_type> { + pub fn Convert_to_native_reference(&self, Address: WASM_pointer) -> Result_type<&'a T> { if !self.Validate_WASM_pointer(Address, size_of::() as WASM_usize) { return Err(Error_type::Invalid_pointer); } @@ -196,7 +204,7 @@ impl<'a> Environment_type<'a> { pub fn Convert_to_native_mutable_reference( &self, Address: WASM_pointer, - ) -> Result<&'a mut T, Error_type> { + ) -> Result_type<&'a mut T> { if !self.Validate_WASM_pointer(Address, size_of::() as WASM_usize) { return Err(Error_type::Invalid_pointer); } @@ -208,7 +216,7 @@ impl<'a> Environment_type<'a> { Ok(Reference) } - pub fn Allocate(&self, Size: WASM_usize) -> Result<&mut [T], Error_type> { + pub fn Allocate(&self, Size: WASM_usize) -> Result_type<&mut [T]> { let mut Pointer: *mut c_void = null_mut(); unsafe { @@ -238,6 +246,58 @@ impl<'a> Environment_type<'a> { } } + /// Make an indirect function call (call a function by its index which is not exported). + /// For exported functions use `Call_export_function`. + pub fn Call_indirect_function( + &self, + Function_index: u32, + Parameters: &Vec, + ) -> Result_type<()> { + let mut Arguments = Vec::new(); + + for Parameter in Parameters { + Arguments.append(&mut Parameter.encode()); + } + + if Arguments.is_empty() { + Arguments.append(&mut WasmValue::I32(0).encode()); + } + + if !unsafe { + wasm_runtime_call_indirect( + self.0, + Function_index, + Arguments.len() as u32, + Arguments.as_mut_ptr(), + ) + } { + let Exception_message = + unsafe { wasm_runtime_get_exception(self.Get_instance_pointer()) }; + let Exception_message = unsafe { CStr::from_ptr(Exception_message) }; + let Exception_message = + String::from_utf8_lossy(Exception_message.to_bytes()).to_string(); + + return Err(Error_type::Execution_error(Exception_message)); + } + + Ok(()) + } + + /// Create a new execution environment. + /// This environment should be initialized with `Initialize_thread_environment` and deinitialized with `Deinitialize_thread_environment`. + pub fn Create_environment(&self, Stack_size: usize) -> Result_type { + let Execution_environment = + unsafe { wasm_runtime_create_exec_env(self.Get_instance_pointer(), Stack_size as u32) }; + + if Execution_environment.is_null() { + return Err(Error_type::Execution_error( + "Execution environment creation failed".to_string(), + )); + } + + Ok(Self(Execution_environment, PhantomData)) + } + fn Get_instance_pointer(&self) -> wasm_module_inst_t { unsafe { wasm_runtime_get_module_inst(self.0) } } diff --git a/Modules/Virtual_machine/src/Error.rs b/Modules/Virtual_machine/src/Error.rs index 42905a2..6286d7e 100644 --- a/Modules/Virtual_machine/src/Error.rs +++ b/Modules/Virtual_machine/src/Error.rs @@ -1,6 +1,11 @@ +#![allow(non_camel_case_types)] + use wamr_rust_sdk::RuntimeError; +pub type Result_type = std::result::Result; + #[derive(Debug)] +#[repr(C)] pub enum Error_type { Invalid_pointer, Invalid_UTF8_string, diff --git a/Modules/Virtual_machine/src/Instance.rs b/Modules/Virtual_machine/src/Instance.rs index 513acec..49512be 100644 --- a/Modules/Virtual_machine/src/Instance.rs +++ b/Modules/Virtual_machine/src/Instance.rs @@ -1,10 +1,10 @@ #![allow(non_snake_case)] #![allow(non_camel_case_types)] -use wamr_rust_sdk::{function::Function, instance::Instance, value::WasmValue, RuntimeError}; +use wamr_rust_sdk::{function::Function, instance::Instance, value::WasmValue}; use crate::{ - Data::Data_type, Environment_type, Error_type, Module::Module_type, Runtime::Runtime_type, + Data::Data_type, Environment_type, Module::Module_type, Result_type, Runtime::Runtime_type, }; pub struct Instance_type(Instance); @@ -15,7 +15,7 @@ impl Instance_type { Module: &Module_type, Stack_size: usize, Data: &Data_type, - ) -> Result { + ) -> Result_type { let Instance = Instance_type(Instance::new( Runtime.Get_inner_reference(), Module.Get_inner_reference(), @@ -33,16 +33,21 @@ impl Instance_type { &self, Name: &str, Parameters: &Vec, - ) -> Result { + ) -> Result_type { if Parameters.is_empty() { - Function::find_export_func(self.Get_inner_reference(), Name)? - .call(&self.0, &vec![WasmValue::I32(0)]) + Ok( + Function::find_export_func(self.Get_inner_reference(), Name)? + .call(&self.0, &vec![WasmValue::I32(0)])?, + ) } else { - Function::find_export_func(self.Get_inner_reference(), Name)?.call(&self.0, Parameters) + Ok( + Function::find_export_func(self.Get_inner_reference(), Name)? + .call(&self.0, Parameters)?, + ) } } - pub fn Call_main(&self, Parameters: &Vec) -> Result { + pub fn Call_main(&self, Parameters: &Vec) -> Result_type { self.Call_export_function("main", Parameters) } diff --git a/Modules/Virtual_machine/src/Runtime.rs b/Modules/Virtual_machine/src/Runtime.rs index 85db26a..1b443b3 100644 --- a/Modules/Virtual_machine/src/Runtime.rs +++ b/Modules/Virtual_machine/src/Runtime.rs @@ -1,9 +1,9 @@ use wamr_rust_sdk::{ runtime::{Runtime, RuntimeBuilder}, - RuntimeError, + sys::{wasm_runtime_destroy_thread_env, wasm_runtime_init_thread_env}, }; -use crate::Registrable_trait; +use crate::{Registrable_trait, Result_type}; pub struct Runtime_builder_type(RuntimeBuilder); @@ -31,7 +31,7 @@ impl Runtime_builder_type { self } - pub fn Build(self) -> Result { + pub fn Build(self) -> Result_type { Ok(Runtime_type(self.0.build()?)) } } @@ -46,4 +46,16 @@ impl Runtime_type { pub(crate) fn Get_inner_reference(&self) -> &Runtime { &self.0 } + + pub fn Initialize_thread_environment() -> Option<()> { + if unsafe { wasm_runtime_init_thread_env() } { + Some(()) + } else { + None + } + } + + pub fn Deinitialize_thread_environment() { + unsafe { wasm_runtime_destroy_thread_env() } + } } diff --git a/src/Users/Manager.rs b/src/Users/Manager.rs deleted file mode 100644 index 230e70c..0000000 --- a/src/Users/Manager.rs +++ /dev/null @@ -1,30 +0,0 @@ -use super::*; -use std::{ - collections::HashMap, - sync::{Arc, RwLock}, -}; - -struct Internal_user_type { - pub Name: String, -} - -pub struct Manager_type { - Users: Arc>>, -} - -impl Manager_type { - pub fn New() -> Self { - Self { - Users: Arc::new(RwLock::new(HashMap::new())), - } - } - - pub fn Get_user_name(&self, Identifier: Identifier_type) -> Option { - let Users = self.Users.read().unwrap(); - Some(Users.get(&Identifier).unwrap().Name.clone()) - } - - pub fn Check_credentials(&self, User_name: &str, Password: &str) -> bool { - true - } -} diff --git a/src/Users/User.rs b/src/Users/User.rs deleted file mode 100644 index 4812ed5..0000000 --- a/src/Users/User.rs +++ /dev/null @@ -1,19 +0,0 @@ -use super::*; - -pub struct User_type<'a> { - User_manager: &'a Manager_type, - Identifier: Identifier_type, -} - -impl<'a> User_type<'a> { - pub fn New(User_manager: &'a Manager_type, Identifier: Identifier_type) -> Self { - User_type { - User_manager, - Identifier, - } - } - - pub fn Get_name(&self) -> String { - self.User_manager.Get_user_name(self.Identifier).unwrap() - } -} diff --git a/src/Users/mod.rs b/src/Users/mod.rs deleted file mode 100644 index 915039d..0000000 --- a/src/Users/mod.rs +++ /dev/null @@ -1,7 +0,0 @@ -type Identifier_type = u8; - -mod Manager; -pub use Manager::*; - -mod User; -pub use User::*; diff --git a/src/main.rs b/src/main.rs index 605b3cb..ecd1439 100644 --- a/src/main.rs +++ b/src/main.rs @@ -12,9 +12,6 @@ use esp_idf_hal::{ #[cfg(target_os = "espidf")] use esp_idf_sys as _; // If using the `binstart` feature of `esp-idf-sys`, always keep this module imported -mod Users; -use Virtual_machine; - fn main() { // It is necessary to call this function once. Otherwise some patches to the runtime // implemented by esp-idf-sys might not link properly. See https://github.com/esp-rs/esp-idf-template/issues/71