Is it possible in Rust to create new keywords that function as an alias to another keyword?
For example, create keyword fun that points to fn and use it as if it were fn:
// somehow alias `fun` to `fn`
fun main() {
println!("Hello, world!")
}
If possible, how would this be accomplished?
If you are looking for an alternative to C's #define, there is nothing that will allow arbitrary words to be used as keywords (which is probably a good thing).
If you are looking to alias a type, Rust has type, which can be used to to rename i64 to int like this: type int = i64;, for example.
Actually, you can do this via procedural macro, since it is just "string transformation".
You cant use crate dtolnay/syn to simplify the work.
Related
I'm writing code to parse HTTP requests. I'd rather keep some things like request methods and response codes as enums because of their exhaustibility.
But it also means that for each of those enums I would have to make a From<String> implementation. The obvious way to do it is to match against a plethora of constant strings. That seems like a lot of almost identical code which I would want to factor out.
Someone suggested I use a macro to do it, but my knowledge of rust macros is limited so it made me question some things:
How can I ensure the argument is of type &str or String? Macros can take expressions, but I don't want to use type_name and panic if it doesn't match as it seems to be a very dirty fix.
How can I convert a string to a token stream? So far I've seen that the proc_macro crate offers that functionality, but is it possible to do with simple declarative macro?
Is it possible to achieve one to one mapping by any other means? I hoped I could pre-initialize enum variants with some known values like in Java.
You really want to use a library for this. You can write the macro yourself, but someone else has already made a battle-tested version of what you're trying to do.
Use strum's EnumString derive:
In Cargo.toml:
[dependencies]
strum = "0.24"
strum_macros = "0.24"
In your source code: (eg main.rs)
use std::str::FromStr;
use strum_macros::EnumString;
#[derive(Debug, EnumString)]
enum MyEnum {
Foo,
Bar,
Baz,
}
fn main() {
dbg!(MyEnum::from_str("Foo").unwrap());
}
Gives you
[src/main.rs:12] MyEnum::from_str("Foo").unwrap() = Foo
For more details see The documentation for the FromString derive and strum's readme.
I'm interested in using wasm-bindgen via rust-webpack-template to compile Rust code to WebAssembly. However, I'd like to avoid directly wrapping my code with the #[wasm_bindgen] attribute macro directly so that I can separate out the function logic from the generated WebAssembly interface to better organize my project. Instead, I would prefer to have binding generation be in a separate file, for example:
mod my_code;
use my_code::my_function;
#[wasm_bindgen]
my_function; // I want to do something like this!
I understand that #[wasm_bindgen] is a macro attribute that operates on the AST of the function definition that usually follows, but is there an approach for applying that macro to code defined elsewhere?
As far as I know, there's no way to do this. Macros operate on the AST of the code they are attached to, and there's no code to be attached to here.
If you really need this, you'll have to copy-and-paste the signature of your function:
mod my_code {
pub fn my_function(_: i32) -> String {
unimplemented!()
}
}
#[wasm_bindgen]
fn my_function(a: i32) -> String {
my_code::my_function(a)
}
It's possible you could write a macro to make the wrapping slightly less tedious, but you'll still need to replicate the function name, argument types, and return type.
I'm interested in using wasm-bindgen via rust-webpack-template to compile Rust code to WebAssembly. However, I'd like to avoid directly wrapping my code with the #[wasm_bindgen] attribute macro directly so that I can separate out the function logic from the generated WebAssembly interface to better organize my project. Instead, I would prefer to have binding generation be in a separate file, for example:
mod my_code;
use my_code::my_function;
#[wasm_bindgen]
my_function; // I want to do something like this!
I understand that #[wasm_bindgen] is a macro attribute that operates on the AST of the function definition that usually follows, but is there an approach for applying that macro to code defined elsewhere?
As far as I know, there's no way to do this. Macros operate on the AST of the code they are attached to, and there's no code to be attached to here.
If you really need this, you'll have to copy-and-paste the signature of your function:
mod my_code {
pub fn my_function(_: i32) -> String {
unimplemented!()
}
}
#[wasm_bindgen]
fn my_function(a: i32) -> String {
my_code::my_function(a)
}
It's possible you could write a macro to make the wrapping slightly less tedious, but you'll still need to replicate the function name, argument types, and return type.
Where is the recommended place to put use declarations? I couldn't find any decisive answer in the book, in FAQs, mailing lists or online forums. I'm beginning a new project in Rust and I'd prefer to get the right approach right away.
Is one of the two below approaches recommended? Is it only for "aliasing" stuff or does it do more, like initialize a module if it hasn't been used before?
use std::io;
use std::io::Write;
fn some_func() -> () {
[...] // We assume we need std::io here
}
fn some_other_func() -> () {
[...] // We assume we need std::io and std::io::Write here
}
OR
fn some_func() -> () {
use std::io;
[...] // We assume we need std::io here
}
fn some_other_func() -> () {
use std::io;
use std::io::Write;
[...] // We assume we need std::io and std::io::Write here
}
TL;DR: Like almost every other piece of software, it depends on what you are doing. The common style that I have observed (and prefer myself) is to put them at the top of the file and only moving them to narrower scope as needed.
Generally, I recommend starting by placing use statements directly after any extern crate and mod statements, separated by a blank line:
extern crate foo;
extern crate bar;
mod interesting;
use std::collections::HashMap;
use foo::Foo;
use bar::{Quux, moo};
use interesting::something;
// structs, functions, etc.
I base this default on the fact that — most times — an import is used in multiple top-level items. Thus, it makes sense to only import it once.
There are times where imported traits have conflicting methods, and in those cases I scope the import to where it's needed. There are also cases where I'm heavily dealing with a single enum and wish to glob-import it to avoid re-stating the enum's name:
fn foo(e: MyEnum) {
use MyEnum::*;
match e {
One => 1,
Two => 2,
}
}
In certain cases, conflicting use statements indicate that you are attempting too much in a single file and it should be split into separate files and then the use statements are no longer ambiguous.
What is the difference between
use hyper::status::StatusCode as Error;
and
type Error = hyper::status::StatusCode;
Are the any more differences between them except that type can be also pub type? What are the benefits between using one or another?
In case of simple types, like in your example, there doesn't seem to be any semantic difference. Moreover, there is a direct analogue with use to pub type, it's pub use:
// will be available to other modules
pub use hyper::status::StatusCode as Error;
However, there are differences in more complex cases. For example, you can define generic type aliases or aliases for specialized generic types:
type Result<T> = ::std::result::Result<T, MyError>;
type OptionI32 = Option<i32>;
The general idea is that you usually use type aliases because they are more powerful and suggest the intent more clearly, like with Result, and you use use .. as .. when you only want to import that specific name but it conflicts with something which is already in the current namespace:
use std::io::Read as StdRead;
trait Read: StdRead { ... }
Note that using path-qualified identifiers should be preferred to use renaming. The above is better written as
use std::io;
trait Read: io::Read { ... }
(unless Read methods are used for some concrete type in the same file, of course).
Using use .. as .. as a substitute for type (in case where it is possible) is uncommon and I think it should be avoided.