How to combine different algorithms in one executable - rust

To learn Rust, I have started to implement some of the Project Euler problems. Now I want to take the next step and create a console based user interface, which has the ability for running all or only specific problems. Another requirement is that the user should be able to pass optional parameters only to a specific problem.
My current solution is to have a Trait ProjectEulerProblem that declares for example run(). With that I can do something like this:
fn main() {
let args: Args = Args::docopt().decode().unwrap_or_else(|e| e.exit());
let problems: Vec<Box<problems::ProjectEulerProblem>> = vec![
box problems::Problem1,
box problems::Problem2
];
match args.flag_problem {
Some(x) => println!("Result of problem: {} is {}", x, problems[x-1].run()),
None => println!("No problem number given.")
}
}
My question is, is there a way to get rid of the explicit problems vector initialization, maybe by using macros? Alternative ideas for implementing my application like described above are also welcome.

You can use a macro with repetition to generate your list without having to type out the full path and name every time.
macro_rules! problem_vec(
($( $prob:tt ),*) => ({
&[
$(
&concat_idents!(Proble, $prob),
)*
]
});
);
const PROBLEMS: &'static[&'static ProjectEulerProblem] = problem_vec!(m1, m2);
Note, you cannot simply use indices, because the concat_idents macro requires an identifier and numbers are not identifiers. concat_idents is also only available on nightly. On stable you need to give the entire struct name:
macro_rules! problem_vec(
($( $prob:ident ),*) => ({
&[
$(
&problems::$prob,
)*
]
});
);
const PROBLEMS: &'static [&'static problems::ProjectEulerProblem] = problem_vec!(
Problem1, Problem2
);
PlayPen

My mashup crate lets you define a concise way to build the problems array as problems![1, 2]. This approach works with any Rust version >= 1.15.0.
#[macro_use]
extern crate mashup;
mod problems {
pub trait ProjectEulerProblem {
fn run(&self);
}
pub struct Problem1;
impl ProjectEulerProblem for Problem1 {
fn run(&self) {
println!("running Project Euler problem 1");
}
}
pub struct Problem2;
impl ProjectEulerProblem for Problem2 {
fn run(&self) {
println!("running Project Euler problem 2");
}
}
}
macro_rules! problems {
($($number:tt),*) => {{
// Use mashup to define a substitution macro `m!` that replaces every
// occurrence of the tokens `"Problem" $number` in its input with the
// concatenated identifier `Problem $number`.
mashup! {
$(
m["Problem" $number] = Problem $number;
)*
}
// Invoke the substitution macro to build a slice of problems. This
// expands to:
//
// &[
// &problems::Problem1 as &problems::ProjectEulerProblem,
// &problems::Problem2 as &problems::ProjectEulerProblem,
// ]
m! {
&[
$(
&problems::"Problem" $number as &problems::ProjectEulerProblem,
)*
]
}
}}
}
fn main() {
for p in problems![1, 2] {
p.run();
}
}

Related

Disable unnecessary unsafe warning when cfg given

I have two versions of a structure, one is enabled when a feature is enabled, the other when its not enabled, as shown below. The thing is that one contains unsafe methods, the other does not. So when these functions are called in other parts of the library, I have surrounded them with an unsafe { } block. When my library is compiled without the feature enabled, I get the following warning:
unnecessary unsafe block
How do I get around / disable this warning when its not applicable, ie. when the feature is not enabled.
#[cfg(feature = "my-feature")]
pub struct MyStruct {
// some fields
}
#[cfg(not(feature = "my-feature"))]
pub struct MyStruct {
// some different fields
}
#[cfg(feature = "my-feature")]
impl MyStruct {
pub unsafe fn my_func() {}
}
#[cfg(not(feature = "my-feature"))]
impl MyStruct {
pub fn my_func() {}
}
fn main() {
// I want to get rid of this unsafe when its not needed.
unsafe { MyStruct::my_func() };
}
If these cases are only inside your library, so you can afford little incovenience, you can use a macro:
macro_rules! call {
// For static methods.
{
unsafe {
$($method:ident)::+ ( $($arg:expr),* $(,)? )
}
} => {{
#[cfg(feature = "my-feature")]
let v = unsafe { $($method)::+ ( $($arg),* ) };
#[cfg(not(feature = "my-feature"))]
let v = $($method)::+ ( $($arg),* );
v
}};
// For instance methods.
{
unsafe {
$object:ident . $method:ident ( $($arg:expr),* $(,)? )
}
} => {{
#[cfg(feature = "my-feature")]
let v = unsafe { $object . $method ( $($arg),* ) };
#[cfg(not(feature = "my-feature"))]
let v = $object . $method ( $($arg),* );
v
}};
}
call!(unsafe { MyStruct::my_func() });
call!(unsafe { v.my_method() });
This macro does not allow generics or complex expression as the receiver. Extending it to support generics should be fairly easy; supporting complex expressions will probably require a proc macro.
There is a better way to write the macro: instead of requiring unsafe inside it, and wrapping the call in cfg, just do something unsafe inside it, thus always requiring unsafe outside of it. This also solves the problem with generics and complex receivers:
pub(crate) unsafe fn always_unsafe() {}
macro_rules! call {
($($call:tt)+) => {{
$crate::always_unsafe();
$($call)*
}};
}
unsafe {
call!(MyStruct::my_func());
}
unsafe {
call!(v.my_method());
}

