how to implement an iterator that delegates to HashMap::values() - rust

I am trying to implement a datastructure to store 'registers' in groups. There is a master list which I am considering the owner of the register data.
I have the following:
use std::collections::hash_map::HashMap;
pub struct Register {
pub name: String,
pub address: u16,
}
// map with references to 'master' list of registers
type RegisterMap<'a> = HashMap<String, &'a Register>;
struct RegisterGroup<'a> {
start_address: u16,
registers: RegisterMap<'a>,
}
struct RegisterGroupIter<'a> {
inner: std::collections::hash_map::Values<'a,String,&'a Register>,
}
impl<'a> Iterator for RegisterGroupIter<'a> {
type Item = &'a Register;
fn next(&mut self) -> Option<&'a Register> {
self.inner.next()
}
}
impl<'a> RegisterGroup<'a> {
// return iterator over references to Register
fn registers(&self) -> RegisterGroupIter {
RegisterGroupIter {
inner: self.registers.values(),
}
}
}
Is this reasonable/idiomatic? If so what is the correct setup for the item type wrt references/lifetimes etc? Otherwise what should I be doing instead?
Compiling playground v0.0.1 (/playground)
error[E0308]: mismatched types
--> src/main.rs:22:9
|
21 | fn next(&mut self) -> Option<&'a Register> {
| -------------------- expected `std::option::Option<&'a Register>` because of return type
22 | self.inner.next()
| ^^^^^^^^^^^^^^^^^ expected struct `Register`, found `&Register`
|
= note: expected enum `std::option::Option<&'a Register>`
found enum `std::option::Option<&&'a Register>`

Since the values iterator of a HashMap yields references to the values type, and the values type is a reference itself in this case, the iterator items are of type &&Register. This means you need to dereference the items before returning them in your iterator. The easiest way to dereference inside an option is to use the copied() method:
impl<'a> Iterator for RegisterGroupIter<'a> {
type Item = &'a Register;
fn next(&mut self) -> Option<&'a Register> {
self.inner.next().copied()
}
}
I'm not sure why you store the name both as the hash map key and inside the Register struct. I'd usually try to normalize the data and only sore the name as the map keys.
You don't really need to implement your own iterator type here. Directly returning the values iterator of the hash map will work just fine:
impl RegisterGroup<'_> {
fn registers(&self) -> impl Iterator<Item = &Register> {
self.registers.values().copied()
}
}

Related

Iterator implementation on custom struct - problems

