Using a macro type argument inside a generated function - macros

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() {}

Related

Using argument number in macro expansion?

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).

How to use a type (ty) within a macro to construct a struct instance in Rust?

When using ty in a macro, this works in nearly all cases I've tried.
However, it seems it cant be used to declare a new struct instance.
eg: $my_type { some_member: some_value }
A more comprehensive example
macro_rules! generic_impl {
($my_type:ty) => {
impl $rect_ty {
pub fn flip(&self) -> $my_type { self.some_method() }
pub fn swap(&self, &other: $my_type) -> { self.some_swap_method(other) }
// so far so good!
// now our troubles start :(
pub fn create(&self) -> $my_type {
return $my_type { foo: 1, bar: 2, baz: 2 };
// ^^^^^^^^ this fails!!!
}
}
}
}
// example use
generic_impl(MyStruct);
generic_impl(MyOtherStruct);
The error is:
error: expected expression, found `MyStruct`
Changing the ty to an expr means I can't use impl $my_type.
Besides passing in 2x arguments, one a ty the other an expr:
Is there a way to construct a struct based on a ty argument to a macro?
No, not with ty.
The simple fix is to capture an ident instead, which is valid in both contexts. If you need something more complex than a simple identifier, then you're probably going to need to capture the name (for construction) and the type (for other uses) separately and specify them both on use.

How to implement idiomatic operator overloading for values and references in Rust?

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.

How to use constructs defined in module in exporting macro implicitly

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.

What's the standard way to create custom conversion between types in Rust?

If I defined some enum and wanted to create a parser from string to that type, is there something better than just:
impl TheType {
fn from_str(s: &str) -> TheType {
// ...
}
}
The right way for converting from a string / parsing text is to implement the FromStr trait. For the example from the question it would look like this:
use std::str::FromStr;
enum Failure {
ReasonOne,
ReasonTwo,
}
impl FromStr for TheType {
type Err = Failure;
fn from_str(s: &str) -> Result<TheType, Self::Err> {
unimplemented!()
}
}
For generic conversion that cannot fail, you should implement the std::convert::From trait:
use std::convert::From;
#[derive(PartialEq, Eq, Debug)]
enum MyEnum {
One,
Two,
Many(i64),
}
impl From<i64> for MyEnum {
fn from(val: i64) -> Self {
match val {
1 => MyEnum::One,
2 => MyEnum::Two,
_ => MyEnum::Many(val),
}
}
}
fn main() {
assert_eq!(MyEnum::from(1), MyEnum::One);
assert_eq!(MyEnum::from(2), MyEnum::Two);
assert_eq!(MyEnum::from(3), MyEnum::Many(3));
}
Conveniently, implementing From also automatically implements Into:
let one: MyEnum = 1.into(); assert_eq!(one, MyEnum::One);
let two: MyEnum = 2.into(); assert_eq!(two, MyEnum::Two);
let many: MyEnum = 3.into(); assert_eq!(many, MyEnum::Many(3));
For potentially failing conversion, you should implement std::convert::TryFrom instead. It's only available in Rust 1.34 and up though, before these versions you can use the implementation in the conv crate.