Derive a Trait for particular variants - enums

Let's say I have the following Enum
enum MyEnum {
VariantA,
VariantB,
VariantC,
}
I can derive the PartialEq trait for the whole enum by doing so
#[derive(PartialEq)]
enum MyEnum {
VariantA,
VariantB,
VariantC,
}
What I want to do, is derive the trait but only to particular variants and not the whole enum. Is that possible? (or does it even make sense?).

Assuming you have a setup like:
#[derive(PartialEq)]
struct VarB{
pub value: u32,
}
#[derive(PartialEq)]
enum MyEnum{
VarA(VarA),
VarB(VarB)
}
VarA comes from a different crate and you can't compile due to it not having derived PartialEq (or any other external trait).
You can solve that with the newtype pattern (assuming you have access to the relevent fields / accessors)
struct MyVarA(VarA);
impl PartialEq for MyVarA{
fn eq(&self, other: &MyVarA) -> bool {
self.0.value == other.0.value
}
fn ne(&self, other: &MyVarA) -> bool {
self.0.value != other.0.value
}
}
#[derive(PartialEq)]
struct VarB{
value: u32,
}
#[derive(PartialEq)]
enum MyEnum{
VarA(MyVarA),
VarB(VarB)
}
further informations:
https://doc.rust-lang.org/rust-by-example/generics/new_types.html

What I want to do, is derive the trait but only to particular variants and not the whole enum. Is that possible? (or does it even make sense?).
This doesn't really make sense.
Traits are implemented for types. An enum is a type and its variants are its values. Your question is equivalent to asking if you could implement a trait for some Strings but not others.
If it is acceptable for unsupported variants to always return false, similar to how f32's PartialEq implementation returns false whenever you compare a NaN value, then you can write that impl by hand:
impl PartialEq for MyEnum {
fn eq(&self, other: &MyEnum) -> bool {
use MyEnum::*;
match (self, other) {
// VariantA and VariantB are supported
(VariantA(value), VariantA(other_value)) => value == other_value,
(VariantB(value), VariantB(other_value)) => value == other_value,
// Any other combinations of variants end up here
_ => false,
}
}
}
Note that you must not implement Eq this way, since implementations of Eq may be assumed to be total, which this is not.

Related

How to implement a trait like `Debug` specifically for certain enum variants? [duplicate]

Let's say I have the following Enum
enum MyEnum {
VariantA,
VariantB,
VariantC,
}
I can derive the PartialEq trait for the whole enum by doing so
#[derive(PartialEq)]
enum MyEnum {
VariantA,
VariantB,
VariantC,
}
What I want to do, is derive the trait but only to particular variants and not the whole enum. Is that possible? (or does it even make sense?).
Assuming you have a setup like:
#[derive(PartialEq)]
struct VarB{
pub value: u32,
}
#[derive(PartialEq)]
enum MyEnum{
VarA(VarA),
VarB(VarB)
}
VarA comes from a different crate and you can't compile due to it not having derived PartialEq (or any other external trait).
You can solve that with the newtype pattern (assuming you have access to the relevent fields / accessors)
struct MyVarA(VarA);
impl PartialEq for MyVarA{
fn eq(&self, other: &MyVarA) -> bool {
self.0.value == other.0.value
}
fn ne(&self, other: &MyVarA) -> bool {
self.0.value != other.0.value
}
}
#[derive(PartialEq)]
struct VarB{
value: u32,
}
#[derive(PartialEq)]
enum MyEnum{
VarA(MyVarA),
VarB(VarB)
}
further informations:
https://doc.rust-lang.org/rust-by-example/generics/new_types.html
What I want to do, is derive the trait but only to particular variants and not the whole enum. Is that possible? (or does it even make sense?).
This doesn't really make sense.
Traits are implemented for types. An enum is a type and its variants are its values. Your question is equivalent to asking if you could implement a trait for some Strings but not others.
If it is acceptable for unsupported variants to always return false, similar to how f32's PartialEq implementation returns false whenever you compare a NaN value, then you can write that impl by hand:
impl PartialEq for MyEnum {
fn eq(&self, other: &MyEnum) -> bool {
use MyEnum::*;
match (self, other) {
// VariantA and VariantB are supported
(VariantA(value), VariantA(other_value)) => value == other_value,
(VariantB(value), VariantB(other_value)) => value == other_value,
// Any other combinations of variants end up here
_ => false,
}
}
}
Note that you must not implement Eq this way, since implementations of Eq may be assumed to be total, which this is not.

Unwrap enum when all variants are of the same type

