Suppose I have some macro invoked as such:
my_macro!(Blah, (a, b, c));
And it outputs something like this:
struct Blah {
a: i32,
b: i32,
c: i32
}
impl Blah {
fn foo() -> i32 {
a + b + c
}
}
(artificial example)
These fields will be private to the struct, but I need to allow redefinitions. So, the input
my_macro!(Blah, (a, b, c, a));
Will generate something like:
struct Blah {
a1: i32,
b: i32,
c: i32,
a2: i32
}
impl Blah {
fn foo() -> i32 {
a1 + b + c + a2
}
}
The naming scheme doesn't need to follow any logical pattern.
Is this possible?
My mashup crate provides a way for you to expand my_macro!(Blah, (a, b, c, a)) into fields x_a, xx_b, xxx_c, xxxx_d if that naming convention would work for you. We prepend an additional x for each field, followed by an underscore, followed by the original field name so that way no fields can end up with conflicting names. This approach works with any Rust version >= 1.15.0.
#[macro_use]
extern crate mashup;
macro_rules! my_macro {
($name:ident, ($($field:ident),*)) => {
my_macro_helper!($name (x) () $($field)*);
};
}
macro_rules! my_macro_helper {
// In the recursive case: append another `x` into our prefix.
($name:ident ($($prefix:tt)*) ($($past:tt)*) $next:ident $($rest:ident)*) => {
my_macro_helper!($name ($($prefix)* x) ($($past)* [$($prefix)* _ $next]) $($rest)*);
};
// When there are no fields remaining.
($name:ident ($($prefix:tt)*) ($([$($field:tt)*])*)) => {
// Use mashup to define a substitution macro `m!` that replaces every
// occurrence of the tokens `"concat" $($field)*` in its input with the
// resulting concatenated identifier.
mashup! {
$(
m["concat" $($field)*] = $($field)*;
)*
}
// Invoke the substitution macro to build a struct and foo method.
// This expands to:
//
// pub struct Blah {
// x_a: i32,
// xx_b: i32,
// xxx_c: i32,
// xxxx_a: i32,
// }
//
// impl Blah {
// pub fn foo(&self) -> i32 {
// 0 + self.x_a + self.xx_b + self.xxx_c + self.xxxx_a
// }
// }
m! {
pub struct $name {
$(
"concat" $($field)*: i32,
)*
}
impl $name {
pub fn foo(&self) -> i32 {
0 $(
+ self."concat" $($field)*
)*
}
}
}
};
}
my_macro!(Blah, (a, b, c, a));
fn main() {}
Without using a compiler plugin, no, I don't believe this is possible. Two reasons:
You can't construct identifiers. There's concat_idents!, but due to the way macros are expanded, it's useless in this situation.
You can't do non-literal comparisons. That is, there's no way of the macro working out that it's already seen a once before.
About the closest you could get is to just outright replace all the provided identifiers with a fixed list of identifiers, but that's probably not what you want; in that case, it'd be easier to just specify that you want 4 fields, and generate a fixed-size array [i32; 4].
My paste crate provides a way for you to expand my_macro!(Blah, (a, b, c, a)) into fields x_a, xx_b, xxx_c, xxxx_d if that naming convention would work for you. We prepend an additional x for each field, followed by an underscore, followed by the original field name so that way no fields can end up with conflicting names. This approach works with any Rust version >= 1.31.0.
use paste::paste;
macro_rules! my_macro {
($name:ident, ($($field:ident),*)) => {
my_macro_helper!($name (x) () $($field)*);
};
}
macro_rules! my_macro_helper {
// In the recursive case: append another `x` into our prefix.
($name:ident ($($prefix:tt)*) ($($past:tt)*) $next:ident $($rest:ident)*) => {
my_macro_helper!($name ($($prefix)* x) ($($past)* [$($prefix)* _ $next]) $($rest)*);
};
// When there are no fields remaining.
($name:ident ($($prefix:tt)*) ($([$($field:tt)*])*)) => {
paste! {
// Expands to:
// pub struct Blah {
// x_a: i32,
// xx_b: i32,
// xxx_c: i32,
// xxxx_a: i32,
// }
pub struct $name {
$(
[<$($field)*>]: i32,
)*
}
// Expands to:
// impl Blah {
// pub fn foo(&self) -> i32 {
// 0 + self.x_a + self.xx_b + self.xxx_c + self.xxxx_a
// }
// }
impl $name {
pub fn foo(&self) -> i32 {
0 $(
+ self.[<$($field)*>]
)*
}
}
}
};
}
my_macro!(Blah, (a, b, c, a));
Related
I've successfully impl From<tokio_postgres::Row> for AStruct, but is it possible to (1) impl From<AStruct> to tokio_postgres::Row and (2) subsequently insert the created tokio_postgres::Row into a table? I've looked at tokio_postgres::Row (see bellow), and also tried to impl tokio_postgres::types::ToSql as well as
tokio_postgres::types::FromSql.
I'd really like to exclusively use Tokio-Postgres for this project, if it's possible.
I have written up a minimal code example bellow to show what I am trying to do.
Let me know if I can clarify my question in any way.
#[derive(ToSql, FromSql, Debug)]
enum E {
A,
B,
}
#[derive(ToSql, FromSql, Debug)]
struct AStruct {
i: i32,
e: E,
d: DateTime<Utc>
}
impl From<Row> for AStruct {
fn from(row: Row) -> Self {
Self {
i: row.get(0),
e: row.get(1),
d: row.get(2),
}
}
}
// TODO
impl From<AStruct> for Row {
fn from(s: S) -> Self {
Self {
statement: ...?,
body: ...?,
ranges: ...?,
}
}
}
#[tokio::main]
async fn main() -> Result<(), Error> {
let (client, _) = tokio_postgres::connect(database_url, NoTls).await?;
let s = AStruct {
i: 1,
e: E::A,
d: Utc::now(),
};
// This works!
let s: AStruct = client
.query("SELECT * FROM structs WHERE id = $1", &[&id])
.await?
.into_iter()
.next()
.unwrap()
.into();
// This does not work :(
let row: Row = s.into();
Ok(())
}
When expanding arguments to a macro, is there a way to include the argument number within the macro
Here is a complete example showing how this might be used to assign an index to a struct using a trait. Currently struct_number() always returns 0, could this be made to return a constant number based on the order of the argument to the macro?
struct Foo {_var: bool}
struct Bar {_var: u8}
struct Baz {_var: i16}
trait NumberStruct {
fn struct_number() -> usize;
}
macro_rules! number_structs_impl {
($($t:ty)*) => ($(
impl NumberStruct for $t {
fn struct_number() -> usize {
// How to return a number based on the argument order?
return 0;
}
}
)*)
}
number_structs_impl!(Foo Bar Baz);
fn main() {
// see if the numbers are correct
macro_rules! print_numbers {
($($t:tt)*) => ($(
print!("{}:{} ", stringify!($t), $t::struct_number());
)*)
}
// should print:
// Baz:2 Bar:1 Foo:0
print_numbers!(Baz Bar Foo);
println!();
}
This can be done:
First counting all arguments.
Using a recursive macro, so the tail* arguments can be counted.
Optionally storing the list of structs in a macro so both macro invocations don't need to repeat the list.
Working example:
struct Foo {_var: bool}
struct Bar {_var: u8}
struct Baz {_var: i16}
trait NumberStruct {
fn struct_number() -> usize;
}
macro_rules! count_tts {
() => {0usize};
($_head:tt $($tail:tt)*) => {1usize + count_tts!($($tail)*)};
}
macro_rules! number_structs_impl {
() => {};
($head:tt $($tail:tt)*) => {
impl NumberStruct for $head {
fn struct_number() -> usize {
return STRUCT_NUM - (1 + count_tts!($($tail)*));
}
}
number_structs_impl!($($tail)*);
};
}
// avoid repeating same structs
macro_rules! apply_structs {
($macro_id:ident) => (
$macro_id! {
Foo
Bar
Baz
}
)
}
const STRUCT_NUM: usize = apply_structs!(count_tts);
apply_structs!(number_structs_impl);
fn main() {
// see if the numbers are correct
macro_rules! print_numbers {
($($t:tt)*) => ($(
print!("{}:{} ", stringify!($t), $t::struct_number());
)*)
}
// should print:
// Baz:2 Bar:1 Foo:0
print_numbers!(Baz Bar Foo);
println!();
}
Note: I'm posting this answer to show its possible, however it is a bit of a messy solution since it involves passing macros to macros and two invocations, this could be done more cleanly if recursive macros could be expanded, taking the last argument each recursion, see related question.
An approach to defining numbered implementations is to use a recursive macro. A unique number can be created by counting arguments, in this case counting trailing arguments.
The problem with this, is the indices are reversed where the first struct has the largest number, the last struct zero.
If you only need the numbers to be unique, it wont matter, however in this case I want each structs index to match the order its passed to the macro.
Input arguments can be reversed using a recursive macro, see this example.
Using this macro, its possible to write a generic macro:
apply_args_reverse!(macro_name, arg1 arg2 arg3)
Which expands into:
macro_name!(arg3 arg2 arg1)
Of course thats not very useful on its own, but it can be useful if the arguments aren't written directly, but passed as arguments.
This can be used to create make a macro that expands with the number of each argument as follows:
struct Foo {_var: bool}
struct Bar {_var: u8}
struct Baz {_var: i16}
trait NumberStruct {
fn struct_number() -> usize;
}
macro_rules! count_args_space {
() => {0_usize};
($_head:tt $($tail:tt)*) => {1_usize + count_args_space!($($tail)*)};
}
macro_rules! number_structs_impl {
(#single $t:tt $($tail:tt)*) => (
impl NumberStruct for $t {
fn struct_number() -> usize {
return count_args_space!($($tail)*);
}
}
);
() => {};
($head:tt $($tail:tt)*) => {
number_structs_impl!(#single $head $($tail)*);
number_structs_impl!($($tail)*);
};
}
macro_rules! apply_args_reverse {
($macro_id:tt [] $($reversed:tt)*) => {
$macro_id!($($reversed) *);
};
($macro_id:tt [$first:tt $($rest:tt)*] $($reversed:tt)*) => {
apply_args_reverse!($macro_id [$($rest)*] $first $($reversed)*);
};
// Entry point, use brackets to recursively reverse above.
($macro_id:tt, $($t:tt)*) => {
apply_args_reverse!($macro_id [ $($t)* ]);
};
}
// Note that both commands below work, and can be swapped to reverse argument order.
// number_structs_impl!(Foo Bar Baz);
apply_args_reverse!(number_structs_impl, Foo Bar Baz);
fn main() {
// see if the numbers are correct
macro_rules! print_numbers {
($($t:tt)*) => ($(
print!("{}:{} ", stringify!($t), $t::struct_number());
)*)
}
print_numbers!(Baz Bar Foo);
println!();
}
Notice the statements:
number_structs_impl!(Foo Bar Baz);
... and
apply_args_reverse!(number_structs_impl, Foo Bar Baz);
... are interchangeable, swapping which is commented reverses the order of numbers assigned to each struct.
Note: keeping my other answer, while this is more concise, it's also more fragile, prone to hard-to-troubleshoot problems, since macro expansion gets deeply nested (I found this while getting it to work at least).
When implementing a primitive fixed-size vector type (float2 for example), I want to support the Add and Sub traits. Later, I will want to support Mul and *Assign.
Looking up the documentation and other examples, I came up with this:
use std::ops::{Add, Sub};
#[derive(Copy, Clone)]
struct float2(f64, f64);
impl Add for float2 {
type Output = float2;
fn add(self, _rhs: float2) -> float2 {
float2(self.0 + _rhs.0, self.1 + _rhs.1)
}
}
impl Sub for float2 {
type Output = float2;
fn sub(self, _rhs: float2) -> float2 {
float2(self.0 - _rhs.0, self.1 - _rhs.1)
}
}
This works for basic examples, however I found in practice I would often end up with references passed in as arguments as well as local float2's on the stack.
To mix these I needed to either:
De-reference variables (OK but makes code a little less readable).
Declare operator overloading combinations of references too.
Example:
impl<'a, 'b> Add<&'b float2> for &'a float2 {
type Output = float2;
fn add(self, _rhs: &'b float2) -> float2 {
float2(self.0 + _rhs.0, self.1 + _rhs.1)
}
}
impl<'a> Add<float2> for &'a float2 {
type Output = float2;
fn add(self, _rhs: float2) -> float2 {
float2(self.0 + _rhs.0, self.1 + _rhs.1)
}
}
impl<'b> Add<&'b float2> for float2 {
type Output = float2;
fn add(self, _rhs: &'b float2) -> float2 {
float2(self.0 + _rhs.0, self.1 + _rhs.1)
}
}
/*... and again for Sub */
While this allows to write expressions without de-referencing. it becomes quite tedious to enumerate each combinations, especially when adding more operations & types (float3, float4...).
Is there a generally accepted way to...
Automatically coerce types for operator overloading?
Use macros or some other feature of the language to avoid tedious repetition?
Or is it expected that developers either:
Explicitly access variables as references as needed.
Explicitly de-reference variables as needed.
Write a lot of repetitive operator overloading functions.
Note, I'm currently a beginner, I've checked some quite advanced math libraries in Rust, they're way over my head, while I could use them - I would like to understand how to write operator overloading for my own types.
The great thing about Rust is that it's open source. This means you can see how the authors of the language have solved a problem. The closest analogue is primitive integer types:
macro_rules! add_impl {
($($t:ty)*) => ($(
#[stable(feature = "rust1", since = "1.0.0")]
impl Add for $t {
type Output = $t;
#[inline]
fn add(self, other: $t) -> $t { self + other }
}
forward_ref_binop! { impl Add, add for $t, $t }
)*)
}
forward_ref_binop is defined as:
macro_rules! forward_ref_binop {
(impl $imp:ident, $method:ident for $t:ty, $u:ty) => {
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a> $imp<$u> for &'a $t {
type Output = <$t as $imp<$u>>::Output;
#[inline]
fn $method(self, other: $u) -> <$t as $imp<$u>>::Output {
$imp::$method(*self, other)
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a> $imp<&'a $u> for $t {
type Output = <$t as $imp<$u>>::Output;
#[inline]
fn $method(self, other: &'a $u) -> <$t as $imp<$u>>::Output {
$imp::$method(self, *other)
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, 'b> $imp<&'a $u> for &'b $t {
type Output = <$t as $imp<$u>>::Output;
#[inline]
fn $method(self, other: &'a $u) -> <$t as $imp<$u>>::Output {
$imp::$method(*self, *other)
}
}
}
}
It's certainly valid to write wrapper implementations of the traits for references that simply dereference and call the value-oriented version.
I advise you to use the impl_os crate for that purpose, see that other answer that I wrote.
Trying to export a macro from module. Macro generates structure implementing some traits defined in module. Is there a way to get macro without importing that traits manually?
// src/lib.rs
#![crate_name="macro_test"]
#![crate_type="lib"]
#![crate_type="rlib"]
pub trait B<T> where T: Copy {
fn new(x: T) -> Self;
}
#[macro_export]
macro_rules! test {
( $n:ident ) => {
struct $n<T> where T: Copy {
x: T
}
impl<T> B<T> for $n<T> where T: Copy {
fn new(x: T) -> Self {
$n { x: x }
}
}
}
}
// tests/test_simple.rs
#[macro_use]
extern crate macro_test;
test!(Test);
#[test]
fn test_macro() {
let a = Test::<i32>::new(1);
}
In that case I get an error:
<macro_test macros>:2:54: 2:61 error: use of undeclared trait name `B` [E0405]
<macro_test macros>:2 struct $ n < T > where T : Copy { x : T } impl < T > B < T > for $ n < T >
If I rewrite the trait implementation with $crate variable:
impl<T> $crate::B<T> for $n<T> where T: Copy {
error message changes to next:
tests\test_simple.rs:8:13: 8:29 error: no associated item named `new` found for type `Test<i32>` in the current scope
tests\test_simple.rs:8 let a = Test::<i32>::new(1);
^~~~~~~~~~~~~~~~
tests\test_simple.rs:8:13: 8:29 help: items from traits can only be used if the trait is in scope; the following trait is implemented but not in scope, perhaps add a `use` for it:
tests\test_simple.rs:8:13: 8:29 help: candidate #1: use `macro_test::B`
Why does it happen?
Because you can't call trait methods without useing the trait. That's got nothing to do with macros—it's just a standard rule in Rust.
Maybe you want the macro to generate an inherent impl instead? i.e.
impl<T> $n<T> where T: Copy {
pub fn new(x: T) -> Self {
$n { x: x }
}
}
instead of what you have currently.
I'm trying to implement a macro which implements the Add trait for a struct, like so:
macro_rules! implement_add {
($t:ty) => {
impl std::ops::Add for $t {
type Output = $t;
fn add(self, rhs: $t) -> $t {
$t(self.0 + rhs.0) // error on this line
}
}
}
}
pub struct Length(f64);
implement_add!(Length);
fn main() {}
However, this gives an error on the indicated line:
<anon>:6:17: 6:19 error: unexpected token: `Length`
<anon>:6 $t(self.0 + rhs.0) // error on this line
^~
This makes no sense to me. Especially since, if I replace $t there with Length, it compiles fine. Am I doing something wrong in my macro?
Playground: http://is.gd/EIEKub
You've stumbled on a subtle bit of Rust's type system. Length is a type, but Length() is a function. These exist in different namespaces.
One work around is to extend your macro to accept a type and a function:
macro_rules! implement_add {
($t:ty, $c:ident) => {
impl std::ops::Add for $t {
type Output = $t;
fn add(self, rhs: $t) -> $t {
$c(self.0 + rhs.0) // error on this line
}
}
}
}
pub struct Length(f64);
implement_add!(Length, Length);
fn main() {}