Im trying print out a encoded hex string of some basic data ive inserted as a lesson how to serialize/deserialize data. However todo this im having to implement an iterator for a Struct that has a single element of type Vec. Im getting the below error and don't understand why, I realize my code is incomplete in the next() implementation. I'm fairly new to iterators, any help would be appreciated.
Error:
error[E0599]: no method named `iter_mut` found for struct `MyData` in the current scope
--> src/main.rs:110:22
|
21 | pub(crate) struct MyData {
| ------------------------ method `iter_mut` not found for this struct
...
110 | for v in my_data.iter_mut() {
|
#[derive(Serialize, Deserialize, Debug)]
#[serde(transparent)]
struct MyHex {
#[serde(with = "hex::serde")]
hex: Vec<u8>,
}
#[derive(Serialize, Deserialize, Debug)]
pub(crate) struct MyData {
data: Vec<MyHex>,
}
impl Iterator for MyData {
type Item = usize;
fn next(&mut self) -> Option<Self::Item>;
}
fn main() -> Result<()> {
let data = "
{
\"data\": [\"bbac4013c1ca3482155b584d35dac185\",
\"a08898e81f1ddb6612aa12641b856aa9\",
\"bbac4013c1ca3482155b584d35dac185\"
]
}";
let my_data: MyData = serde_json::from_str(data)?;
for v in my_data.iter_mut() {
println!("{:?}", hex::encode(v));
}
return Ok(());
}
You question is a little fuzzy but let's try to see what we can do:
Iterating over inner field
If you want to do something with the data byte by byte, you can iterate over data itself:
for hex in my_data.data { ... }
Iterating without exposing inner fields
You can also return iterator over data without exposing the field to the rest of the code:
impl MyData {
fn iter_data(&self) -> impl Iterator<Item = &MyHex> {
self.data.iter()
}
}
...
for hex in my_data.iter_data() { ... }
Implementing IntoIterator
If you want MyData work as an iterator, you can implement IntoIterator trait for it:
impl<'a> IntoIterator for &'a MyData {
type Item = &'a MyHex;
type IntoIter = std::slice::Iter<'a, MyHex>;
fn into_iter(self) -> Self::IntoIter {
self.data.iter()
}
}
...
for v in &my_data {
println!("{:?}", v);
}
Playground
Implementing Iterator for MyData
To implement Iterator you need to provide the next method, which on every call will return the next item in the iterator while there are any items left. To do so you would add a field to you MyData that keeps track of the last item that was return, and increment that pointer on every call of next().
But from your code I guess this is not something you actually want. Go rather with one of the previous options.

How to solve "no method named `foo` found for mutable reference `&mut Bar<X>` in the current scope"

I'm working on a generic data structure that will hold pointers to some structs, and using a Handle that would normally be held by the struct, will call back into the structure to remove the pointer when the Handle is dropped. I'm unable to come up with a solution that will allow the call from the handle back into the node. I've tried a few different permutations of trait bound narrowing and associated type hackery with no success... I'm feeling like the issue is related to some kind of infinite associated type recursion (something like https://github.com/rust-lang/rust/issues/23122), but just not sure. The error is
error[E0599]: no method named `remove` found for mutable reference `&mut Node<X>` in the current scope
--> src/lib.rs:50:15
|
50 | m.remove(self.index); // <<----- ???
| ^^^^^^ method not found in `&mut Node<X>`
|
= note: the method `remove` exists but the following trait bounds were not satisfied:
`<X as FooTrait>::T = X`
pub struct Node<T: FooTrait> {
items: Vec<*mut T>,
}
impl <T: FooTrait<T=T>> Node<T> {
pub fn new() ->Node<T> {
Node {
items: Default::default(),
}
}
pub fn insert(&mut self, item: &mut T) {
let handle = Handle::new(self,0);
item.set_handle(handle);
self.items.push(item);
}
pub fn remove(&mut self, index: u16) {
self.items.swap_remove(index as usize);
}
}
pub struct Handle<X:FooTrait> {
node: *mut Node<X>,
index: u16,
}
impl <T:FooTrait> Handle<T> {
fn new(node: &mut Node<T>, i: u16) -> Handle<T> {
Handle {
node: node,
index: i
}
}
}
impl <X:FooTrait> Drop for Handle<X> {
fn drop(&mut self) {
unsafe {
let m = self.node.as_mut().unwrap();
m.remove(self.index); // <<----- ???
}
}
}
pub trait FooTrait {
type T : FooTrait;
fn set_handle(&mut self, h: Handle<Self::T>);
}
Yes this is caused by recursive constraints.
remove(&mut self, index: u16) is only defined for types that contain to T: FooTrait<T=T>, causing the FooTrait::T to reference itself, because T is that FooTrait<T=T> type.

Why does SmallVec have different behaviour when storing types with lifetimes compared to Vec?

I've got three examples, one using Vec one using SmallVec, and one with my own implementation of SmallVec. The ones using Vec and my own SmallVec compile but the one using the real SmallVec does not.
Working example using Vec
use std::borrow::Cow;
use std::collections::HashMap;
pub trait MyTrait {
fn get_by_id(&self, id: usize) -> &ItemTraitReturns;
}
/// IMPORTANT PART IS HERE: `Vec<Cow<'a, str>>`
pub struct ItemTraitReturns<'a>(Vec<Cow<'a, str>>);
/// this implementation only takes items with static lifetime (but other implementations also might have different lifetimes)
pub struct MyTraitStruct {
map: HashMap<usize, ItemTraitReturns<'static>>,
}
impl MyTrait for MyTraitStruct {
fn get_by_id(&self, id: usize) -> &ItemTraitReturns {
let temp: &ItemTraitReturns<'static> = self.map.get(&id).unwrap();
// Works as expected: I expect that I can return `&ItemTraitReturns<'_>`
// when I have `&ItemTraitReturns<'static>` (since 'static outlives everything).
temp
// Will return `&ItemTraitReturns<'_>`
}
}
Failing example with SmallVec
Uses SmallVec instead of Vec with no other changes.
use smallvec::SmallVec;
use std::borrow::Cow;
use std::collections::HashMap;
pub trait MyTrait {
fn get_by_id(&self, id: usize) -> &ItemTraitReturns;
}
/// IMPORTANT PART IS HERE: Uses SmallVec instead of Vec
pub struct ItemTraitReturns<'a>(SmallVec<[Cow<'a, str>; 2]>);
/// this implementation only takes items with static lifetime (but other implementations also might have different lifetimes)
pub struct MyTraitStruct {
map: HashMap<usize, ItemTraitReturns<'static>>,
}
impl MyTrait for MyTraitStruct {
fn get_by_id(&self, id: usize) -> &ItemTraitReturns {
let temp: &ItemTraitReturns<'static> = self.map.get(&id).unwrap();
temp
}
}
error[E0308]: mismatched types
--> src/lib.rs:23:9
|
23 | temp
| ^^^^ lifetime mismatch
|
= note: expected type `&ItemTraitReturns<'_>`
found type `&ItemTraitReturns<'static>`
note: the anonymous lifetime #1 defined on the method body at 18:5...
--> src/lib.rs:18:5
|
18 | / fn get_by_id(&self, id: usize) -> &ItemTraitReturns {
19 | | let temp: &ItemTraitReturns<'static> = self.map.get(&id).unwrap();
20 | | // Error:
21 | | // = note: expected type `&demo2::ItemTraitReturns<'_>`
22 | | // found type `&demo2::ItemTraitReturns<'static>`
23 | | temp
24 | | }
| |_____^
= note: ...does not necessarily outlive the static lifetime
Working example with my own SmallVec
When I implement my own (very naive) SmallVec<[T; 2]> (called NaiveSmallVec2<T>) the code also compiles... Very strange!
use std::borrow::Cow;
use std::collections::HashMap;
/// This is a very naive implementation of a SmallVec<[T; 2]>
pub struct NaiveSmallVec2<T> {
item1: Option<T>,
item2: Option<T>,
more: Vec<T>,
}
impl<T> NaiveSmallVec2<T> {
pub fn push(&mut self, item: T) {
if self.item1.is_none() {
self.item1 = Some(item);
} else if self.item2.is_none() {
self.item2 = Some(item);
} else {
self.more.push(item);
}
}
pub fn element_by_index(&self, index: usize) -> Option<&T> {
match index {
0 => self.item1.as_ref(),
1 => self.item2.as_ref(),
_ => self.more.get(index - 2),
}
}
}
pub trait MyTrait {
fn get_by_id(&self, id: usize) -> &ItemTraitReturns;
}
/// IMPORTANT PART IS HERE: Uses NaiveSmallVec2
pub struct ItemTraitReturns<'a>(NaiveSmallVec2<Cow<'a, str>>);
/// only takes items with static lifetime
pub struct MyTraitStruct {
map: HashMap<usize, ItemTraitReturns<'static>>,
}
impl MyTrait for MyTraitStruct {
fn get_by_id(&self, id: usize) -> &ItemTraitReturns {
let temp: &ItemTraitReturns<'static> = self.map.get(&id).unwrap();
// astonishingly this works!
temp
}
}
I expect the SmallVec version to compile like the Vec version does. I don't understand why in some cases (in the case of Vec) &ItemTraitReturns<'static> can be converted to &ItemTraitReturns<'_> and in some cases (SmallVec) it's not possible (I don't see the influence of Vec / SmallVec).
I don't want to change lifetimes of this trait:
pub trait MyTrait {
fn get_by_id(&self, id: usize) -> &ItemTraitReturns;
}
... since when using the trait I don't care about lifetimes (this should be an implementation detail) ... but still would like to use SmallVec.
This difference appears to be caused by a difference in variance between Vec and SmallVec. While Vec<T> is covariant in T, SmallVec appears to be invariant. As a result, SmallVec<[&'a T; 1]> can't be converted to SmallVec<[&'b T; 1]> even when lifetime 'a outlives 'b and the conversion should be safe. Here is a minimal example triggering the compiler error:
fn foo<'a, T>(x: SmallVec<[&'static T; 1]>) -> SmallVec<[&'a T; 1]> {
x // Compiler error here: lifetime mismatch
}
fn bar<'a, T>(x: Vec<&'static T>) -> Vec<&'a T> {
x // Compiles fine
}
This appears to be a shortcoming of SmallVec. Variance is automatically determined by the compiler, and it is sometimes cumbersome to convince the compiler that it is safe to assume that a type is covariant.
There is an open Github issue for this problem.
Unfortunately, I don't know a way of figuring out the variance of a type based on its public interface. Variance is not included in the documentation, and depends on the private implementation details of a type. You can read more on variance in the language reference or in the Nomicon.

