How do I define a nested HashMap with an unknown nesting level? - rust

I want to traverse through a file tree and save the file and directory names in a nested HashMap. How do I define such a nested HashMap?
Something like this doesn't compile:
type NestedHashMap = HashMap<String, HashMap>;
It throws:
error[E0107]: wrong number of type arguments: expected at least 2, found 0
--> src/lib.rs:3:38
|
3 | type NestedHashMap = HashMap<String, HashMap>;
| ^^^^^^^ expected at least 2 type arguments

Rust is a statically typed language, so you need to tell the compiler in advance the exact type of the elements in your HashMap. Since each entry can be either a file name or another HashMap, the easiest solution is to use an enum type:
enum Entry {
File(String),
Directory(HashMap<String, Entry>),
}
This allows you to model arbitrary nesting.

Related

Iterate over a collection of function items with generic bounds of associated types

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.

Convert Vec<Cow<'_, [u8]> to &str

A lib (quick_xml) function (attributes()) returns a value with a type Vec<Cow<'_, [u8]>.
The exact line is e.attributes().map(|a| a.unwrap().value).collect::<Vec<_>>() and the printed value = [[116, 101, 115, 116]].
How can I convert it to a string ("test" in this case) so I can use it later?
I assume you are referencing this example. In the future, please give us the whole source code – this makes answering the question much easier.
Understanding the code
Let's take it one step at a time:
e.attributes().map(|a| a.unwrap().value).collect::<Vec<_>>()
^
e is a BytesStart struct, so it represents an opening XML tag, in your case <tag1 att1 = "test">.
e.attributes().map(|a| a.unwrap().value).collect::<Vec<_>>()
^^^^^^^^^^^^
This is the attributes method of BytesStart. It returns the Attributes struct which represents the set of attributes that one tag has. In your case, that is only one attribute: It has the name attr1 and the value test.
Attributes is an iterator, this means you can iterate over the contained Attributes (note that Attributes contains multiple Attributes – these are not the same type!). If you want to learn more about iterators, you may want to read the chapter about it in the Rust book.
e.attributes().map(|a| a.unwrap().value).collect::<Vec<_>>()
^^^^^^^^^^^^^^^^^^^^^^^^^
Here, we call the map method of the Iterator struct. It lets us transform one iterator (in this case the Attributes struct) into another iterator by transforming each value of the iterator. We call it with a closure (if you don't know what this is, the Rust book also has a chapter about this) that takes one value of the original iterator and returns the transformed value of the new iterator. Now, let's look at that iterator:
|a| a.unwrap().value
^^^
This iterator takes one argument named a, which is, as I said above, the type that the original iterator contains. I said above that Attributes contains multiple Attributes – while this is true, it is not the full picture, the iterator iterates over Result<Attribute>, and that is the type of a.
|a| a.unwrap().value
^^^^^^^^^^
When operating normally, a will always be an instance of Result::Ok containing your Attribute, but if your XML is somehow invalid, amay also be a Result::Err to indicate some kind of parse error. We don't want to care about error handling here, so we just call the unwrap method of Result that returns the contained Argument and panics if there was an error.
|a| a.unwrap().value
^^^^^
The Attribute struct contains two values: key and [value]. We are only interested in value, so let's select it. The value field is of type Cow<'a, [u8]>. Cow is a smart pointer with some interesting properties that aren't really relevant here. If you want to learn more about it, you may be interested in the documentation of Cow (although his may be a bit too complicated for a Rust newbie). For the remainder of this explanation, I will just pretend value is of type &[u8] (a reference to a u8 slice).
We now have determined that the closure returns a &[u8], therefore the iterator returned by map iterates over &[u8].
e.attributes().map(|a| a.unwrap().value).collect::<Vec<_>>()
^^^^^^^^^^^^^^^^^^^
Now we call the collect method of Iterator which transforms the iterator into a collection. The type of the collection is given as a generic parameter an is Vec<_>. The underscore tells rustc to try to find out the correct type by context or output an error if this is not possible. The only type possible here is &[u8], therefore, this method returns a Vec<&[u8]>.
The solution
You can use the unescape_and_decode_value method of Attribute. This transforms the Attribute value to a String and also unescapes escape sequences if the attribute contains them.
e.attributes().map(|a| a.unwrap().unescape_and_decode_value(&reader).unwrap()).collect::<Vec<_>>()
Note that this still returns Vector<String>, not String. The vector contains the values of all attributes assigned to this element – in this case, it's just the attribute value "Test".
You can use std::str::from_utf8 for fallible conversion of &[u8] to &str:
use std::borrow::Cow;
fn main() {
let s = "test";
let v = s.as_bytes();
let c = Cow::Borrowed(v);
println!("{}", std::str::from_utf8(&*c).unwrap());
}
The crucial part is the deref and reborrow of Cow since from_utf8 takes &[u8] instead of Cow. Cow implements Deref for T, in this case T is [u8], thus you can get a &[u8] via &*.
Playground Link
In your concrete example you should be able to get a Vec<&str> by:
e.attributes().map(|a| std::str::from_utf8(&*a.unwrap().value).unwrap()).collect::<Vec<_>>()

Why can't the compiler automatically infer the type returned by Iterator::collect? [duplicate]

I want to get a length of a string which I've split:
fn fn1(my_string: String) -> bool {
let mut segments = my_string.split(".");
segments.collect().len() == 55
}
error[E0282]: type annotations needed
--> src/lib.rs:3:14
|
3 | segments.collect().len() == 55
| ^^^^^^^ cannot infer type for type parameter `B` declared on the associated function `collect`
|
= note: type must be known at this point
Previous compiler versions report the error:
error[E0619]: the type of this value must be known in this context
--> src/main.rs:3:5
|
3 | segments.collect().len() == 55
| ^^^^^^^^^^^^^^^^^^^^^^^^
How can I fix this error?
On an iterator, the collect method can produce many types of collections:
fn collect<B>(self) -> B
where
B: FromIterator<Self::Item>,
Types that implement FromIterator include Vec, String and many more. Because there are so many possibilities, something needs to constrain the result type. You can specify the type with something like .collect::<Vec<_>>() or let something: Vec<_> = some_iter.collect().
Until the type is known, you cannot call the method len() because it's impossible to know if an unknown type has a specific method.
If you’re purely wanting to find out how many items there are in an iterator, use Iterator.count(); creating a vector for the purpose is rather inefficient.

Function signature for generic numbers

I am trying to make a few generic functions that work on numbers, but I'm struggling with the function signatures.
Perhaps I am attacking the problem from the wrong angle, but here is where I got on my own so far. I am not hellbent on making this work this way; so if I am attacking the problem (of creating a small lib of generally useful math functions) from the wrong angle, then by all means educate me.
Let's say I want a function, add that adds up two numbers:
use std::ops::Add;
fn add(a: Add, b: Add) -> Add::Output {
a + b
}
This won't compile. Here is a playground though: https://play.integer32.com/?version=stable&mode=debug&edition=2015&gist=4589325b5c8d1f1b19440424878caa98
I get essentially two errors. The first:
error[E0393]: the type parameter `RHS` must be explicitly specified
--> src/main.rs:8:11
|
8 | fn add(a: Add, b: Add) -> Add::Output {
| ^^^ missing reference to `RHS`
|
= note: because of the default `Self` reference, type parameters must be specified on object types
I have read the chapter on advanced traits in the Rust book, so i "sort-of/kind-of" understand the RHS message, but they attack the problem of adding the Add trait to your particular data structure (a Point in the example); but never show a function signature of a function that takes anything that can be added up. So I am a little lost.
The second error:
error[E0223]: ambiguous associated type
--> src/main.rs:8:27
|
8 | fn add(a: Add, b: Add) -> Add::Output {
| ^^^^^^^^^^^ ambiguous associated type
|
= note: specify the type using the syntax `<Type as std::ops::Add>::Output`
This goes away if I write <i32 as Add>::Output, but that is not what I want. I specifically want the function to work on anything that can be added up (assuming both a and b to be the same type).
You are conflating traits and types.
Add is a trait. A trait can be implemented for a type or a class of types, but it is not a type itself.
Function arguments need to be declared with a type, not a trait. This is the main problem with your prototype – Add is not a type, so you can't use it as the type of a variable or a function argument.
Rust allows you to declare generic types, essentially type variables. You can then place trait bounds on the generic types, which require that whatever type is substituted for the generic type must implement some trait. Your example using a generic type parameter T looks like this:
fn add<T: Add>(a: T, b: T) -> T::Output
This prototype requires that a and b both have the same type T, and that T implements the Add trait.

"Expected reference, found struct Rc" when cloning and returning an Rc

I have a piece of code like this:
use std::cell::RefCell;
use std::rc::Rc;
struct A(bool);
impl A {
fn get_ref(&self) -> &Rc<RefCell<bool>> {
&Rc::new(RefCell::new(self.0))
}
fn copy_ref(&self) -> &Rc<RefCell<bool>> {
Rc::clone(self.get_ref())
}
}
fn main() {
let a = A(true);
a.copy_ref();
}
and I received warning complaining about the Rc::clone function not getting a reference:
error[E0308]: mismatched types
--> src/main.rs:12:9
|
12 | Rc::clone(self.get_ref())
| ^^^^^^^^^^^^^^^^^^^^^^^^^ expected reference, found struct `std::rc::Rc`
|
= note: expected type `&std::rc::Rc<std::cell::RefCell<bool>>`
found type `std::rc::Rc<std::cell::RefCell<bool>>`
I have been working on this all night but I cannot get it to work. The method get_ref is already typed as returning &Rc<RefCell<bool>>, but why would the compiler give the error?
The error is not talking about the argument you put into Arc::clone(), but the whole expression Rc::clone(...) which has a different type (Rc<...>) than the return type of your function (&Rc<...>).
If you were passing a wrong argument to Rc::clone, it would like look this:
--> src/main.rs:13:19
|
13 | Rc::clone(false)
| ^^^^^ expected reference, found bool
|
= note: expected type `&std::rc::Rc<_>`
found type `bool`
So the naive way to fix the type error is to write &Rc::clone(...) instead. Then the last expression of your function has the same type as your function's declared return type. But as you will notice, you will get other errors afterwards.
Let's take a step back to see that your approach is flawed here. For the most important point, please see "Is there any way to return a reference to a variable created in a function?". Spoiler: you really don't want to. So constructs like your get_ref() just don't make sense, as you return a reference to a variable you create inside your function (a variable of type Rc).
In your case the direct solution is probably pretty simple: just remove the reference. Rc<T> is already a pointer/reference type, so there is no need (in general) to have a reference to it.
However, since you are using Rc, you are probably interested in reference counting. So in that case, you probably shouldn't create a new Rc every time the function is called. Otherwise you could end up with a bunch of Rcs with reference count 1, which is not really the point. So instead, your type A should already store an Rc<RefCell<bool>>.
But all I'm doing here is guessing what you actually want to do which is not clear from your question. Maybe you can ask a different question, or add the information to this question, or explain this in the comments.

Resources