What's the meaning of starting with :: Rust macro

I saw macro coding right below.
Why should :: be first of the statement and what does it mean?
::std::collections::HashMap::new()
macro_rules! hashmap {
() => {
{
::std::collections::HashMap::new()
}
};
($($k:expr => $v:expr),*) => {
{
let mut _map = ::std::collections::HashMap::new();
$(_map.insert($k, $v);)*
_map
}
};
($($k:expr => $v:expr),+ $(,)?) => {
{
let mut _map = ::std::collections::HashMap::new();
$(_map.insert($k, $v);)*
_map
}
};
}
It means "search in the global namespace". See the documentation.
It basically means (in edition 2018 and beyond) to not search in this crate. Suppose we were using unqualified std::collections::HashMap (without the leading ::), and the macro was used in a module that defines a std submodule, like that:
mod std;
hashmap! {}
In this case, the declared std module will take precedence over the preexisting std library, and the macro will refer to it. Of course there isn't a collections::HashMap in there (or worse, there is but it is different from the expected HashMap). To prevent that, we use ::std and that means "search for a crate named std, do not look for modules with that name".
Path starting with :: means that search in global namespace. Since #Chayin already pointed the documentation, A example might be useful for you and future readers.
When you run this program:
test-program/src/main
mod std {
pub mod f64 {
pub mod consts {
pub const PI: f64 = 4.0;
}
}
}
macro_rules! test_mactro {
() => {{
pub mod std { pub mod f64 { pub mod consts {
pub const PI: f64 = 5.0;
}}}
println!("{}", std::f64::consts::PI);
println!("{}", ::std::f64::consts::PI);
println!("{}", self::std::f64::consts::PI);
}};
}
fn main() {
test_mactro!()
}
And see the output:
$ cargo run
5
3.141592653589793
4

Match on pair of enum when both are of the same kind

