Create tuple struct in macro

In macro_rules! macros, you can match on a type (ty). You can use this pattern where you would use a return type, e.g. for a function's input types or return type.

Is there a way to use this type pattern as a constructor?

https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=bd0ea212c4875d0161591ed6b88f34c6

My specific case would be to construct a single-element tuple struct, but for curiosity, it would be nice to know if it was generally possible.

I looked into this, which seemed like it might be close but didn't seem to work.

I'm guessing the problem here is the difference between a "type" and an "initializer function with the same name as the type". Am I on the right path?

Code if you don't want to visit the playground:

#[derive(Debug)]
struct Foo(u32);

#[derive(Debug)]
struct Bar {
    inner: u32,
}

macro_rules! tuple_constructor {
    ($ty:ty, $name:ident) => {
        fn $name() -> $ty {
            $ty(42)
        }
    };
}

macro_rules! inner_field_constructor {
    ($ty:ty, $name:ident) => {
        fn $name() -> $ty {
            $ty {
                inner: 42,
            }
        }
    };
}

tuple_constructor!(Foo, make_foo);
inner_field_constructor!(Bar, make_bar);

fn main() {
    let x = make_foo();
    println!("x: {:?}", x);
    let x = make_bar();
    println!("x: {:?}", x);
}

Using $ty:path instead of $ty:ty seems to work decently, even in the presence of generic arguments.

Rust Playground

Sorry for the short reply without explanations, I'm on mobile :slightly_smiling_face:

1 Like

This works:

#[derive(Debug)]
struct Foo(u32);

#[derive(Debug)]
struct Bar {
    inner: u32,
}

type SameType<T> = T;

macro_rules! tuple_constructor {
    ($ty:ty, $name:ident) => {
        fn $name() -> $ty {
            SameType::<$ty> { 0: 42 }
        }
    };
}

macro_rules! inner_field_constructor {
    ($ty:ty, $name:ident) => {
        fn $name() -> $ty {
            SameType::<$ty> {
                inner: 42,
            }
        }
    };
}

tuple_constructor!(Foo, make_foo);
inner_field_constructor!(Bar, make_bar);

fn main() {
    let x = make_foo();
    println!("x: {:?}", x);
    let x = make_bar();
    println!("x: {:?}", x);
}
1 Like

These both worked, thanks to @steffahn and @Kestrer for your help! @steffahn's solution is probably easier. I'm intrigued by @Kestrer's solution though...is there a way to do that without the extra SameType declaration?

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.