Consider an enum definition like this:
enum Money {
USD(u32),
EUR(u32),
CHF(u32),
// many more...
}
Note that all enum variants are of type u32.
fn amount(money: Money) -> u32 {
// ?
}
Can I generically extract the wrapped u32 contained in a Money instance without matching on all cases, if yes, how?
There isn't a built-in way to do this, unfortunately. The usual approach is to create an accessor method:
impl Money {
pub fn amount(&self) -> u32 {
match *self {
Money::USD(amount) => amount,
Money::EUR(amount) => amount,
Money::CHF(amount) => amount,
}
}
}
At least this way you only have to do it once.

"error: trait bounds are not allowed in structure definitions" when attempting to use polymorphism

Editor's note: This question was asked before Rust 1.0 and before certain features were implemented. The code as-is works today.
I'm writing a board game AI in Rust. There are multiple rulesets for the game and I'd like to have the rules logic separated from the board layout (they are currently mixed). In a language like Ruby, I'd have the separate rule sets implement the same interface. In Rust I thought about using a trait and parameterizing the Board with the ruleset I want to use (e.g. Board<Rules1>::new()).
Saving an object that implements this trait in a struct (like Board) is not allowed. I could turn the Rules into an enum, but it looks a bit messy to me because I can't define separate implementations for the members of the enum. Using pattern matching would work, but that splits the functionality along the function axis and not along the struct axis. Is this just something I have to live with or there some way?
The following code is what I'd like to use:
pub struct Rules1;
pub struct Rules2;
trait Rules {
fn move_allowed() -> bool;
}
impl Rules for Rules1 {
fn move_allowed() -> bool {
true
}
}
impl Rules for Rules2 {
fn move_allowed() -> bool {
false
}
}
struct Board<R: Rules> {
rules: R
}
fn main() {}
It produces the following error:
test.rs:20:1: 22:2 error: trait bounds are not allowed in structure definitions
test.rs:20 struct Board<R: Rules> {
test.rs:21 rules: R
test.rs:22 }
error: aborting due to previous error
The code presented in the question works on all recent versions of Rust, trait bounds on structs are now allowed. The original answer is also still valid.
You need to refine that in the trait implementation, not the struct definition.
pub struct Rules1;
pub struct Rules2;
trait Rules {
fn move_allowed(&self) -> bool;
}
impl Rules for Rules1 {
fn move_allowed(&self) -> bool {
true
}
}
impl Rules for Rules2 {
fn move_allowed(&self) -> bool {
false
}
}
struct Board<R> {
rules: R,
}
impl<R: Rules> Board<R> {
fn move_allowed(&self) -> bool {
self.rules.move_allowed()
}
}
fn main() {
let board = Board { rules: Rules2 };
assert!(!board.move_allowed());
}

How can I force a struct's field to always be immutable in Rust?

