What does the mut usage here? - rust

See the comments, What does the mut self_encoded means here?
pub trait DecodeLength {
fn len(self_encoded: &[u8]) -> Result<usize, Error>;
}
// This can compile.
impl DecodeLength for i32 {
// here
fn len(mut self_encoded: &[u8]) -> Result<usize, Error> {
usize::try_from(u32::from(Compact::<u32>::decode(&mut self_encoded)?))
.map_err(|_| "Failed convert decoded size into usize.".into())
}
}
// This way not works since the signature of this len is not correctly.
// impl DecodeLength for i32 {
// fn len(self_encoded: &mut [u8]) -> Result<usize, Error> {
// Ok(2)
// }
// }

you must remember when you change your fn like this
fn len(mut self_encoded: &[u8]) -> usize {
2
}
you didn't change actual input, your input still is &[u8], you just tell the compiler that value of input variable can be changed
like this
impl DecodeLength for i32 {
// here
fn len(mut self_encoded: &[u8]) -> usize {
self_encoded = b"123";
2
}
}
but when you change the input type &[u8] to &mut [u8] you chose a new type for input
now compiler give you an error and says "expected &[u8] but found &mut [u8]
// Error: expected fn pointer `fn(&[u8]) -> _` found fn pointer `fn(&mut [u8]) -> _
impl DecodeLength for i32 {
fn len(self_encoded: &mut [u8]) -> usize {
2
}
}
remember &[u8] and &mut [u8] are different and have different use
[Edit]
you can't use ? in function when your function doesn't return Result
[Edit 2]
look at the following code
impl DecodeLength for i32 {
// here
fn len(mut self_encoded: &[u8]) -> usize {
let mut_ref = &mut self_encoded; // this give you `&mut &[u8]`
let mut_ref2 = self_encoded.as_mut(); // Error: `as_mut` is only valid for `&mut` references
1
}
}
you can't change &[u8] type into &mut [u8], this will give you an error
the simple way is change your DecodeLength like this
pub trait DecodeLength {
fn len(self_encoded: &mut [u8]) -> Result<usize, Error>;
}
&[u8]
it's reference to a bytes slice, value of this slice can't change and is immutable, you can only read it
fn immutable_slice(input: &[u8]) {
//input[0] = b'a'; // Give you an Error
if input[0] == b'a' {
println!("Index 0 is 'a'");
}
}
&mut [u8]
it's reference to a editable bytes slice, it' can be change inside of fn
fn mutable_slice(input: &mut [u8]) {
input[0] = b'a';
println!("{:?}", input);
}
you can test it like this
fn main() {
let numbers1: Vec<u8> = vec![1, 2, 3, 4, 5];
immutable_slice(&numbers1);
let mut numbers2: Vec<u8> = vec![1, 2, 3, 4, 5];
mutable_slice(&mut numbers2);
}

Related

how to solve cyclic-dependency & Iterator lifetime problem?

