Macro Markdown Table Generation

Just thought I'd share a macro I made recently that others here might appreciate. If you have ideas for improvements, I'll all ears. I do want to modify it so that it can accept variable number of columns.

This macro generates a rustdoc markdown table from data. It also generates constants to index into an array.

md_data_table! {
    MyOffsets
    | DATA_TAG      |  2 |
    | DATA_TAG_EXT  |  2 |
    | LENGTH        |  4 |
    | CODE          | 12 |
}

#[macro_export]
macro_rules! md_data_table {
    ( $Table:ident $(| $ident:ident | $length:literal |)* ) => {
        md_table!($Table $(| $ident | $length |)*);
        impl $Table {
            data_table!($(| $ident | $length |)*);
        }
    };
}

#[macro_export]
macro_rules! md_table {
    ( $Table:ident $(| $ident:ident | $length:literal |)* ) => {
        ///
        #[doc = "| Name | Len |"]
        #[doc = "| -- | -- |"]
        $(
            #[doc = concat!("| ", stringify!($ident), " | ", stringify!($length), " |")]
        )*
        #[allow(unused)]
        struct $Table;
    };
}

#[macro_export]
macro_rules! data_table {
    ( $(| $ident:ident | $length:literal |)* ) => {
        data_table!(0 => $(| $ident | $length |)* );
    };
    ($offset:expr => | $a_ident:ident | $a_length:literal |) => {
        #[allow(unused)]
        const $a_ident: std::ops::Range<usize> = (($offset)..(($offset) + $a_length));
    };
    ($offset:expr => | $a_ident:ident | $a_length:literal | $(| $ident:ident | $length:literal |)* ) => {
        #[allow(unused)]
        const $a_ident: std::ops::Range<usize> = (($offset)..(($offset) + $a_length));
        data_table!($offset + $a_length => $(| $ident | $length |)* );
    };
}

Expanded this generates something like:


///
#[doc = "| Name | Len |"]
#[doc = "| -- | -- |"]
#[doc = "| DATA_TAG | 2 |"]
#[doc = "| DATA_TAG_EXT | 2 |"]
#[doc = "| LENGTH | 4 |"]
#[doc = "| CODE | 12 |"]
#[allow(unused)]
struct MyOffsets;
impl MyOffsets {

    #[allow(unused)]
    const DATA_TAG: std::ops::Range<usize> = ((0)..((0) + 2));
    #[allow(unused)]
    const DATA_TAG_EXT: std::ops::Range<usize> = ((0 + 2)..((0 + 2) + 2));
    #[allow(unused)]
    const LENGTH: std::ops::Range<usize> = ((0 + 2 + 2)..((0 + 2 + 2) + 4));
    #[allow(unused)]
    const CODE: std::ops::Range<usize> =
        ((0 + 2 + 2 + 4)..((0 + 2 + 2 + 4) + 12));
}
3 Likes

I got multiple arguments working with repeats. I'm sure you could copy something from my code.

1 Like

The code you shared is the exact same code as the original. I think maybe you didn't generate a new url properly.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.