In Rust, you don't specify mutability inside a struct, but it is inherited from the variable binding. That's great, but is it possible to force a field to be always immutable, even when the root is mutable?
Something like this hypothetical syntax:
struct A {
immut s: Shape, // immutable by design
bla: Bla, // this field inheriting (im)mutability
}
let mut a = make_a();
a.s = x/*...*/; // illegal
This would help to maintain nice semantic restrictions in a program, just like Java's final does (in a very limited way).
Also, we could imagine this kind of struct having some non-owning references to internal immutable data, taking advantage of this immutability...
It's impossible to have immutability of a single field. That was an option in an ancient version of Rust (think before 0.8), but it was dropped because the rules confused a LOT of people. How was it confusing, you might ask? Think about it like this: if a field is declared mutable and struct is declared mutable and the reference used was an immutable reference (&) then the field is _______.
The best, as Lily Ballard noted, is that you can declare your Shape field as private and make a getter method using impl A {...}.
mod inner {
pub struct A {
s: i32, // can't be seen outside of module
pub bla: i32,
}
impl A {
pub fn new() -> Self {
Self { s: 0, bla: 42 }
}
pub fn get_s(&self) -> i32 {
self.s
}
}
}
let mut a = inner::A::new();
a.s = 42; // illegal
println!("{}", a.s); // also illegal
println!("{}", a.get_s()); // could be made to serve as a read-only method
error[E0616]: field `s` of struct `main::inner::A` is private
--> src/main.rs:20:5
|
20 | a.s = 42; // illegal
| ^^^
error[E0616]: field `s` of struct `main::inner::A` is private
--> src/main.rs:21:20
|
21 | println!("{}", a.s); // also illegal
| ^^^
There is proposition that might drop notions of mutability and immutability completely (you can't say a struct never changes). See Niko's explanation for that change.
You can create a struct and only implement the Deref trait for it. Without the DerefMut trait it won't be possible for contained values to be mutated.
https://doc.rust-lang.org/std/ops/trait.Deref.html
This way the compiler will make the member usable as if it's not wrapped in another struct, no need for any written getter method call.
use std::ops::Deref;
/// A container for values that can only be deref'd immutably.
struct Immutable<T> {
value: T,
}
impl<T> Immutable<T> {
pub fn new(value: T) -> Self {
Immutable { value }
}
}
impl<T> Deref for Immutable<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
&self.value
}
}
struct Foo {
bar: Immutable<Vec<u8>>,
baz: usize,
}
impl Foo {
pub fn new(vec: Vec<u8>) -> Self {
Foo {
bar: Immutable::new(vec),
baz: 1337,
}
}
pub fn mutate(&mut self) {
self.bar.push(0); // This will cause a compiler error
}
}
|
| self.bar.push(0);
| ^^^^^^^^ cannot borrow as mutable
|
= help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `runnable::immutable::Immutable<std::vec::Vec<u8>>`
You can't force immutability on a field. How would the struct mutate its own value when necessary?
What you can do is make the field private and expose a getter method to return a reference to it (or to copy/clone the value).
A Solution could be to have a more general approach:
pub struct Immutable<T> {
value : T ,
}
impl<T> Immutable<T> {
pub fn new(value : T) -> Immutable<T> {
Immutable { value : value }
}
pub fn get( &self) -> &T { &self.value }
}
Now it is possible to use the Immutable struct in every case for every other type.
Given this into a module avoids changing the content of the Immutable object. It is still possible to change the variable which holds the Immutable object itself by overwriting it by a new Object but you should notice it by the Immutable::new statement and so you can avoid using it.
In many cases an associated constant achieves the desired behaviour:
struct Foo { blah: Blah }
impl Foo {
const S: Shape = Shape { x: 1, y: 1 };
}
Of course, constants cannot be set on creation, they are set at compile-time. Making the field private as explained in other answers will work if dynamicism is required.
Probably the easiest way to achieve this today is by using the readonly crate from prolific developer David Tolnay (author of serde and many others). From the github documentation:
This crate provides an attribute macro to expose struct fields that are readable and writable from within the same module but readable only outside the module.
#[readonly::make]
pub struct S {
// This field can be read (but not written) by super.
#[readonly]
pub(super) readable: i32,
// This field can be neither read nor written by other modules.
private: i32,
}

In Rust, is there a way to iterate through the values of an enum?

