Macro for option arguments

I want to write macro for function with Option Arguments:

pub fn certain_func(first: String, second: Option<&str>, third: Option<u32> /*... for example 4 Optional*/){
//long code
}

in separate namespace(straightforward aproach):

use  certain_func;
    #[macro_export]
    #[warn(unused_macros)]
    macro_rules! certain_func {
         ($a: expr) => {
               certain_func($a, None, None, None, None)
          };
         ($a: expr, $b: expr) =>{
               certain_func($a , $b, None, None, None)
          };
         ($a: expr, $b: expr, $c: expr) =>{
               certain_func($a , $b, $c,None, None)
          };
         ($a: expr, $b: expr, $c: expr, $d: expr) =>{
               certain_func($a , $b, $c, $d, None)
          };
         ($a: expr, $b: expr, $c: expr, $d: expr, $e: expr) =>{
               certain_func($a , $b, $c, $d, $e)
          };
    }

Tried to write like this:

    #[macro_export]
    #[warn(unused_macros)]
    macro_rules! certain_func {
         ($a: expr) => {
               certain_func($a, None, None, None, None)
          };
         ($a: expr, $($opt:expr),*) =>{
               certain_func($a , $($opt)*, ... , None)
          };
    }

Nothing work, ^^ not found in this scope for first approach in every line, despite i certainly use function in the scope.
Second Also error as it suppose that there are 2 arguments(first and None), how to do this,
thanks in advance)

I don't generally consider one necessary, but if I wanted to write a macro here, it'd be something like this:

// Syntax:
// fill_none!{
//     ( /* Function to call */ )
//     ( /* Processed arguments, comma delimited */ )
//     [ /* Unprocessed arguments, comma delimited */ ]
//     [ /* Unprocessed position specifications, not delimited *]
// }
//
// Each position specification is one of the following characters:
//    `!` represents a required argument, and
//    `?` represents an optional argument
#[macro_export]
macro_rules! fill_none {
    // No more positions; we're done
    { ($func:expr) ($($arg:expr,)*) [] [] } => {
        ($func)($($arg),*)
    };
    
    // Empty position, use None
    { ($func:expr) ($($arg:expr,)*) [] [? $($pos:tt)*] } => {
        $crate::fill_none! { ($func)($($arg,)* None,) [] [$($pos)*] }
    };
    
    // Optional position with argument, use Some($next)
    { ($func:expr) ($($arg:expr,)*) [$next:expr, $($rest:tt)*] [? $($pos:tt)*] }
    => {
        $crate::fill_none! { ($func)($($arg,)* Some($next),) [$($rest)*] [$($pos)*] }
    };

    // Required position with argument, use $next
    { ($func:expr) ($($arg:expr,)*) [$next:expr, $($rest:tt)*] [! $($pos:tt)*] }
    => {
        $crate::fill_none! { ($func)($($arg,)* $next,) [$($rest)*] [$($pos)*] }
    };

}

#[macro_export]
macro_rules! certain_func {
    ($($arg:expr),*) => {
        $crate::fill_none!(($crate::certain_func)() [$($arg,)*] [! ? ? ? ?])
    }
}
2 Likes

This clearly looks like an attempt to write some other language in Rust (JavaScript? C++? Python?).

Rust is pretty opinionated and would fight you tooth and nail.

What you are actually trying to achieve?

If you want to pass various optional flags to the constructor then usually fluent interface is considered a way to go.

This being said this:

is obviously not true. Macros are textual¹) modifications of source, which means that your certain_func must be in scope not when macro is defined, but when it's used. That's why you need $crate.

¹) Well, not exactly, but close enough. You can find details in the obvious place.

2 Likes

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.