sdmmc-core 0.5.0

SD/MMC core data structures and algorithms
Documentation
//! Macros for reducing boilerplate, and increasing consistency in the library.

mod bitfield;
mod command;
mod enums;
mod response;

/// Implements a function to determine if a `bitflag` has a set flag.
#[macro_export]
macro_rules! bitflag_is_set {
    ($ty:ident) => {
        impl $ty {
            /// Determines whether `oth` flag is set.
            pub fn is_set(self, oth: Self) -> bool {
                self & oth != Self::NONE
            }
        }
    };
}

#[macro_export]
macro_rules! data_block {
    (
        $(#[$block_doc:meta])+
        $block:ident: $block_len:expr,
        $(#[$wide_block_doc:meta])+
        $wide_block:ident: $wide_block_len:expr$(,)?
    ) => {
        paste::paste! {
            $(#[$block_doc])+
            #[repr(C)]
            #[derive(Clone, Copy, Debug, Eq, PartialEq)]
            pub struct $block {
                data: [u8; $block_len],
            }

            impl $block {
                #[doc = "Creates a new [" $block "]."]
                pub const fn new() -> Self {
                    Self {
                        data: [0u8; $block_len],
                    }
                }

                #[doc = "Creates a new [" $block "] from line data."]
                pub const fn from_bytes(data: [u8; $block_len]) -> Self {
                    Self { data }
                }

                /// Gets a reference to the inner data bytes.
                pub const fn data(&self) -> &[u8] {
                    &self.data
                }

                #[doc = "Converts the [" $block "] into a [" $wide_block "]."]
                #[doc = ""]
                #[doc = "This is for using all four `DAT` lines on a SD bus."]
                pub const fn wide_data(&self) -> $wide_block {
                    use $crate::data::{wide_bus_encode, DataLine};

                    let mut wide = $wide_block::new();

                    let mut i = 0;
                    let len = self.data.len();

                    while i < len {
                        let b = self.data[i];
                        let dat_idx = i.saturating_div(WIDE_BUS_WIDTH);

                        wide.dat0[dat_idx] |= wide_bus_encode(b, i, DataLine::Dat0);
                        wide.dat1[dat_idx] |= wide_bus_encode(b, i, DataLine::Dat1);
                        wide.dat2[dat_idx] |= wide_bus_encode(b, i, DataLine::Dat2);
                        wide.dat3[dat_idx] |= wide_bus_encode(b, i, DataLine::Dat3);

                        i += 1;
                    }

                    wide
                }
            }

            impl Default for $block {
                fn default() -> Self {
                    Self::new()
                }
            }

            $(#[$wide_block_doc])+
            #[repr(C)]
            #[derive(Clone, Copy, Debug, Eq, PartialEq)]
            pub struct $wide_block {
                dat0: [u8; $wide_block_len],
                dat1: [u8; $wide_block_len],
                dat2: [u8; $wide_block_len],
                dat3: [u8; $wide_block_len],
            }

            impl $wide_block {
                #[doc = "Creates a new [" $wide_block "]."]
                pub const fn new() -> Self {
                    Self {
                        dat0: [0u8; $wide_block_len],
                        dat1: [0u8; $wide_block_len],
                        dat2: [0u8; $wide_block_len],
                        dat3: [0u8; $wide_block_len],
                    }
                }

                #[doc = "Creates a new [" $wide_block "] from `DAT` line data."]
                pub const fn from_data_lines(
                    dat0: [u8; $wide_block_len],
                    dat1: [u8; $wide_block_len],
                    dat2: [u8; $wide_block_len],
                    dat3: [u8; $wide_block_len],
                ) -> Self {
                    Self {
                        dat0,
                        dat1,
                        dat2,
                        dat3,
                    }
                }

                #[doc = "Converts the [" $wide_block "] into a [" $block "]."]
                #[doc = ""]
                #[doc = "This is for using all four `DAT` lines on a SD bus."]
                pub const fn decode(&self) -> $block {
                    use $crate::data::{wide_bus_decode, DataLine, WIDE_BUS_WIDTH};

                    let mut block = $block::new();

                    let mut i = 0;
                    let len = block.data.len();

                    while i < len {
                        let j = i.saturating_div(WIDE_BUS_WIDTH);

                        block.data[i] |= wide_bus_decode(self.dat0[j], i, DataLine::Dat0);
                        block.data[i] |= wide_bus_decode(self.dat1[j], i, DataLine::Dat1);
                        block.data[i] |= wide_bus_decode(self.dat2[j], i, DataLine::Dat2);
                        block.data[i] |= wide_bus_decode(self.dat3[j], i, DataLine::Dat3);

                        i += 1;
                    }

                    block
                }
            }

            impl Default for $wide_block {
                fn default() -> Self {
                    Self::new()
                }
            }

            impl From<$block> for $wide_block {
                fn from(val: $block) -> Self {
                    val.wide_data()
                }
            }
        }
    };
}

/// Convenience macro to define a library struct.
///
/// Useful for reducing boilerplate, and increasing consistency.
#[macro_export]
macro_rules! lib_struct {
    (
        $(#[$doc:meta])+
        $ty:ident {
            $($field:ident: $field_ty:ident$(,)?)+
        }
    ) => {
        paste::paste! {
            $(#[$doc])+
            #[repr(C)]
            #[derive(Clone, Copy, Debug, Eq, PartialEq)]
            pub struct $ty {
                $($field: $field_ty,)+
            }

            impl $ty {
                $(
                #[doc = "Gets the [" $field_ty "] for the [" $ty "]."]
                pub const fn $field(&self) -> $field_ty {
                    self.$field
                }

                #[doc = "Sets the [" $field_ty "] for the [" $ty "]."]
                pub fn [<set_ $field>](&mut self, $field: $field_ty) {
                    self.$field = $field;
                }

                #[doc = "Builder function that sets the [" $field_ty "] for the [" $ty "]."]
                pub const fn [<with_ $field>](self, $field: $field_ty) -> Self {
                    Self {
                        $field: $field,
                        ..self
                    }
                }
                )+
            }
        }
    }
}

/// Convenience macro for testing bitfields.
#[macro_export]
macro_rules! test_field {
    ($t:ident, $field:ident) => {
        paste::paste! {
            $t.[<set_ $field>](true);
            assert!($t.$field());

            $t.[<set_ $field>](false);
            assert!(!$t.$field());
        }
    };

    ($t:ident, $field:ident: $bit:expr) => {
        paste::paste! {
            $t.[<set_ $field>](true);
            assert!($t.$field());
            assert_eq!($t.bits() & (1 << $bit), 1 << $bit);

            $t.[<set_ $field>](false);
            assert!(!$t.$field());
            assert_eq!($t.bits() & (1 << $bit), 0);
        }
    };

    ($t:ident, $field:ident { bit: $bit:expr, [$base:ty; $N:expr] }) => {
        paste::paste! {
            let idx = ($N - (($bit / $base::BITS) as usize) - 1);
            let bit = $bit % $base::BITS;

            $t.[<set_ $field>](true);
            assert!($t.$field());

            assert_eq!($t.bytes()[idx] & (1 << bit), 1 << bit);

            $t.[<set_ $field>](false);
            assert!(!$t.$field());
            assert_eq!($t.bytes()[idx] & (1 << bit), 0);
        }
    };
}

/// Helper macro for a `const` version of the `?` operator.
#[macro_export]
macro_rules! const_try {
    ($e:expr) => {
        match $e {
            Ok(v) => v,
            Err(err) => return Err(err),
        }
    };
}