I come from a Java background and I might have something like enum Direction { NORTH, SOUTH, EAST, WEST} and I could do something with each of the values in turn with the enhanced for loop like:
for(Direction dir : Direction.values()) {
//do something with dir
}
I would like to do a similar thing with Rust enums.
You can use the strum crate to easily iterate through the values of an enum.
use strum::IntoEnumIterator; // 0.17.1
use strum_macros::EnumIter; // 0.17.1
#[derive(Debug, EnumIter)]
enum Direction {
NORTH,
SOUTH,
EAST,
WEST,
}
fn main() {
for direction in Direction::iter() {
println!("{:?}", direction);
}
}
Output:
NORTH
SOUTH
EAST
WEST
If the enum is C-like (as in your example), then you can create a static array of each of the variants and return an iterator of references to them:
use self::Direction::*;
use std::slice::Iter;
#[derive(Debug)]
pub enum Direction {
North,
South,
East,
West,
}
impl Direction {
pub fn iterator() -> Iter<'static, Direction> {
static DIRECTIONS: [Direction; 4] = [North, South, East, West];
DIRECTIONS.iter()
}
}
fn main() {
for dir in Direction::iterator() {
println!("{:?}", dir);
}
}
If you make the enum implement Copy, you can use Iterator::copied and return impl Trait to have an iterator of values:
impl Direction {
pub fn iterator() -> impl Iterator<Item = Direction> {
[North, South, East, West].iter().copied()
}
}
See also:
What is the correct way to return an Iterator (or any other trait)?
Why can I return a reference to a local literal but not a variable?
No, there is none. I think that is because enums in Rust are much more powerful than in Java - they are in fact full-fledged algebraic data types. For example, how would you expect to iterate over values of this enum:
enum Option<T> {
None,
Some(T)
}
?
Its second member, Some, is not a static constant - you use it to create values of Option<T>:
let x = Some(1);
let y = Some("abc");
So there is no sane way you can iterate over values of any enum.
Of course, I think, it would be possible to add special support for static enums (i.e. enums with only static items) into the compiler, so it would generate some function which return values of the enum or a static vector with them, but I believe that additional complexity in the compiler is just not worth it.
If you really want this functionality, you could write a custom syntax extension (see this issue). This extension should receive a list of identifiers and output an enum and a static constant vector with these identifiers as a content. A regular macro would also work to some extent, but as far as I remember you cannot transcript macro arguments with multiplicity twice, so you'll have to write enum elements twice manually, which is not convenient.
Also this issue may be of some interest: #5417
And of course you can always write code which returns a list of enum elements by hand.
I implemented basic functionality in the crate plain_enum.
It can be used to declare a C-like enum as follows:
#[macro_use]
extern crate plain_enum;
plain_enum_mod!(module_for_enum, EnumName {
EnumVal1,
EnumVal2,
EnumVal3,
});
And will then allow you to do things like the following:
for value in EnumName::values() {
// do things with value
}
let enummap = EnumName::map_from_fn(|value| {
convert_enum_value_to_mapped_value(value)
})
You can use an associated constant:
impl Direction {
const VALUES: [Self; 4] = [Self::NORTH, Self::SOUTH, Self::EAST, Self::WEST];
}
fn main() {
for direction in Direction::VALUES.iter().copied() {
todo!();
}
}
If you do not want to import a third-party crate, you can make your own macro to do so. Here is how I achieved it (there are probably ways to improve this):
macro_rules! iterable_enum {
($visibility:vis, $name:ident, $($member:tt),*) => {
$visibility enum $name {$($member),*}
impl $name {
fn iterate() -> Vec<$name> {
vec![$($name::$member,)*]
}
}
};
($name:ident, $($member:tt),*) => {
iterable_enum!(, $name, $($member),*)
};
}
And then you can do:
iterable_enum!(pub, EnumName, Value1, Value2, Value3);
fn main() {
for member in EnumName::iterate() {
// ...
}
}
This implementation is limited to simple enums. Consider the following enum, how would you iterate over it?:
enum MoreComplexEnum<T1, T2> {
One(T1),
Two(T2),
Other,
Both(T1, T2),
Error(String),
}
Because of the power of enums in Rust, it can be difficult to implement a perfectly iterable enum, since they are not like the simple enums you have in C or Java.
The enum-iterator crate helps iterating enumerators.
Here's my take on #Ahmed Merez's answer that:
doesn't allocate on the heap
is const
accepts (almost) an actual enum as input (requires vis cause Rust doesn't seem to like an empty visibility parameter with an error of error: repetition matches empty token tree)
including:
derive input
attribute properties
#[macro_export]
macro_rules! count {
() => (0usize);
( $x:tt $($xs:tt)* ) => (1usize + $crate::count!($($xs)*));
}
/// https://stackoverflow.com/a/64678145/10854888
macro_rules! iterable_enum {
($(#[$derives:meta])* $(vis $visibility:vis)? enum $name:ident { $($(#[$nested_meta:meta])* $member:ident),* }) => {
const count_members:usize = $crate::count!($($member)*);
$(#[$derives])*
$($visibility)? enum $name {
$($(#[$nested_meta])* $member),*
}
impl $name {
pub const fn iter() -> [$name; count_members] {
[$($name::$member,)*]
}
}
};
}
fn main() {
iterable_enum! {
#[derive(Debug, serde::Deserialize)]
vis pub(crate) enum X {
#[serde(rename="a")]
A,
B
}
}
for x in X::iter() {
dbg!(x);
}
}
My variation for #koral's answer
doesn't require vis
implements into_iter which returns an actual iterator instead of an array
macro_rules! iterable_enum {(
$(#[$derives:meta])*
$pub:vis enum $name:ident {
$(
$(#[$nested_meta:meta])*
$member:ident,
)*
}) => {
const _MEMBERS_COUNT:usize = iterable_enum!(#count $($member)*);
$(#[$derives])*
$pub enum $name {
$($(#[$nested_meta])* $member),*
}
impl $name {
pub fn into_iter() -> std::array::IntoIter<$name, _MEMBERS_COUNT> {
[$($name::$member,)*].into_iter()
}
}
};
(#count) => (0usize);
(#count $x:tt $($xs:tt)* ) => (1usize + iterable_enum!(#count $($xs)*));
}
fn main() {
iterable_enum! {
#[derive(Debug, serde::Deserialize)]
pub enum X {
#[serde(rename="a")]
A,
B,
}}
X::into_iter().fold(...);
}

Resources