Rust function to return generic trait - rust

I have two structs implementing same trait. I need a single fuction that returs object of any of these structure.
trait
pub trait DbfFile{
fn new(fields: HashMap<String, FieldValue>) -> Self;
}
The structures are
pub struct InsertableAttachable {
pub f1: String,
pub f2: String,
pub f3: String,
pub f4: i8,
}
impl DbfFile for InsertableAttachable{
fn new(fields: HashMap<String, FieldValue, RandomState>) -> Self {
InsertableAttachable {
// fields
}
}
}
// Converting this to generic
impl InsertableAttachable{
pub fn get_data_vector(mut iter: DatabaseRecordIterator) -> Vec<InsertableAttachable>{
let mut db_data: Vec<InsertableAttachable> = vec!();
while let Some(table_row) = iter.next() {
let fields = table_row.fields;
db_data.push(InsertableAttachable::new(fields));
};
db_data
}
}
And another structure
pub struct InsertableAttached {
pub f1: String,
pub f2: i32,
pub f3: i32,
}
impl DbfFile for InsertableAttached {
fn new(fields: HashMap<String, FieldValue, RandomState>) -> Self {
InsertableAttached {
// fields
}
}
}
// Converting this to generic
impl InsertableAttached{
pub fn get_data_vector(mut iter: DatabaseRecordIterator) -> Vec<InsertableAttached>{
let mut db_data: Vec<InsertableAttached> = vec!();
while let Some(table_row) = iter.next() {
let fields = table_row.fields;
db_data.push(InsertableAttached::new(fields));
};
db_data
}
}
Here are example like this returns box / struct and this one returns an option.
The following function has compile time error
error[E0277]: the size for values of type `(dyn models::traits::DbfFile + 'static)` cannot be known at compilation time
--> src/dbf.rs:75:1
|
75 | / pub fn get_data_vector(&mut iter: DatabaseRecordIterator) -> Vec<DbfFile>{
76 | | let mut db_data: Vec<DbfFile> = vec!();
77 | | while let Some(table_row) = iter.next() {
78 | | let fields = table_row.fields;
... |
81 | | db_data
82 | | }
| |_^ doesn't have a size known at compile-time
|
= help: the trait `std::marker::Sized` is not implemented for `(dyn models::traits::DbfFile + 'static)`
= note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
= note: required by `std::vec::Vec`
error[E0038]: the trait `models::traits::DbfFile` cannot be made into an object
--> src/dbf.rs:75:1
|
75 | pub fn get_data_vector(&mut iter: DatabaseRecordIterator) -> Vec<DbfFile>{
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `models::traits::DbfFile` cannot be made into an object

You would need to box the results in order to be able to return a heterogenous collection via dynamic dispatch:
pub fn get_data_vector(&mut iter: DatabaseRecordIterator) -> Vec<Box<dynDbfFile>>
However you will then get the following error:
| pub fn get_data_vector(&mut iter: DatabaseRecordIterator) -> Vec<Box<dyn DbfFile>> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `DbfFile` cannot be made into an object
|
The reason for this is that your function returns Self - which is different for each implementation. You would need to change it to a common type to make the trait object-safe (allow dynamic dispatch).
An alternative could be to return multiple types via an enumeration:
enum GetDataVectorResult {
Attachable(InsertableAttachable),
Attached(InsertableAttached),
}
pub fn get_data_vector(&mut iter: DatabaseRecordIterator) -> Vec<GetDataVectorResult>

Related

How do I create a HashMap with value of function?

I'm trying to set HashMap of functions in a struct to a field in the struct and call them like below code. But it has compiler error. How can I fix?
main.rs
use std::collections::HashMap;
struct A{
pub funcs: HashMap<&'static str, fn()->()>,
f1:i32,
f2:i32
}
impl A {
fn func1(&mut self) {self.f1+=1;println!("func1 has called {} time(s)",self.f1);}
fn func2(&mut self) {self.f2+=1;println!("func2 has called {} time(s)",self.f2);}
fn set_funcs(&mut self) {
self.funcs = HashMap::from([("f1",Self::func1),("f2",Self::func2)]);
}
}
fn main() {
let mut a = A{funcs:HashMap::new(),f1:0,f2:0};
a.set_funcs();
a.funcs.get("f1").unwrap()();
}
compiler error
error[E0308]: mismatched types
--> src/main.rs:12:58
|
12 | self.funcs = HashMap::from([("f1",Self::func1),("f2",Self::func2)]);
| ^^^^^^^^^^^ expected fn item, found a different fn item
|
= note: expected fn item `for<'r> fn(&'r mut A) {A::func1}`
found fn item `for<'r> fn(&'r mut A) {A::func2}`
error[E0308]: mismatched types
--> src/main.rs:12:18
|
12 | self.funcs = HashMap::from([("f1",Self::func1),("f2",Self::func2)]);
| ---------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected fn pointer, found fn item
| |
| expected due to the type of this binding
|
= note: expected struct `HashMap<&'static str, fn()>`
found struct `HashMap<&str, for<'r> fn(&'r mut A) {A::func1}>`
Your functions have an argument: &mut self. self has type Self/A. A::func1 is fn(&mut A) -> () not fn() -> ()
use std::collections::HashMap;
struct A{
pub funcs: HashMap<&'static str, fn(&mut Self)->()>,
f1:i32,
f2:i32
}
impl A {
fn func1(&mut self) {self.f1+=1;println!("func1 has called {} time(s)",self.f1);}
fn func2(&mut self) {self.f2+=1;println!("func2 has called {} time(s)",self.f2);}
fn set_funcs(&mut self) {
self.funcs.insert("f1", Self::func1);
self.funcs.insert("f2", Self::func2);
}
}
fn main() {
let mut a = A{funcs:HashMap::new(),f1:0,f2:0};
a.set_funcs();
a.funcs.get("f1").unwrap()(&mut a);
}

Rust passing closures and they lifetime

Hi I try to pass my closure to mockall crate returning function in following way:
pub fn set_dialog_game_selection(dialogs: &mut Box<MockAsk>, steam_id: String) {
dialogs
.expect_ask_for_game_decision_if_needed_and_set_game_to_launch()
.returning(ask_for_game_decision_if_needed_return_mock(steam_id));
}
pub fn ask_for_game_decision_if_needed_return_mock<'x, 'y>(
steam_id: String,
) -> Box<dyn Fn(&'x mut REvilConfig, &'y mut REvilManagerState) -> ResultDialogsErr<()> + Send> {
let default = move |_: &'x mut REvilConfig, state: &'y mut REvilManagerState| {
state.selected_game_to_launch = Some(steam_id.clone());
Ok(())
};
return Box::new(default);
}
but I get
error[E0308]: mismatched types
--> src\tests\integration.rs:128:14
|
128 | .returning(ask_for_game_decision_if_needed_return_mock(steam_id.to_string()));
| ^^^^^^^^^ lifetime mismatch
|
= note: expected associated type `<dyn Fn(&mut configStruct::REvilConfig, &mut rManager_header::REvilManagerState) -> Result<(), error_stack::Report<DialogsErrors>> + Send as FnOnce<(&mut configStruct::REvilConfig, &mut rManager_header::REvilManagerState)>>::Output`
found associated type `<dyn Fn(&mut configStruct::REvilConfig, &mut rManager_header::REvilManagerState) -> Result<(), error_stack::Report<DialogsErrors>> + Send as FnOnce<(&mut configStruct::REvilConfig, &mut rManager_header::REvilManagerState)>>::Output`
note: the lifetime requirement is introduced here
--> src\dialogs\dialogs.rs:54:10
|
54 | ) -> ResultDialogsErr<()>;
| ^^^^^^^^^^^^^^^^^^^^
P.S I'm writting mod manager for Resident Evil game that's why "REvil" :p
P.S2 In the end I managed to rewrite it like:
pub fn set_dialog_game_selection(dialogs: &mut Box<MockAsk>, steam_id: String) {
dialogs
.expect_ask_for_game_decision_if_needed_and_set_game_to_launch()
.returning(move |_, state| {
set_game_decision(steam_id.clone(), state);
Ok(())
});
}
pub fn set_game_decision(steam_id: String, state: &mut REvilManagerState) {
state.selected_game_to_launch = Some(steam_id);
}
But why my first approach doeasn't work? :(
Function signature I'm trying to mock is as follow:
pub type ResultDialogsErr<T> = Result<T, DialogsErrors>;
fn ask_for_game_decision_if_needed_and_set_game_to_launch(
&mut self,
config: &mut REvilConfig,
state: &mut REvilManagerState,
) -> ResultDialogsErr<()>;
If you remove the manual lifetime annotations, it works:
pub fn ask_for_game_decision_if_needed_return_mock(
steam_id: String,
) -> Box<dyn Fn(&mut REvilConfig, &mut REvilManagerState) -> DynResult<()> + Send> {
let default = move |_: &mut REvilConfig, state: &mut REvilManagerState| {
state.selected_game_to_launch = Some(steam_id.clone());
Ok(())
};
return Box::new(default);
}

Implement a trait for both Iter<&> and Iter<&mut> [duplicate]

This question already has answers here:
Conflicting trait implementations even though associated types differ
(2 answers)
Closed 9 months ago.
I am trying to write a conversion trait that can take both Iterators to references and Iterators to mutable references.
Sadly, it seems that once you implement a trait for Iter<&>, you cannot implement the trait also for Iter<&mut> as they seem to collide. Which doesn't make sense, though, because Iter<&mut> doesn't seem to be able to utilize the implementation for Iter<&>.
Here is a minimal example:
// A dummy object
#[derive(Debug)]
struct MyObj(i32);
// A collection of MyObj references
#[derive(Debug)]
struct RefVec<'a>(Vec<&'a MyObj>);
// Goal: create a conversion function that can take *either* a `Iterator<&MyObj>` *or* `Iterator<&mut MyObj>`.
// Attempt: Create a Conversion Trait and implement it for both of those types
trait ConvertToRefVec<'a> {
fn convert(&mut self) -> RefVec<'a>;
}
// Implement the conversion for Iter<&MyObj>
impl<'a, T> ConvertToRefVec<'a> for T
where
T: Iterator<Item = &'a MyObj>,
{
fn convert(&mut self) -> RefVec<'a> {
RefVec(self.collect::<Vec<_>>())
}
}
// Problem: the impl above does not apply to Iter<&mut MyObj>. But the attempt to write an impl
// for Iter<&mut MyObj> fails with the message that it collides with the impl above:
impl<'a, T> ConvertToRefVec<'a> for T
where
T: Iterator<Item = &'a mut MyObj>,
{
fn convert(&mut self) -> RefVec<'a> {
RefVec(self.collect::<Vec<_>>())
}
}
fn main() {
let owned = [MyObj(42), MyObj(69)];
let ref_vec = owned.iter().convert();
println!("{:?}", ref_vec);
let ref_vec = owned.iter_mut().convert();
println!("{:?}", ref_vec);
}
Which gives me:
error[E0119]: conflicting implementations of trait `ConvertToRefVec<'_>`
--> src/main.rs:27:1
|
16 | / impl<'a, T> ConvertToRefVec<'a> for T
17 | | where
18 | | T: Iterator<Item = &'a MyObj>,
19 | | {
... |
22 | | }
23 | | }
| |_- first implementation here
...
27 | / impl<'a, T> ConvertToRefVec<'a> for T
28 | | where
29 | | T: Iterator<Item = &'a mut MyObj>,
30 | | {
... |
33 | | }
34 | | }
| |_^ conflicting implementation
But if I leave out the impl for Iterator<&mut>, then I get this error:
error[E0599]: the method `convert` exists for struct `std::slice::IterMut<'_, MyObj>`, but its trait bounds were not satisfied
--> src/main.rs:42:36
|
42 | let ref_vec = owned.iter_mut().convert();
| ^^^^^^^ method cannot be called on `std::slice::IterMut<'_, MyObj>` due to unsatisfied trait bounds
|
::: /home/.../.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/slice/iter.rs:187:1
|
187 | pub struct IterMut<'a, T: 'a> {
| -----------------------------
| |
| doesn't satisfy `<_ as Iterator>::Item = &MyObj`
| doesn't satisfy `std::slice::IterMut<'_, MyObj>: ConvertToRefVec`
|
note: trait bound `<std::slice::IterMut<'_, MyObj> as Iterator>::Item = &MyObj` was not satisfied
--> src/main.rs:18:17
|
16 | impl<'a, T> ConvertToRefVec<'a> for T
| ------------------- -
17 | where
18 | T: Iterator<Item = &'a MyObj>,
| ^^^^^^^^^^^^^^^^ unsatisfied trait bound introduced here
So my question is: How can I write such a conversion mechanism that works with both Iterator<Item = &MyObj> and Iterator<Item = &mut MyObj?
The thing is that you are trying to implement your trait in two different ways for the same type. So the problem that you treat T as the same one. Then you can just split the cases for concrete types. Like to following:
#[derive(Debug)]
struct MyObj(i32);
#[derive(Debug)]
struct RefVec<'a>(Vec<&'a MyObj>);
trait ConvertToRefVec<'a> {
fn convert(&mut self) -> RefVec<'a>;
}
impl<'a> ConvertToRefVec<'a> for std::slice::Iter<'a, MyObj>
{
fn convert(&mut self) -> RefVec<'a> {
RefVec(self.collect::<Vec<_>>())
}
}
impl<'a> ConvertToRefVec<'a> for std::slice::IterMut<'a, MyObj>
{
fn convert(&mut self) -> RefVec<'a> {
RefVec(self.map(|el| &*el).collect::<Vec<&MyObj>>())
}
}
fn main() {
let mut owned = [MyObj(42), MyObj(69)];
let ref_vec = owned.iter().convert();
println!("{:?}", ref_vec);
let ref_vec = owned.iter_mut().convert();
println!("{:?}", ref_vec);
}