Rustaceans. when I start to write a BloomFilter example in rust. I found I have serveral problems have to solve. I struggle to solve them but no progress in a day. I need help, any suggestion will help me a lot, Thanks.
Problems
How to solve lifetime when pass a Iterator into another function?
// let bits = self.hash(value); // how to solve such lifetime error without use 'static storage?
// Below is a workaround code but need to computed in advanced.
let bits = Box::new(self.hash(value).collect::<Vec<u64>>().into_iter());
self.0.set(bits);
How to solve cyclic-dependency between struts without modify lower layer code, e.g: bloom_filter ?
// cyclic-dependency:
// RedisCache -> BloomFilter -> Storage
// | ^
// ------------<impl>------------
//
// v--- cache ownership has moved here
let filter = BloomFilter::by(Box::new(cache));
cache.1.replace(filter);
Since rust does not have null value, How can I solve the cyclic-dependency initialization without any stubs?
let mut cache = RedisCache(
Client::open("redis://localhost").unwrap(),
// I found can use Weak::new() to solve it,but need to downgrade a Rc reference.
// v-- need a BloomFilter stub to create RedisCache
RefCell::new(BloomFilter::new()),
);
Code
#![allow(unused)]
mod bloom_filter {
use std::{hash::Hash, marker::PhantomData};
pub type BitsIter = Box<dyn Iterator<Item = u64>>;
pub trait Storage {
fn set(&mut self, bits: BitsIter);
fn contains_all(&self, bits: BitsIter) -> bool;
}
pub struct BloomFilter<T: Hash>(Box<dyn Storage>, PhantomData<T>);
impl<T: Hash> BloomFilter<T> {
pub fn new() -> BloomFilter<T> {
return Self::by(Box::new(ArrayStorage([0; 5000])));
struct ArrayStorage<const N: usize>([u8; N]);
impl<const N: usize> Storage for ArrayStorage<N> {
fn set(&mut self, bits: BitsIter) {
let size = self.0.len() as u64;
bits.map(|bit| (bit % size) as usize)
.for_each(|index| self.0[index] = 1);
}
fn contains_all(&self, bits: BitsIter) -> bool {
let size = self.0.len() as u64;
bits.map(|bit| (bit % size) as usize)
.all(|index| self.0[index] == 1)
}
}
}
pub fn by(storage: Box<dyn Storage>) -> BloomFilter<T> {
BloomFilter(storage, PhantomData)
}
pub fn add(&mut self, value: T) {
// let bits = self.hash(value); // how to solve such lifetime error?
let bits = Box::new(self.hash(value).collect::<Vec<u64>>().into_iter());
self.0.set(bits);
}
pub fn contains(&self, value: T) -> bool {
// lifetime problem same as Self::add(T)
let bits = Box::new(self.hash(value).collect::<Vec<u64>>().into_iter());
self.0.contains_all(bits)
}
fn hash<'a, H: Hash + 'a>(&self, _value: H) -> Box<dyn Iterator<Item = u64> + 'a> {
todo!()
}
}
}
mod spi {
use super::bloom_filter::*;
use redis::{Client, Commands, RedisResult};
use std::{
cell::RefCell,
rc::{Rc, Weak},
};
pub struct RedisCache<'a>(Client, RefCell<BloomFilter<&'a str>>);
impl<'a> RedisCache<'a> {
pub fn new() -> RedisCache<'a> {
let mut cache = RedisCache(
Client::open("redis://localhost").unwrap(),
// v-- need a BloomFilter stub to create RedisCache
RefCell::new(BloomFilter::new()),
);
// v--- cache ownership has moved here
let filter = BloomFilter::by(Box::new(cache));
cache.1.replace(filter);
return cache;
}
pub fn get(&mut self, key: &str, load_value: fn() -> Option<String>) -> Option<String> {
let filter = self.1.borrow();
if filter.contains(key) {
if let Ok(value) = self.0.get::<&str, String>(key) {
return Some(value);
}
if let Some(actual_value) = load_value() {
let _: () = self.0.set(key, &actual_value).unwrap();
return Some(actual_value);
}
}
return None;
}
}
impl<'a> Storage for RedisCache<'a> {
fn set(&mut self, bits: BitsIter) {
todo!()
}
fn contains_all(&self, bits: BitsIter) -> bool {
todo!()
}
}
}
Updated
First, thanks #Colonel Thirty Two give me a lot of information that I haven't mastered and help me fixed the problem of the iterator lifetime.
The cyclic-dependency I have solved by break the responsibility of the Storage into another struct RedisStorage without modify the bloom_filter module, but make the example bloated. Below is their relationships:
RedisCache -> BloomFilter -> Storage <---------------
| |
|-------> redis::Client <- RedisStorage ---<impl>---
I realized the ownership & lifetime system is not only used by borrow checker, but also Rustaceans need a bigger front design to obey the rules than in a GC language, e.g: java. Am I right?
Final Code
mod bloom_filter {
use std::{
hash::{Hash, Hasher},
marker::PhantomData,
};
pub type BitsIter<'a> = Box<dyn Iterator<Item = u64> + 'a>;
pub trait Storage {
fn set(&mut self, bits: BitsIter);
fn contains_all(&self, bits: BitsIter) -> bool;
}
pub struct BloomFilter<T: Hash>(Box<dyn Storage>, PhantomData<T>);
impl<T: Hash> BloomFilter<T> {
#[allow(unused)]
pub fn new() -> BloomFilter<T> {
return Self::by(Box::new(ArrayStorage([0; 5000])));
struct ArrayStorage<const N: usize>([u8; N]);
impl<const N: usize> Storage for ArrayStorage<N> {
fn set(&mut self, bits: BitsIter) {
let size = self.0.len() as u64;
bits.map(|bit| (bit % size) as usize)
.for_each(|index| self.0[index] = 1);
}
fn contains_all(&self, bits: BitsIter) -> bool {
let size = self.0.len() as u64;
bits.map(|bit| (bit % size) as usize)
.all(|index| self.0[index] == 1)
}
}
}
pub fn by(storage: Box<dyn Storage>) -> BloomFilter<T> {
BloomFilter(storage, PhantomData)
}
pub fn add(&mut self, value: T) {
self.0.set(self.hash(value));
}
pub fn contains(&self, value: T) -> bool {
self.0.contains_all(self.hash(value))
}
fn hash<'a, H: Hash + 'a>(&self, value: H) -> BitsIter<'a> {
Box::new(
[3, 11, 31, 71, 131]
.into_iter()
.map(|salt| SimpleHasher(0, salt))
.map(move |mut hasher| hasher.hash(&value)),
)
}
}
struct SimpleHasher(u64, u64);
impl SimpleHasher {
fn hash<H: Hash>(&mut self, value: &H) -> u64 {
value.hash(self);
self.finish()
}
}
impl Hasher for SimpleHasher {
fn finish(&self) -> u64 {
self.0
}
fn write(&mut self, bytes: &[u8]) {
self.0 += bytes.iter().fold(0u64, |acc, k| acc * self.1 + *k as u64)
}
}
}
mod spi {
use super::bloom_filter::*;
use redis::{Client, Commands};
use std::{cell::RefCell, rc::Rc};
pub struct RedisCache<'a>(Rc<RefCell<Client>>, BloomFilter<&'a str>);
impl<'a> RedisCache<'a> {
pub fn new(client: Rc<RefCell<Client>>, filter: BloomFilter<&'a str>) -> RedisCache<'a> {
RedisCache(client, filter)
}
pub fn get<'f>(
&mut self,
key: &str,
load_value: fn() -> Option<&'f str>,
) -> Option<String> {
if self.1.contains(key) {
let mut redis = self.0.as_ref().borrow_mut();
if let Ok(value) = redis.get::<&str, String>(key) {
return Some(value);
}
if let Some(actual_value) = load_value() {
let _: () = redis.set(key, &actual_value).unwrap();
return Some(actual_value.into());
}
}
return None;
}
}
struct RedisStorage(Rc<RefCell<Client>>);
const BLOOM_FILTER_KEY: &str = "bloom_filter";
impl Storage for RedisStorage {
fn set(&mut self, bits: BitsIter) {
bits.for_each(|slot| {
let _: bool = self
.0
.as_ref()
.borrow_mut()
.setbit(BLOOM_FILTER_KEY, slot as usize, true)
.unwrap();
})
}
fn contains_all(&self, mut bits: BitsIter) -> bool {
bits.all(|slot| {
self.0
.as_ref()
.borrow_mut()
.getbit(BLOOM_FILTER_KEY, slot as usize)
.unwrap()
})
}
}
#[test]
fn prevent_cache_penetration_by_bloom_filter() {
let client = Rc::new(RefCell::new(Client::open("redis://localhost").unwrap()));
redis::cmd("FLUSHDB").execute(&mut *client.as_ref().borrow_mut());
let mut filter: BloomFilter<&str> = BloomFilter::by(Box::new(RedisStorage(client.clone())));
assert!(!filter.contains("Rust"));
filter.add("Rust");
assert!(filter.contains("Rust"));
let mut cache = RedisCache::new(client, filter);
assert_eq!(
cache.get("Rust", || Some("System Language")),
Some("System Language".to_string())
);
assert_eq!(
cache.get("Rust", || panic!("must never be called after cached")),
Some("System Language".to_string())
);
assert_eq!(
cache.get("Go", || panic!("reject to loading `Go` from external storage")),
None
);
}
}
pub type BitsIter = Box<dyn Iterator<Item = u64>>;
In this case, the object in the box must be valid for the 'static lifetime. This isn't the case for the iterator returned by hash - its limited to the lifetime of self.
Try replacing with:
pub type BitsIter<'a> = Box<dyn Iterator<Item = u64> + 'a>;
Or using generics instead of boxed trait objects.
So your RedisClient needs a BloomFilter, but the BloomFilter also needs the RedisClient?
Your BloomFilter should not use the RedisCache that itself uses the BloomFilter - that's a recipe for infinitely recursing calls (how do you know what calls to RedisCache::add should update the bloom filter and which calls are from the bloom filter?).
If you really have to, you need some form of shared ownership, like Rc or Arc. Your BloomFilter will also need to use a weak reference, or else the two objects will refer to each other and will never free.

