cargo_subcommand_metadata/
lib.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
/// Cargo's name for the purpose of ELF notes.
///
/// The `name` field of an ELF note is designated to hold the entry's "owner" or
/// "originator". No formal mechanism exists for avoiding name conflicts. By
/// convention, vendors use their own name such as "XYZ Computer Company".
pub const ELF_NOTE_NAME: &str = "rust-lang/cargo";

/// Values used by Cargo as the `type` of its ELF notes.
///
/// Each originator controls its own note types. Multiple interpretations of a
/// single type value can exist. A program must recognize both the `name` and
/// the `type` to understand a descriptor.
#[repr(i32)]
#[non_exhaustive]
pub enum ElfNoteType {
    //              DESCRIP
    Description = 0xDE5C819,
}

/// Embed a description into a compiled Cargo subcommand, to be shown by `cargo
/// --list`.
///
/// The following restrictions apply to a subcommand description:
///
/// - String length can be at most 280 bytes in UTF-8, although much shorter is
///   better.
/// - Must not contain the characters `\n`, `\r`, or `\x1B` (ESC).
///
/// Please consider running `cargo --list` and following the style of the
/// existing descriptions of the built-in Cargo subcommands.
///
/// # Example
///
/// ```
/// // subcommand's main.rs
///
/// cargo_subcommand_metadata::description! {
///     "Draw a spiffy visualization of things"
/// }
///
/// fn main() {
///     /* … */
/// }
/// ```
#[macro_export]
macro_rules! description {
    ($description:expr) => {
        const _: () = {
            const CARGO_SUBCOMMAND_DESCRIPTION: &str = $description;

            assert!(
                CARGO_SUBCOMMAND_DESCRIPTION.len() <= 280,
                "subcommand description too long, must be at most 280",
            );

            #[cfg(target_os = "linux")]
            const _: () = {
                #[repr(C)]
                struct ElfNote {
                    namesz: u32,
                    descsz: u32,
                    ty: $crate::ElfNoteType,

                    name: [u8; $crate::ELF_NOTE_NAME.len()],
                    // At least 1 to nul-terminate the string as is convention
                    // (though not required), plus zero padding to a multiple of 4
                    // bytes.
                    name_padding: [$crate::private::Padding;
                        1 + match ($crate::ELF_NOTE_NAME.len() + 1) % 4 {
                            0 => 0,
                            r => 4 - r,
                        }],

                    desc: [u8; CARGO_SUBCOMMAND_DESCRIPTION.len()],
                    // Zero padding to a multiple of 4 bytes.
                    desc_padding: [$crate::private::Padding;
                        match CARGO_SUBCOMMAND_DESCRIPTION.len() % 4 {
                            0 => 0,
                            r => 4 - r,
                        }],
                }

                #[used]
                #[link_section = ".note.cargo.subcommand"]
                static ELF_NOTE: ElfNote = {
                    ElfNote {
                        namesz: $crate::ELF_NOTE_NAME.len() as u32 + 1,
                        descsz: CARGO_SUBCOMMAND_DESCRIPTION.len() as u32,
                        ty: $crate::ElfNoteType::Description,
                        name: unsafe { *$crate::ELF_NOTE_NAME.as_ptr().cast() },
                        name_padding: $crate::private::padding(),
                        desc: unsafe { *CARGO_SUBCOMMAND_DESCRIPTION.as_ptr().cast() },
                        desc_padding: $crate::private::padding(),
                    }
                };
            };
        };
    };
}

// Implementation details. Not public API.
#[doc(hidden)]
pub mod private {
    #[derive(Copy, Clone)]
    #[repr(u8)]
    pub enum Padding {
        Zero = 0,
    }

    pub const fn padding<const N: usize>() -> [Padding; N] {
        [Padding::Zero; N]
    }
}