I'm writing a test case for a function which returns a tuple including an enum. I want to verify that the returned tuple matches what I am expecting.
How I do compare tuples composed of enums in Rust? The following fails to compile:
enum Test {
Foo,
Bar
}
assert_eq!((1, Test::Foo), (1, Test::Foo));
(Of course, one of those tuples is generated at runtime by a method.)
Tuples already implement PartialEq and Debug if all their elements do, but you're missing both a Debug and PartialEq implementation for your custom enum:
#[derive(Debug, PartialEq)]
enum Test {
Foo,
Bar
}
With that your expected assert_eq!((1, Test::Foo), (1, Test::Foo)); works.
If you can't implement either trait you can use matches!(<value>, <pattern>):
let got = (1, Test::Foo); // calculate your result
assert!(matches!(got, (1, Test::Foo)))
Note that the second parameter, <pattern>, has to be a pattern and thus must be known at compile time (your call to a function will need to be passed as the first parameter).
Related
I'm using config-rs crate. I want to set an array to a default value in my configuration. I want to use set_default() method from the crate that accepts an argument of type Value<Array> https://docs.rs/config/latest/config/builder/struct.ConfigBuilder.html#method.set_default
I'm new to rust and having a hard time as to how I can quickly create a vector<Value>
let default: Vec<ValueKind>= vec![1,2,3];// Errors
let default: Vec<Value>= vec![1,2,3]; // Errros
If you want to create a Vec<T>, the items have to be of type T. Rust does not perform implicit conversions so you need to write a little more code to make this work. It won't even allow implicit conversions between primitive types (Ex: i32 to i64).
For this, you can create a new Value or ValueKind by using From. I know this can be done because the documentation states that ValueKind implements From<i32>. The same thing also applies to Value, but it is much harder to spot when reading through the documentation.
// Same applies to `Value`.
let default: Vec<ValueKind> = vec![ValueKind::from(1), ValueKind::from(2), ValueKind::from(3)];
To make this easier, you also have a few other options. Into is implemented automatically for all types implimenting From, we can replace the lengthy ValueKind::from(1) with a shorter 1.into() call.
let default: Vec<ValueKind> = vec![1.into(), 2.into(), 3.into()];
If you have a lot of values you could also choose to use an iterator to convert an array of values all in one go.
let default: Vec<ValueKind> = [1, 2, 3, 4, 5, 6, 7, 8, 9]
.into_iter()
.map(|x| ValueKind::from(x))
.collect();
That being said, I am somewhat surprised the crate authors did not give the option to use Vec<i32> as-is (Though I have not checked the documentation on this since I do not know how it is used)*. It is not too difficult to write a generic function which accepts any iterable type like a Vec, array, or a bunch of other things, and turn it into ValueKind or Value as it goes.
/// Takes some iterable value and turns it into a Vec<ValueKind>.
pub fn to_valuekind<A, T>(values: A) -> Vec<ValueKind>
where
A: IntoIterator<Item = T>,
ValueKind: From<T>,
{
values.into_iter().map(|x| ValueKind::from(x)).collect()
}
*Looks like it is a restriction on how set_default functions. It accepts any Into<Value>, but by doing so they can't also implement across IntoIterator since it could theoretically cause a conflict if a type implemented both Into<Value> and IntoIterator<T> where T: Into<Value>.
In the vec! macro implementation there is this rule:
($($x:expr),+ $(,)?) => (
$crate::__rust_force_expr!(<[_]>::into_vec(box [$($x),+]))
);
What exactly is that <[_]> in it?
Breaking down the specific parts of the syntax:
<T>::f is the syntax to explicitly call f associated with a type T. Usually just T::f is enough, but pedantically, :: requires a path, which is why it is used here since [_] is not. The <...> allows any type to be used as a path. See Why do I need angle brackets in <$a> when implementing macro based on type?
[T] is the type denoting a slice of type T.
_ used as a type is a placeholder or "wildcard". It is not a type itself, but serves to indicate that the type should be inferred. See What does it mean to instantiate a Rust generic with an underscore?
Let's go step by step to see how <[_]>::into_vec(box [$($x),+]) produces a Vec:
[$($x),+] expands to an array of input elements: [1, 2, 3]
box ... puts that into a Box. box expressions are nightly-only syntax sugar for Box::new: box 5 is syntax sugar for Box::new(5) (actually it's the other way around: internally Box::new uses box, which is implemented in the compiler)
<[_]>::into_vec(...) calls the to_vec method on a slice containing elements that have an inferred type ([_]). Wrapping the [_] in angled brackets is needed for syntactic reasons to call an method on a slice type. And into_vec is a function that takes a boxed slice and produces a Vec:
pub fn into_vec<A: Allocator>(self: Box<Self, A>) -> Vec<T, A> {
// ...
}
This could be done in many simpler ways, but this code was fine-tuned to improve the performance of vec!. For instance, since the size of the Vec can be known in an advance, into_vec doesn't cause the Vec to be reallocated during its construction.
I'm trying to detect if two square tiles are symmetries of each other, by iterating over the 8 symmetries of the square, applying each of the symmetry transforms to one of the tiles, and comparing the result of that with the other tile.
All of the transforms have the same inputs and outputs. I'd like to loop over them.
I'm using the image crate, which exports the transforms I need, with signatures like this:
pub fn rotate90<I: GenericImageView>(
image: &I
) -> ImageBuffer<I::Pixel, Vec<<I::Pixel as Pixel>::Subpixel>>
where
I::Pixel: 'static,
Note that these include a bound on an associated type; this is making it hard.
This compiles:
for transform in [imageops::rotate90, imageops::rotate180] {}
But this doesn't:
for (transform, orientation) in [(imageops::rotate90, Rot90(id)), (imageops::rotate180, Rot180(id))] {
| ^^^^^^^^^^^^^^^^^^^ expected fn item, found a different fn item
|
= note: expected fn item `for<'r> fn(&'r _) -> ImageBuffer<<_ as GenericImageView>::Pixel, std::vec::Vec<<<_ as GenericImageView>::Pixel as image::Pixel>::Subpixel>> {rotate90::<_>}`
found fn item `for<'r> fn(&'r _) -> ImageBuffer<<_ as GenericImageView>::Pixel, std::vec::Vec<<<_ as GenericImageView>::Pixel as image::Pixel>::Subpixel>> {rotate180::<_>}`
..and unfortunately, the second case is actually what I needed to write.
I'm guessing there's some sort of coercion going on that doesn't work when the type of a fn item is used as a type parameter for another type, e.g. of an anonymous tuple type.
I don't feel too strongly about boxing these things into a trait object (although, well, I did just spend about an hour trying to get around it). At this point, I think I'd just be happy with anything that works. But I'm not even sure how to Box these, because how do I spell the type I'm trying to box up?
I'd appreciate any help at all with this.
As documented in the Reference under Function item types (emphasis added):
When referred to, a function item, or the constructor of a tuple-like struct or enum variant, yields a zero-sized value of its function item type. That type explicitly identifies the function - its name, its type arguments, and its early-bound lifetime arguments (but not its late-bound lifetime arguments, which are only assigned when the function is called) - so the value does not need to contain an actual function pointer, and no indirection is needed when the function is called.
There is no syntax that directly refers to a function item type, but the compiler will display the type as something like fn(u32) -> i32 {fn_name} in error messages.
Because the function item type explicitly identifies the function, the item types of different functions - different items, or the same item with different generics - are distinct, and mixing them will create a type error:
fn foo<T>() { }
let x = &mut foo::<i32>;
*x = foo::<u32>; //~ ERROR mismatched types
However, there is a coercion from function items to function pointers with the same signature, which is triggered not only when a function item is used when a function pointer is directly expected, but also when different function item types with the same signature meet in different arms of the same if or match:
// `foo_ptr_1` has function pointer type `fn()` here
let foo_ptr_1: fn() = foo::<i32>;
// ... and so does `foo_ptr_2` - this type-checks.
let foo_ptr_2 = if want_i32 {
foo::<i32>
} else {
foo::<u32>
};
All function items implement Fn, FnMut, FnOnce, Copy, Clone, Send, and Sync.
In your working example, Rust LUB coerces the function item typed values to function pointers (each element in an array literal is a coercion site). However, in your failing example, Rust is unable to automatically infer that coercion* and so you must provide some help to the compiler. For example, you can:
explicitly set the type of the tuple's first element:
let transformations: &[(fn(_) -> _, _)] = &[
(imageops::rotate90, Rot90(id)),
(imageops::rotate180, Rot180(id)),
];
for (transform, _orientation) in transformations {
transform(buf);
}
or
cast the first function item in the array:
let transformations = &[
(imageops::rotate90 as fn(_) -> _, Rot90(id)),
(imageops::rotate180, Rot180(id)),
];
for (transform, _orientation) in transformations {
transform(buf);
}
* My reading of the Reference leads me to think this failure to infer the coercion may be a bug, and indeed there is an open issue about it.
I found four different ways to create a struct with no data:
struct A{} // empty struct / empty braced struct
struct B(); // empty tuple struct
struct C(()); // unit-valued tuple struct
struct D; // unit struct
(I'm leaving arbitrarily nested tuples that contain only ()s and single-variant enum declarations out of the question, as I understand why those shouldn't be used).
What are the differences between these four declarations? Would I use them for specific purposes, or are they interchangeable?
The book and the reference were surprisingly unhelpful. I did find this accepted RFC (clarified_adt_kinds) which goes into the differences a bit, namely that the unit struct also declares a constant value D and that the tuple structs also declare constructors B() and C(_: ()). However it doesn't offer a design guideline on why to use which.
My guess would be that when I export them with pub, there are differences in which kinds can actually be constructed outside of my module, but I found no conclusive documentation about that.
There are only two functional differences between these four definitions (and a fifth possibility I'll mention in a minute):
Syntax (the most obvious). mcarton's answer goes into more detail.
When the struct is marked pub, whether its constructor (also called struct literal syntax) is usable outside the module it's defined in.
The only one of your examples that is not directly constructible from outside the current module is C. If you try to do this, you will get an error:
mod stuff {
pub struct C(());
}
let _c = stuff::C(()); // error[E0603]: tuple struct `C` is private
This happens because the field is not marked pub; if you declare C as pub struct C(pub ()), the error goes away.
There's another possibility you didn't mention that gives a marginally more descriptive error message: a normal struct, with a zero-sized non-pub member.
mod stuff {
pub struct E {
_dummy: (),
}
}
let _e = stuff::E { _dummy: () }; // error[E0451]: field `_dummy` of struct `main::stuff::E` is private
(Again, you can make the _dummy field available outside of the module by declaring it with pub.)
Since E's constructor is only usable inside the stuff module, stuff has exclusive control over when and how values of E are created. Many structs in the standard library take advantage of this, like Box (to take an obvious example). Zero-sized types work in exactly the same way; in fact, from outside the module it's defined in, the only way you would know that an opaque type is zero-sized is by calling mem::size_of.
See also
What is an idiomatic way to create a zero-sized struct that can't be instantiated outside its crate?
Why define a struct with single private field of unit type?
struct D; // unit struct
This is the usual way for people to write a zero-sized struct.
struct A{} // empty struct / empty braced struct
struct B(); // empty tuple struct
These are just special cases of basic struct and tuple struct which happen to have no parameters. RFC 1506 explains the rational to allow those (they didn't used to):
Permit tuple structs and tuple variants with 0 fields. This restriction is artificial and can be lifted trivially. Macro writers dealing with tuple structs/variants will be happy to get rid of this one special case.
As such, they could easily be generated by macros, but people will rarely write those on their own.
struct C(()); // unit-valued tuple struct
This is another special case of tuple struct. In Rust, () is a type just like any other type, so struct C(()); isn't much different from struct E(u32);. While the type itself isn't very useful, forbidding it would make yet another special case that would need to be handled in macros or generics (struct F<T>(T) can of course be instantiated as F<()>).
Note that there are many other ways to have empty types in Rust. Eg. it is possible to have a function return Result<(), !> to indicate that it doesn't produce a value, and cannot fail. While you might think that returning () in that case would be better, you might have to do that if you implement a trait that dictates you to return Result<T, E> but lets you choose T = () and E = !.
Let's say I have a function with following signature:
fn validate(samples: &[(&str, &[Token])])
Where Token is a custom enum.
I would like to be able to write something along those lines:
let samples = vec![
("a string", &[Token::PLUS, Token::MINUS, Token::PLUS]),
("another string", &[Token::MUL]),
];
validate(&samples);
But code like this yields mismatched types compile error:
error: mismatched types:
expected `&[(&str, &[Token])]`,
found `&collections::vec::Vec<(&str, &[Token; 3])>`
Is it possible to somehow convert the version with static length (&[Token; 3]) to a static slice (&[Token])?
In other words, I would like to be able to specify a static slice in similar way I specify &str, as some kind of "slice literal".
Or I am doing it completely wrong?
EDIT:
In short, I would like to find a syntax that creates an array with static lifetime (or at least a lifetime that is as long as the samples vector's one), and returns slice of it.
Something similar to how strings work, where just typing "a string" gives me reference of type &'static str.
EDIT2:
#Pablo's answer provides pretty good solution to my particular problem, although it is not exactly what I have meant at first.
I guess that the exact thing I have in mind might not be possible, so I will just accept that one for now, unless something more in lines of my initial idea come around.
In short, I would like to find a syntax that creates an array with
static lifetime (or at least a lifetime that is as long as the samples
vector's one), and returns slice of it.
You’d want something like this:
fn sliced(array: [Token; 3]) -> &'static [Token] { unimplemented!() }
So you could use it like this in your example:
let samples: Vec<(&str, &[Token])> = vec![
("a string", sliced([Token::PLUS, Token::MINUS, Token::PLUS])),
// ...
But there are two problems with it. The first and most glaring is that you can’t get a static reference out of a function which doesn’t take in a static reference (in which case it would just return it).
Therefore, since you want a slice at least as long-lived as your array, either you declare a const/static slice (which requires also a const/static declaration of its array), or you declare the array with a let statement first, and then make the slice. (This is what is done at my first alternative, below.) If you create the array inside a use of vec!, together with its slice, the array end its life with vec!, rendering the slice invalid. As an illustration, consider this, which fails due to the same reason:
fn main() {
let slice;
{
let array: [u8; 3] = [1,2,3];
slice = &array;
}
}
The second problem with the sliced function is that its input array has a fixed size, and you’d want to work generically over arrays of arbitrary size. However, this is currently not supported by Rust[1]. You have to work with slices in order to deal with arrays of arbitrary size.
One possibility, then, is to do the following [playpen]:
enum Token {
PLUS,
MINUS,
MUL,
}
fn validate(samples: &[(&str, &[Token])]) {
unimplemented!()
}
fn main() {
let tokens_0 = [Token::PLUS, Token::MINUS, Token::PLUS];
let tokens_1 = [Token::MUL];
let samples: Vec<(&str, &[Token])> = vec![
("a string", &tokens_0),
("another string", &tokens_1),
];
validate(&samples);
}
There are two changes here with respect to your code.
One, this code relies on implicit coercing of an array ([T; N]) as a slice (&[T]) by taking a reference to it. This is demanded by the declaration of samples as being of type Vec<(&str, &[Token])>. This is later satisfied, when using vec!, by passing references to the arrays, and thus eliciting the appropriate coercions.
Two, it creates the arrays of Token before using the vec! macro, which guarantees that they’ll live enough to be referenced from within the Vec it creates, keeping these references valid after vec! is done. This is necessary after resolving the previous type mismatch.
Addendum:
Or, for convenience, you may prefer to use a Vec instead of slices. Consider the following alternative [playpen]:
enum Token {
PLUS,
MINUS,
MUL,
}
fn validate<T>(samples: &[(&str, T)]) where
T: AsRef<[Token]>
{
let _: &[Token] = samples[0].1.as_ref();
unimplemented!()
}
fn main() {
let samples: Vec<(&str, Vec<Token>)> = vec![
("a string", vec![Token::PLUS, Token::MINUS, Token::PLUS]),
("another string", vec![Token::MUL]),
];
validate(&samples);
}
In this case, the AsRef<[Token]> bound on the second element of the tuple accepts any type from which you may take a &[Token], offering an as_ref() method which returns the expected reference. Vec<Token> is an example of such kind of type.
[1] “Rust does not currently support generics over the size of an array type.” [source]
Note: this answer is not valid in this particular situation because the arrays pointed by the nested slices cannot outlive the vector because they are only allocated for the duration of their respective expressions, therefore slices to them can't be stored in the vector.
The proper way would be to either hoist slices to the upper level and put them before the vector, or to use an entirely different structure, e.g. nested Vecs. Examples of all of these are provided in Pablo's answer.
You need to do this:
let samples = vec![
("a string", &[Token::PLUS, Token::MINUS, Token::PLUS] as &[_]),
("another string", &[Token::MUL] as &[_]),
];
validate(&samples);
Rust automatically converts references to arrays (&[T; n]) to slices (&[T]) when the target type is known, but in this case type inference doesn't work well because of the necessary deref coercion, so the compiler can't deduce that you need a slice instead of array and can't insert the appropriate conversion, thus you need to specify the type explicitly.
Also, there is no such thing as "static slice". The closest entity would be a slice with static lifetime, &'static [T], but as far as I remember, this is not the case of it.