Understanding Self within a trait impl

Im a bit confused by self. Could you please help me along?? Im trying to append or push a new value into the vec. This only shows me that I have no idea what self actually is. The error I'm getting is :
---- ^^^^ this call modifies `self` in-place
| |
| you probably want to use this value after calling the method...
= note: ...instead of the `()` output of method `push`
Why does the following work but...
trait AppendBar {
fn append_bar(self) -> Self;
}
impl AppendBar for String {
fn append_bar(self) -> Self{
self.to_string() + "Bar"
}
}
this and...
impl AppendBar for Vec<String> {
fn append_bar(self) -> Self{
let mut bar = vec![String::from("Bar")];
bar.push(self);
bar
}
}
this and...
impl AppendBar for Vec<String> {
fn append_bar(self) -> Self{
let bar_vec = vec!["Bar".to_string()];
self.append(bar_vec)
}
}
this do not?
trait AppendBar<T> {
fn append_bar(self) -> Self;
}
impl<T> AppendBar<T> for Vec<T> {
fn append_bar(self) -> Self{
self.push("Bar".to_string())
}
}
impl AppendBar for Vec<String> {
fn append_bar(self) -> Self{
let mut bar = vec![String::from("Bar")];
bar.push(self);
bar
}
}
Because self is a Vec<String> and you can't push a Vec<String> into a Vec<String> (which the error message tells you: "Expected String got Vec<String>").
impl AppendBar for Vec<String> {
fn append_bar(self) -> Self{
let bar_vec = vec!["Bar".to_string()];
self.append(bar_vec)
}
}
Because Vec::append doesn't return anything, so you need to return self yourself (or take &mut self as parameter and return nothing).
impl<T> AppendBar<T> for Vec<T> {
fn append_bar(self) -> Self{
self.push("Bar".to_string())
}
}
Because "Bar".to_string() is not guaranteed to be a T for all types T.

