Following this discussion I thought I’ll describe a functionality which I think can be quite useful for some cases and AFAIK can not be implemented today using other means. In short I would like to propose an idea of static variables which can be extended by other crates. It can look like this:
// crate `foo`
// extendable static should be public and have type `&[T]`
#[extendable]
pub static ERROR_MSGS: &'static [(u32, &'static str)] = &[
(ERROR_CODE_1, ERROR_MSG_1),
(ERROR_CODE_2, ERROR_MSG_2),
];
// crate `bar` which depends on crate `foo`
use foo::ERROR_MSGS;
// if extended static has type `&[T]`, then this const should have type `T`
#[extend(ERROR_MSGS)]
const CUSTOM_ERROR: (u32, &'static str) = (0x123456, "custom err message");
Now if our project contains both foo
and bar
, then foo::ERROR_MSGS
will contain 3 elements. In other words compiler will have to collect all #[extend(..)]
statements and construct extendable static only after all dependencies got compiled. (yes, I am aware that it does not fit the current build process) Now we can use linear search to convert error codes to human readable error messages.
Because crates are compiled in parallel, it’s probably will be better to define inclusion order for extension elements to make order deterministic, one option is to use crate names to determine inclusion order.
What do you think about such functionality? Does associated complexity outweigh potential merits? Do you see other uses for it outside of error codes?
UPD: linkme
project by @dtolnay does very similar thing using linker shenanigans.