Code in boxed.rs:
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_box", issue = "92521")]
impl<T: ?Sized, A: Allocator> const Deref for Box<T, A> {
type Target = T;
fn deref(&self) -> &T {
&**self
}
}
In my understanding:
self -> &Box,
*self -> Box.
**self -> *Box, will call: *(Box.deref())? Doesn't that lead to recursion?
I create a test code:
impl<T> Deref for MyBox<T> {
type Target = T;
fn deref(&self) -> &T {
&**self
}
}
When I run it, Rust return me: fatal runtime error: stack overflow
So how does &**self work in std's Box?
Box is special. It is a lang item, and the compiler knows to deref it without help. So:
self - &Box.
*self - Box, builtin deref of shared reference.
**self - T, builtin deref of Box.
&**self - &T.
Similar things happen for all builtin operations. For example, this is the Add impl for integers (inside a macro):
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_ops", issue = "90080")]
impl const Add for $t {
type Output = $t;
#[inline]
#[rustc_inherit_overflow_checks]
fn add(self, other: $t) -> $t { self + other }
}
Again, the compiler knows to add integers. It is a builtin operation.
The reason we need the impl is for generics. Code like 0i32 + 0i32 translates to the builtin addition, but in a generic function:
fn add<T: Add>(a: T, b: T) -> T::Output { a + b }
If integers wouldn't implement Add, this function wouldn't accept them. The same happens for Box and Deref.
You can see that by inspecting the MIR. For example, the following function:
pub fn deref(b: &Box<i32>) -> &i32 {
&**b
}
Generates the following MIR:
fn deref(_1: &Box<i32>) -> &i32 {
let mut _0: &i32;
bb0: {
_0 = &(*(*_1));
return;
}
}
However, the following function:
pub fn deref<T: std::ops::Deref<Target = i32>>(b: &T) -> &i32 {
&**b
}
Generates the following MIR, that calls deref():
fn deref(_1: &T) -> &i32 {
let mut _0: &i32;
let _2: &i32;
let mut _3: &T;
bb0: {
_3 = _1;
_2 = <T as Deref>::deref(move _3) -> bb1;
}
bb1: {
_0 = _2;
return;
}
}
The same happens for other Deref implementors, e.g. Rc:
pub fn deref(b: &std::rc::Rc<i32>) -> &i32 {
&**b
}
fn deref(_1: &Rc<i32>) -> &i32 {
let mut _0: &i32;
let _2: &i32;
let mut _3: &std::rc::Rc<i32>;
bb0: {
_3 = _1;
_2 = <Rc<i32> as Deref>::deref(move _3) -> bb1;
}
bb1: {
_0 = _2;
return;
}
}
Related
I'd like to store a boxed closure (Box<dyn Fn(f64, f64) -> f64>) in a global variable EXPRESSION_FUNCTION.
Here is my attempt at achieving this:
type F2d = Box<dyn Fn(f64, f64) -> f64>;
static mut EXPRESSION_FUNCTION: *mut F2d = 0 as *mut F2d;
fn create_function() -> F2d {
Box::new(|_: f64, _: f64| 0.0)
}
fn set_expression_function() {
unsafe {
EXPRESSION_FUNCTION = Box::into_raw(create_function());
}
}
I get a type mismatch:
error[E0308]: mismatched types
--> src\lib.rs:79:45
|
79 | EXPRESSION_FUNCTION = Box::into_raw(create_function());
| ^^^^^^^^^^^^^^^^^ expected struct `Box`, found trait object `dyn Fn`
|
= note: expected struct `Box<Box<(dyn Fn(f64, f64) -> f64 + 'static)>, _>`
found struct `Box<(dyn Fn(f64, f64) -> f64 + 'static), std::alloc::Global>`
How can I convert the result of create_function to fit into a global variable?
Do not use static mut. It is extremely easy to write incorrect programs that violate Rust's reference and aliasing rules using static mut. Instead, use static together with some kind of cell (interior-mutable type) — even UnsafeCell (which should be a last resort) is easier to use correctly than static mut.
If your variable is going to be initialized only once, the simplest solution is to use once_cell (which is on its way to being included in the standard library, but for now is a widely used third-party library).
use once_cell::sync::OnceCell;
type F2d = Box<dyn Fn(f64, f64) -> f64 + Send + Sync>;
static EXPRESSION_FUNCTION: OnceCell<F2d> = OnceCell::new();
fn create_function() -> F2d {
Box::new(|_: f64, _: f64| 2.0)
}
fn set_expression_function() {
if let Err(_) = EXPRESSION_FUNCTION.set(create_function()) {
panic!("already set");
}
}
fn main() {
set_expression_function();
let f = EXPRESSION_FUNCTION.get().expect("not set");
assert_eq!(f(10., 0.), 2.0);
}
If it needs to be reassignable, then you need a lock. parking_lot::RwLock is a nice choice because it can be constructed at compile time, so no lazy initialization is needed:
use parking_lot::RwLock;
type F2d = Box<dyn Fn(f64, f64) -> f64 + Send + Sync>;
static EXPRESSION_FUNCTION: RwLock<Option<F2d>> = RwLock::new(None);
fn create_function() -> F2d {
Box::new(|_: f64, _: f64| 2.0)
}
fn set_expression_function() {
*EXPRESSION_FUNCTION.write() = Some(create_function());
}
fn main() {
set_expression_function();
let option_fn_guard = EXPRESSION_FUNCTION.read();
let f = option_fn_guard.as_ref().expect("not set");
assert_eq!(f(10., 0.), 2.0);
}
Unlike the static mut you started with, both of these programs are sound (will not segfault, etc.) no matter how the functions and global variable are used. This is good Rust programming practice.
I got it working using Some:
type F2d = Box<dyn Fn(f64, f64) -> f64>;
static mut EXPRESSION_FUNCTION: Option<F2d> = None;
fn create_function() -> F2d {
Box::new(|x: f64, y: f64| x+y)
}
fn set_expression_function() {
unsafe {
EXPRESSION_FUNCTION = Some(create_function());
}
}
fn main() {
set_expression_function();
unsafe {
if let Some(f) = &EXPRESSION_FUNCTION{
println!("{}", f(1.0, 2.0));
}
};
}
This is valid code:
use std::rc::Rc;
use std::sync::{Arc, Mutex};
fn foo(n: i32) {
println!("n = {}", n)
}
fn main() {
let a = 1;
let b = Rc::new(2);
let c = Mutex::new(3);
let d = Arc::new(Mutex::new(4));
foo(a);
foo(*b);
foo(*(c.lock().unwrap()));
foo(*((*d).lock().unwrap()));
}
Are there any traits (or anything else) that I can implement so that the function calls could simply become:
foo(a);
foo(b);
foo(c);
foo(d);
What is the Rust idiomatic way for handling the actual data and not caring about how the data is protected/wrapped?
As others have pointed out, it is a bad idea to ignore the fallibility of Mutex::lock. However for the other cases, you can make your function accept owned values and references transparently by using Borrow:
use std::borrow::Borrow;
use std::rc::Rc;
fn foo (n: impl Borrow<i32>) {
println!("n = {}", n.borrow())
}
fn main() {
let a = 1;
let b = Rc::new (2);
let c = &3;
foo (a);
foo (b);
foo (c);
}
Playground
Here is an extremely literal answer to your specific question. I wouldn't use it.
use std::{
rc::Rc,
sync::{Arc, Mutex},
};
fn foo(n: impl DontCare<Output = i32>) {
let n = n.gimme_it();
println!("n = {}", n)
}
fn main() {
let a = 1;
let b = Rc::new(2);
let c = Mutex::new(3);
let d = Arc::new(Mutex::new(4));
foo(a);
foo(b);
foo(c);
foo(d);
}
trait DontCare {
type Output;
fn gimme_it(self) -> Self::Output;
}
impl DontCare for i32 {
type Output = Self;
fn gimme_it(self) -> Self::Output {
self
}
}
impl<T: DontCare> DontCare for Mutex<T> {
type Output = T::Output;
fn gimme_it(self) -> Self::Output {
self.into_inner()
.expect("Lets first assume unwrap() will not panic")
.gimme_it()
}
}
impl<T: DontCare> DontCare for Rc<T> {
type Output = T::Output;
fn gimme_it(self) -> Self::Output {
match Rc::try_unwrap(self) {
Ok(v) => v.gimme_it(),
_ => unreachable!("Lets first assume unwrap() will not panic"),
}
}
}
impl<T: DontCare> DontCare for Arc<T> {
type Output = T::Output;
fn gimme_it(self) -> Self::Output {
match Arc::try_unwrap(self) {
Ok(v) => v.gimme_it(),
_ => unreachable!("Lets first assume unwrap() will not panic"),
}
}
}
The function signatures you've specified take ownership of the value. That will be highly painful, especially paired with any type that doesn't implement Copy.
There are a number of code paths that panic implicitly. I'm not a fan of baking in panics — I reserve that for algorithmic failures, not data-driven ones.
See also:
Why is it discouraged to accept a reference to a String (&String), Vec (&Vec), or Box (&Box) as a function argument?
My answer is similar to Shepmaster's answer, but maybe a little more practical since it doesn't consume the argument to foo2 and it gives you a reference to the target instead of taking it out of the container.
I never have any luck implementing traits based on other traits so I didn't try to do that here.
use std::ops::Deref;
use std::rc::Rc;
use std::sync::{Arc, Mutex, MutexGuard};
fn foo(n: i32) {
println!("n = {}", n)
}
trait Holding<T> {
type Holder: Deref<Target = T>;
fn held(self) -> Self::Holder;
}
fn foo2<H: Holding<i32>>(x: H) {
let h = x.held();
println!("x = {}", *h);
}
impl<'a, T: 'a> Holding<T> for &'a T {
type Holder = &'a T;
fn held(self) -> Self::Holder {
self
}
}
impl<'a, T> Holding<T> for &'a Rc<T> {
type Holder = &'a T;
fn held(self) -> Self::Holder {
&**self
}
}
impl<'a, T> Holding<T> for &'a Mutex<T> {
type Holder = MutexGuard<'a, T>;
fn held(self) -> Self::Holder {
// this can panic
self.lock().unwrap()
}
}
impl<'a, T> Holding<T> for &'a Arc<Mutex<T>> {
type Holder = MutexGuard<'a, T>;
fn held(self) -> Self::Holder {
// this can panic
(*self).lock().unwrap()
}
}
fn main() {
let a = 1;
let b = Rc::new(2);
let c = Mutex::new(3);
let d = Arc::new(Mutex::new(4));
foo(a);
foo(*b);
foo(*(c.lock().unwrap()));
foo(*((*d).lock().unwrap()));
foo2(&a);
foo2(&b);
foo2(&c);
foo2(&d);
}
I am writing a command line application in rust for processing audio from a sensor. I would like the user to be able to choose an algorithm or filter to apply from several options. I was hoping to use dynamic dispatch to switch out a struct which implements my filter trait at runtime. However, this is not allowed by the compiler, because one of the trait methods takes a generic parameter.
How could I implement this same functionality, without causing any compiler troubles? I know that an easy solution is to change the parameter of the process method to an array or a vector, but this is my last resort, as I would much prefer to take an iterator or an IntoIterator, as it is more general, and suits my specific needs.
Here is some code which demonstrates the problem.
trait SensorFilter {
fn process(&self, sig: &mut impl Iterator<Item = f32>) -> Vec<f32>;
}
struct Alg1 {
mul: f32,
}
struct Alg2 {
add: f32,
}
impl SensorFilter for Alg1 {
fn process(&self, sig: &mut impl Iterator<Item = f32>) -> Vec<f32> {
sig.map(|x| x * self.mul).collect()
}
}
impl SensorFilter for Alg2 {
fn process(&self, sig: &mut impl Iterator<Item = f32>) -> Vec<f32> {
sig.map(|x| x * self.add).collect()
}
}
enum AlgChoice {
Alg1,
Alg2
}
fn main() {
let choice = AlgChoice::Alg1; // user chooses via command-line.
let mut sig = vec![0.,1.,2.,3.,4.,5.,6.].into_iter(); // iterator gets data from sensor.
// This doesn't work, because my trait cannot be made into an object.
let alg: &dyn SensorFilter = match choice {
AlgChoice::Alg1 => Alg1{mul:0.3},
_ => Alg2{add:1.2},
};
let result = alg.process(&mut sig);
println!("{:?}",result);
}
Thanks :)
The trick here is to change your generic function parameter to a generic trait parameter:
// Make the generic param into a type argument w/ constraints
trait SensorFilter<I> where I: Iterator<Item = f32> {
fn process(&self, sig: &mut I) -> Vec<f32>;
}
struct Alg1 {
mul: f32,
}
struct Alg2 {
add: f32,
}
// Implement trait for all I that match the iterator constraint
impl<I: Iterator<Item = f32>> SensorFilter<I> for Alg1 {
fn process(&self, sig: &mut I) -> Vec<f32> {
sig.map(|x| x * self.mul).collect()
}
}
impl<I: Iterator<Item = f32>> SensorFilter<I> for Alg2 {
fn process(&self, sig: &mut I) -> Vec<f32> {
sig.map(|x| x * self.add).collect()
}
}
enum AlgChoice {
Alg1,
Alg2
}
fn main() {
let choice = AlgChoice::Alg1; // user chooses via command-line.
let mut sig = vec![0.,1.,2.,3.,4.,5.,6.].into_iter(); // iterator gets data from sensor.
// Specify the type argument of your trait.
let alg: &dyn SensorFilter<std::vec::IntoIter<f32>> = match choice {
AlgChoice::Alg1 => &Alg1{mul:0.3},
_ => &Alg2{add:1.2},
};
let result = alg.process(&mut sig);
println!("{:?}",result);
}
The simplest way to make SensorFilter object safe is to simply change process to accept dyn Iterator instead of impl Iterator:
trait SensorFilter {
fn process(&self, sig: &mut dyn Iterator<Item = f32>) -> Vec<f32>;
}
If you couldn't do this, for example because Iterator were actually non-object-safe, you could instead extract the common, non-object-safe part into a second trait, and implement it automatically for everything that is SensorFilter:
// This trait is object-safe.
trait SensorFilter {
fn filter(&self, x: f32) -> f32;
}
// This trait will not be object-safe because it uses generics.
trait Process {
fn process<I: IntoIterator<Item = f32>>(&self, sig: I) -> Vec<f32>;
}
// The `?Sized` bound allows you to call `.process()` on `dyn SensorFilter`.
impl<T: ?Sized + SensorFilter> Process for T {
fn process<I: IntoIterator<Item = f32>>(&self, sig: I) -> Vec<f32> {
sig.into_iter().map(|x| self.filter(x)).collect()
}
}
// ...
impl SensorFilter for Alg1 {
fn filter(&self, x: f32) -> f32 {
x * self.mul
}
}
impl SensorFilter for Alg2 {
fn filter(&self, x: f32) -> f32 {
x * self.add
}
}
Playground
Note that instead of Iterator I used IntoIterator, which is strictly more general.
A variation on this idea, when you can't easily remove the genericity from SensorFilter, is to use double dispatch: write SensorFilter to use dyn Iterator instead of impl Iterator, and then write a convenience trait that just wraps it with the specific type:
trait SensorFilter {
fn process_dyn(&self, sig: &mut dyn Iterator<Item = f32>) -> Vec<f32>;
}
trait Process {
fn process<I: IntoIterator<Item = f32>>(&self, sig: I) -> Vec<f32>;
}
impl<T: ?Sized + SensorFilter> Process for T {
fn process<I: IntoIterator<Item = f32>>(&self, sig: I) -> Vec<f32> {
self.process_dyn(&mut sig.into_iter())
}
}
I have this code:
use std::fmt::Debug;
struct S<A>
where
for<'a> A: Debug + 'a,
{
f: Box<Fn(A) -> i32>,
}
impl<A> S<A>
where
for<'a> A: Debug + 'a,
{
fn call(&self, a: A) {
println!("Return {:?}", (self.f)(a));
}
}
fn create<A>(f: Box<Fn(A) -> i32>) -> S<A>
where
for<'a> A: Debug + 'a,
{
S::<A> { f }
}
fn helper() {
let x = create::<&i32>(Box::new(|x: &i32| *x * 2));
let arg = 333;
x.call(&arg);
}
fn main() {
let x = helper();
}
It's failed to compile:
error[E0310]: the parameter type `A` may not live long enough
In code 2, I changed Fn(A) -> i32 to Fn(&A) -> i32, the code works.
...
f: Box<Fn(&A) -> i32>,
...
Since A is argument of Fn trait, it's a type that has Higher-Rank lifetime. It shouldn't be affected by the lifetime of struct S<A> .
But why can't code 1 be compiled?
How can I workaround it for borrow or non-borrow type A?
There is no easy way to make helper work in current Rust, even if you remove all the for<'a> A: Debug + 'a, bounds (which only further restricts what types A can be, whereas you want to allow more).
This is as simple as I can make your example:
struct S<A> {
f: Box<Fn(A) -> i32>,
}
impl<A> S<A> {
fn call(&self, a: A) {
println!("Return {:?}", (self.f)(a));
}
}
fn create<A>(f: Box<Fn(A) -> i32>) -> S<A> {
S { f }
}
fn helper() {
let x = create(Box::new(|x: &i32| *x * 2));
let arg = 333;
x.call(&arg);
}
fn main() {
helper();
}
The reason it doesn't work is that A "comes from the outside", and Rust can't infer that you want for<'a> S<&'a A>, it can't even talk about such a type.
Note that if let arg = 333; is placed above let x, this example does compile (because it infers a reference to arg specifically, not a for<'a>).
The closest you can get today is with an associated type on a trait with a lifetime parameter, e.g.:
// Emulating `type Type<'a>` by moving `'a` to the trait.
trait Apply<'a> {
type Type;
}
struct Plain<T>(std::marker::PhantomData<T>);
impl<'a, T> Apply<'a> for Plain<T> {
type Type = T;
}
struct Ref<T: ?Sized>(std::marker::PhantomData<T>);
impl<'a, T: ?Sized + 'a> Apply<'a> for Ref<T> {
type Type = &'a T;
}
struct S<A: for<'a> Apply<'a>> {
f: Box<for<'a> Fn(<A as Apply<'a>>::Type) -> i32>,
}
impl<A: for<'a> Apply<'a>> S<A> {
fn call<'a>(&self, a: <A as Apply<'a>>::Type) {
println!("Return {:?}", (self.f)(a));
}
}
fn create<A: for<'a> Apply<'a>>(
f: Box<for<'a> Fn(<A as Apply<'a>>::Type) -> i32>,
) -> S<A> {
S { f }
}
fn helper() {
let x = create::<Ref<i32>>(Box::new(|x: &i32| *x * 2));
let arg = 333;
x.call(&arg);
}
fn main() {
helper();
}
However, it turns out that this encoding hits https://github.com/rust-lang/rust/issues/52812, so it's not actually usable at the moment (and I'm not aware of an workaround).
(Hi), I have tow questions concerning generics in rust:
1-I'm trying to port some C++ boost like concepts to rust (here an example with a 2D point):
#![feature(associated_types)]
pub trait Point2D {
type value_type;
fn x(&self) -> &<Self as Point2D>::value_type;
fn y(&self) -> &<Self as Point2D>::value_type;
}
#[deriving(Show)]
pub struct Point2<T> {
x : T,
y : T,
}
impl<T> Point2D for Point2<T> {
type value_type = T;
#[inline]
fn x(&self) -> &T {
&self.x
}
#[inline]
fn y(&self) -> &T {
&self.y
}
}
fn main(){
let mut p = Point2{x: 0i32, y : 0i32};
println!("p = {}", p);
//*p.x() = 1i32; //error: cannot assign to immutable dereference of `&`-pointer
}
Here what I want is that x() and y() return a reference to mutable T when T is mutable, and an immutable reference otherwise, is it possible ?
I saw some internals talks about parametric mutability but I didn't find any established RFC.
2- Is there any plans to add parametrization over numeric values (like template<size_t n>) to rust ?
thanks
Update: so I guest for now the only solution is something like that :
#![feature(associated_types)]
pub trait Point2D {
type value_type;
fn x_as_mut(&mut self) -> &mut <Self as Point2D>::value_type;
fn y_as_mut(&mut self) -> &mut <Self as Point2D>::value_type;
fn x_as_ref(&self) -> &<Self as Point2D>::value_type;
fn y_as_ref(&self) -> &<Self as Point2D>::value_type;
}
#[deriving(Show)]
pub struct Point2<T> {
x : T,
y : T,
}
impl<T> Point2D for Point2<T> {
type value_type = T;
#[inline]
fn x_as_mut(&mut self) -> &mut T {
&mut self.x
}
#[inline]
fn y_as_mut(&mut self) -> &mut T {
&mut self.y
}
#[inline]
fn x_as_ref(&self) -> &T {
&self.x
}
#[inline]
fn y_as_ref(&self) -> &T {
&self.y
}
}
trait Channel {
}
fn main(){
let mut p1 = Point2{x: 0i32, y : 0i32};
println!("p1 = {}", p1);
*p1.x_as_mut() = 1i32;
println!("p1 = {}", p1);
let p2 = Point2{x:0u8, y:10u8};
println!("p2 = {}", p2.y_as_ref());
}
Any cleaner way ?
There is no parametric mutability. I know that several people have expressed a strong desire for something along those lines, but I'm not aware of any actual plans as yet.
There is also no generic value parameters. I believe the core team definitely wants it, but it's not a priority right now.