Generic type parameter with constraints from unsigned integer type

I am trying to use a generic datatype which implements 2 methods from the unsigned primitive integer types in rust (u8, u32, u64, etc.). The goal is to be able to read some predefined datatype from a stream (playground link):
use std::io::Read;
use std::io::BufReader;
pub trait ReadExt {
fn read<T>(&mut self) -> Result<T, std::io::Error>;
}
impl<R: Read> ReadExt for R {
fn read<T>(&mut self) -> Result<T, std::io::Error> {
let mut v = Vec::with_capacity((T::BITS >> 3).into());
self.read_exact(&mut v);
Ok(T::from_le_bytes(v))
}
}
fn main() {
let mut stream = BufReader::new(&0xffffffffu32.to_le_bytes()[..]);
let x = ReadExt::read::<u32>(&mut stream).unwrap();
assert_eq!(x, 0xffffffffu32);
}
I get the compile error:
error[E0599]: no associated item named `BITS` found for type parameter `T` in the current scope
--> src/main.rs:11:44
|
11 | let mut v = Vec::with_capacity((T::BITS >> 3).into());
| ^^^^ associated item not found in `T`
error[E0599]: no function or associated item named `from_le_bytes` found for type parameter `T` in the current scope
--> src/main.rs:13:15
|
13 | Ok(T::from_le_bytes(v))
| ^^^^^^^^^^^^^ function or associated item not found in `T`
How do I add constraints on T and specify that T must implement the traits from u8, u16, u32? Specifically, I want T to implement BITS and from_le_bytes.
If you want to use any methods or constants coming from T, then T must be bounded/constrained by some trait, because you can use only methods/constants/etc coming from the trait bounds.
In your case that would be:
pub trait FromLeBytes {
const BITS: u32;
fn from_le_bytes(bytes: [u8; 4]) -> Self;
}
which defines the required method from_le_bytes() and the constant BITS.
You will have to implement that trait for each type that you want to use. Currently I've implemented it only for u32:
impl FromLeBytes for u32 {
const BITS: u32 = u32::BITS;
fn from_le_bytes(bytes: [u8; 4]) -> Self {
u32::from_le_bytes(bytes)
}
}
Then you need to declare that constraint by modifying your ReadExt trait:
pub trait ReadExt {
fn read<T: FromLeBytes>(&mut self) -> Result<T, std::io::Error>;
}
After which you are ready to use the method and the constant in your code:
use std::io::BufReader;
use std::io::Read;
pub trait FromLeBytes {
const BITS: u32;
fn from_le_bytes(bytes: [u8; 4]) -> Self;
}
impl FromLeBytes for u32 {
const BITS: u32 = u32::BITS;
fn from_le_bytes(bytes: [u8; 4]) -> Self {
u32::from_le_bytes(bytes)
}
}
pub trait ReadExt {
fn read<T: FromLeBytes>(&mut self) -> Result<T, std::io::Error>;
}
impl<R: Read> ReadExt for R {
fn read<T: FromLeBytes>(&mut self) -> Result<T, std::io::Error> {
// Could NOT have been done like that because of: https://github.com/rust-lang/rust/issues/68436
// let mut v = [0; T::BITS as usize / 8];
// self.read_exact(&mut v);
// Ok(T::from_le_bytes(v))
let mut v = Vec::with_capacity(T::BITS as usize / 8);
v.resize(v.capacity(), 0);
self.read_exact(&mut v).unwrap();
let mut a = [0; 4];
for (i, b) in v.iter().copied().enumerate() {
a[i] = b;
}
Ok(T::from_le_bytes(a))
}
}
fn main() {
let x = &0xffffffffu32.to_le_bytes()[..];
let mut stream = BufReader::new(x);
let x = ReadExt::read::<u32>(&mut stream).unwrap();
assert_eq!(x, 0xffffffffu32);
}
PS: I've also fixed some compilation errors in your original code
This is not easily possible because BITS and from_le_bytes are both not from a trait, but associated functions of u8, u16 etc. There is no common trait that has those functions/consts.
You can partially work around this by relying on num_traits::int::PrimInt::from_le() to convert endianness and std::mem::size_of() to get the number of bytes in the integer. However, from_le() only allows converting an existing integer – it does not allow to convert a byte buffer, and your use case needs that.
If you are okay with using unsafe Rust, you can achieve what you want via std::mem::transmute_copy. Below you find code doing exactly that (I also fixed a few bugs in your original code). But please read on – there is still a subtle problem.
use std::io::Read;
use std::io::BufReader;
use num_traits::int::PrimInt;
pub trait ReadExt {
fn read<T: PrimInt>(&mut self) -> Result<T, std::io::Error>;
}
impl<R: Read> ReadExt for R {
fn read<T: PrimInt>(&mut self) -> Result<T, std::io::Error> {
let mut v = vec![0u8; std::mem::size_of::<T>()];
self.read_exact(&mut v).unwrap();
let result_in_le: T = unsafe {
std::mem::transmute_copy(&v[0])
};
Ok(T::from_le(result_in_le))
}
}
fn main() {
let buf = 0xffffffffu32.to_le_bytes();
let mut stream = BufReader::new(&buf[..]);
let x = ReadExt::read::<u32>(&mut stream).unwrap();
assert_eq!(x, 0xffffffffu32);
}
Playground
This implementation has a way for the user to trigger undefined behavior: As PrimInt is not sealed, one could implement the trait on some custom struct containing a f64. Using ReadExt::read(), one could then transform arbitrary byte patterns into a f64 – this triggers undefined behavior.
To solve this, we can construct our own trait that is a subtrait of PrimInt and unsafe:
use std::io::Read;
use std::io::BufReader;
use num_traits::int::PrimInt;
pub unsafe trait UnsafeInt: PrimInt {
}
unsafe impl UnsafeInt for u8 {}
unsafe impl UnsafeInt for u16 {}
unsafe impl UnsafeInt for u32 {}
unsafe impl UnsafeInt for u64 {}
unsafe impl UnsafeInt for usize {}
unsafe impl UnsafeInt for i8 {}
unsafe impl UnsafeInt for i16 {}
unsafe impl UnsafeInt for i32 {}
unsafe impl UnsafeInt for i64 {}
unsafe impl UnsafeInt for isize {}
pub trait ReadExt {
fn read<T: UnsafeInt>(&mut self) -> Result<T, std::io::Error>;
}
impl<R: Read> ReadExt for R {
fn read<T: UnsafeInt>(&mut self) -> Result<T, std::io::Error> {
let mut v = vec![0u8; std::mem::size_of::<T>()];
self.read_exact(&mut v).unwrap();
let result_in_le: T = unsafe {
std::mem::transmute_copy(&v[0])
};
Ok(T::from_le(result_in_le))
}
}
fn main() {
let buf = 0xffffffffu32.to_le_bytes();
let mut stream = BufReader::new(&buf[..]);
let x = ReadExt::read::<u32>(&mut stream).unwrap();
assert_eq!(x, 0xffffffffu32);
}
Playground
This guarantees that T is a primitive type, thereby making the transmute_copy sound.