Why must the associated type be specified in a collection of trait object references?

Here is an offending example (Playground):
// Some traits
trait Behaviour {
type Sub: SubBehaviour;
}
trait SubBehaviour {}
// Some implementations of these traits
struct A;
impl Behaviour for A {
type Sub = B;
}
struct B;
impl SubBehaviour for B {}
// Struct that holds a collection of these traits.
struct Example<'a> {
behaviours: Vec<&'a dyn Behaviour>,
}
impl<'a> Example<'a> {
fn add_behaviour<T: Behaviour>(&mut self, b: &'a T) {
self.behaviours.push(b);
}
}
fn main() {
let b = A;
let mut e = Example {
behaviours: Vec::new(),
};
e.add_behaviour(&b);
}
I get:
error[E0191]: the value of the associated type `Sub` (from trait `Behaviour`) must be specified
--> src/main.rs:17:29
|
3 | type Sub: SubBehaviour;
| ----------------------- `Sub` defined here
...
17 | behaviours: Vec<&'a dyn Behaviour>,
| ^^^^^^^^^ help: specify the associated type: `Behaviour<Sub = Type>`
Why must this type must be specified, particularly in this case where we are only storing a reference to the object? How can I get this code to work?
All types must be statically known at compile time. If Rust would allow different associated types for elements of a Vec, type information could depend on indices which are only known at runtime.
I find it helpful to consider a smaller example:
trait Behaviour {
type T;
fn make_t(&self) -> T;
}
fn foo(my_vec: Vec<&dyn Behaviour>, index: usize) {
let t = my_vec[index].make_t(); //Type of t depends on index
}
You were on the right track to fixing this though. I assume you introduced the SubBehaviour trait because you realized you need to put restrictions of what T can be. The thing is, in that case you don't need an associated type anymore.
trait SubBehaviour {}
trait Behaviour {
fn make_t(&self) -> Box<dyn SubBehaviour>;
fn ref_t(&self) -> &dyn SubBehaviour; // also fine
}
fn some_function(my_vec: Vec<&dyn Behaviour>, index: usize) {
let t1 = my_vec[index].make_t();
}
The only limitation is that in your definition of Behaviour you can not do anything which would depend on the size of T, (like allocating it on the stack or moving it) since the size of T can not be specified by the SubBehaviour trait.
You need to specify the associated type of the trait (i.e. Behavior<Sub = ???>).
When adding the associated type at all places, it compiles:
struct Example<'a, S: SubBehaviour + 'a> {
behaviours: Vec<&'a Behaviour<Sub = S>>,
}
impl<'a, S: SubBehaviour> Example<'a, S> {
fn add_behaviour<T: Behaviour<Sub = S>>(&mut self, b: &'a T) {
self.behaviours.push(b);
}
}
See this in action on the Playground
So the answer to your first question is covered by Tim's answer and is correct, you might not want your Example to be generic. In that case, you need to use some sort of type erasure:
// Some traits
trait Behaviour {
type Sub: SubBehaviour;
}
trait SubBehaviour {}
// Some implementations of these traits
struct A;
impl Behaviour for A {
type Sub = B;
}
struct B;
impl SubBehaviour for B {}
struct AnyBehaviour {
closure: Box<Fn()>,
}
impl AnyBehaviour {
fn new<U: SubBehaviour, T: Behaviour<Sub = U>>(b: &T) -> Self {
let closure = || {
//let sub = T::Sub::new();
println!("Can use T here");
};
AnyBehaviour {
closure: Box::new(closure),
}
}
}
// Struct that holds a collection of these traits.
struct Example {
behaviours: Vec<AnyBehaviour>,
}
impl Example {
fn add_behaviour<U: SubBehaviour, T: Behaviour<Sub = U>>(&mut self, b: &T) {
self.behaviours.push(AnyBehaviour::new(b));
}
}
fn main() {
let b = A;
let mut e = Example {
behaviours: Vec::new(),
};
e.add_behaviour(&b);
}
Within the closure, you have access to all the types needed call the traits functions with whatever subtype needed.
Why this happens, is mostly because you actually need a definition of the associated type in order for the trait to be "complete" so the compiler can work with it. Tim's answer answers that by the definition to be higher up in the chain (outside of Example) instead of inside.