I want to get rid of the repeated code here, and not have to list each enum kind:
use Geometry::*;
let geometry = match (&self.geometry, &other.geometry) {
(Point(a), Point(b)) => Point(*a.interpolate(b, t)),
(Curve(a), Curve(b)) => Curve(*a.interpolate(b, t)),
(EPBox(a), EPBox(b)) => EPBox(*a.interpolate(b, t)),
(_, _) => unimplemented!("Kinds not matching")
};
The types inside the kinds all implement the Interpolate trait which has the interpolate method:
enum Geometry {
Point(Point),
Curve(Curve),
EPBox(EPBox)
}
trait Interpolate {
fn interpolate(&self, other: &Self, t: f64) -> Box<Self> {
// ...
}
}
impl Interpolate for Point {}
impl Interpolate for Curve {}
impl Interpolate for EPBox {}
What I want to do is something like this:
let geometry = match (&self.geometry, &other.geometry) {
(x(a), x(b)) => x(*a.interpolate(b, t)), // and check that a and b impls Interpolate
(_, _) => unimplemented!("Kinds not matching")
};
I'm not sure how many of these operations you want to implement, and how many enum variants you actually have. Depending on that, the best answer changes quite a bit, I think. If you really only have one operation (interpolate), and three variants: type it out, anything else will be a lot less simple and maintainable.
That being said, I might use
let geometry = binop!(match (&self.geometry, &other.geometry) {
(a, b) => *a.interpolate(b, t)
});
based on
macro_rules! binop {
(match ($av:expr, $bv:expr) { ($a:ident, $b:ident) => $op:expr }) => {{
use Geometry::*;
binop!($av, $bv, $a, $b, $op, Point, Curve, EPBox)
}};
($av:expr, $bv:expr, $a:ident, $b:ident, $op:expr, $($var:path),*) => {
match ($av, $bv) {
$(($var($a), $var($b)) => $var($op),)*
_ => unimplemented!("Kinds not matching")
}
};
}
Playground
You'll have to list up the enum variants once. If you don't want that, you'll have to go for a proc macro. I think that would be overkill.
With your current code, you can't really do this. Checking if the enum variants are the same variant is fairly simple with the use of core::mem::discriminant, but you can't access the contained value without match or if let statements. What you can do is use type parameters for the variables and type IDs. This is a really tacky way to do things, and should be avoided really, but it works. I've given an example to show you how you could implement it
use std::any::Any;
trait SomeTrait {
fn some_function(&self, other: Self) -> &Self;
}
#[derive(Clone)]
struct Var0 {
eg: i64
}
#[derive(Clone)]
struct Var1 {
other_eg: f64
}
fn check<T: 'static, B: 'static>(lhs: T, rhs: B) -> Option<T> {
if lhs.type_id() == rhs.type_id() {
Some(lhs.some_function(rhs))
} else {
None
}
}
fn main() {
let a = Var0{ eg: 2 };
let b = Var0{ eg: 9 };
let c = Var1 { other_eg: -3f64 };
assert!(check(a.clone(), b).is_some());
assert!(check(a, c).is_none());
}
impl SomeTrait for Var0 { /* ... */ }
impl SomeTrait for Var1 { /* ... */ }
Please note though: as I said before this is messy and pretty hacky and not very nice to read. If I were writing this I would use the match statement over this, but it's up to you what you do since this does require some reworking to implement. I'm also not sure if you can use different lifetimes for the check function other than `static which might be a problem.
I came up with the following solution, which is easy to extend with new Interpolate types:
macro_rules! geometries {
( $( $x:ident ),+ ) => {
enum Geometry {
$(
$x($x),
)*
}
fn interpolate_geometries(a: &Geometry, b: &Geometry, t: f64) -> Geometry {
use Geometry::*;
match (a, b) {
$(
($x(a), $x(b)) => $x(a.interpolate(b, t)),
)*
_ => unimplemented!("Kinds not matching")
}
}
$(
impl Interpolate for $x {}
)*
};
}
geometries!(Point, Curve, EPBox);
Which make it possible to later do:
let geometry = interpolate_geometries(&self.geometry, &other.geometry, t);
Thanks for all answers and comments! Especially the one with the binop macro, which is quite similar to my solution. After reading up on macros (thanks to comments here) I came up with this solution.

Write a macro that invokes methods base on the input ident token [duplicate]

I'd like to create a setter/getter pair of functions where the names are automatically generated based on a shared component, but I couldn't find any example of macro rules generating a new name.
Is there a way to generate code like fn get_$iden() and SomeEnum::XX_GET_$enum_iden?
If you are using Rust >= 1.31.0 I would recommend using my paste crate which provides a stable way to create concatenated identifiers in a macro.
macro_rules! make_a_struct_and_getters {
($name:ident { $($field:ident),* }) => {
// Define the struct. This expands to:
//
// pub struct S {
// a: String,
// b: String,
// c: String,
// }
pub struct $name {
$(
$field: String,
)*
}
paste::item! {
// An impl block with getters. Stuff in [<...>] is concatenated
// together as one identifier. This expands to:
//
// impl S {
// pub fn get_a(&self) -> &str { &self.a }
// pub fn get_b(&self) -> &str { &self.b }
// pub fn get_c(&self) -> &str { &self.c }
// }
impl $name {
$(
pub fn [<get_ $field>](&self) -> &str {
&self.$field
}
)*
}
}
};
}
make_a_struct_and_getters!(S { a, b, c });
My mashup crate provides a stable way to create new identifiers that works with any Rust version >= 1.15.0.
#[macro_use]
extern crate mashup;
macro_rules! make_a_struct_and_getters {
($name:ident { $($field:ident),* }) => {
// Define the struct. This expands to:
//
// pub struct S {
// a: String,
// b: String,
// c: String,
// }
pub struct $name {
$(
$field: String,
)*
}
// Use mashup to define a substitution macro `m!` that replaces every
// occurrence of the tokens `"get" $field` in its input with the
// concatenated identifier `get_ $field`.
mashup! {
$(
m["get" $field] = get_ $field;
)*
}
// Invoke the substitution macro to build an impl block with getters.
// This expands to:
//
// impl S {
// pub fn get_a(&self) -> &str { &self.a }
// pub fn get_b(&self) -> &str { &self.b }
// pub fn get_c(&self) -> &str { &self.c }
// }
m! {
impl $name {
$(
pub fn "get" $field(&self) -> &str {
&self.$field
}
)*
}
}
}
}
make_a_struct_and_getters!(S { a, b, c });
No, not as of Rust 1.22.
If you can use nightly builds...
Yes: concat_idents!(get_, $iden) and such will allow you to create a new identifier.
But no: the parser doesn't allow macro calls everywhere, so many of the places you might have sought to do this won't work. In such cases, you are sadly on your own. fn concat_idents!(get_, $iden)(…) { … }, for example, won't work.
There's a little known crate gensym that can generate unique UUID names and pass them as the first argument to a macro, followed by a comma:
macro_rules! gen_fn {
($a:ty, $b:ty) => {
gensym::gensym!{ _gen_fn!{ $a, $b } }
};
}
macro_rules! _gen_fn {
($gensym:ident, $a:ty, $b:ty) => {
fn $gensym(a: $a, b: $b) {
unimplemented!()
}
};
}
mod test {
gen_fn!{ u64, u64 }
gen_fn!{ u64, u64 }
}
If all you need is a unique name, and you don't care what it is, that can be useful. I used it to solve a problem where each invocation of a macro needed to create a unique static to hold a singleton struct. I couldn't use paste, since I didn't have unique identifiers I could paste together in the first place.

How to check arg type inside a macro_rule? [duplicate]

This is just pseudocode:
macro_rules! attribute {
$e: expr<f32> => { /* magical float stuff */ };
$e: expr<i64> => { /* mystical int stuff */ };
};
I would like to have a differently expanded macro depending on the type that I passed to the macro.
This is how it would work in C++
template <typename T>
struct Attribute{ void operator(T)() {} };
template <>
struct Attribute<float> {
void operator(float)(float) { /* magical float stuff */ }
};
template <>
struct Attribute<long> {
void operator()(long) { /* mystical int stuff */ }
}
Rust macros aren't able to do that. Macros operate at the syntactic level, not at the semantic level. That means that although the compiler knows it has an expression (syntax), it doesn't know what the type of the expression's value (semantic) is at the moment the macro is expanded.
A workaround would be to pass the expected type to the macro:
macro_rules! attribute {
($e:expr, f32) => { /* magical float stuff */ };
($e:expr, i64) => { /* mystical int stuff */ };
}
fn main() {
attribute!(2 + 2, i64);
}
Or, more simply, define multiple macros.
If you want to do static (compile-time) dispatch based on the type of an expression, you can use traits. Define a trait with the necessary methods, then implement the trait for the types you need. You can implement a trait for any type (including primitives and types from other libraries) if the impl block is in the same crate as the trait definition.
trait Attribute {
fn process(&self);
}
impl Attribute for f32 {
fn process(&self) { /* TODO */ }
}
impl Attribute for i64 {
fn process(&self) { /* TODO */ }
}
macro_rules! attribute {
($e:expr) => { Attribute::process(&$e) };
}
fn main() {
attribute!(2 + 2);
}
Note: You could also write $e.process() in the macro's body, but then the macro might call an unrelated process method.
As already explained, you cannot expand differently depending on the type of an expr. But as a workaround, you can use the any module and try to downcast from the Any trait:
use std::any::Any;
macro_rules! attribute {
( $e:expr ) => {
if let Some(f) = (&$e as &Any).downcast_ref::<f32>() {
println!("`{}` is f32.", f);
} else if let Some(f) = (&$e as &Any).downcast_ref::<f64>() {
println!("`{}` is f64.", f);
} else {
println!("I dunno what is `{:?}` :(", $e);
}
};
}
fn main() {
attribute!(0f32);
attribute!(0f64);
attribute!(0);
}
Displays:
`0` is f32.
`0` is f64.
I dunno what is `0` :(
While all the answers here are correct, I'd like to provide an answer more akin to your C++ version.
Rust provides its own version of templates, generics, and they can be used in the same way you use templates.
So, to define a struct and implement functions for certain types:
struct Attribute<T> {
value: T,
}
impl Attribute<u32> {
fn call(&self) {
println!("{} is a u32", self.value);
}
}
impl Attribute<f64> {
fn call(&self) {
println!("{} is a f64", self.value);
}
}
impl Attribute<String> {
fn call(&self) {
println!("{} is a string", self.value);
}
}
We'd use it like that:
fn main() {
let a = Attribute{
value: 5_u32
};
a.call();
}
Or simply like this:
Attribute{value: 6.5}.call()
Sadly, Rust doesn't provide () operator overloading in its stable version. You can still define a macro to do the job:
macro_rules! attribute {
( $e:expr ) => {
Attribute{value: $e}.call();
};
}
And use it as so:
attribute!("Hello World!".to_string());
I'd recommend using the trait based approach shown in this answer, as it doesn't use a struct, but a trait, which is considered better practice. This answer may still be helpful in many situations.

Resources