file_system/fundamentals/
control.rs

1use shared::{AnyByLayout, flags};
2
3use crate::{Error, Result};
4
5flags! {
6    /// The kinds of control commands.
7    pub enum ControlDirectionFlags: u8 {
8        /// Read data from the device.
9        Read,
10        /// Write data to the device.
11        Write,
12    }
13}
14
15struct ControlCommandInputOutput<I, O> {
16    pub _input: I,
17    pub _output: O,
18}
19
20pub trait ControlCommand: Clone + Copy {
21    type Input;
22    type Output;
23
24    const IDENTIFIER: ControlCommandIdentifier;
25
26    fn cast_input(input: &AnyByLayout) -> Result<&Self::Input> {
27        input.cast().ok_or(Error::InvalidParameter)
28    }
29
30    fn cast_output(output: &mut AnyByLayout) -> Result<&mut Self::Output> {
31        output.cast_mutable().ok_or(Error::InvalidParameter)
32    }
33
34    fn cast<'i, 'o>(
35        input: &'i AnyByLayout,
36        output: &'o mut AnyByLayout,
37    ) -> Result<(&'i Self::Input, &'o mut Self::Output)> {
38        Ok((Self::cast_input(input)?, Self::cast_output(output)?))
39    }
40}
41
42#[macro_export]
43macro_rules! define_command {
44    ($name:ident, Read, $kind:expr, $number:expr, $I:ty, $O:ty) => {
45        $crate::define_command!(
46            $name,
47            $crate::ControlDirectionFlags::Read,
48            $kind,
49            $number,
50            $I,
51            $O
52        );
53    };
54    ($name:ident, Write, $kind:expr, $number:expr, $I:ty, $O:ty) => {
55        $crate::define_command!(
56            $name,
57            $crate::ControlDirectionFlags::Write,
58            $kind,
59            $number,
60            $I,
61            $O
62        );
63    };
64    ($name:ident, $direction:expr, $kind:expr, $number:expr, $I:ty, $O:ty) => {
65        #[derive(Clone, Copy, Debug)]
66        #[allow(non_camel_case_types)]
67        pub struct $name;
68
69        impl ControlCommand for $name {
70            type Input = $I;
71            type Output = $O;
72
73            const IDENTIFIER: $crate::ControlCommandIdentifier =
74                $crate::ControlCommandIdentifier::new::<$I, $O>($direction, $kind, $number);
75        }
76    };
77}
78
79#[repr(transparent)]
80#[derive(Clone, Copy, Debug, PartialEq, Eq)]
81pub struct ControlCommandIdentifier(usize);
82
83impl ControlCommandIdentifier {
84    const NUMBER_SIZE: usize = 8;
85    const KIND_SIZE: usize = 8;
86    const SIZE_SIZE: usize = 14;
87    const DIRECTION_SIZE: usize = 2;
88
89    const NUMBER_SHIFT: usize = 0;
90    const KIND_SHIFT: usize = Self::NUMBER_SHIFT + Self::NUMBER_SIZE; // 8
91    const SIZE_SHIFT: usize = Self::KIND_SHIFT + Self::KIND_SIZE; // 16
92    const DIRECTION_SHIFT: usize = Self::SIZE_SHIFT + Self::SIZE_SIZE; // 30
93
94    pub const fn new<I, O>(direction: ControlDirectionFlags, kind: u8, number: u8) -> Self {
95        let size = core::mem::size_of::<ControlCommandInputOutput<I, O>>();
96
97        Self::new_with_size(direction, size, kind, number)
98    }
99
100    pub const fn new_read<I, O>(kind: u8, number: u8) -> Self {
101        Self::new_with_size(
102            ControlDirectionFlags::Read,
103            size_of::<ControlCommandInputOutput<I, O>>(),
104            kind,
105            number,
106        )
107    }
108
109    pub const fn new_write<I, O>(kind: u8, number: u8) -> Self {
110        Self::new_with_size(
111            ControlDirectionFlags::Write,
112            size_of::<ControlCommandInputOutput<I, O>>(),
113            kind,
114            number,
115        )
116    }
117
118    pub const fn new_with_size(
119        direction: ControlDirectionFlags,
120        size: usize,
121        kind: u8,
122        number: u8,
123    ) -> Self {
124        let direction = direction.bits() as usize;
125        let kind = kind as usize;
126        let number = number as usize;
127
128        Self(
129            (direction << Self::DIRECTION_SHIFT)
130                | (size << Self::SIZE_SHIFT)
131                | (kind << Self::KIND_SHIFT)
132                | (number << Self::NUMBER_SHIFT),
133        )
134    }
135
136    pub const fn get_direction(&self) -> ControlDirectionFlags {
137        let direction = (self.0 >> Self::DIRECTION_SHIFT) & ((1 << Self::DIRECTION_SIZE) - 1);
138        ControlDirectionFlags(direction as u8)
139    }
140
141    pub const fn get_size(&self) -> usize {
142        (self.0 >> Self::SIZE_SHIFT) & ((1 << Self::SIZE_SIZE) - 1)
143    }
144
145    pub const fn get_kind(&self) -> u8 {
146        ((self.0 >> Self::KIND_SHIFT) & ((1 << Self::KIND_SIZE) - 1)) as u8
147    }
148
149    pub const fn get_number(&self) -> u8 {
150        ((self.0 >> Self::NUMBER_SHIFT) & ((1 << Self::NUMBER_SIZE) - 1)) as u8
151    }
152}