Storing types in a HashMap to dynamically instantiate them

I am trying to store structs in a HashMap keyed by string so that I can later create new objects by string. Think of a REST API where clients can get the server to instantiate a specific object by supplying a name.
use std::collections::HashMap;
struct MyStruct;
impl MyStruct {
pub fn new() -> Self {
Self {}
}
}
struct MyOtherStruct;
impl MyOtherStruct {
pub fn new() -> Self {
Self {}
}
}
fn main() {
let mut h = HashMap::new();
h.insert("MyStruct", MyStruct);
h.insert("MyOtherStruct", MyOtherStruct);
// This is pseudo-code
let obj = h.get("MyStruct").unwrap()::new();
}
As I expected, this doesn't work due to syntax errors:
error: expected one of `.`, `;`, `?`, or an operator, found `::`
--> src/main.rs:25:41
|
25 | let obj = h.get("MyStruct").unwrap()::new();
| ^^ expected one of `.`, `;`, `?`, or an operator here
My second attempt was to store a reference to the new method of each struct instead of the types themselves.
use std::collections::HashMap;
struct MyStruct;
impl MyStruct {
pub fn new() -> Self {
Self {}
}
}
struct MyOtherStruct;
impl MyOtherStruct {
pub fn new() -> Self {
Self {}
}
}
fn main() {
let mut h = HashMap::new();
h.insert("MyStruct", &MyStruct::new);
h.insert("MyOtherStruct", &MyOtherStruct::new);
let obj = h.get("MyStruct").unwrap()();
}
This fails because the fn items have different types and can't be stored in the same HashMap:
error[E0308]: mismatched types
--> src/main.rs:22:31
|
22 | h.insert("MyOtherStruct", &MyOtherStruct::new);
| ^^^^^^^^^^^^^^^^^^^ expected fn item, found a different fn item
|
= note: expected type `&fn() -> MyStruct {MyStruct::new}`
found type `&fn() -> MyOtherStruct {MyOtherStruct::new}`
Since I'm pretty new to Rust, I'm out of ideas. How can I solve this problem?
This is ultimately fundamentally impossible. In Rust, local variables are stored on the stack, which means that they have to have a fixed size, known at compile time. Your construction requires the size of the value on the stack to be determined at runtime.
The closest alternative is to move to trait objects, which introduce a layer of indirection:
use std::collections::HashMap;
trait NewThing {
fn new(&self) -> Box<Thing>;
}
trait Thing {}
struct MyStruct;
impl NewThing for MyStruct {
fn new(&self) -> Box<Thing> {
Box::new(Self {})
}
}
impl Thing for MyStruct {}
struct MyOtherStruct;
impl NewThing for MyOtherStruct {
fn new(&self) -> Box<Thing> {
Box::new(Self {})
}
}
impl Thing for MyOtherStruct {}
fn main() {
let mut h: HashMap<_, Box<NewThing>> = HashMap::new();
h.insert("MyStruct", Box::new(MyStruct));
h.insert("MyOtherStruct", Box::new(MyOtherStruct));
let obj = h["MyStruct"].new();
}
You will find this pattern out in the world, such as in hyper's NewService.
what is [the value of &self of method new] when calling h["MyStruct"].new()
It's an instance of MyStruct or MyOtherStruct. The only reason that the same type can implement both traits is because there's no real unique state for the "factory" and the "instance". In more complicated implementations, these would be two different types.
Using the same type is common for such cases as sharing a reference-counted value.
See also:
Is it possible to have a constructor function in a trait?
Here is a more complex example of #Shepmaster's solution, using different types for Factories and the objects themselves:
use std::collections::HashMap;
trait NewThing {
fn new(&self) -> Box<Thing>;
}
trait Thing {
fn execute(&mut self);
}
// MyStruct
struct MyStructFactory;
impl NewThing for MyStructFactory {
fn new(&self) -> Box<Thing> {
Box::new(MyStruct {test: 12, name: "Test".into()})
}
}
struct MyStruct {
test: i32,
name: String
}
impl Thing for MyStruct {
fn execute(&mut self) {
self.test+=1;
println!("MyStruct {} {}", self.test, self.name);
}
}
// MyOtherStruct
struct MyOtherStructFactory;
impl NewThing for MyOtherStructFactory {
fn new(&self) -> Box<Thing> {
Box::new(MyOtherStruct {my_member: 1})
}
}
struct MyOtherStruct {
my_member: u32
}
impl Thing for MyOtherStruct {
fn execute(&mut self) { println!("MyOtherStruct.my_member: {}", self.my_member); }
}
fn main() {
let mut h: HashMap<_, Box<NewThing>> = HashMap::new();
h.insert("MyStruct", Box::new(MyStructFactory));
h.insert("MyOtherStruct", Box::new(MyOtherStructFactory));
h["MyStruct"].new().execute();
h["MyOtherStruct"].new().execute();
}
You could use std::any::Any to erase the type of the entry. They use Any::downcast<T> to check if the entry at the location matches your type, and get a Ok(Box<T>)

Resources