Macros calling core or std functions


#1

I’m making a crate that exports a few macros. I want to make the crate support compiling with and without no_std, which means sometimes calling std::mem::transmute and sometimes calling ::core::mem::transmute. Right now, the best solution I have found is this:

#[cfg(feature="use_std")]
#[macro_export]
#[doc(hidden)]
macro_rules! slice_as_array_transmute {
    ($slice:expr) => { ::std::mem::transmute($slice) }
}

#[cfg(not(feature="use_std"))]
#[macro_export]
macro_rules! slice_as_array_transmute {
    ($slice:expr) => { ::core::mem::transmute($slice) }
}

And then I call slice_as_array_transmute! from my macro with the actual meat. It works, but it is a lot of boilerplate and exports a macro that I would rather not. Is there a better way to do this?

Thanks!


#2

Why don’t you just use a function? Or heck, a conditional re-export?

#[cfg(feature="use_std")]
pub use ::std::mem::transmute as transmute;
#[cfg(not(feature="use_std"))]
pub use ::core::mem::transmute as transmute;

You can also just pub use ::core as std or somesuch if you’re only accessing the “core subset” of std.


#3

I tried that, but if I define a function or do “pub use”, the symbol I define there doesn’t seem to be visible in the calling crate after the macro gets expanded. As a minimal example:

pub fn wont_be_visible() {
}

#[macro_export]
macro_rules! references_invisible_symbol {
    () => {
        wont_be_visible()
    }
}

being used like

#[macro_use]
extern crate vistest;

fn try_to_use_macro() {
    references_invisible_symbol!();
}

gives the error message:

<vistest macros>:1:11: 1:26 error: unresolved name `wont_be_visible` [E0425]
<vistest macros>:1 (  ) => { wont_be_visible (  ) }

It does work if I add

use vistest::wont_be_visible;

, but I’d rather not have the implementation details of the macro show up in code outside the crate.


#4

Macros aren’t like other things; they have no concept of names. The contents of the macro are interpreted in the expansion context, not the definition context.

Use $crate::wont_be_visible; $crate expands to a path to the crate that defined the macro. It’s the one way to reliably name a symbol in your own crate from a macro.


#5

Thanks! That is exactly what I needed.

In case anyone from the future stumbles on this thread, the documentation I should have read more carefully is here and what I ended up doing in the library defining the macros was:

#![no_std]

pub use core as local_core;

and then called functions like

$crate::local_core::mem::transmute(xs.as_ptr())

Edit: Actually, it looks like they are planning to make this code break in the future, so I’ll probably have to define each function on its own.