Populate vector of references to traits

Rust noob here. How can I populate a vector of references to a trait with variables defined locally?
I tried something like this (playground):
trait Trait {
fn as_trait(&self) -> &dyn Trait;
}
struct Struct1 {
value: i32,
}
impl Trait for Struct1 {
fn as_trait(&self) -> &dyn Trait {
self
}
}
struct Collection {
values: Vec<&'static dyn Trait>,
}
fn populate(coll: &mut Collection) {
for i in 0..10 {
let foo = Struct1 {value: i};
coll.values.push(foo.as_trait());
}
}
fn main() {
let mut coll = Collection { values: vec![] };
populate(&mut coll);
}
This obviously returns the following error:
error[E0597]: `foo` does not live long enough
--> src/main.rs:21:26
|
21 | coll.values.push(foo.as_trait());
| ^^^-----------
| |
| borrowed value does not live long enough
| cast requires that `foo` is borrowed for `'static`
22 | }
23 | }
| - `foo` dropped here while still borrowed
I also tried to use lazy_static macro without success (playground):
use lazy_static::lazy_static;
trait Trait {
fn as_trait(&self) -> &dyn Trait;
}
struct Struct1 {
value: i32,
}
impl Trait for Struct1 {
fn as_trait(&self) -> &dyn Trait {
self
}
}
struct Collection {
values: Vec<&'static dyn Trait>,
}
fn populate(coll: &mut Collection) {
for i in 0..10 {
lazy_static! {
static ref foo: Struct1 = Struct1 {value: i};
}
coll.values.push(foo.as_trait());
}
}
fn main() {
let mut coll = Collection { values: vec![] };
populate(&mut coll);
}
In this case the error is the following:
error[E0434]: can't capture dynamic environment in a fn item
--> src/main.rs:23:55
|
23 | static ref foo: Struct1 = Struct1 {value: i};
| ^
|
= help: use the `|| { ... }` closure form instead