How to define a generic function that takes a function that converts a slice to an iterator

I want to write a function that process some slices in different order, so I decided to write a function that is generic over the iterating order, something like:
fn foo<'a, I: Iterator<Item = &'a mut i32>>(make_iter: impl Fn(&'a mut [i32]) -> I) {
let mut data = [1, 2, 3, 4];
make_iter(&mut data);
}
fn main() {
foo(|x| x.iter_mut());
foo(|x| x.iter_mut().rev());
}
This causes “borrowed value does not live long enough” error.
I imagine something like
fn foo(make_iter: impl for<'a> Fn(&'a mut [i32]) -> impl Iterator<Item = &'a mut i32>) {
let mut data = [1, 2, 3, 4];
make_iter(&mut data);
}
should be used, but impl Iterator is not allow at that position. So is there anything I can do?
Update:
The slices to to processed should be considered dynamically generated inside the foo function, and are dropped after processing.
Your function is mostly correct. The compiled error "borrowed value does not live long enough" is due to the fact that you are defining your data inside the foo rather than pass it in. The error is because of the linelet mut data = [1, 2, 3, 4];
The life time of the data is same as the function foo because it is created in the function foo. However, the closure's life time is longer than the variable data as the closure is passed in as an argument to foo so its lifetime is longer than data. When the function foo goes out of the scope, the data is dropped. Then your closure's is trying to return a reference data which is already dropped. This is why you have compiled error "borrowed value does not live long enough".
You can make this compile by passing the data into foo as an argument, in this case, you will not have the issue due to lifetime.
The below code will compile.
fn foo<'a, I: Iterator<Item = &'a mut i32>>(make_iter: impl Fn(&'a mut [i32]) -> I, data: &'a mut Vec<i32>) {
// let mut data = [1, 2, 3, 4];
make_iter(data);
}
fn main() {
let mut data= vec![1,2,3,4];
foo(|x| x.iter_mut(), &mut data);
foo(|x| x.iter_mut().rev(), &mut data);
}
The rustplay ground link : https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=8b263451fcb01518b3f35bda8485af9c
Update: Sry to misunderstand your requirements. I was trying to come out a clean way to write this, but the best I can come up with is using Box<dyn to do. I know there are runtime cost for Box<dyn..., but I can't come out a better way using impl Iterator
The implementation using Box<dyn ... is
fn foo<F>(make_iter: F) where for<'a> F: Fn(&'a mut [i32])->Box<dyn Iterator<Item=&'a mut i32>+'a>{
let mut data = vec![1, 2, 3, 4];
make_iter(&mut data);
}
fn main() {
foo(|x| Box::new(x.iter_mut()));
foo(|x| Box::new(x.iter_mut().rev()));
}
I came up with one solution:
use std::iter::Rev;
use std::slice::IterMut;
trait MakeIter<'a> {
type Iter: Iterator<Item = &'a mut i32>;
fn make_iter(&mut self, slice: &'a mut [i32]) -> Self::Iter;
}
fn foo(mut make_iter: impl for<'a> MakeIter<'a>) {
let mut data = [1, 2, 3, 4];
make_iter.make_iter(&mut data);
}
struct Forward;
impl<'a> MakeIter<'a> for Forward {
type Iter = IterMut<'a, i32>;
fn make_iter(&mut self, slice: &'a mut [i32]) -> Self::Iter {
slice.iter_mut()
}
}
struct Backward;
impl<'a> MakeIter<'a> for Backward {
type Iter = Rev<IterMut<'a, i32>>;
fn make_iter(&mut self, slice: &'a mut [i32]) -> Self::Iter {
slice.iter_mut().rev()
}
}
fn main() {
foo(Forward);
foo(Backward);
}
But I am not sure whether it can be simplified.
Update
Here is a simplification:
trait MakeIter<'a> {
type Iter: Iterator<Item = &'a mut i32>;
fn make_iter(&mut self, slice: &'a mut [i32]) -> Self::Iter;
}
fn foo(mut make_iter: impl for<'a> MakeIter<'a>) {
let mut data = [1, 2, 3, 4];
make_iter.make_iter(&mut data);
}
impl<'a, F, R> MakeIter<'a> for F
where
F: FnMut(&'a mut [i32]) -> R,
R: Iterator<Item = &'a mut i32>,
{
type Iter = R;
fn make_iter(&mut self, slice: &'a mut [i32]) -> Self::Iter {
self(slice)
}
}
fn iter_forward(slice: &mut [i32]) -> impl Iterator<Item = &mut i32> {
slice.iter_mut()
}
fn iter_backward(slice: &mut [i32]) -> impl Iterator<Item = &mut i32> {
slice.iter_mut().rev()
}
fn main() {
foo(iter_forward);
foo(iter_backward);
}

How can I create a generic function that returns a modified instance of the generic type?

I have a number of generic functions that need to return new instances of the generic. However, the fields in the generic are not known, but I need to get/set the field values to create the instance (a simple Default will not work). For primitive fields, I can update my struct, but for fields with Vector or HashMap types, I get the error:
the size for values of type `[usize]` cannot be known at compilation time
Here is a minimal working example of my issue:
https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=6db1dd0b5982eca526725f4e5b423263
trait MyTrait {
fn id(&self) -> &usize;
fn id_mut(&mut self) -> &mut usize;
fn data(&self) -> &[usize];
fn data_mut(&mut self) -> &mut [usize];
}
#[derive(Debug)]
struct MyStruct {
id: usize,
data: Vec<usize>,
}
impl MyTrait for MyStruct {
fn id(&self) -> &usize {
&self.id
}
fn id_mut(&mut self) -> &mut usize {
&mut self.id
}
fn data(&self) -> &[usize] {
&self.data
}
fn data_mut(&mut self) -> &mut [usize] {
&mut self.data
}
}
impl Default for MyStruct {
fn default() -> MyStruct {
MyStruct {
id: 0,
data: vec![],
}
}
}
fn my_func<T: MyTrait + Default>() -> T {
let mut d = T::default();
// this correctly updates the struct field "id" to 26
*d.id_mut() = 26;
// this however, does not work. i get an error:
// the size for values of type `[usize]` cannot be known at compilation time
*d.data_mut() = vec![1, 2, 3].as_slice();
d
}
fn main() {
let _my_instance = my_func::<MyStruct>();
}
How can I create a generic function that returns an instance of the generic type?
For your Default instance of MyStruct, data is an empty Vec, but you are exposing it as a mutable slice. This is pretty meaningless because you can't change the length of a mutable slice; you can only mutate existing elements.
You will need to expose data as a &mut Vec<usize> instead, so that you can insert elements. The immutable getter can stay the same.
trait MyTrait {
fn id(&self) -> &usize;
fn id_mut(&mut self) -> &mut usize;
fn data(&self) -> &[usize];
fn data_mut(&mut self) -> &mut Vec<usize>;
}
And change the code that updates it:
fn my_func<T: MyTrait + Default>() -> T {
let mut d = T::default();
*d.id_mut() = 26;
*d.data_mut() = vec![1, 2, 3];
d
}

Resources