Why should I disclose the use of "use" macros in the client library?

I am trying to use a macro that I created in a separate module. Regarding this SO question , I have imported a macro. However, it seems that I have

Refresh to add macro implementation

lib.rs

#![macro_use] use std::fmt; use std::ffi::CString; use std::ffi::CStr; use std::str; extern crate libc; pub enum DbaxError { DBAXException(String) } #[macro_export] macro_rules! dbax_call_test { ( $func : expr ) => { { let call_c_func = unsafe { dbax_function(CString::new($func).unwrap().as_ptr(),0) }; match unsafe { getErrorCode() as i32 } { 0 => Ok("Done".to_owned() + $func), _ => Err(DbaxError::DBAXException( str::from_utf8(unsafe { CStr::from_ptr(getError()) }.to_bytes()).unwrap().to_string())) } } } } 

and main.rs in a separate box

 // Import macro #[macro_use] extern crate rustdbax; // Import implementation details of macro use rustdbax::*; use std::ffi::CString; use std::ffi::CStr; use std::str; fn main() { // Call my macro dbax_call_test!("DateAdd"); } 

This works fine, but the use std::* lines are part of the implementation in lib.rs

Why do I need to expose the "use" implementation in the client library? Shouldn't rustc as part of this extension include everything in lib.rs ?

+5
source share
1 answer

Because macro_rules! a little dumber than you might expect. For example, it does not import imports when it expands something. It’s best to think about expanding macros, as basically just dumb copy + paste work.

If you look at any well-written macro that depends on external characters, you will see things like ::std::result::Result instead of Result . This is because a macro writer cannot depend on Result , which means waiting in the context of an extension. So, the first step is to fully qualify the paths.

The second thing you need to know is that each macro extension gets the $crate substitution, which is the path to the box in which the macro was defined. You can use this to access, for example, a DbaxError as $crate::DbaxError .

Finally, you are lucky; given the extension, you can trick a little and just add use elements inside the extension:

 #[macro_export] macro_rules! dbax_call_test { ($func: expr) => { { use std::ffi::CString; use $crate::dbax_function; let call_c_func = unsafe { dbax_function(CString::new($func).unwrap().as_ptr(),0) }; // ... } } } 
+5
source

All Articles