diff --git a/drivers/native/src/devices/window_screen/screen.rs b/drivers/native/src/devices/window_screen/screen.rs index 891979b4..e84f04d6 100644 --- a/drivers/native/src/devices/window_screen/screen.rs +++ b/drivers/native/src/devices/window_screen/screen.rs @@ -1,6 +1,9 @@ -use file_system::{DirectBaseOperations, DirectCharacterDevice, MountOperations, Size}; +use file_system::{ + ControlCommand, ControlCommandIdentifier, DirectBaseOperations, DirectCharacterDevice, + MountOperations, Size, +}; use graphics::{Area, GET_RESOLUTION, RenderingColor, SET_DRAWING_AREA, WAS_RESIZED}; -use shared::align_slice_to; +use shared::{AnyByLayout, align_slice_to}; use crate::window_screen::inner_window::InnerWindow; @@ -32,28 +35,23 @@ impl<'a> DirectBaseOperations for ScreenDevice<'a> { fn control( &self, - command: file_system::ControlCommand, - argument: &mut file_system::ControlArgument, + command: ControlCommandIdentifier, + input: &AnyByLayout, + output: &mut AnyByLayout, ) -> file_system::Result<()> { match command { - SET_DRAWING_AREA => { - let area: &Area = argument - .cast() - .ok_or(file_system::Error::InvalidParameter)?; + SET_DRAWING_AREA::IDENTIFIER => { + let area: &Area = SET_DRAWING_AREA::cast_input(input)?; task::block_on(self.0.set_drawing_area(*area)).unwrap(); } - GET_RESOLUTION => { - let resolution: &mut graphics::Point = argument - .cast() - .ok_or(file_system::Error::InvalidParameter)?; + GET_RESOLUTION::IDENTIFIER => { + let resolution: &mut graphics::Point = GET_RESOLUTION::cast_output(output)?; *resolution = task::block_on(self.0.get_resolution()).unwrap(); } - WAS_RESIZED => { - let was_resized: &mut bool = argument - .cast() - .ok_or(file_system::Error::InvalidParameter)?; + WAS_RESIZED::IDENTIFIER => { + let was_resized: &mut bool = WAS_RESIZED::cast_output(output)?; *was_resized = task::block_on(self.0.was_resized()).unwrap(); } diff --git a/drivers/shared/src/devices/hash.rs b/drivers/shared/src/devices/hash.rs index d7fdbaaa..6e420dca 100644 --- a/drivers/shared/src/devices/hash.rs +++ b/drivers/shared/src/devices/hash.rs @@ -1,9 +1,10 @@ -use device::hash::{self, HashAlgorithm}; +use device::hash::{self, HashAlgorithm, SET_ALGORITHM}; use file_system::{ - BaseOperations, CharacterDevice, Context, ControlArgument, ControlCommand, Error, + BaseOperations, CharacterDevice, Context, ControlCommand, ControlCommandIdentifier, Error, MountOperations, Result, Size, }; use sha2::{Digest, Sha224, Sha256, Sha384, Sha512, Sha512_224, Sha512_256, digest::DynDigest}; +use shared::AnyByLayout; #[derive(Clone)] struct HashDeviceContext { @@ -69,22 +70,21 @@ impl BaseOperations for HashDevice { fn control( &self, context: &mut Context, - command: ControlCommand, - argument: &mut ControlArgument, + command: ControlCommandIdentifier, + input: &AnyByLayout, + _: &mut AnyByLayout, ) -> Result<()> { let hash_context = context .get_private_data_mutable_of_type::() .ok_or_else(|| file_system::Error::InvalidParameter)?; match command { - hash::RESET => { + hash::RESET::IDENTIFIER => { hash_context.hasher.reset(); Ok(()) } - hash::SET_ALGORITHM => { - let algorithm = argument - .cast::() - .ok_or_else(|| file_system::Error::InvalidParameter)?; + hash::SET_ALGORITHM::IDENTIFIER => { + let algorithm = SET_ALGORITHM::cast_input(input)?; *hash_context = HashDeviceContext::new(*algorithm)?; Ok(()) diff --git a/drivers/std/Cargo.toml b/drivers/std/Cargo.toml index 8c6c32a0..95a7a6fd 100644 --- a/drivers/std/Cargo.toml +++ b/drivers/std/Cargo.toml @@ -13,6 +13,7 @@ task = { workspace = true } users = { workspace = true } synchronization = { workspace = true } virtual_file_system = { workspace = true } +shared = { workspace = true } libc = { version = "0.2" } linked_list_allocator = { version = "0.10", default-features = false, features = [ diff --git a/drivers/std/src/console.rs b/drivers/std/src/console.rs index f6111234..1de834ac 100644 --- a/drivers/std/src/console.rs +++ b/drivers/std/src/console.rs @@ -1,11 +1,10 @@ -use std::io::{Read, Write, stderr, stdin, stdout}; - +use crate::io::map_error; use file_system::{ - ControlArgument, ControlCommand, DirectBaseOperations, DirectCharacterDevice, MountOperations, - Size, character_device, + ControlCommand, ControlCommandIdentifier, DirectBaseOperations, DirectCharacterDevice, + MountOperations, Size, character_device::IS_A_TERMINAL, }; - -use crate::io::map_error; +use shared::AnyByLayout; +use std::io::{Read, Write, stderr, stdin, stdout}; pub struct StandardInDevice; @@ -27,10 +26,11 @@ impl DirectBaseOperations for StandardInDevice { fn control( &self, - command: ControlCommand, - argument: &mut ControlArgument, + command: ControlCommandIdentifier, + input: &AnyByLayout, + output: &mut AnyByLayout, ) -> file_system::Result<()> { - control(command, argument) + control(command, input, output) } } @@ -55,10 +55,11 @@ impl DirectBaseOperations for StandardOutDevice { fn control( &self, - command: ControlCommand, - argument: &mut ControlArgument, + command: ControlCommandIdentifier, + input: &AnyByLayout, + output: &mut AnyByLayout, ) -> file_system::Result<()> { - control(command, argument) + control(command, input, output) } } @@ -83,10 +84,11 @@ impl DirectBaseOperations for StandardErrorDevice { fn control( &self, - command: ControlCommand, - argument: &mut ControlArgument, + command: ControlCommandIdentifier, + input: &AnyByLayout, + output: &mut AnyByLayout, ) -> file_system::Result<()> { - control(command, argument) + control(command, input, output) } } @@ -94,12 +96,15 @@ impl MountOperations for StandardErrorDevice {} impl DirectCharacterDevice for StandardErrorDevice {} -fn control(command: ControlCommand, argument: &mut ControlArgument) -> file_system::Result<()> { +fn control( + command: ControlCommandIdentifier, + _: &AnyByLayout, + output: &mut AnyByLayout, +) -> file_system::Result<()> { match command { - character_device::IS_A_TERMINAL => { - *argument - .cast::() - .ok_or(file_system::Error::InvalidParameter)? = true; + IS_A_TERMINAL::IDENTIFIER => { + let output: &mut bool = IS_A_TERMINAL::cast_output(output)?; + *output = true; Ok(()) } diff --git a/drivers/std/src/drive_file.rs b/drivers/std/src/drive_file.rs index c1e61728..699452de 100644 --- a/drivers/std/src/drive_file.rs +++ b/drivers/std/src/drive_file.rs @@ -4,9 +4,12 @@ use std::{ }; use file_system::{ - ControlArgument, ControlCommand, DirectBaseOperations, DirectBlockDevice, Error, - MountOperations, Path, Position, Size, block_device, mount::MutexMountWrapper, + ControlCommand, ControlCommandIdentifier, DirectBaseOperations, DirectBlockDevice, Error, + MountOperations, Path, Position, Size, + block_device::{GET_BLOCK_COUNT, GET_BLOCK_SIZE}, + mount::MutexMountWrapper, }; +use shared::AnyByLayout; use synchronization::blocking_mutex::raw::CriticalSectionRawMutex; use crate::io::map_error; @@ -93,19 +96,19 @@ impl DirectBaseOperations for FileDriveDevice { fn control( &self, - command: ControlCommand, - argument: &mut ControlArgument, + command: ControlCommandIdentifier, + _: &AnyByLayout, + output: &mut AnyByLayout, ) -> file_system::Result<()> { match command { - block_device::GET_BLOCK_SIZE => { - let block_size = argument.cast::().ok_or(Error::InvalidParameter)?; - + GET_BLOCK_SIZE::IDENTIFIER => { + let block_size = GET_BLOCK_SIZE::cast_output(output)?; *block_size = 512; // Fixed block size for file drive device Ok(()) } - block_device::GET_BLOCK_COUNT => { - let block_count = argument.cast::().ok_or(Error::InvalidParameter)?; + GET_BLOCK_COUNT::IDENTIFIER => { + let block_count = GET_BLOCK_COUNT::cast_output(output)?; let file_size = self .0 @@ -115,7 +118,7 @@ impl DirectBaseOperations for FileDriveDevice { .map_err(map_error)? .len(); - *block_count = file_size / 512; // Fixed block size for file drive device + *block_count = (file_size / 512) as _; // Fixed block size for file drive device Ok(()) } diff --git a/drivers/std/src/memory.rs b/drivers/std/src/memory.rs index 5ed331d7..e173d072 100644 --- a/drivers/std/src/memory.rs +++ b/drivers/std/src/memory.rs @@ -122,7 +122,7 @@ impl ManagerTrait for MemoryManager { } } - unsafe fn get_used(&self) -> usize { + fn get_used(&self) -> usize { self.regions.lock(|regions| { let regions = regions.borrow(); let mut used = 0; @@ -133,7 +133,7 @@ impl ManagerTrait for MemoryManager { }) } - unsafe fn get_free(&self) -> usize { + fn get_free(&self) -> usize { self.regions.lock(|regions| { let regions = regions.borrow(); let mut free = 0; diff --git a/drivers/wasm/src/devices/graphics/canvas_screen.rs b/drivers/wasm/src/devices/graphics/canvas_screen.rs index 96d577b0..5ff30b08 100644 --- a/drivers/wasm/src/devices/graphics/canvas_screen.rs +++ b/drivers/wasm/src/devices/graphics/canvas_screen.rs @@ -1,9 +1,12 @@ use core::slice; use alloc::{boxed::Box, rc::Rc, string::String, vec::Vec}; -use file_system::{DirectBaseOperations, DirectCharacterDevice, MountOperations, Size}; +use file_system::{ + ControlCommand, ControlCommandIdentifier, DirectBaseOperations, DirectCharacterDevice, + MountOperations, Size, +}; use graphics::{Area, GET_RESOLUTION, Point, RenderingColor, SET_DRAWING_AREA, WAS_RESIZED}; -use shared::align_slice_to; +use shared::{AnyByLayout, align_slice_to}; use synchronization::{blocking_mutex::raw::CriticalSectionRawMutex, rwlock::RwLock}; use task::block_on; use wasm_bindgen::{Clamped, JsCast, JsValue, prelude::Closure}; @@ -160,22 +163,19 @@ impl DirectBaseOperations for CanvasScreenDevice { fn control( &self, - command: file_system::ControlCommand, - argument: &mut file_system::ControlArgument, + command: ControlCommandIdentifier, + input: &AnyByLayout, + output: &mut AnyByLayout, ) -> file_system::Result<()> { match command { - SET_DRAWING_AREA => { - let area: &mut Area = argument - .cast() - .ok_or(file_system::Error::InvalidParameter)?; + SET_DRAWING_AREA::IDENTIFIER => { + let area = SET_DRAWING_AREA::cast_input(input)?; let mut inner = block_on(self.0.write()); inner.area = *area; } - GET_RESOLUTION => { - let point: &mut Point = argument - .cast() - .ok_or(file_system::Error::InvalidParameter)?; + GET_RESOLUTION::IDENTIFIER => { + let point = GET_RESOLUTION::cast_output(output)?; let inner = block_on(self.0.read()); @@ -185,10 +185,8 @@ impl DirectBaseOperations for CanvasScreenDevice { *point = resolution; } - WAS_RESIZED => { - let was_resized: &mut bool = argument - .cast() - .ok_or(file_system::Error::InvalidParameter)?; + WAS_RESIZED::IDENTIFIER => { + let was_resized = WAS_RESIZED::cast_output(output)?; let mut inner = block_on(self.0.write()); *was_resized = inner.was_resized; diff --git a/drivers/wasm/src/memory.rs b/drivers/wasm/src/memory.rs index 26c5cefc..a36c5d4c 100644 --- a/drivers/wasm/src/memory.rs +++ b/drivers/wasm/src/memory.rs @@ -145,14 +145,14 @@ impl ManagerTrait for MemoryManager { .lock(|inner| unsafe { inner.borrow_mut().heap.deallocate(pointer, layout) }); } - unsafe fn get_used(&self) -> usize { + fn get_used(&self) -> usize { self.0.lock(|inner| { let inner = inner.borrow(); inner.heap.used() }) } - unsafe fn get_free(&self) -> usize { + fn get_free(&self) -> usize { self.0.lock(|inner| { let inner = inner.borrow(); inner.heap.free() diff --git a/modules/abi/definitions/src/file_system/functions.rs b/modules/abi/definitions/src/file_system/functions.rs index 0b6d16fd..b584776d 100644 --- a/modules/abi/definitions/src/file_system/functions.rs +++ b/modules/abi/definitions/src/file_system/functions.rs @@ -392,13 +392,13 @@ pub unsafe extern "C" fn xila_file_system_is_a_terminal( Err(Error::InvalidParameter)?; } - let is_a_terminal = unsafe { &mut *is_a_terminal }; - - context::get_instance() - .perform_operation_on_file(file.try_into()?, |file| { - file.control(character_device::IS_A_TERMINAL, is_a_terminal) - }) - .ok_or(Error::InvalidIdentifier)??; + unsafe { + *is_a_terminal = context::get_instance() + .perform_operation_on_file(file.try_into()?, |file| { + file.control(character_device::IS_A_TERMINAL, &()) + }) + .ok_or(Error::InvalidIdentifier)??; + } Ok(()) }) diff --git a/modules/authentication/src/hash.rs b/modules/authentication/src/hash.rs index 236067c3..77477e8e 100644 --- a/modules/authentication/src/hash.rs +++ b/modules/authentication/src/hash.rs @@ -95,9 +95,7 @@ pub async fn hash_password( .await .map_err(Error::FailedToHashPassword)?; - let mut algorithm = HashAlgorithm::Sha512; - - file.control(SET_ALGORITHM, &mut algorithm) + file.control(SET_ALGORITHM, &HashAlgorithm::Sha512) .await .map_err(Error::FailedToHashPassword)?; diff --git a/modules/device/src/hash.rs b/modules/device/src/hash.rs index fd3c9ee2..c2cf888e 100644 --- a/modules/device/src/hash.rs +++ b/modules/device/src/hash.rs @@ -1,4 +1,4 @@ -use file_system::{ControlCommand, ControlDirectionFlags}; +use file_system::{ControlCommand, define_command}; #[repr(u8)] #[derive(Clone, Copy, Debug, PartialEq, Eq)] @@ -13,6 +13,5 @@ pub enum HashAlgorithm { Sha512_256 = 7, } -pub const RESET: ControlCommand = ControlCommand::new::<()>(ControlDirectionFlags::Write, b'H', 0); -pub const SET_ALGORITHM: ControlCommand = - ControlCommand::new::(ControlDirectionFlags::Write, b'H', 1); +define_command!(RESET, Write, b'H', 0, (), ()); +define_command!(SET_ALGORITHM, Write, b'H', 1, HashAlgorithm, ()); diff --git a/modules/executable/Cargo.toml b/modules/executable/Cargo.toml index 28726c03..7bb77655 100644 --- a/modules/executable/Cargo.toml +++ b/modules/executable/Cargo.toml @@ -8,7 +8,7 @@ file_system = { workspace = true } virtual_file_system = { workspace = true } task = { workspace = true } users = { workspace = true } - +shared = { workspace = true } log = { workspace = true } [dev-dependencies] diff --git a/modules/executable/src/lib.rs b/modules/executable/src/lib.rs index 7bafb073..af28b93f 100644 --- a/modules/executable/src/lib.rs +++ b/modules/executable/src/lib.rs @@ -112,9 +112,7 @@ pub async fn execute( .get_file_name() .ok_or(virtual_file_system::Error::InvalidPath)?; - let mut main_function: MainFunction = None; - - file.control(GET_MAIN_FUNCTION, &mut main_function).await?; + let main_function: MainFunction = file.control(GET_MAIN_FUNCTION, &()).await?; let main = main_function.ok_or(Error::FailedToGetMainFunction)?; diff --git a/modules/executable/src/traits.rs b/modules/executable/src/traits.rs index cdf90cca..48c137b2 100644 --- a/modules/executable/src/traits.rs +++ b/modules/executable/src/traits.rs @@ -2,12 +2,12 @@ use crate::Standard; use alloc::{boxed::Box, string::String, vec::Vec}; use core::{num::NonZeroUsize, pin::Pin}; use file_system::{ - ControlCommand, ControlDirectionFlags, DirectBaseOperations, DirectCharacterDevice, - MountOperations, + ControlCommand, ControlCommandIdentifier, DirectBaseOperations, DirectCharacterDevice, + MountOperations, define_command, }; +use shared::AnyByLayout; -pub const GET_MAIN_FUNCTION: ControlCommand = - ControlCommand::new::(ControlDirectionFlags::Read, b'E', 1); +define_command!(GET_MAIN_FUNCTION, Read, b'E', 1, (), MainFunction); pub trait ExecutableTrait: 'static + Send + Sync { fn main(standard: Standard, arguments: Vec) -> MainFuture; @@ -47,16 +47,16 @@ impl DirectBaseOperations for ExecutableWrapper { fn control( &self, - command: ControlCommand, - argument: &mut file_system::ControlArgument, + command: ControlCommandIdentifier, + _: &AnyByLayout, + output: &mut AnyByLayout, ) -> file_system::Result<()> { log::debug!("ExecutableWrapper control command: {:?}", command); match command { - GET_MAIN_FUNCTION => { - *argument - .cast::() - .ok_or(file_system::Error::InvalidParameter)? = Some(Box::new(T::main)); + GET_MAIN_FUNCTION::IDENTIFIER => { + let output = GET_MAIN_FUNCTION::cast_output(output)?; + *output = Some(Box::new(T::main)); Ok(()) } _ => Err(file_system::Error::UnsupportedOperation), diff --git a/modules/file_system/src/devices/memory_device.rs b/modules/file_system/src/devices/memory_device.rs index 592a38bf..07a71d8e 100644 --- a/modules/file_system/src/devices/memory_device.rs +++ b/modules/file_system/src/devices/memory_device.rs @@ -10,10 +10,13 @@ use core::fmt::Debug; use alloc::vec::Vec; use alloc::{boxed::Box, vec}; +use shared::AnyByLayout; use synchronization::{blocking_mutex::raw::CriticalSectionRawMutex, rwlock::RwLock}; +use crate::block_device::GET_BLOCK_SIZE; use crate::{ - DirectBaseOperations, DirectBlockDevice, Error, MountOperations, Result, Size, block_device, + ControlCommand, DirectBaseOperations, DirectBlockDevice, Error, MountOperations, Result, Size, + block_device, }; /// In-memory device implementation with configurable block size. @@ -51,9 +54,9 @@ use crate::{ /// /// The device uses an `RwLock` to ensure thread-safe access to the underlying data. /// Multiple readers can access the device simultaneously, but writes are exclusive. -pub struct MemoryDevice(RwLock>); +pub struct MemoryDevice(RwLock>); -impl Debug for MemoryDevice { +impl Debug for MemoryDevice { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { f.debug_struct("MemoryDevice") .field("size", &self.0.try_read().map(|data| data.len())) @@ -61,7 +64,7 @@ impl Debug for MemoryDevice { } } -impl MemoryDevice { +impl MemoryDevice { /// Create a new memory device with the specified size. /// /// The device will be initialized with zeros and have the specified total size. @@ -85,7 +88,7 @@ impl MemoryDevice { /// let device = MemoryDevice::<512>::new(4096); /// ``` pub fn new(size: usize) -> Self { - assert!(size.is_multiple_of(BLOCK_SIZE)); + assert!(size.is_multiple_of(BLOCK_SIZE as usize)); let data: Vec = vec![0; size]; @@ -121,13 +124,13 @@ impl MemoryDevice { /// let device = MemoryDevice::<512>::from_vec(data); /// ``` pub fn from_vec(data: Vec) -> Self { - assert!(data.len().is_multiple_of(BLOCK_SIZE)); + assert!(data.len().is_multiple_of(BLOCK_SIZE as usize)); Self(RwLock::new(data)) } } -impl DirectBaseOperations for MemoryDevice { +impl DirectBaseOperations for MemoryDevice { /// Read data from the memory device. /// /// Reads data from the current position into the provided buffer. @@ -167,37 +170,35 @@ impl DirectBaseOperations for MemoryDevice fn control( &self, - command: crate::ControlCommand, - argument: &mut crate::ControlArgument, + command: crate::ControlCommandIdentifier, + _: &AnyByLayout, + output: &mut AnyByLayout, ) -> Result<()> { match command { - block_device::GET_BLOCK_SIZE => { - *argument - .cast::() - .ok_or(crate::Error::InvalidParameter)? = BLOCK_SIZE; - Ok(()) + GET_BLOCK_SIZE::IDENTIFIER => { + let output = GET_BLOCK_SIZE::cast_output(output)?; + *output = BLOCK_SIZE; } - block_device::GET_BLOCK_COUNT => { - let block_count = argument - .cast::() - .ok_or(crate::Error::InvalidParameter)?; + block_device::GET_BLOCK_COUNT::IDENTIFIER => { + let output = block_device::GET_BLOCK_COUNT::cast_output(output)?; - *block_count = self + *output = (self .0 .try_read() .map_err(|_| crate::Error::RessourceBusy)? .len() - / BLOCK_SIZE; - Ok(()) + / BLOCK_SIZE as usize) as u32; } - _ => Err(Error::UnsupportedOperation), + _ => return Err(Error::UnsupportedOperation), } + + Ok(()) } } -impl MountOperations for MemoryDevice {} +impl MountOperations for MemoryDevice {} -impl DirectBlockDevice for MemoryDevice {} +impl DirectBlockDevice for MemoryDevice {} #[cfg(test)] mod tests { diff --git a/modules/file_system/src/devices/partition_device.rs b/modules/file_system/src/devices/partition_device.rs index 8707d19b..80aca136 100644 --- a/modules/file_system/src/devices/partition_device.rs +++ b/modules/file_system/src/devices/partition_device.rs @@ -7,9 +7,12 @@ use core::fmt; +use shared::AnyByLayout; + use crate::{ - BaseOperations, DirectBaseOperations, DirectBlockDevice, Error, MountOperations, Position, - Result, Size, block_device, + BaseOperations, ControlCommand, ControlCommandIdentifier, DirectBaseOperations, + DirectBlockDevice, Error, MountOperations, Position, Result, Size, + block_device::{self, GET_BLOCK_COUNT, GET_BLOCK_SIZE}, }; /// A device implementation that represents a partition within a larger storage device. @@ -44,7 +47,7 @@ pub struct PartitionDevice<'a, D> { /// Base device containing this partition base_device: &'a D, /// Block size - block_size: usize, + block_size: u32, /// Byte offset from the beginning of the base device offset: Size, /// Size of this partition in bytes @@ -71,12 +74,7 @@ impl<'a, D: BaseOperations> PartitionDevice<'a, D> { /// // Create a partition starting at block 128 (64KB) with 256 blocks (128KB) /// let partition = PartitionDevice::new(&base_device, 128, 256, 512); /// ``` - pub fn new( - base_device: &'a D, - start_block: Size, - block_count: Size, - block_size: usize, - ) -> Self { + pub fn new(base_device: &'a D, start_block: Size, block_count: Size, block_size: u32) -> Self { Self { base_device, block_size, @@ -102,7 +100,7 @@ impl<'a, D: BaseOperations> PartitionDevice<'a, D> { /// assert_eq!(partition.get_block_count(), 50); /// ``` pub const fn get_block_count(&self) -> u32 { - self.size as u32 / (self.block_size as u32) + self.size as u32 / self.block_size } pub const fn get_start_lba(&self) -> Size { @@ -224,24 +222,25 @@ impl<'a, D: DirectBaseOperations> DirectBaseOperations for PartitionDevice<'a, D fn control( &self, - command: crate::ControlCommand, - argument: &mut crate::ControlArgument, + command: ControlCommandIdentifier, + input: &AnyByLayout, + output: &mut AnyByLayout, ) -> Result<()> { match command { - block_device::GET_BLOCK_SIZE => { - *argument - .cast::() - .ok_or(crate::Error::InvalidParameter)? = self.block_size; - Ok(()) + GET_BLOCK_SIZE::IDENTIFIER => { + let output = GET_BLOCK_SIZE::cast_output(output)?; + + *output = self.block_size; } - block_device::GET_BLOCK_COUNT => { - *argument - .cast::() - .ok_or(crate::Error::InvalidParameter)? = self.get_block_count() as Size; - Ok(()) + GET_BLOCK_COUNT::IDENTIFIER => { + *output + .cast_mutable::() + .ok_or(Error::InvalidParameter)? = self.get_block_count() as Size; } - _ => self.base_device.control(command, argument), + _ => return self.base_device.control(command, input, output), } + + Ok(()) } } diff --git a/modules/file_system/src/fundamentals/control.rs b/modules/file_system/src/fundamentals/control.rs index 1a8901a3..85546051 100644 --- a/modules/file_system/src/fundamentals/control.rs +++ b/modules/file_system/src/fundamentals/control.rs @@ -1,5 +1,6 @@ -use alloc::slice; -use shared::flags; +use shared::{AnyByLayout, flags}; + +use crate::{Error, Result}; flags! { /// The kinds of control commands. @@ -11,11 +12,75 @@ flags! { } } +struct ControlCommandInputOutput { + pub _input: I, + pub _output: O, +} + +pub trait ControlCommand: Clone + Copy { + type Input; + type Output; + + const IDENTIFIER: ControlCommandIdentifier; + + fn cast_input(input: &AnyByLayout) -> Result<&Self::Input> { + input.cast().ok_or(Error::InvalidParameter) + } + + fn cast_output(output: &mut AnyByLayout) -> Result<&mut Self::Output> { + output.cast_mutable().ok_or(Error::InvalidParameter) + } + + fn cast<'i, 'o>( + input: &'i AnyByLayout, + output: &'o mut AnyByLayout, + ) -> Result<(&'i Self::Input, &'o mut Self::Output)> { + Ok((Self::cast_input(input)?, Self::cast_output(output)?)) + } +} + +#[macro_export] +macro_rules! define_command { + ($name:ident, Read, $kind:expr, $number:expr, $I:ty, $O:ty) => { + $crate::define_command!( + $name, + $crate::ControlDirectionFlags::Read, + $kind, + $number, + $I, + $O + ); + }; + ($name:ident, Write, $kind:expr, $number:expr, $I:ty, $O:ty) => { + $crate::define_command!( + $name, + $crate::ControlDirectionFlags::Write, + $kind, + $number, + $I, + $O + ); + }; + ($name:ident, $direction:expr, $kind:expr, $number:expr, $I:ty, $O:ty) => { + #[derive(Clone, Copy, Debug)] + #[allow(non_camel_case_types)] + pub struct $name; + + impl ControlCommand for $name { + type Input = $I; + type Output = $O; + + const IDENTIFIER: $crate::ControlCommandIdentifier = + $crate::ControlCommandIdentifier::new::<$I, $O>($direction, $kind, $number); + } + }; +} + #[repr(transparent)] #[derive(Clone, Copy, Debug, PartialEq, Eq)] -pub struct ControlCommand(usize); +pub struct ControlCommandIdentifier(usize); -impl ControlCommand { +impl ControlCommandIdentifier { const NUMBER_SIZE: usize = 8; const KIND_SIZE: usize = 8; const SIZE_SIZE: usize = 14; @@ -26,8 +91,28 @@ impl ControlCommand { const SIZE_SHIFT: usize = Self::KIND_SHIFT + Self::KIND_SIZE; // 16 const DIRECTION_SHIFT: usize = Self::SIZE_SHIFT + Self::SIZE_SIZE; // 30 - pub const fn new(direction: ControlDirectionFlags, kind: u8, number: u8) -> Self { - Self::new_with_size(direction, size_of::(), kind, number) + pub const fn new(direction: ControlDirectionFlags, kind: u8, number: u8) -> Self { + let size = core::mem::size_of::>(); + + Self::new_with_size(direction, size, kind, number) + } + + pub const fn new_read(kind: u8, number: u8) -> Self { + Self::new_with_size( + ControlDirectionFlags::Read, + size_of::>(), + kind, + number, + ) + } + + pub const fn new_write(kind: u8, number: u8) -> Self { + Self::new_with_size( + ControlDirectionFlags::Write, + size_of::>(), + kind, + number, + ) } pub const fn new_with_size( @@ -65,53 +150,3 @@ impl ControlCommand { ((self.0 >> Self::NUMBER_SHIFT) & ((1 << Self::NUMBER_SIZE) - 1)) as u8 } } - -#[repr(transparent)] -#[derive(Debug, PartialEq, Eq)] -pub struct ControlArgument([u8]); - -impl<'a, T> From<&'a mut T> for &'a mut ControlArgument { - fn from(argument: &'a mut T) -> Self { - ControlArgument::from(argument) - } -} - -impl ControlArgument { - pub fn from(argument: &mut T) -> &mut Self { - unsafe { - let slice = slice::from_raw_parts_mut(argument as *mut T as *mut u8, size_of::()); - &mut *(slice as *mut [u8] as *mut Self) - } - } - - pub fn cast(&mut self) -> Option<&mut T> { - if size_of::() > self.0.len() { - return None; - } - - let argument = self.0.as_mut_ptr(); - - if argument.is_null() { - return None; - } - - // check alignment - if argument.align_offset(align_of::()) != 0 { - return None; - } - - Some(unsafe { &mut *(argument as *mut T) }) - } - - pub fn get_size(&self) -> usize { - self.0.len() - } - - pub fn get_alignment(&self) -> usize { - self.0.as_ptr().align_offset(1) - } - - pub fn as_mutable_bytes(&mut self) -> &mut [u8] { - &mut self.0 - } -} diff --git a/modules/file_system/src/operations/base.rs b/modules/file_system/src/operations/base.rs index 3bd54e20..4a7a9590 100644 --- a/modules/file_system/src/operations/base.rs +++ b/modules/file_system/src/operations/base.rs @@ -3,7 +3,9 @@ //! This module provides the core device trait and types for abstracting various //! storage devices, peripherals, and I/O endpoints in the file system. -use crate::{Context, ControlArgument, ControlCommand, Error, Position, Result, Size}; +use shared::AnyByLayout; + +use crate::{Context, ControlCommandIdentifier, Error, Position, Result, Size}; /// Core trait for all device implementations in the file system. /// @@ -250,8 +252,9 @@ pub trait BaseOperations: Send + Sync { fn control( &self, _context: &mut Context, - _command: ControlCommand, - _argument: &mut ControlArgument, + _command: ControlCommandIdentifier, + _input: &AnyByLayout, + _output: &mut AnyByLayout, ) -> Result<()> { Err(Error::UnsupportedOperation) } @@ -373,7 +376,12 @@ pub trait DirectBaseOperations: Send + Sync { } } - fn control(&self, _command: ControlCommand, _argument: &mut ControlArgument) -> Result<()> { + fn control( + &self, + _command: ControlCommandIdentifier, + _input: &AnyByLayout, + _output: &mut AnyByLayout, + ) -> Result<()> { Err(Error::UnsupportedOperation) } } @@ -429,10 +437,11 @@ where fn control( &self, _: &mut Context, - command: ControlCommand, - argument: &mut ControlArgument, + command: ControlCommandIdentifier, + input: &AnyByLayout, + output: &mut AnyByLayout, ) -> Result<()> { - self.control(command, argument) + self.control(command, input, output) } fn clone_context(&self, _context: &Context) -> Result { diff --git a/modules/file_system/src/operations/block_device.rs b/modules/file_system/src/operations/block_device.rs index b671709c..280646ba 100644 --- a/modules/file_system/src/operations/block_device.rs +++ b/modules/file_system/src/operations/block_device.rs @@ -1,27 +1,34 @@ use crate::{ - BaseOperations, ControlArgument, ControlCommand, ControlDirectionFlags, DirectBaseOperations, - Error, MountOperations, Position, Result, Size, + BaseOperations, ControlCommand, DirectBaseOperations, Error, MountOperations, Position, Result, + Size, define_command, }; +use shared::AnyByLayout; -pub const GET_BLOCK_SIZE: ControlCommand = - ControlCommand::new::(ControlDirectionFlags::Read, b'B', 0); -pub const GET_BLOCK_COUNT: ControlCommand = - ControlCommand::new::(ControlDirectionFlags::Read, b'B', 1); +define_command!(GET_BLOCK_SIZE, Read, b'B', 0, (), u32); +define_command!(GET_BLOCK_COUNT, Read, b'B', 1, (), u32); pub trait BlockDevice: BaseOperations + MountOperations {} pub trait DirectBlockDevice: DirectBaseOperations + MountOperations { - fn get_block_size(&self) -> Result { - let mut block_size: usize = 0; - - self.control(GET_BLOCK_SIZE, ControlArgument::from(&mut block_size))?; + fn get_block_size(&self) -> Result { + let mut block_size: u32 = 0; + + self.control( + GET_BLOCK_SIZE::IDENTIFIER, + AnyByLayout::NONE, + AnyByLayout::from_mutable(&mut block_size), + )?; Ok(block_size) } fn get_block_count(&self) -> Result { let mut total_size: Size = 0; - self.control(GET_BLOCK_COUNT, ControlArgument::from(&mut total_size))?; + self.control( + GET_BLOCK_COUNT::IDENTIFIER, + AnyByLayout::NONE, + AnyByLayout::from_mutable(&mut total_size), + )?; Ok(total_size) } } @@ -177,8 +184,9 @@ pub mod tests { device .control( &mut context, - GET_BLOCK_COUNT, - ControlArgument::from(&mut (block_count)), + GET_BLOCK_COUNT::IDENTIFIER, + AnyByLayout::NONE, + AnyByLayout::from_mutable(&mut block_count), ) .unwrap(); @@ -188,8 +196,9 @@ pub mod tests { device .control( &mut context, - GET_BLOCK_SIZE, - ControlArgument::from(&mut (block_size)), + GET_BLOCK_SIZE::IDENTIFIER, + AnyByLayout::NONE, + AnyByLayout::from_mutable(&mut block_size), ) .unwrap(); diff --git a/modules/file_system/src/operations/character_device.rs b/modules/file_system/src/operations/character_device.rs index be032a12..d574bd6d 100644 --- a/modules/file_system/src/operations/character_device.rs +++ b/modules/file_system/src/operations/character_device.rs @@ -1,9 +1,8 @@ use crate::{ - BaseOperations, ControlCommand, ControlDirectionFlags, DirectBaseOperations, MountOperations, + BaseOperations, ControlCommand, DirectBaseOperations, MountOperations, define_command, }; -pub const IS_A_TERMINAL: ControlCommand = - ControlCommand::new::(ControlDirectionFlags::Read, b'T', 0); +define_command!(IS_A_TERMINAL, Read, b'T', 0, (), bool); pub trait CharacterDevice: BaseOperations + MountOperations {} diff --git a/modules/graphics/src/display.rs b/modules/graphics/src/display.rs index 9622702e..493196b6 100644 --- a/modules/graphics/src/display.rs +++ b/modules/graphics/src/display.rs @@ -1,10 +1,12 @@ use alloc::boxed::Box; -use file_system::{ControlArgument, DirectCharacterDevice}; +use file_system::{ControlCommand, DirectCharacterDevice}; +use shared::AnyByLayout; use core::{ffi::c_void, ptr::null_mut, slice}; use crate::{ - Area, GET_RESOLUTION, Point, RenderingColor, Result, SET_DRAWING_AREA, draw_buffer::Buffer, + Area, GET_RESOLUTION, Point, RenderingColor, Result, SET_DRAWING_AREA, WAS_RESIZED, + draw_buffer::Buffer, }; use super::lvgl; @@ -40,7 +42,11 @@ unsafe extern "C" fn binding_callback_function( let device = &user_data.device; device - .control(SET_DRAWING_AREA, ControlArgument::from(&mut area)) + .control( + SET_DRAWING_AREA::IDENTIFIER, + AnyByLayout::from_mutable(&mut area), + AnyByLayout::NONE, + ) .expect("Error setting drawing area"); device.write(buffer, 0).expect("Error writing to display"); @@ -65,7 +71,11 @@ impl Display { // Get the resolution from the device. let mut resolution = Point::new(0, 0); device - .control(GET_RESOLUTION, ControlArgument::from(&mut resolution)) + .control( + GET_RESOLUTION::IDENTIFIER, + AnyByLayout::NONE, + AnyByLayout::from_mutable(&mut resolution), + ) .expect("Error getting resolution"); // Create the display. @@ -120,8 +130,9 @@ impl Display { user_data .device .control( - crate::screen::WAS_RESIZED, - ControlArgument::from(&mut was_resize), + WAS_RESIZED::IDENTIFIER, + AnyByLayout::NONE, + AnyByLayout::from_mutable(&mut was_resize), ) .expect("Error checking if display was resized"); @@ -133,7 +144,11 @@ impl Display { user_data .device - .control(GET_RESOLUTION, ControlArgument::from(&mut resolution)) + .control( + GET_RESOLUTION::IDENTIFIER, + AnyByLayout::NONE, + AnyByLayout::from_mutable(&mut resolution), + ) .expect("Error getting resolution"); unsafe { diff --git a/modules/graphics/src/screen.rs b/modules/graphics/src/screen.rs index f23fa25f..33c5e3e1 100644 --- a/modules/graphics/src/screen.rs +++ b/modules/graphics/src/screen.rs @@ -1,10 +1,7 @@ -use file_system::{ControlCommand, ControlDirectionFlags}; +use file_system::{ControlCommand, define_command}; use crate::{Area, Point}; -pub const SET_DRAWING_AREA: ControlCommand = - ControlCommand::new::(ControlDirectionFlags::Write, b'D', 0x01); -pub const GET_RESOLUTION: ControlCommand = - ControlCommand::new::(ControlDirectionFlags::Read, b'D', 0x02); -pub const WAS_RESIZED: ControlCommand = - ControlCommand::new::(ControlDirectionFlags::Read, b'D', 0x03); +define_command!(SET_DRAWING_AREA, Write, b'D', 0x01, Area, ()); +define_command!(GET_RESOLUTION, Read, b'D', 0x02, (), Point); +define_command!(WAS_RESIZED, Read, b'D', 0x03, (), bool); diff --git a/modules/little_fs/src/file_system.rs b/modules/little_fs/src/file_system.rs index 3185a7ec..fb63e77c 100644 --- a/modules/little_fs/src/file_system.rs +++ b/modules/little_fs/src/file_system.rs @@ -47,8 +47,8 @@ impl FileSystem { let configuration: littlefs::lfs_config = Configuration::new( device, - block_size, - block_count as usize, + block_size as _, + block_count as _, cache_size, cache_size, ) @@ -102,8 +102,8 @@ impl FileSystem { let configuration: littlefs::lfs_config = Configuration::new( device, - block_size, - block_count as usize, + block_size as _, + block_count as _, cache_size, cache_size, ) diff --git a/modules/memory/src/manager.rs b/modules/memory/src/manager.rs index 74a8e20d..d333ac1e 100644 --- a/modules/memory/src/manager.rs +++ b/modules/memory/src/manager.rs @@ -140,7 +140,7 @@ impl<'a> Manager<'a> { /// # Returns /// The number of bytes currently allocated. pub fn get_used(&self) -> usize { - unsafe { self.0.get_used() } + self.0.get_used() } /// Returns the amount of memory currently available. @@ -149,7 +149,15 @@ impl<'a> Manager<'a> { /// The number of bytes available for allocation. /// pub fn get_free(&self) -> usize { - unsafe { self.0.get_free() } + self.0.get_free() + } + + /// Returns the total size of the memory managed by this allocator. + /// + /// # Returns + /// The total number of bytes managed by the allocator. + pub fn get_total_size(&self) -> usize { + self.0.get_total_size() } } diff --git a/modules/memory/src/trait.rs b/modules/memory/src/trait.rs index bb0f9964..01d0ff86 100644 --- a/modules/memory/src/trait.rs +++ b/modules/memory/src/trait.rs @@ -112,21 +112,21 @@ pub trait ManagerTrait: Send + Sync { /// /// # Returns /// The number of bytes currently allocated. - /// - /// # Safety - /// This function is unsafe because it may rely on internal allocator state - /// that could be concurrently modified by other threads. - unsafe fn get_used(&self) -> usize; + fn get_used(&self) -> usize; /// Returns the amount of memory currently available in this allocator. /// /// # Returns /// The number of bytes available for allocation. + fn get_free(&self) -> usize; + + /// Returns the total size of the memory managed by this allocator. /// - /// # Safety - /// This function is unsafe because it may rely on internal allocator state - /// that could be concurrently modified by other threads. - unsafe fn get_free(&self) -> usize; + /// # Returns + /// The total number of bytes managed by the allocator. + fn get_total_size(&self) -> usize { + self.get_used() + self.get_free() + } /// Flushes the instruction cache for a specific memory region. /// diff --git a/modules/shared/src/any.rs b/modules/shared/src/any.rs new file mode 100644 index 00000000..9670442b --- /dev/null +++ b/modules/shared/src/any.rs @@ -0,0 +1,256 @@ +use core::slice; + +#[repr(transparent)] +#[derive(Debug, PartialEq, Eq)] +pub struct AnyByLayout([u8]); + +impl<'a, T> From<&'a mut T> for &'a mut AnyByLayout { + fn from(argument: &'a mut T) -> Self { + AnyByLayout::from_mutable(argument) + } +} + +impl<'a, T> From<&'a T> for &'a AnyByLayout { + fn from(argument: &'a T) -> Self { + AnyByLayout::from(argument) + } +} + +impl AnyByLayout { + pub const NONE: &mut Self = Self::from_mutable(&mut [0u8; 0]); + + /// Gets a mutable reference to an `AnyByLayout` from raw parts. + /// + /// # Safety + /// The caller must ensure that the provided data pointer is valid for reads and writes + /// for the specified size, and that the memory is properly aligned. + pub unsafe fn from_raw_parts<'a>(data: *mut u8, size: usize) -> &'a mut Self { + unsafe { + let slice = slice::from_raw_parts_mut(data, size); + &mut *(slice as *mut [u8] as *mut Self) + } + } + + pub const fn from_mutable(argument: &mut T) -> &mut Self { + unsafe { + let slice = slice::from_raw_parts_mut(argument as *mut T as *mut u8, size_of::()); + &mut *(slice as *mut [u8] as *mut Self) + } + } + + pub fn from(argument: &T) -> &Self { + unsafe { + let slice = slice::from_raw_parts(argument as *const T as *const u8, size_of::()); + &*(slice as *const [u8] as *const Self) + } + } + + pub fn cast_mutable(&mut self) -> Option<&mut T> { + let (prefix, value, suffix) = unsafe { self.0.align_to_mut::() }; + + if !prefix.is_empty() && !suffix.is_empty() && value.len() != 1 { + return None; + } + + value.get_mut(0) + } + + pub fn cast(&self) -> Option<&T> { + let (prefix, value, suffix) = unsafe { self.0.align_to::() }; + + if !prefix.is_empty() && !suffix.is_empty() && value.len() != 1 { + return None; + } + + value.first() + } + + pub fn get_size(&self) -> usize { + self.0.len() + } + + pub fn get_alignment(&self) -> usize { + self.0.as_ptr().align_offset(1) + } + + pub fn as_mutable_bytes(&mut self) -> &mut [u8] { + &mut self.0 + } +} + +#[cfg(test)] +mod tests { + extern crate alloc; + use super::*; + use alloc::vec; + + #[test] + fn test_from_mutable_primitive() { + let mut value: u32 = 42; + let any = AnyByLayout::from_mutable(&mut value); + + assert_eq!(any.get_size(), size_of::()); + assert_eq!(any.as_mutable_bytes(), &[42, 0, 0, 0]); + } + + #[test] + fn test_from_immutable_primitive() { + let value: u64 = 0x0102030405060708; + let any = AnyByLayout::from(&value); + + assert_eq!(any.get_size(), size_of::()); + } + + #[test] + fn test_from_trait_mutable() { + let mut value: i32 = -100; + let any: &mut AnyByLayout = (&mut value).into(); + + assert_eq!(any.get_size(), size_of::()); + } + + #[test] + fn test_from_trait_immutable() { + let value: i16 = 256; + let any: &AnyByLayout = (&value).into(); + + assert_eq!(any.get_size(), size_of::()); + } + + #[test] + fn test_cast_mutable_success() { + let mut value: u32 = 12345; + let any = AnyByLayout::from_mutable(&mut value); + + let cast_back = any.cast_mutable::(); + assert!(cast_back.is_some()); + + if let Some(cast_ref) = cast_back { + assert_eq!(*cast_ref, 12345); + // Modify through the cast reference + *cast_ref = 67890; + } + assert_eq!(value, 67890); + } + + #[test] + fn test_cast_immutable_success() { + let value: i64 = -9876543210; + let any = AnyByLayout::from(&value); + + let cast_back = any.cast::(); + assert!(cast_back.is_some()); + assert_eq!(*cast_back.unwrap(), -9876543210); + } + + #[test] + fn test_cast_wrong_type_size() { + let value: u32 = 42; + let any = AnyByLayout::from(&value); + + // Try to cast u32 (4 bytes) as u64 (8 bytes) + let cast_result = any.cast::(); + assert!(cast_result.is_none()); + } + + #[test] + fn test_from_raw_parts() { + let mut data = vec![1u8, 2, 3, 4, 5, 6, 7, 8]; + let any = unsafe { AnyByLayout::from_raw_parts(data.as_mut_ptr(), data.len()) }; + + assert_eq!(any.get_size(), 8); + assert_eq!(any.as_mutable_bytes(), &[1, 2, 3, 4, 5, 6, 7, 8]); + } + + #[test] + fn test_empty_constant() { + let empty = AnyByLayout::NONE; + assert_eq!(empty.get_size(), 0); + } + + #[test] + fn test_as_mutable_bytes_modify() { + let mut value: u32 = 0x12345678; + let any = AnyByLayout::from_mutable(&mut value); + + let bytes = any.as_mutable_bytes(); + bytes[0] = 0xFF; + + // Value should be modified + assert_eq!(value & 0xFF, 0xFF); + } + + #[test] + fn test_struct_conversion() { + #[derive(Debug, PartialEq, Clone)] + struct TestStruct { + a: u32, + b: u16, + c: u8, + } + + let mut original = TestStruct { + a: 100, + b: 200, + c: 50, + }; + let expected = original.clone(); + let any = AnyByLayout::from_mutable(&mut original); + + assert_eq!(any.get_size(), size_of::()); + + let cast_back = any.cast_mutable::(); + assert!(cast_back.is_some()); + + if let Some(cast_ref) = cast_back { + assert_eq!(*cast_ref, expected); + // Modify and verify + cast_ref.a = 999; + } + assert_eq!(original.a, 999); + } + + #[test] + fn test_array_conversion() { + let mut array = [1u8, 2, 3, 4, 5]; + let any = AnyByLayout::from_mutable(&mut array); + + assert_eq!(any.get_size(), 5); + assert_eq!(any.as_mutable_bytes(), &[1, 2, 3, 4, 5]); + + let cast_back = any.cast_mutable::<[u8; 5]>(); + assert!(cast_back.is_some()); + assert_eq!(*cast_back.unwrap(), [1, 2, 3, 4, 5]); + } + + #[test] + fn test_zero_sized_type() { + let mut unit = (); + let any = AnyByLayout::from_mutable(&mut unit); + + assert_eq!(any.get_size(), 0); + } + + #[test] + fn test_equality() { + let value1: u32 = 42; + let value2: u32 = 42; + let value3: u32 = 43; + + let any1 = AnyByLayout::from(&value1); + let any2 = AnyByLayout::from(&value2); + let any3 = AnyByLayout::from(&value3); + + assert_eq!(any1, any2); + assert_ne!(any1, any3); + } + + #[test] + fn test_roundtrip_conversion() { + let original: f64 = 3.141592653589793; + let any = AnyByLayout::from(&original); + let cast_back = any.cast::().unwrap(); + + assert_eq!(*cast_back, original); + } +} diff --git a/modules/shared/src/lib.rs b/modules/shared/src/lib.rs index 53510281..9e71b392 100644 --- a/modules/shared/src/lib.rs +++ b/modules/shared/src/lib.rs @@ -2,6 +2,7 @@ extern crate alloc; +mod any; mod error; pub mod flags; mod http; @@ -11,6 +12,7 @@ mod time; mod unit; mod utf8; +pub use any::*; pub use error::*; pub use http::*; pub use size::*; diff --git a/modules/virtual_file_system/Cargo.toml b/modules/virtual_file_system/Cargo.toml index 91e04067..a88517d8 100644 --- a/modules/virtual_file_system/Cargo.toml +++ b/modules/virtual_file_system/Cargo.toml @@ -10,7 +10,7 @@ users = { workspace = true } time = { workspace = true } network = { workspace = true } synchronization = { workspace = true } - +shared = { workspace = true } log = { workspace = true } embedded-io-async = { workspace = true } diff --git a/modules/virtual_file_system/src/file.rs b/modules/virtual_file_system/src/file.rs index f8d3b592..14a07c65 100644 --- a/modules/virtual_file_system/src/file.rs +++ b/modules/virtual_file_system/src/file.rs @@ -198,7 +198,11 @@ impl File { poll(|| self.0.set_permissions(permissions)).await } - pub async fn control(&mut self, command: ControlCommand, argument: &mut A) -> Result<()> { + pub async fn control(&mut self, command: C, argument: &C::Input) -> Result + where + C: ControlCommand, + C::Output: Default, + { poll(|| self.0.control(command, argument)).await } @@ -219,3 +223,42 @@ impl File { self.0 } } + +pub struct FileControlIterator<'a, C> { + file: &'a mut File, + get_command: C, + index: usize, + count: usize, +} + +impl<'a, C> FileControlIterator<'a, C> +where + C: ControlCommand, + C::Output: Default, +{ + pub async fn new(file: &'a mut File, count_command: Cc, get_command: C) -> Result + where + Cc: ControlCommand, + { + let count: usize = file.control(count_command, &()).await?; + + Ok(Self { + file, + get_command, + index: 0, + count, + }) + } + + pub async fn next(&mut self) -> Result> { + if self.index >= self.count { + return Ok(None); + } + + let result = self.file.control(self.get_command, &self.index).await?; + + self.index += 1; + + Ok(Some(result)) + } +} diff --git a/modules/virtual_file_system/src/synchronous_file.rs b/modules/virtual_file_system/src/synchronous_file.rs index f7a1ae2a..be225902 100644 --- a/modules/virtual_file_system/src/synchronous_file.rs +++ b/modules/virtual_file_system/src/synchronous_file.rs @@ -2,10 +2,11 @@ use core::{fmt::Debug, mem::forget}; use crate::{Error, ItemStatic, Result, VirtualFileSystem}; use alloc::{vec, vec::Vec}; -use exported_file_system::{ControlArgument, ControlCommand, Permissions}; +use exported_file_system::{ControlCommand, Permissions}; use file_system::{ AccessFlags, AttributeFlags, Attributes, Context, Flags, Path, Position, Size, Statistics, }; +use shared::AnyByLayout; use task::TaskIdentifier; use task::block_on; use users::{GroupIdentifier, UserIdentifier}; @@ -224,13 +225,24 @@ impl SynchronousFile { Ok(()) } - pub fn control(&mut self, command: ControlCommand, argument: &mut A) -> Result<()> { + pub fn control(&mut self, _command: C, argument: &C::Input) -> Result + where + C: ControlCommand, + C::Output: Default, + { + let mut output = C::Output::default(); + self.item .as_base_operations() .ok_or(Error::UnsupportedOperation)? - .control(&mut self.context, command, ControlArgument::from(argument))?; - - Ok(()) + .control( + &mut self.context, + C::IDENTIFIER, + AnyByLayout::from(argument), + AnyByLayout::from_mutable(&mut output), + )?; + + Ok(output) } pub fn get_access(&self) -> Result {