Unexpected auto deref behavior - rust

when tried impl a double linked list in rust, i found below unexpected error
if let Some(link) = self.tail.take() {
let x = link.borrow_mut();
link.borrow_mut().next = Some(node.clone());
} else { ... }
here link is inferred to be Rc<RefCell<Node<..>>> and compiler says:
Cannot borrow immutable local variable link as mutable.
After tried, I guess when use std::borrow::BorrowMut, the error occurs.
// compiles
fn test1() {
let a = Rc::new(RefCell::new(1));
let b = RefCell::new(1);
b.borrow_mut();
a.borrow_mut();
}
// doesn't compile
fn test2() {
use std::borrow::BorrowMut; // inserted this import!
let a = Rc::new(RefCell::new(1));
let b = RefCell::new(1);
b.borrow_mut();
a.borrow_mut();
}
here test2() fails to be compiled. I wanna know why it works this way.

What you want to call is the method RefCell::borrow_mut().
However, a is a Rc and not a RefCell, so it has no borrow_mut method. This is where auto-dereferencing enters the picture. Because Rc<RefCell<T>> implements the Deref trait, it can be automatically dereferenced to a &RefCell<T> at method calls, and that's exactly what happens in the first test.
Now, if we import the BorrowMut trait, the test stops working. This is because the BorrowMut trait also has a method called borrow_mut, which is implemented for all types:
impl<T: ?Sized> BorrowMut<T> for T { ... }
This means that there is now a borrow_mut method available for Rc, so no auto-dereferencing occurs, and our code calls the wrong method.
The most comprehensive explanation of how auto-dereferencing works is in this SO answer.

Related

In Rust, why can higher-level references be assigned to lower-level references, and why not the other way around?

Rust allows assigning references with a higher level of indirection to references with a lower level of indirection. For instance, the compiler allows assigning a &&&&&& to a &:
fn main() {
let mut some_number = 5;
// assign an &&&&&&i32 to an &i32, which works.
let reference : &i32 = &&&&&&some_number;
}
This also works for function parameters:
fn main() {
let num = 5;
// ref1 is an &&i32
let ref1 = &&num;
// Pass an &&i32 to a function parameter, which itself is an &i32 (works)
func(ref1);
}
fn func(test: &i32) {
println!("^^^^ This works!");
}
I've learned that this works because of automatic dereferencing, which allows the Rust compiler to dereference a type as much as it needs to match some other type (please correct me if I'm wrong on this).
However, Rust doesn't seem to allow assigning lower-indirection references to higher-indirection references:
fn main() {
let num = 5;
// Try assigning an &i32 to an &&i32 (error)
let ref1 : &&i32 = &num;
}
This results in an expected &i32, found integer compiler error. We get a similar compiler error when testing this with function parameters:
fn main() {
let num = 5;
// ref1 is an &&&i32
let ref1 = &&&num;
// Try passing an &&&i32 to a function parameter of type &&&&&i32 (error)
func(ref1);
}
fn func(test: &&&&&i32) {
println!("^^^^^^^^ This does not work!")
}
Here, we get a mismatched types error as well. Something I'm curious about, however, is that the compiler output isn't exactly what we expect. Rather than expected &&&&&i32, found &&&i32, the compiler error is expected &&i32, found integer. It seems that the compiler dereferenced both references until one was no longer a reference - why does it dereference both references? I thought it only dereferenced whatever was being passed to the function.
Overall, my main question is
Why, exactly, should assigning lower-indirection to higher-indirection references be disallowed when assigning higher-indirection to lower-indirection references is allowed? What is so different about these two things, that their behaviors must be different as well?
&&T can be coerced to &T because of deref coercion ("&T or &mut T to &U if T implements Deref<Target = U>") and the impl Deref<Target = T> for &T the other way is not possible because there exists no impl Deref<Target = &T> for T.
By repeatet application &&&&&&T can be coerced to &T
As to why one is allowed while the other isn't well if implicit referencing was allowed everywhere tracking ownership would be even harder than it currently is, we have this problem already with auto-referencing of method receivers.
let s = String::from("Hello");
my_fun(s);
The question "Does s get moved?" can't be answered without looking at the definition of my_fun if we allow automatic referencing.

How to store async closure created at runtime in a struct?

I'm learning Rust's async/await feature, and stuck with the following task. I would like to:
Create an async closure (or better to say async block) at runtime;
Pass created closure to constructor of some struct and store it;
Execute created closure later.
Looking through similar questions I wrote the following code:
use tokio;
use std::pin::Pin;
use std::future::Future;
struct Services {
s1: Box<dyn FnOnce(&mut Vec<usize>) -> Pin<Box<dyn Future<Output = ()>>>>,
}
impl Services {
fn new(f: Box<dyn FnOnce(&mut Vec<usize>) -> Pin<Box<dyn Future<Output = ()>>>>) -> Self {
Services { s1: f }
}
}
enum NumberOperation {
AddOne,
MinusOne
}
#[tokio::main]
async fn main() {
let mut input = vec![1,2,3];
let op = NumberOperation::AddOne;
let s = Services::new(Box::new(|numbers: &mut Vec<usize>| Box::pin(async move {
for n in numbers {
match op {
NumberOperation::AddOne => *n = *n + 1,
NumberOperation::MinusOne => *n = *n - 1,
};
}
})));
(s.s1)(&mut input).await;
assert_eq!(input, vec![2,3,4]);
}
But above code won't compile, because of invalid lifetimes.
How to specify lifetimes to make above example compile (so Rust will know that async closure should live as long as input). As I understand in provided example Rust requires closure to have static lifetime?
Also it's not clear why do we have to use Pin<Box> as return type?
Is it possible somehow to refactor code and eliminate: Box::new(|arg: T| Box::pin(async move {}))? Maybe there is some crate?
Thanks
Update
There is similar question How can I store an async function in a struct and call it from a struct instance?
. Although that's a similar question and actually my example is based on one of the answers from that question. Second answer contains information about closures created at runtime, but seems it works only when I pass an owned variable, but in my example I would like to pass to closure created at runtime mutable reference, not owned variable.
How to specify lifetimes to make above example compile (so Rust will know that async closure should live as long as input). As I understand in provided example Rust requires closure to have static lifetime?
Let's take a closer look at what happens when you invoke the closure:
(s.s1)(&mut input).await;
// ^^^^^^^^^^^^^^^^^^
// closure invocation
The closure immediately returns a future. You could assign that future to a variable and hold on to it until later:
let future = (s.s1)(&mut input);
// do some other stuff
future.await;
The problem is, because the future is boxed, it could be held around for the rest of the program's life without ever being driven to completion; that is, it could have 'static lifetime. And input must obviously remain borrowed until the future resolves: else imagine, for example, what would happen if "some other stuff" above involved modifying, moving or even dropping input—consider what would then happen when the future is run?
One solution would be to pass ownership of the Vec into the closure and then return it again from the future:
let s = Services::new(Box::new(move |mut numbers| Box::pin(async move {
for n in &mut numbers {
match op {
NumberOperation::AddOne => *n = *n + 1,
NumberOperation::MinusOne => *n = *n - 1,
};
}
numbers
})));
let output = (s.s1)(input).await;
assert_eq!(output, vec![2,3,4]);
See it on the playground.
#kmdreko's answer shows how you can instead actually tie the lifetime of the borrow to that of the returned future.
Also it's not clear why do we have to use Pin as return type?
Let's look at a stupidly simple async block:
async {
let mut x = 123;
let r = &mut x;
some_async_fn().await;
*r += 1;
x
}
Notice that execution may pause at the await. When that happens, the incumbent values of x and r must be stored temporarily (in the Future object: it's just a struct, in this case with fields for x and r). But r is a reference to another field in the same struct! If the future were then moved from its current location to somewhere else in memory, r would still refer to the old location of x and not the new one. Undefined Behaviour. Bad bad bad.
You may have observed that the future can also hold references to things that are stored elsewhere, such as the &mut input in #kmdreko's answer; because they are borrowed, those also cannot be moved for the duration of the borrow. So why can't the immovability of the future similarly be enforced by r's borrowing of x, without pinning? Well, the future's lifetime would then depend on its content—and such circularities are impossible in Rust.
This, generally, is the problem with self-referential data structures. Rust's solution is to prevent them from being moved: that is, to "pin" them.
Is it possible somehow to refactor code and eliminate: Box::new(|arg: T| Box::pin(async move {}))? Maybe there is some crate?
In your specific example, the closure and future can reside on the stack and you can simply get rid of all the boxing and pinning (the borrow-checker can ensure stack items don’t move without explicit pinning). However, if you want to return the Services from a function, you'll run into difficulties stating its type parameters: impl Trait would normally be your go-to solution for this type of problem, but it's limited and does not (currently) extend to associated types, such as that of the returned future.
There are work-arounds, but using boxed trait objects is often the most practical solution—albeit it introduces heap allocations and an additional layer of indirection with commensurate runtime cost. Such trait objects are however unavoidable where a single instance of your Services structure may hold different closures in s1 over the course of its life, where you're returning them from trait methods (which currently can’t use impl Trait), or where you're interfacing with a library that does not provide any alternative.
If you want your example to work as is, the missing component is communicating to the compiler what lifetime associations are allowed. Trait objects like dyn Future<...> are constrained to be 'static by default, which means it cannot have references to non-static objects. This is a problem because your closure returns a Future that needs to keep a reference to numbers in order to work.
The direct fix is to annotate that the dyn FnOnce can return a Future that can be bound to the life of the first parameter. This requires a higher-ranked trait bound and the syntax looks like for<'a>:
struct Services {
s1: Box<dyn for<'a> FnOnce(&'a mut Vec<usize>) -> Pin<Box<dyn Future<Output = ()> + 'a>>>,
}
impl Services {
fn new(f: Box<dyn for<'a> FnOnce(&'a mut Vec<usize>) -> Pin<Box<dyn Future<Output = ()> + 'a>>>) -> Self {
Services { s1: f }
}
}
The rest of your code now compiles without modification, check it out on the playground.

Calling map on an Option<Rc<Struct>> works differently than calling it on a Option<Rc<i32>>

I'm new to Rust and I'm trying to figure out why Rc is behaving differently when being passed to a closure. My full code is the following:
use std::rc::Rc;
struct Something {
value: i32
}
fn main() {
let wrapped_struct = Some(Rc::new(Something { value: 1 }));
let wrapped_integer = Some(Rc::new(1));
// Case 1: This works
let works: Option<i32> = wrapped_struct.map(|i| { i.value });
// Case 2: This fails
let fails: Option<i32> = wrapped_integer.map(|i| { i });
}
The error message is:
|
13 | let fails: Option<i32> = wrapped_integer.map(|i| { i });
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected i32, found struct `std::rc::Rc`
|
= note: expected type `std::option::Option<i32>`
found type `std::option::Option<std::rc::Rc<{integer}>>`
What I don't understand is why in the first closure (Case 1) I can use i as a Something (I'd expect Rc<Something>) but in the second one (Case 2) I can't use i as an i32 (I actually get an Rc<i32>).
I appreciate any pointers to the relevant documentation. Thanks a lot!
The type of the i in both closures is actually Rc<Something> and Rc<i32> respectively. Rc can be dereferenced to access its inner data, but there are places in Rust where dereferencing happens automatically, for convenience.
In the struct case, when you write i.value, it will automatically dereference i to access the field. It then returns a copy of the i32, because i32 is a Copy type. So the type of the expression i.value is i32. It's as if you wrote (*i).value, but Rust did the dereferencing for you.
In the i32 case, you are just returning the i, which still has type Rc<i32>. You can fix it by explicitly dereferencing:
wrapped_integer.map(|i| { *i });
See also:
What are Rust's exact auto-dereferencing rules?

Is it possible in Rust to delete an object before the end of scope?

From what I understand, the compiler automatically generates code to call the destructor to delete an object when it's no longer needed, at the end of scope.
In some situations, it is beneficial to delete an object as soon as it's no longer needed, instead of waiting for it to go out of scope. Is it possible to call the destructor of an object explicitly in Rust?
Is it possible in Rust to delete an object before the end of scope?
Yes.
Is it possible to call the destructor of an object explicitly in Rust?
No.
To clarify, you can use std::mem::drop to transfer ownership of a variable, which causes it to go out of scope:
struct Noisy;
impl Drop for Noisy {
fn drop(&mut self) {
println!("Dropping Noisy!");
}
}
fn main() {
let a = Noisy;
let b = Noisy;
println!("1");
drop(b);
println!("2");
}
1
Dropping Noisy!
2
Dropping Noisy!
However, you are forbidden from calling the destructor (the implementation of the Drop trait) yourself. Doing so would lead to double free situations as the compiler will still insert the automatic call to the the Drop trait.
Amusing side note — the implementation of drop is quite elegant:
pub fn drop<T>(_x: T) { }
The official answer is to call mem::drop:
fn do_the_thing() {
let s = "Hello, World".to_string();
println!("{}", s);
drop(s);
println!("{}", 3);
}
However, note that mem::drop is nothing special. Here is the definition in full:
pub fn drop<T>(_x: T) { }
That's all.
Any function taking ownership of a parameter will cause this parameter to be dropped at the end of said function. From the point of view of the caller, it's an early drop :)

Caught between a lifetime and an FFI place

I am caught between two different issues/bugs, and can't come up with a decent solution. Any help would be greatly appreciated
Context, FFI, and calling a lot of C functions, and wrapping C types in rust structs.
The first problem is ICE: this path should not cause illegal move.
This is forcing me to do all my struct-wrapping using & references as in:
pub struct CassResult<'a> {
result:&'a cql_ffi::CassResult
}
Instead of the simpler, and preferable:
pub struct CassResult {
result:cql_ffi::CassResult
}
Otherwise code like:
pub fn first_row(&self) -> Result<CassRow,CassError> {unsafe{
Ok(CassRow{row:*cql_ffi::cass_result_first_row(self.result)})
}}
Will result in:
error: internal compiler error: this path should not cause illegal move
Ok(CassRow{row:*cql_ffi::cass_result_first_row(self.result)})
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
So, I go ahead and wrap everything using lifetime managed references, and all is not-horrible until I try to implement an iterator. At which point I see no way around this problem.
method next has an incompatible type for trait: expected concrete lifetime, found bound lifetime parameter
So given those two conflicting issues, I am totally stuck and can't find any way to implement a proper rust iterator around a FFI iterator-like construct.
Edit: With Shep's suggestion, I get:
pub struct CassResult {
pub result:cql_ffi::CassResult
}
and
pub fn get_result(&mut future:future) -> Option<CassResult> {unsafe{
let result:&cql_ffi::CassResult = &*cql_ffi::cass_future_get_result(&mut future.future);
Some(CassResult{result:*result})
}}
but then get:
error: cannot move out of borrowed content
Some(CassResult{result:*result}
Is there any way to make that pattern work? It's repeated all over this FFI wrapping code.
Only a partial answer: use the "streaming iterator" trait and macro.
I have had a similar problem making Rust bindings around the C mysql API. The result is code like this, instead of native for syntax:
let query = format!("SELECT id_y, value FROM table_x WHERE id = {}", id_x);
let res = try!(db::run_query(&query));
streaming_for!( row, res.into_iter(), {
let id_y: usize = try!(row.convert::<usize>(0));
let value: f64 = try!(row.convert::<f64>(1));
});
Here res holds the result and frees memory on drop. The lifetime of row is tied to res:
/// Res has an attached lifetime to guard an internal pointer.
struct Res<'a>{ p: *mut c_void }
/// Wrapper created by into_iter()
struct ResMoveIter<'a>{ res: Res<'a> }
impl<'a> /*StreamingIterator<'a, Row<'a>> for*/ ResMoveIter<'a>{
/// Get the next row, or None if no more rows
pub fn next(&'a mut self) -> Option<Row<'a>>{
...
}
}
#[unsafe_destructor]
impl<'a> Drop for Res<'a>{
fn drop(&mut self){
...
}
}
To answer my own question. The only decent answer was a way around the original ICE, but as thepowersgang comments, the correct way to do this now is to use :std::ptr::read, so using that approach, no ICE, and hopefully progress.

Resources