For example, if I have code like:
enum Foo {
Bar,
Baz,
Bat,
Quux
}
impl Foo {
from(input: &str) -> Foo {
Foo::input
}
}
This will obviously fail because input is not a method of Foo. I can manually type:
from(input: &str) -> Foo {
match(input) {
"Bar" => Foo::Bar,
// and so on...
}
}
but I'm not getting the automatic convenience.
It looks like Java has a string lookup function on enums for this specific purpose.
Is it possible to get this without writing my own macro or importing one from a crate?
You should implement std::str::FromStr trait.
use std::str::FromStr;
#[derive(Debug, PartialEq)]
enum Foo {
Bar,
Baz,
Bat,
Quux,
}
impl FromStr for Foo {
type Err = ();
fn from_str(input: &str) -> Result<Foo, Self::Err> {
match input {
"Bar" => Ok(Foo::Bar),
"Baz" => Ok(Foo::Baz),
"Bat" => Ok(Foo::Bat),
"Quux" => Ok(Foo::Quux),
_ => Err(()),
}
}
}
fn main() {
// Use it like this
let f = Foo::from_str("Baz").unwrap();
assert_eq!(f, Foo::Baz);
}
Code-generation (aka automatic convenience) and reflections usually bear a cost. In practice, it is unlikely that you will end up with more than a few enum variants.
Run in the playground
Same disclaimer as in other answers: "without macros" isn't possible.
Extending on the highest voted answer. As noted in this thread the combination of custom_derive + enum_derive is somewhat outdated. Modern Rust doesn't need a solution based on custom_derive anymore.
A modern alternative is strum. Usage could look like this:
use strum_macros::EnumString;
use std::str::FromStr;
#[derive(EnumString)]
enum Foo {
Bar,
Baz,
Bat,
Quux
}
fn example_usage(input: &str) -> Foo {
Foo::from_str(input).unwrap()
}
Note: You need both strum and strum_macros in your Cargo.toml.
strum also gives some nice flexibility regarding the string representation. From the docs:
Note that the implementation of FromStr by default only matches on the name of the variant. There is an option to match on different case conversions through the #[strum(serialize_all = "snake_case")] type attribute.
Edit: The answer is no. Rust does not provide reflection and usually use #[derive] for that kind of tasks.
You can use the crates enum_derive and custom_derive to do what you want.
Here is an exemple:
#[macro_use]
extern crate custom_derive;
#[macro_use]
extern crate enum_derive;
custom_derive! {
#[derive(Debug, EnumFromStr)]
enum Foo {
Bar,
Baz,
Bat,
Quux
}
}
fn main() {
let variable: Foo = "Bar".parse().unwrap();
println!("{:?}", variable);
}
the derive of the custom EnumFromStr allows you to use the parse method to get a Foo.
Related
Suppose I have the following src/lib.rs
pub enum Toppings {
Almond,
Caramel,
Cookie,
Marshmallow,
ChocolateSprinkles,
}
pub enum Icecream {
Chocolate(Toppings),
Mint(Toppings),
Vanilla(Toppings),
}
I want to allow pattern destructure s.t. people can use the library like any other enum with associated data:
use Icecream::*;
use Toppings::*;
fn order_how_many(icecream: Icecream) -> usize {
match icecream {
Chocolate(Marshmallow) => 42,
Vanilla(Cookie) => 69,
_ => 42069,
}
}
But at the same time I want to forbid creation of certain combinations of enum and its associated data, e.g. maybe the local ice cream store thinks double chocolate is too much and would never sell Icecream::Chocolate(Toppings::ChocolateSprinkles), so we should outright forbid any possibility this combination is constructed. I find this hard to implement in Rust, since I need pub enum to allow pattern destruction, but making the enum public means all of its variants are pub.
I tried private token similar to which sometimes could be found in sealed trait pattern, using private modules and prevents any accidental pub use via #[forbid(missing_docs)], s.t. only crate implementation can decide what Icecream/Toppings combination are possible, but this makes pattern matching ugly (require _ or .. in every pattern destruction).
mod icecream {
// Intentionally NOT use /// comment for this mod
// to prevent accidental `pub use`
#[forbid(missing_docs)]
mod hide {
pub struct Hide;
}
pub enum Toppings {
Almond,
Caramel,
Cookie,
Marshmallow,
ChocolateSprinkles,
}
pub enum Icecream {
Chocolate(Toppings, hide::Hide),
Mint(Toppings, hide::Hide),
Vanilla(Toppings, hide::Hide),
}
pub use Icecream::*;
pub use Toppings::*;
}
pub use icecream::*;
fn order_how_many(icecream: Icecream) -> usize { // OK
match icecream {
Chocolate(Marshmallow, _) => 42,
Vanilla(Cookie, ..) => 69,
_ => 42069,
}
}
fn str_to_icecream(base: &str, topping: &str) -> Option<Icecream> { // Compile fail as intended
if base.to_lowercase() == "chocollate" && topping.to_lowercase() == "chocolatesprinkles" {
Some(Chocolate(ChocolateSprinkles, icecream::hide::Hide))
} else {
None
}
}
Before posting the question SO suggested me this, but it also doesn't seem to fix the problem of enum here, since enum unlike struct cannot have different visibility between the type itself and its associated members, and that this would make having different shape of associated data more cumbersome to implement, e.g. if the length of tuples are different I'd probably have to implement a trait and return trait objects if I were to use this method.
Is there a more elegant/natural/rustacean way to do this? Or one should outright try avoid such code at the beginning, maybe since it's deemed as a bad practice?
You can't allow pattern-matching on enums without also allowing them to be constructed.
However, struct fields can be private, which lets you do things like this:
pub enum Toppings {
Almond,
Caramel,
Cookie,
Marshmallow,
ChocolateSprinkles,
}
pub enum Flavour {
Chocolate,
Mint,
Vanilla,
}
pub struct Icecream {
pub flavour: Flavour,
pub toppings: Toppings,
_secret: (), // non-pub, prevents construction from outside the module
}
You can no longer construct Icecream except from functions in the same module; these are the only things allowed to access the _secret field. Code outside of the module may still destructure the values, but must use .. to avoid naming the _secret field.
You'd rewrite your other functions like this:
// this can be in any module
fn order_how_many(icecream: Icecream) -> usize { // OK
match icecream {
Icecream { flavour: Chocolate, .. } => 42,
Icecream { flavour: Vanilla, toppings: Cookie, .. } => 69,
_ => 42069,
}
}
// this must be in the same module as the `Icecream` struct
fn str_to_icecream(base: &str, topping: &str) -> Option<Icecream> {
if base.to_lowercase() == "chocolate" && topping.to_lowercase() == "chocolatesprinkles" {
Some(
Icecream {
flavour: Chocolate,
toppings: ChocolateSprinkles,
_secret: ()
}
)
} else {
None
}
}
How can I expose a struct generated from the quote macro in my derive macro without having to introduce a struct name out of the blue in my usage file (due to macro expansion)?
To illustrate the point, currently, my code looks something like this:
// "/my_derive/lib.rs"
// inside a derive macro function
let tokens = quote! {
struct MyDeriveMacroInternalStruct {
variant: #ident_name,
// other stuff ...
}
impl #ident_name {
pub fn something() -> Vec<MyDeriveMacroInternalStruct> {
vec![MyDeriveMacroInternalStruct { variant: #ident_name::#variant_name, /*...*/ }, /*...*/]
}
}
};
tokens.into()
The usage of my code would look something like this:
use my_derive::MyDerive;
#[derive(MyDerive)]
enum Something {
A,
B,
C,
}
fn process_data() -> Vec<MyDeriveMacroInternalStruct> { // having to write that struct name that came out of nowhere bothers me
Something::something()
}
fn main() {
let result = process_data();
// do stuff...
}
This is a condensed version of my actual code (process_data is in another file). To reiterate my question in light of the example, how can I access the struct without having it randomly appear out of nowhere (due to macro expansion)? To me the code unchanged is hard to understand, read, and change.
I would like to be able to do something like this:
use my_derive::{MyDerive, MyDeriveStruct};
#[derive(MyDerive)]
enum Something {
A,
B,
C,
}
fn process_data() -> Vec<MyDeriveStruct> { // importing the struct instead of magically appearing
Something::something()
}
fn main() {
let result = process_data();
// do stuff...
}
Obviously the idea seems quite stupid, but there has to be a way around it (an arbitrary struct definition). If what I imagined isn't possible, is there some way to be more clear about where the random struct came from?
Actually I thought of something better. Your derive should probably be associated with a trait of the same name.
Add an associated type to your trait:
trait MyDerive {
type Output;
...
}
Then set the associated type when you impl the trait:
struct MyDeriveMacroInternalStruct {
variant: #ident_name,
// other stuff ...
}
impl MyDerive for #ident_name {
type Output = MyDeriveMacroInternalStruct;
pub fn something() -> Vec<MyDeriveMacroInternalStruct> {
vec![MyDeriveMacroInternalStruct { variant: #ident_name::#variant_name, /*...*/ }, /*...*/]
}
}
Then you can refer to that associated type in return position or wherever:
use my_derive::MyDerive;
#[derive(MyDerive)]
enum Something {
A,
B,
C,
}
fn process_data() -> Vec<<Something as MyDerive>::Output> {
Something::something()
}
fn main() {
let result = process_data();
// do stuff...
}
Note: the convention is for #[derive(Trait)] to correspond to an impl for the given Trait, but your proc macro crate can't export a trait directly for importing in your library code.
So generally the solution is to have two crates:
my-trait is the "library" crate which contains the MyTrait trait definition
my-trait-derive is the proc-macro crate which contains the derive macro code
my-trait has my-trait-derive as a direct dependency, and re-exports the proc macro from it:
// my-trait lib.rs
pub use my_trait_derive::MyTrait;
// macro and trait names can overlap as they're
// treated as different item kinds
pub trait MyTrait {
type Output;
fn something();
}
see how clap does it here (they also re-export the whole clap_derive)
Then a user can use your proc macro + trait like this:
use my_trait::MyTrait;
#[derive(MyTrait)]
enum Something {}
fn process_data() -> Vec<<Something as MyTrait>::Output> {
Something::something()
}
Older Answer
What I would do is create a trait MyDeriveOutput or something with whatever stuff you want exposed from MyDeriveMacroInternalStruct:
trait MyDeriveOutput {
fn variant() ...
}
And then generate an impl for each internal struct you create:
struct MyDeriveMacroInternalStruct {
variant: #ident_name,
// other stuff ...
}
impl MyDeriveOutput for MyDeriveMacroInternalStruct {
// whatever
}
Then you can expose the trait and require it to be imported and used with impl Trait in return position:
use my_derive::{MyDerive, MyDeriveOutput};
#[derive(MyDerive)]
enum Something {
A,
B,
C,
}
fn process_data() -> Vec<impl MyDeriveOutput> {
Something::something()
}
fn main() {
let result = process_data();
// do stuff...
}
An enum is clearly a kind of key/value pair structure. Consequently, it would be nice to automatically create a dictionary from one wherein the enum variants become the possible keys and their payload the associated values. Keys without a payload would use the unit value. Here is a possible usage example:
enum PaperType {
PageSize(f32, f32),
Color(String),
Weight(f32),
IsGlossy,
}
let mut dict = make_enum_dictionary!(
PaperType,
allow_duplicates = true,
);
dict.insert(dict.PageSize, (8.5, 11.0));
dict.insert(dict.IsGlossy, ());
dict.insert_def(dict.IsGlossy);
dict.remove_all(dict.PageSize);
Significantly, since an enum is merely a list of values that may optionally carry a payload, auto-magically constructing a dictionary from it presents some semantic issues.
How does a strongly typed Dictionary<K, V> maintain the discriminant/value_type dependency inherent with enums where each discriminant has a specific payload type?
enum Ta {
K1(V1),
K2(V2),
...,
Kn(Vn),
}
How do you conveniently refer to an enum discriminant in code without its payload (Ta.K1?) and what type is it (Ta::Discriminant?) ?
Is the value to be set and get the entire enum value or just the payload?
get(&self, key: Ta::Discriminant) -> Option<Ta>
set(&mut self, value: Ta)
If it were possible to augment an existing enum auto-magically with another enum of of its variants then a reasonably efficient solution seems plausible in the following pseudo code:
type D = add_discriminant_keys!( T );
impl<D> for Vec<D> {
fn get(&self, key: D::Discriminant) -> Option<D> { todo!() }
fn set(&mut self, value: D) { todo!() }
}
I am not aware whether the macro, add_discriminant_keys!, or the construct, D::Discriminant, is even feasible. Unfortunately, I am still splashing in the shallow end of the Rust pool, despite this suggestion. However, the boldness of its macro language suggests many things are possible to those who believe.
Handling of duplicates is an implementation detail.
Enum discriminants are typically functions and therefore have a fixed pointer value (as far as I know). If such values could become constants of an associated type within the enum (like a trait) with attributes similar to what has been realized by strum::EnumDiscriminants things would look good. As it is, EnumDiscriminants seems like a sufficient interim solution.
A generic implementation over HashMap using strum_macros crate is provided based on in the rust playground; however, it is not functional there due to the inability of rust playground to load the strum crate from there. A macro derived solution would be nice.
First, like already said here, the right way to go is a struct with optional values.
However, for completeness sake, I'll show here how you can do that with a proc macro.
When you want to design a macro, especially a complicated one, the first thing to do is to plan what the emitted code will be. So, let's try to write the macro's output for the following reduced enum:
enum PaperType {
PageSize(f32, f32),
IsGlossy,
}
I will already warn you that our macro will not support brace-style enum variants, nor combining enums (your add_discriminant_keys!()). Both are possible to support, but both will complicate this already-complicated answer more. I'll refer to them shortly at the end.
First, let's design the map. It will be in a support crate. Let's call this crate denum (a name will be necessary later, when we'll refer to it from our macro):
pub struct Map<E> {
map: std::collections::HashMap<E, E>, // You can use any map implementation you want.
}
We want to store the discriminant as a key, and the enum as the value. So, we need a way to refer to the free discriminant. So, let's create a trait Enum:
pub trait Enum {
type DiscriminantsEnum: Eq + Hash; // The constraints are those of `HashMap`.
}
Now our map will look like that:
pub struct Map<E: Enum> {
map: std::collections::HashMap<E::DiscriminantsEnum, E>,
}
Our macro will generate the implementation of Enum. Hand-written, it'll be the following (note that in the macro, I wrap it in const _: () = { ... }. This is a technique used to prevent names polluting the global namespaces):
#[derive(PartialEq, Eq, Hash)]
pub enum PaperTypeDiscriminantsEnum {
PageSize,
IsGlossy,
}
impl Enum for PaperType {
type DiscriminantsEnum = PaperTypeDiscriminantsEnum;
}
Next. insert() operation:
impl<E: Enum> Map<E> {
pub fn insert(discriminant: E::DiscriminantsEnum, value: /* What's here? */) {}
}
There is no way in current Rust to refer to an enum discriminant as a distinct type. But there is a way to refer to struct as a distinct type.
We can think about the following:
pub struct PageSize;
But this pollutes the global namespace. Of course, we can call it something like PaperTypePageSize, but I much prefer something like PaperTypeDiscriminants::PageSize.
Modules to the rescue!
#[allow(non_snake_case)]
pub mod PaperTypeDiscriminants {
#[derive(Clone, Copy)]
pub struct PageSize;
#[derive(Clone, Copy)]
pub struct IsGlossy;
}
Now we need a way in insert() to validate the the provided discriminant indeed matches the wanted enum, and to refer to its value. A new trait!
pub trait EnumDiscriminant: Copy {
type Enum: Enum;
type Value;
fn to_discriminants_enum(self) -> <Self::Enum as Enum>::DiscriminantsEnum;
fn to_enum(self, value: Self::Value) -> Self::Enum;
}
And here's how our macro will implements it:
impl EnumDiscriminant for PaperTypeDiscriminants::PageSize {
type Enum = PaperType;
type Value = (f32, f32);
fn to_discriminants_enum(self) -> PaperTypeDiscriminantsEnum { PaperTypeDiscriminantsEnum::PageSize }
fn to_enum(self, (v0, v1): Self::Value) -> Self::Enum { Self::Enum::PageSize(v0, v1) }
}
impl EnumDiscriminant for PaperTypeDiscriminants::IsGlossy {
type Enum = PaperType;
type Value = ();
fn to_discriminants_enum(self) -> PaperTypeDiscriminantsEnum { PaperTypeDiscriminantsEnum::IsGlossy }
fn to_enum(self, (): Self::Value) -> Self::Enum { Self::Enum::IsGlossy }
}
And now insert():
pub fn insert<D>(&mut self, discriminant: D, value: D::Value)
where
D: EnumDiscriminant<Enum = E>,
{
self.map.insert(
discriminant.to_discriminants_enum(),
discriminant.to_enum(value),
);
}
And trivially insert_def():
pub fn insert_def<D>(&mut self, discriminant: D)
where
D: EnumDiscriminant<Enum = E, Value = ()>,
{
self.insert(discriminant, ());
}
And get() (note: seprately getting the value is possible when removing, by adding a method to the trait EnumDiscriminant with the signature fn enum_to_value(enum_: Self::Enum) -> Self::Value. It can be unsafe fn and use unreachable_unchecked() for better performance. But with get() and get_mut(), that returns reference, it's harder because you can't get a reference to the discriminant value. Here's a playground that does that nonetheless, but requires nightly):
pub fn get_entry<D>(&self, discriminant: D) -> Option<&E>
where
D: EnumDiscriminant<Enum = E>,
{
self.map.get(&discriminant.to_discriminants_enum())
}
get_mut() is very similar.
Note that my code doesn't handle duplicates but instead overwrites them, as it uses HashMap. However, you can easily create your own map that handles duplicates in another way.
Now that we have a clear picture in mind what the macro should generate, let's write it!
I decided to write it as a derive macro. You can use an attribute macro too, and even a function-like macro, but you must call it at the declaration site of your enum - because macros cannot inspect code other than the code the're applied to.
The enum will look like:
#[derive(denum::Enum)]
enum PaperType {
PageSize(f32, f32),
Color(String),
Weight(f32),
IsGlossy,
}
Usually, when my macro needs helper code, I put this code in crate and the macro in crate_macros, and reexports the macro from crate. So, the code in denum (besides the aforementioned Enum, EnumDiscriminant and Map):
pub use denum_macros::Enum;
denum_macros/src/lib.rs:
use proc_macro::TokenStream;
use quote::{format_ident, quote};
#[proc_macro_derive(Enum)]
pub fn derive_enum(item: TokenStream) -> TokenStream {
let item = syn::parse_macro_input!(item as syn::DeriveInput);
if item.generics.params.len() != 0 {
return syn::Error::new_spanned(
item.generics,
"`denum::Enum` does not work with generics currently",
)
.into_compile_error()
.into();
}
if item.generics.where_clause.is_some() {
return syn::Error::new_spanned(
item.generics.where_clause,
"`denum::Enum` does not work with `where` clauses currently",
)
.into_compile_error()
.into();
}
let (vis, name, variants) = match item {
syn::DeriveInput {
vis,
ident,
data: syn::Data::Enum(syn::DataEnum { variants, .. }),
..
} => (vis, ident, variants),
_ => {
return syn::Error::new_spanned(item, "`denum::Enum` works only with enums")
.into_compile_error()
.into()
}
};
let discriminants_mod_name = format_ident!("{}Discriminants", name);
let discriminants_enum_name = format_ident!("{}DiscriminantsEnum", name);
let mut discriminants_enum = Vec::new();
let mut discriminant_structs = Vec::new();
let mut enum_discriminant_impls = Vec::new();
for variant in variants {
let variant_name = variant.ident;
discriminant_structs.push(quote! {
#[derive(Clone, Copy)]
pub struct #variant_name;
});
let fields = match variant.fields {
syn::Fields::Named(_) => {
return syn::Error::new_spanned(
variant.fields,
"`denum::Enum` does not work with brace-style variants currently",
)
.into_compile_error()
.into()
}
syn::Fields::Unnamed(fields) => Some(fields.unnamed),
syn::Fields::Unit => None,
};
let value_destructuring = fields
.iter()
.flatten()
.enumerate()
.map(|(index, _)| format_ident!("v{}", index));
let value_destructuring = quote!((#(#value_destructuring,)*));
let value_builder = if fields.is_some() {
value_destructuring.clone()
} else {
quote!()
};
let value_type = fields.into_iter().flatten().map(|field| field.ty);
enum_discriminant_impls.push(quote! {
impl ::denum::EnumDiscriminant for #discriminants_mod_name::#variant_name {
type Enum = #name;
type Value = (#(#value_type,)*);
fn to_discriminants_enum(self) -> #discriminants_enum_name { #discriminants_enum_name::#variant_name }
fn to_enum(self, #value_destructuring: Self::Value) -> Self::Enum { Self::Enum::#variant_name #value_builder }
}
});
discriminants_enum.push(variant_name);
}
quote! {
#[allow(non_snake_case)]
#vis mod #discriminants_mod_name { #(#discriminant_structs)* }
const _: () = {
#[derive(PartialEq, Eq, Hash)]
pub enum #discriminants_enum_name { #(#discriminants_enum,)* }
impl ::denum::Enum for #name {
type DiscriminantsEnum = #discriminants_enum_name;
}
#(#enum_discriminant_impls)*
};
}
.into()
}
This macro has several flaws: it doesn't handle visibility modifiers and attributes correctly, for example. But in the general case, it works, and you can fine-tune it more.
If you want to also support brace-style variants, you can create a struct with the data (instead of the tuple we use currently).
Combining enum is possible if you'll not use a derive macro but a function-like macro, and invoke it on both enums, like:
denum::enums! {
enum A { ... }
enum B { ... }
}
Then the macro will have to combine the discriminants and use something like Either<A, B> when operating with the map.
Unfortunately, a couple of questions arise in that context:
should it be possible to use enum types only once? Or are there some which might be there multiple times?
what should happen if you insert a PageSize and there's already a PageSize in the dictionary?
All in all, a regular struct PaperType is much more suitable to properly model your domain. If you don't want to deal with Option, you can implement the Default trait to ensure that some sensible defaults are always available.
If you really, really want to go with a collection-style interface, the closest approximation would probably be a HashSet<PaperType>. You could then insert a value PaperType::PageSize.
With "default" constructors, it can be useful to document what theā¦ defaults are. If this is textually defined in the doc and separately defined as a literal or a static / const, the two can get out of sync:
impl Foo {
/// Creates a [Foo] with a `bar` of 3.
fn new() -> Foo { Foo::new_with_bar(5) }
/// Creates a [Foo] with the provided `bar`.
fn new_with_bar(bar: usize) -> Foo { Foo { bar } }
}
It's possible to extract the literal to a const or static and link to that, but then the reader has to go through the indirection to know what the value is, and the const / static has to be pub or cargo doc complains and refuses to link to it.
Is there any way to substitute the const value in the docstring instead of linking to it? Or some other method which would avoid the indirection? aka
const DEFAULT_BAR: usize = 5
impl Foo {
/// Creates a [Foo] with a `bar` of ???DEFAULT_BAR???.
fn new() -> Foo { Foo::new_with_bar(DEFAULT_BAR) }
}
should be rendered as:
pub fn new() -> Foo
Creates a Foo with a bar of 5.
Although similar, How to embed a Rust macro variable into documentation? doesn't seem to apply here. [doc] complains about an unexpected token when given a name as a parameter (even a const str) and I don't know if a wrapping macro can force the substitution of a const.
On stable there isn't really an easy solution to doing this, without requiring a specialized macro for each type/method. So the easiest is to fallback to using a const DEFAULT_BAR and referencing it in the docs (which you wanted to avoid.)
However, there's a rather new nightly feature extended_key_value_attributes (see issue #78835 and PR 78837.)
Besides requiring one of the latest nightly builds. It will also be slightly cumbersome to use for your use case (in its current state). This is because it either requires the use of literals, which excludes using const DEFAULT_BAR. Alternatively, you can use a macro which expands to 5, which is the cumbersome solution.
#![feature(extended_key_value_attributes)]
struct Foo {
bar: usize,
}
macro_rules! default_bar {
() => {
5
};
}
impl Foo {
/// Creates a [Foo] with a `bar` of
#[doc = concat!(default_bar!(), ".")]
fn new() -> Foo {
Foo::new_with_bar(default_bar!())
}
/// Creates a [Foo] with the provided `bar`.
fn new_with_bar(bar: usize) -> Foo {
Foo { bar }
}
}
The above works on rustc 1.50.0-nightly (bb1fbbf84 2020-12-22)
Note that you have to use concat!, as otherwise default_bar needs to expand into a string. So if you don't need e.g. ".", then just use an empty string, e.g. concat!("", default_bar!()).
This works in Rust 1.47:
struct Foo { bar: usize }
macro_rules! impl_foo {
($bar_def:expr) => { impl_foo!(# $bar_def, stringify!($bar_def)); };
(# $bar_def:expr, $bar_def_str:expr) => {
impl Foo {
/// Creates a [Foo] with a `bar` of
#[doc = $bar_def_str]
///.
fn new() -> Foo { Foo::new_with_bar($bar_def) }
/// Creates a [Foo] with the provided `bar`.
fn new_with_bar(bar: usize) -> Foo { Foo { bar } }
}
}
}
impl_foo!(3);
You can use the paste to avoid the redirection:
use paste::paste;
struct Foo { bar: usize }
macro_rules! impl_foo {
($bar_def:expr) => {
paste! {
impl Foo {
#[doc = "Creates a [Foo] with a `bar` of " $bar_def "."]
fn new() -> Foo { Foo::new_with_bar($bar_def) }
/// Creates a [Foo] with the provided `bar`.
fn new_with_bar(bar: usize) -> Foo { Foo { bar } }
}
}
}
}
impl_foo!(3);
In the future, you'll be able to skip the re-direction in the macro (or the usage of paste!) by using #![feature(extended_key_value_attributes)], as described in vallentin's answer.
See also:
The doc-comment crate, which uses this trick to allow documenting an item using an external Markdown file.
How to embed a Rust macro variable into documentation?
In Rust, tuple structs with only one field can be created like the following:
struct Centimeters(i32);
I want to do basic arithmetic with Centimeters without extracting their "inner" values every time with pattern matching, and without implementing the Add, Sub, ... traits and overloading operators.
What I want to do is:
let a = Centimeters(100);
let b = Centimeters(200);
assert_eq!(a + a, b);
is there a way to do it without extracting their "inner" values every time with pattern matching, and without implementing the Add, Sub, ... traits and overloading operators?
No, the only way is to implement the traits manually. Rust doesn't have an equivalent to the Haskell's GHC extension GeneralizedNewtypeDeriving which allows deriving on wrapper types to automatically implement any type class/trait that the wrapped type implements (and with the current set-up of Rust's #[derive] as a simple AST transformation, implementing it like Haskell is essentially impossible.)
To abbreviate the process, you could use a macro:
use std::ops::{Add, Sub};
macro_rules! obvious_impl {
(impl $trait_: ident for $type_: ident { fn $method: ident }) => {
impl $trait_<$type_> for $type_ {
type Output = $type_;
fn $method(self, $type_(b): $type_) -> $type_ {
let $type_(a) = self;
$type_(a.$method(&b))
}
}
}
}
#[derive(Eq, PartialEq, Ord, PartialOrd, Clone, Debug)]
pub struct Centimeters(i32);
obvious_impl! { impl Add for Centimeters { fn add } }
obvious_impl! { impl Sub for Centimeters { fn sub } }
#[derive(Eq, PartialEq, Ord, PartialOrd, Clone, Debug)]
pub struct Inches(i32);
obvious_impl! { impl Add for Inches { fn add } }
obvious_impl! { impl Sub for Inches { fn sub } }
fn main() {
let a = Centimeters(100);
let b = Centimeters(200);
let c = Inches(10);
let d = Inches(20);
println!("{:?} {:?}", a + b, c + d); // Centimeters(300) Inches(30)
// error:
// a + c;
}
playpen
I emulated the normal impl syntax in the macro to make it obvious what is happening just by looking at the macro invocation (i.e. reducing the need to look at the macro definition), and also to maintain Rust's natural searchability: if you're looking for traits on Centimeters just grep for for Centimeters and you'll find these macro invocations along with the normal impls.
If you are accessing the contents of the Centimeters type a lot, you could consider using a proper struct with a field to define the wrapper:
struct Centimeters { amt: i32 }
This allows you to write self.amt instead of having to do the pattern matching. You can also define a function like fn cm(x: i32) -> Centimeters { Centimeters { amt: x } }, called like cm(100), to avoid the verbosity of constructing a full struct.
You can also access the inner values of a tuple struct using the .0, .1 syntax.
I made the derive_more crate for this problem. It can derive lots of traits for structs of which the elements implement them.
You need to add derive_more to your Cargo.toml. Then you can write:
#[macro_use]
extern crate derive_more;
#[derive(Clone, Copy, Debug, PartialEq, Eq, Add)]
struct Centimeters(i32);
fn main() {
let a = Centimeters(100);
let b = Centimeters(200);
assert_eq!(a + a, b);
}
For Rust version 1.10.0, it seems to me that type aliases would perfectly fit the situation you are describing. They simply give a type a different name.
Let's say all centimeters are u32s. Then I could just use the code
type Centimeters = u32;
Any trait that u32 has, Centimeters would automatically have. This doesn't eliminate the possibility of adding Centimeters to Inches. If you're careful, you wouldn't need different types.