I want to map all children struct methods to it's parent with reducing some parameters.
Here is a example:-
PlayGround:- https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=0610b6abd57ab3d65435c821829e156b
struct World;
struct Sibling;
struct Parent {
pub child: Child,
pub sibling: Sibling
}
impl Parent {
pub fn new()->Parent {
Parent {
sibling: Sibling,
child: Child,
}
}
}
struct Child;
impl Child {
pub fn set_x(&mut self, _world: &mut World, _sibling: &mut Sibling, _x: f32 ){
// ..
}
pub fn set_y(&mut self, _world: &mut World, _sibling: &mut Sibling, _y: f32){
// ..
}
// 32 methods that taking World as first parameter and Sibling as second parameter
}
fn main(){
let mut world = World;
let mut parent = Parent::new();
parent.child.set_x(&mut world,&mut parent.sibling,0.23);
parent.child.set_y(&mut world,&mut parent.sibling, 0.12);
// Expectation:-
// parent.set_x(&mut world,0.23)
// parent.set_y(&mut world, 1.23)
}
Parent is know who is the sibling, who is the child. There is no need for guidance from the global scope. I need to hide child and sibling from outer scope. And I have tried in the following way.
impl Parent {
pub fn set_x(&mut self, world: &mut World, x: f32){
self.child.set_x(world, &mut self.sibling, x);
}
// ...
}
But I have 32 methods. This is not a clear way.
You can do it with a simple macro:
macro_rules! map_methods {
($stype:ty { $($method:ident ($($param:ident : $ptype:ty),*);)* }) => {
impl $stype {
$(
fn $method (&mut self, world: &mut World, $($param: $ptype),*) {
self.child.$method (world, &mut self.sibling, $($param),*)
}
)*
}
}
}
Which you then use like this:
map_methods!{ Parent {
set_x (_x: f32);
set_y (_y: f32);
}}
Playground
PS: Obligatory reading when starting with Rust macros: The Little Book of Rust Macros
Related
So I have a function. And I want to test it. It takes a struct as param. And the struct has some trait implemented. This trait has a long running io method. I don't want this io method to actually go fetch data, I want to mock this io method and just return the result. I am a little lost about how this can be done. Here is my try (not working)
struct TestStruct {
a: u32,
b: u32,
}
pub trait TestTrait {
fn some_long_running_io_method(&self) -> u32 {
156
}
}
fn important_func(a: TestStruct) {
println!("a: {}", a.some_long_running_io_method());
}
impl TestTrait for TestStruct {
fn some_long_running_io_method(&self) -> u32 {
self.a + self.b
}
}
#[cfg(test)]
mod tests {
use super::*;
use mockall::predicate::*;
use mockall::*;
#[cfg(test)]
mock! {
pub TestStruct {}
impl TestTrait for TestStruct {
fn some_long_running_io_method(&self) -> u32;
}
}
#[test]
fn test_important_func() {
let mut mock = MockTestStruct::new();
mock.expect_some_long_running_io_method()
.returning(|| 1);
important_func(mock);
}
}
I obviously get this error:
error[E0308]: mismatched types
--> src/test.rs:35:24
|
35 | important_func(mock);
| -------------- ^^^^ expected struct `TestStruct`, found struct `MockTestStruct`
| |
| arguments to this function are incorrect
How can I achieve mocking trait methods? 1) One way is to change function param and instead of accepting a concrete struct accept trait. And implement this trait on MockTestStruct. But then we have dynamic dispatching and it hurts the performance. I don't want a performance degrade just for the test. 2) I also tried reimplementing the Trait right where the test is, but conflicting implementations are not allowed in Rust. 3) Make function accept TestStruct or MockTestStruct? Probably not great way either.
Could you please tell me what is the idiomatic way to do it?
You can make your function, important_func a generic function. You can then use generic bounds to restrict the type to implementors of your trait.
Here is an example with your code:
struct TestStruct {
a: u32,
b: u32,
}
pub trait TestTrait {
fn some_long_running_io_method(&self) -> u32 {
156
}
}
// important_func can now use any type T which implements TestTrait,
// including your mock implementation!
fn important_func<T: TestTrait>(a: T) {
println!("a: {}", a.some_long_running_io_method());
}
impl TestTrait for TestStruct {
fn some_long_running_io_method(&self) -> u32 {
self.a + self.b
}
}
#[cfg(test)]
mod tests {
use super::*;
use mockall::predicate::*;
use mockall::*;
#[cfg(test)]
mock! {
pub TestStruct {}
impl TestTrait for TestStruct {
fn some_long_running_io_method(&self) -> u32;
}
}
#[test]
fn test_important_func() {
let mut mock = MockTestStruct::new();
mock.expect_some_long_running_io_method().returning(|| 1);
important_func(mock);
}
}
I've stumbled upon a somewhat quirky situation due to lack of inheritance in Rust.
I'm designing an element structure where all elements have some common behaviour (e.g. having children) and need to propagate function calls down the tree.
My current design is to have a View trait and a ViewInner struct that encapsulates all common behaviour. However it appears that doing so would spawn tons of boilerplate code that forwards calls from View to its ViewInner. And as it appears, adding another level of encapsulation (e.g. AutoLayoutView) would triple the call depth.
Here's a short example:
// "Base" view trait
pub trait View {
fn render(&self, ...);
fn handle_events(&self, ...);
}
// View internals
pub struct ViewInner {
children: Vec<Box<View>>
}
impl ViewInner {
...
pub fn add_child(...);
pub fn layout(...);
}
// Forwarded calls
impl View for ViewInner {
fn render(&self, ...) {
for child in self.children.iter() {
child.render(...);
}
}
fn handle_events(&self, ...) {
for child in self.children.iter() {
child.handle_events(...);
}
}
}
// Actual entity
pub struct SomeView {
inner: ViewInner,
...
}
impl SomeView {
pub fn new() -> Self {
return Self {
inner: ViewInner::new()
}
}
}
impl View for SomeView {
// Forwarding all over again
fn render(&self, ...) {
self.inner.render(...)
}
fn handle_events(&self, ...) {
self.inner.handle_events(...)
}
}
What would be a more optimal way to structure this and minimize boilerplate in the future (in case of more tree-crawling calls and View variations)?
For the generic cases where the calls will be forwarded without any added logic you can write a custom derive macro for the View trait.
With it you just need to write:
#[derive(View)]
pub struct ViewInner {
...
}
and the View trait will be automatically implemented for the struct.
Here is as far as I could get, using rental, partly based on How can I store a Chars iterator in the same struct as the String it is iterating on?. The difference here is that the get_iter method of the locked member has to take a mutable self reference.
I'm not tied to using rental: I'd be just as happy with a solution using reffers or owning_ref.
The PhantomData is present here just so that MyIter bears the normal lifetime relationship to MyIterable, the thing being iterated over.
I also tried changing #[rental] to #[rental(deref_mut_suffix)] and changing the return type of MyIterable.get_iter to Box<Iterator<Item=i32> + 'a> but that gave me other lifetime errors originating in the macro that I was unable to decipher.
#[macro_use]
extern crate rental;
use std::marker::PhantomData;
pub struct MyIterable {}
impl MyIterable {
// In the real use-case I can't remove the 'mut'.
pub fn get_iter<'a>(&'a mut self) -> MyIter<'a> {
MyIter {
marker: PhantomData,
}
}
}
pub struct MyIter<'a> {
marker: PhantomData<&'a MyIterable>,
}
impl<'a> Iterator for MyIter<'a> {
type Item = i32;
fn next(&mut self) -> Option<i32> {
Some(42)
}
}
use std::sync::Mutex;
rental! {
mod locking_iter {
pub use super::{MyIterable, MyIter};
use std::sync::MutexGuard;
#[rental]
pub struct LockingIter<'a> {
guard: MutexGuard<'a, MyIterable>,
iter: MyIter<'guard>,
}
}
}
use locking_iter::LockingIter;
impl<'a> Iterator for LockingIter<'a> {
type Item = i32;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
self.rent_mut(|iter| iter.next())
}
}
struct Access {
shared: Mutex<MyIterable>,
}
impl Access {
pub fn get_iter<'a>(&'a self) -> Box<Iterator<Item = i32> + 'a> {
Box::new(LockingIter::new(self.shared.lock().unwrap(), |mi| {
mi.get_iter()
}))
}
}
fn main() {
let access = Access {
shared: Mutex::new(MyIterable {}),
};
let iter = access.get_iter();
let contents: Vec<i32> = iter.take(2).collect();
println!("contents: {:?}", contents);
}
As user rodrigo has pointed out in a comment, the solution is simply to change #[rental] to #[rental_mut].
I am trying to implement a list zipper. So far I have:
#[derive(RustcDecodable, RustcEncodable, Debug, Clone)]
pub struct ListZipper {
pub focus: Option<Tile>,
pub left: VecDeque<Tile>,
pub right: VecDeque<Tile>,
}
impl PartialEq for ListZipper {
fn eq(&self, other: &ListZipper) -> bool {
self.left == other.left && self.focus == other.focus && self.right == other.right
}
}
I am now trying to implement an iterator
impl Iterator for ListZipper {
type Item = Tile;
fn next(&mut self) -> Option<Tile> {
self.left.iter().chain(self.focus.iter()).chain(self.right.iter()).next().map(|w| *w)
}
}
In my head this makes sense. When iterating over ListZipper, I want to iterate over left, then focus and then right. So I chain those iterators and just return next().
This works fine if all fields in ListZipper are empty. As soon as one is not empty iterating over ListZipper results in an infinite loop.
The problem is not the chain. If I replace that by e.g. self.left.iter(), and left is not empty, the problem is the same. Likewise for focus and right.
I tried printing all elements in the iterator and it appears to go through the VecDeque from front to back, and then gets stuck. I.e. next() does not advance the cursor when it reaches the back.
Why?
I realize I may not want ListZipper itself to be an iterator, but that is another discussion.
As mentioned in the comments, your iterator is lacking a crucial piece of state: how far along in the iteration it is. Every time you call next, it constructs another iterator completely from scratch and gets the first element.
Here's a reduced example:
struct ListZipper {
focus: Option<u8>,
}
impl Iterator for ListZipper {
type Item = u8;
fn next(&mut self) -> Option<Self::Item> {
self.focus.iter().next().cloned()
}
}
fn main() {
let lz = ListZipper { focus: Some(42) };
let head: Vec<_> = lz.take(5).collect();
println!("{:?}", head); // [42, 42, 42, 42, 42]
}
I realize I may not want ListZipper itself to be an iterator, but that is another discussion.
No, it's really not ^_^. You need to somehow mutate the thing being iterated on so that it can change and have different values for each subsequent call.
If you want to return a combination of existing iterators and iterator adapters, refer to Correct way to return an Iterator? for instructions.
Otherwise, you need to somehow change ListZipper during the call to next:
impl Iterator for ListZipper {
type Item = Tile;
fn next(&mut self) -> Option<Self::Item> {
if let Some(v) = self.left.pop_front() {
return Some(v);
}
if let Some(v) = self.focus.take() {
return Some(v);
}
if let Some(v) = self.right.pop_front() {
return Some(v);
}
None
}
}
More succinctly:
impl Iterator for ListZipper {
type Item = Tile;
fn next(&mut self) -> Option<Self::Item> {
self.left.pop_front()
.or_else(|| self.focus.take())
.or_else(|| self.right.pop_front())
}
}
Note that your PartialEq implementation seems to be the same as the automatically-derived one...
use std::collections::VecDeque;
type Tile = u8;
#[derive(Debug, Clone, PartialEq)]
pub struct ListZipper {
pub focus: Option<Tile>,
pub left: VecDeque<Tile>,
pub right: VecDeque<Tile>,
}
impl Iterator for ListZipper {
type Item = Tile;
fn next(&mut self) -> Option<Self::Item> {
self.left.pop_front()
.or_else(|| self.focus.take())
.or_else(|| self.right.pop_front())
}
}
fn main() {
let lz = ListZipper {
focus: Some(42),
left: vec![1, 2, 3].into(),
right: vec![97, 98, 99].into(),
};
let head: Vec<_> = lz.take(5).collect();
println!("{:?}", head);
}
I want to define a .unique() method on iterators that enables me to iterate without duplicates.
use std::collections::HashSet;
struct UniqueState<'a> {
seen: HashSet<String>,
underlying: &'a mut Iterator<Item = String>,
}
trait Unique {
fn unique(&mut self) -> UniqueState;
}
impl Unique for Iterator<Item = String> {
fn unique(&mut self) -> UniqueState {
UniqueState {
seen: HashSet::new(),
underlying: self,
}
}
}
impl<'a> Iterator for UniqueState<'a> {
type Item = String;
fn next(&mut self) -> Option<String> {
while let Some(x) = self.underlying.next() {
if !self.seen.contains(&x) {
self.seen.insert(x.clone());
return Some(x);
}
}
None
}
}
This compiles. However, when I try to use in the same file:
fn main() {
let foo = vec!["a", "b", "a", "cc", "cc", "d"];
for s in foo.iter().unique() {
println!("{}", s);
}
}
I get the following error:
error[E0599]: no method named `unique` found for type `std::slice::Iter<'_, &str>` in the current scope
--> src/main.rs:37:25
|
37 | for s in foo.iter().unique() {
| ^^^^^^
|
= help: items from traits can only be used if the trait is implemented and in scope
= note: the following trait defines an item `unique`, perhaps you need to implement it:
candidate #1: `Unique`
What am I doing wrong? How would I extend this arbitrary hashable types?
In your particular case, it's because you have implemented your trait for an iterator of String, but your vector is providing an iterator of &str. Here's a more generic version:
use std::collections::HashSet;
use std::hash::Hash;
struct Unique<I>
where
I: Iterator,
{
seen: HashSet<I::Item>,
underlying: I,
}
impl<I> Iterator for Unique<I>
where
I: Iterator,
I::Item: Hash + Eq + Clone,
{
type Item = I::Item;
fn next(&mut self) -> Option<Self::Item> {
while let Some(x) = self.underlying.next() {
if !self.seen.contains(&x) {
self.seen.insert(x.clone());
return Some(x);
}
}
None
}
}
trait UniqueExt: Iterator {
fn unique(self) -> Unique<Self>
where
Self::Item: Hash + Eq + Clone,
Self: Sized,
{
Unique {
seen: HashSet::new(),
underlying: self,
}
}
}
impl<I: Iterator> UniqueExt for I {}
fn main() {
let foo = vec!["a", "b", "a", "cc", "cc", "d"];
for s in foo.iter().unique() {
println!("{}", s);
}
}
Broadly, we create a new extension trait called UniqueExt which has Iterator as a supertrait. When Iterator is a supertrait, we will have access to the associated type Iterator::Item.
This trait defines the unique method, which is only valid to call when then iterated item can be:
Hashed
Compared for total equality
Cloned
Additionally, it requires that the item implementing Iterator have a known size at compile time. This is done so that the iterator can be consumed by the Unique iterator adapter.
The other important part is the blanket implementation of the trait for any type that also implements Iterator:
impl<I: Iterator> UniqueExt for I {}