Lifetime error when creating mutable iterator

I had some problems when I tried to create a custom iterator. The non-mutable version worked fine but when copying the same function to create a mutable version, a lifetime error appeared. This is a simplified version of my problem:
struct Test {
map: HashMap<u32, String>
}
impl Test {
pub fn iter(&self, start: u32, end: u32) -> impl Iterator<Item = &String> {
(start..=end).filter_map(move |i| {
self.map.get(&i)
})
}
pub fn iter_mut(&mut self, start: u32, end: u32) -> impl Iterator<Item = &mut String> {
(start..=end).filter_map(move |i| {
self.map.get_mut(&i)
})
}
}
The iter function works fine but the iter_mut function doesn't compile with this error:
error[E0495]: cannot infer an appropriate lifetime for autoref due to conflicting requirements
--> src/main.rs:21:22
|
21 | self.map.get_mut(&i)
| ^^^^^^^
|
note: first, the lifetime cannot outlive the lifetime `'_` as defined on the body at 20:34...
--> src/main.rs:20:34
|
20 | (start..=end).filter_map(|i| {
| ^^^
note: ...so that closure can access `self`
--> src/main.rs:21:13
|
21 | self.map.get_mut(&i)
| ^^^^^^^^
note: but, the lifetime must be valid for the anonymous lifetime defined on the method body at 19:21...
--> src/main.rs:19:21
|
19 | pub fn iter_mut(&mut self, start: u32, end: u32) -> impl Iterator<Item = &mut String> {
| ^^^^^^^^^
note: ...so that the types are compatible
--> src/main.rs:19:57
|
19 | pub fn iter_mut(&mut self, start: u32, end: u32) -> impl Iterator<Item = &mut String> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: expected `std::option::Option<&mut std::string::String>`
found `std::option::Option<&mut std::string::String>`
As said Todd, compile error on iter_mut likely occurs due to creation many mutable references to the same HashMap, but I'm not sure about that. You can do something like that:
struct Test {
map: HashMap<u32, String>
}
impl Test {
pub fn iter(&self, start: u32, end: u32) -> impl Iterator<Item=&String> {
self.map
.iter()
.filter_map(move |k| {
if (start..=end).contains(k.0) {
Some(k.1)
} else {
None
}
})
}
pub fn iter_mut(&mut self, start: u32, end: u32) -> impl Iterator<Item=&mut String> {
self.map
.iter_mut()
.filter_map(move |k| {
if (start..=end).contains(k.0) {
Some(k.1)
} else {
None
}
})
}
}

Resources