Right now, include_str!() works on a syntax level and does not allow a user to pass in a &'static str for the file path. I stumbled upon this after the following code didn't compile in release mode:
const CSS_PATH: &str = "C:\\my\\file\\path\\test.css";
#[cfg(debug_assertions)]
let css = Css::hot_reload(CSS_PATH).unwrap();
#[cfg(not(debug_assertions))]
let css = Css::new_from_str(include_str!(CSS_PATH)).unwrap();
Notice the Css::hot_reload vs the Css::new_from_str - in debug mode I want to hot-reload the file from disk (for quick style changes), but in release mode I want to include it in the binary.
Now I can solve it by doing:
#[cfg(debug_assertions)]
let css = Css::hot_reload("C:\\my\\file\\path\\test.css").unwrap();
#[cfg(not(debug_assertions))]
let css = Css::new_from_str(include_str!("C:\\my\\file\\path\\test.css")).unwrap();
... but then I need to update the file path in two places, which isn't good.
Looking at the source of include_str!(), it seems that include_str! works directly on the AST, i.e. the compiler doesn't know about whether the given string (the file path) is const or not, so if it is implemented it would maybe be necessary to restructure this part of the compiler.
I realize that it's a low-priority issue, but it would be nice to have. And yes, I can solve it with a build script, but that's just a last line of defense - I currently don't see any reason (except from the technical implementation problem) to not have it in the compiler - maybe a potential security concern if the strings are built at compile time from a const fn, but then again include_str!("/usr/bin/passwd") can already be done today, so it doesn't decrease or increase security.
... but then I need to update the file path in two places, which isn't good.
The path can be defined in one place, in a "macro constant":
macro_rules! CSS_PATH { () => { "C:\\my\\file\\path\\test.css" } }
#[cfg(debug_assertions)]
let css = Css::hot_reload(CSS_PATH!()).unwrap();
#[cfg(not(debug_assertions))]
let css = Css::new_from_str(include_str!(CSS_PATH!())).unwrap();
With macros 2.0 and https://internals.rust-lang.org/t/idea-elide-parens-brackets-on-unparametrized-macros/6527 this is going to be even more convenient, probably obviating the need in supporting actual constants:
macro CSS_PATH() { "C:\\my\\file\\path\\test.css" }
#[cfg(debug_assertions)]
let css = Css::hot_reload(CSS_PATH!).unwrap();
#[cfg(not(debug_assertions))]
let css = Css::new_from_str(include_str!(CSS_PATH!)).unwrap();
Yeah, I'm not sure if I should close this... I mean, it's a good workaround but I do think that const would be better suited for this. If I'd implement it - would such a PR be accepted? If not, you can close this issue and I'll use the workaround.
for your specific usage/example could it be inverted such that the cfgd function choice is made into a macro so you call let css = load_hot_on_debug!("C:\\my\\file\\path\\test.css") and the choice is made for you
Feeding CTFE results all the way back to the parser is AFAIK unprecedented as of now, so this would likely not be easy to implement and would possibly need a full RFC.
Feeding CTFE results all the way back to the parser is AFAIK unprecedented as of now, so this would likely not be easy to implement and would possibly need a full RFC.
We don't need to go this far. It would be absolutely possible to add a const fn include_str(path: &Path) -> &'static str intrinsic that will read the file given as an argument and produce the file's contents as a &'static str. We would need to make any use of the intrinsic a hard error outside of a const context or do something like make the runtime body be
let mut file = File::open(path).unwrap();
let mut s = String::new();
file.read_to_string(&mut s).unwrap();
String::leak(s)
Of course this would also require an RFC, and it is sort of equivaletn to what https://github.com/rust-lang/rust/issues/53749#issuecomment-416898577 suggests
Most helpful comment
The path can be defined in one place, in a "macro constant":
With macros 2.0 and https://internals.rust-lang.org/t/idea-elide-parens-brackets-on-unparametrized-macros/6527 this is going to be even more convenient, probably obviating the need in supporting actual constants: