Pointer to a self-defined struct in Rust with raw pointers - pointers

I am implementing some structures to be used with search algorithms. These structures are to be stored in a Linked List during the execution of a program. After struggling a bit with integrating pointers in Rust I decided to do design the structures as it follows.
The following data structures was created to store the state:
pub struct Cell {
map: Map,
cost: CostType,
player: Agent
}
The following data structure was created to store the information of a cell, its parent, and its child.
struct Node {
state: *mut cell::Cell,
parent: *mut cell::Cell,
childs: [*mut cell::Cell; 4],
}
Implementing the constructors (new() methods) for this data structure is being troublesome. I know I am using raw pointers instead of the smart pointers, but it is the purpose for now. There is for sure something wrong with my syntax in the declaration of the method, but cannot find many references to sort this out. The implementation of the method for creating a new instance of a Node is the following:
fn new_node() -> Node{
Node{
state: &cell::Cell::new_cell() as *mut cell::Cell,
parent: &cell::Cell::new_cell() as *mut cell::Cell,
childs: [&cell::Cell::new_cell() as *mut cell::Cell, &cell::Cell::new_cell() as *mut cell::Cell,
&cell::Cell::new_cell() as *mut cell::Cell, &cell::Cell::new_cell() as *mut cell::Cell]
}
}
When I do this, the error that I obtain is the following one:
error[E0606]: casting `&node::cell::Cell` as `*mut node::cell::Cell` is invalid
--> src/node/node.rs:15:20
|
15 | state: &cell::Cell::new_cell() as *mut cell::Cell,
Using ptr::null_mut::cell::Cell() solves the issue, but I would like to know if there are any ways of solving this with the pointer operators.

You are trying to cast a shared reference into a mutable pointer, that is not allowed by default. You can do a double cast, of course,:
&cell::Cell::new_cell() as *const cell::Cell as *mut cell::Cell
But if later you use that pointer to modify the object you will invoke Undefined Behavior, as the pointer was created from a shared reference.
Besides you are getting a pointer to a temporary, assuming new_cell() is defined are returning a Cell, so the pointer is dangling as soon your expresion ends and the temporaries are destroyed. Any use of that pointer will also be Undefined Behavior.
You probably want something like this:
Box::into_raw(Box::new(Cell::new_cell()))
That is, do a dynamic allocation and convert it
into a unmanaged pointer. And it already returns a properly obtained mutable pointer, so no cast is needed.
When you want to delete the cell do:
let _ = Box::from_raw(self.state);
The let _ is not actually needed but it help to document that you are intentionally discarding the returned box, that will be dropped and the cell properly disposed.
But this is Rust, not C, and you should really not be doing this, (unless you do it just for fun). An Rc<RefCell<Cell>> will get you a long way.

&mut cell::Cell::new_cell() as *mut cell::Cell

Related

Using dyn async traits (with async-trait crate) in spawned tokio task

I'm working on an asynchronous rust application which utilizes tokio. I'd also like to define some trait methods as async and have opted for the async-trait crate rather than the feature in the nightly build so that I can use them as dyn objects. However, I'm running into issues trying to use these objects in a task spawned with tokio::spawn. Here's a minimal complete example:
use std::time::Duration;
use async_trait::async_trait;
#[tokio::main]
async fn main() {
// These two lines based on the examples for dyn traits in the async-trait create
let value = MyStruct::new();
let object = &value as &dyn MyTrait;
tokio::spawn(async move {
object.foo().await;
});
}
#[async_trait]
trait MyTrait {
async fn foo(&self);
}
struct MyStruct {}
impl MyStruct {
fn new() -> MyStruct {
MyStruct {}
}
}
#[async_trait]
impl MyTrait for MyStruct {
async fn foo(&self) {
tokio::time::sleep(Duration::from_secs(1)).await;
}
}
When I compile this I get the following output:
error: future cannot be sent between threads safely
--> src/main.rs:11:18
|
11 | tokio::spawn(async move {
| __________________^
12 | | object.foo().await;
13 | | });
| |_____^ future created by async block is not `Send`
|
= help: the trait `Sync` is not implemented for `dyn MyTrait`
note: captured value is not `Send` because `&` references cannot be sent unless their referent is `Sync`
--> src/main.rs:12:9
|
12 | object.foo().await;
| ^^^^^^ has type `&dyn MyTrait` which is not `Send`, because `dyn MyTrait` is not `Sync`
note: required by a bound in `tokio::spawn`
--> /home/wilyle/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.25.0/src/task/spawn.rs:163:21
|
163 | T: Future + Send + 'static,
| ^^^^ required by this bound in `spawn`
error: could not compile `async-test` due to previous error
(The results are similar when making object boxed with let object: Box<dyn MyTrait> = Box::new(MyStruct::new()); and when moving the construction fully inside the tokio::spawn call)
By messing around and trying a few things I found that I could solve the issue by boxing object and adding additional trait bounds. Replacing the first two lines of main in my example with the following seems to work just fine:
let object: Box<dyn MyTrait + Send + Sync> = Box::new(MyStruct::new());
So I have two questions:
Why doesn't my original example work? Is it some inconsistency between the two libraries I'm trying to use or am I approaching async programming in rust incorrectly?
Is the solution of adding additional trait bounds the right way to solve this? I'm rather new to rust and have only been programming with it for a few months so I wouldn't be surprised to hear I'm just approaching this wrong.
If you're not sure what Send and Sync mean, check out those documentation links. Something to note is that if T is Sync, then &T is Send.
Question #2 is simple: yes this is the right way to do it. async-trait uses Pin<Box<dyn Future + Send>> as its return type for basically the same reasons. Note that you can only add auto traits to trait objects.
For question #1, there's two issues: Send and 'static.
Send
When you cast something as dyn MyTrait, you're removing all the original type information and replacing it with the type dyn MyTrait. That means you lose the auto-implemented Send and Sync traits on MyStruct. The tokio::spawn function requires Send.
This issue isn't inherent to async, it's because tokio::spawn will run the future on its threadpool, possibly sending it to another thread. You can run the future without tokio::spawn, for example like this:
fn main() {
let runtime = tokio::runtime::Runtime::new().unwrap();
let value = MyStruct::new();
let object = &value as &dyn MyTrait;
runtime.block_on(object.foo());
}
The block_on function runs the future on the current thread, so Send is not necessary. And it blocks until the future is done, so 'static is also not needed. This is great for things that are created at runtime and contain the entire logic of the program, but for dyn Trait types you usually have other things going on that makes this not as useful.
'static
When something requires 'static, it means that all references need to live as long as 'static. One way of satisfying that is to remove all references. In an ideal world you could do:
let object = value as dyn MyTrait;
However, rust doesn't support dynamically sized types on the stack or as function arguments. We're trying to remove all references, so &dyn MyTrait isn't going to work (unless you leak or have a static variable). Box lets you have ownership over dynamically sized types by putting them on the heap, eliminating the lifetime.
You need Send for this because the upgrade from Sync to Send only happens with &, not Box. Instead, Box<T> is Send when T is Send.
Sync is more subtle. While spawn doesn't require Sync, the async block does require Send + Sync to be Send. Since foo takes &self, that means it returns a Future that holds &self. That type is then polled, so in between polls &self could be sent in between threads. And as before, &T is Send if T is Sync. However, if you change it to foo(&mut self) it compiles without + Sync. Makes sense since now it can check that it's not being used concurrently, but it seems to me like the &self verison could be allowed in the future.

Rust, std::cell::Cell - get immutable reference to inner data

Looking through the documentation for std::cell::Cell, I don't see anywhere how I can retrieve a non-mutable reference to inner data. There is only the get_mut method: https://doc.rust-lang.org/std/cell/struct.Cell.html#method.get_mut
I don't want to use this function because I want to have &self instead of &self mut.
I found an alternative solution of taking the raw pointer:
use std::cell::Cell;
struct DbObject {
key: Cell<String>,
data: String
}
impl DbObject {
pub fn new(data: String) -> Self {
Self {
key: Cell::new("some_uuid".into()),
data,
}
}
pub fn assert_key(&self) -> &str {
// setup key in the future if is empty...
let key = self.key.as_ptr();
unsafe {
let inner = key.as_ref().unwrap();
return inner;
}
}
}
fn main() {
let obj = DbObject::new("some data...".into());
let key = obj.assert_key();
println!("Key: {}", key);
}
Is there any way to do this without using unsafe? If not, perhaps RefCell will be more practical here?
Thank you for help!
First of, if you have a &mut T, you can trivially get a &T out of it. So you can use get_mut to get &T.
But to get a &mut T from a Cell<T> you need that cell to be mutable, as get_mut takes a &mut self parameter. And this is by design the only way to get a reference to the inner object of a cell.
By requiring the use of a &mut self method to get a reference out of a cell, you make it possible to check for exclusive access at compile time with the borrow checker. Remember that a cell enables interior mutability, and has a method set(&self, val: T), that is, a method that can modify the value of a non-mut binding! If there was a get(&self) -> &T method, the borrow checker could not ensure that you do not hold a reference to the inner object while setting the object, which would not be safe.
TL;DR: By design, you can't get a &T out of a non-mut Cell<T>. Use get_mut (which requires a mut cell), or set/replace (which work on a non-mut cell). If this is not acceptable, then consider using RefCell, which can get you a &T out of a non-mut instance, at some runtime cost.
In addition to to #mcarton answer, in order to keep interior mutability sound, that is, disallow mutable reference to coexist with other references, we have three different ways:
Using unsafe with the possibility of Undefined Behavior. This is what UnsafeCell does.
Have some runtime checks, involving runtime overhead. This is the approach RefCell, RwLock and Mutex use.
Restrict the operations that can be done with the abstraction. This is what Cell, Atomic* and (the unstable) OnceCell (and thus Lazy that uses it) does (note that the thread-safe types also have runtime overhead because they need to provide some sort of locking). Each provides a different set of allowed operations:
Cell and Atomic* do not let you to get a reference to the contained value, and only replace it as whole (basically, get() and set, though convenience methods are provided on top of these, such as swap()). Projection (cell-of-slice to slice-of-cells) is also available for Cell (field projection is possible, but not provided as part of std).
OnceCell allows you to assign only once and only then take shared reference, guaranteeing that when you assign you have no references and while you have shared references you cannot assign anymore.
Thus, when you need to be able to take a reference into the content, you cannot choose Cell as it was not designed for that - the obvious choice is RefCell, indeed.

How can I pass multiple elements from a collection into a function with one or more of the elements being mutable?

When passing two elements from the same vector to a function, the borrow checker will not allow one of the elements to be mutable.
struct Point {
x: i32,
y: i32,
}
fn main() {
let mut vec: Vec<Point> = Vec::new();
foo(&mut vec[0], &vec[1]);
}
fn foo(pnt_1: &mut Point, pnt_2: &Point) {
}
error: cannot borrow vec as immutable because it is also borrowed as mutable
vec is never borrowed by foo though, vec[0] is borrowed and vec[0] is a Point.
How can I pass multiple elements from the same collection into a function with one or more of the elements being mutable?
How can I pass multiple elements from the same collection into a function with one or more of the elements being mutable?
The short answer is that you cannot, at least not without support from the collection itself.
Rust disallows mutable aliases - multiple names for the same thing, one of which allows mutation.
It would be far too complicated (with the current state of programming languages) to verify that (&mut vec[0], &vec[1]) does not introduce aliasing but (&mut vec[0], &vec[0]) does. Adding to the complexity is the fact that the [] operator can be overloaded, which allows creating a type such that foo[0] and foo[1] actually point at the same thing.
So, how can a collection help out? Each collection will have (or not have) a specific way of subdivision in an aliasing-safe manner.
There can be methods like slice::split_at_mut which verify that that two halves cannot overlap and thus no aliasing can occur.
Unfortunately, there's no HashMap::get_two_things(&a, &b) that I'm aware of. It would be pretty niche, but that doesn't mean it couldn't exist.
vec is never borrowed by foo though
It most certainly is. When you index a Vec, you are getting a reference to some chunk of memory inside the Vec. If the Vec were to change underneath you, such as when someone adds or removes a value, then the underlying memory may need to be reallocated, invalidating the reference. This is a prime example of why mutable aliasing is a bad thing.

Difference in mutability between reference and box

I'm trying to understand Rust pointer types and their relation to mutability. Specifically, the ways of declaring a variable which holds the pointer and is itself mutable -- i.e. can be pointed to some other memory, and declaring that the data itself is mutable -- i.e. can be changed through the value of the pointer variable.
This is how I understand plain references work:
let mut a = &5; // a is a mutable pointer to immutable data
let b = &mut 5; // b is an immutable pointer to mutable data
So a can be changed to point to something else, while b can't. However, the data to which b points to can be changed through b, while it can't through a. Do I understand this correctly?
For the second part of the question -- why does Box::new seem to behave differently? This is my current understanding:
let mut a = Box::new(5); // a is a mutable pointer to mutable data
let c = Box::new(7); // c is an immutable pointer to immutable data
new should return a pointer to some heap-allocated data, but the data it points to seems to inherit mutability from the variable which holds the pointer, unlike in the example with references where these two states of mutability are independent! Is that how Box::new is supposed to work? If so, how can I create a pointer value to mutable data on the heap that is stored in an immutable variable?
First, you do understand how references behave correctly. mut a is a mutable variable (or, more correctly, a mutable binding), while &mut 5 is a mutable reference pointing to a mutable piece of data (which is implicitly allocated on the stack for you).
Second, Box behaves differently from references because it is fundamentally different from references. Another name for Box is owning/owned pointer. Each Box owns the data it holds, and it does so uniquely, therefore mutability of this data is inherited from mutability of the box itself. So yes, this is exactly how Box should work.
Another, probably more practical, way to understand it is to consider Box<T> exactly equivalent to just T, except of fixed size and allocation method. In other words, Box provides value semantics: it is moved around just like any value and its mutability depends on the binding it is stored in.
There are several ways to create a pointer to a mutable piece of data on the heap while keeping the pointer immutable. The most generic one is RefCell:
use std::cell::RefCell;
struct X { id: u32 }
let x: Box<RefCell<X>> = Box::new(RefCell::new(X { id: 0 }));
x.borrow_mut().id = 1;
Alternatively, you can use Cell (for Copy types):
let x: Box<Cell<u32>> = Box::new(Cell::new(0));
x.set(1);
Note that the above examples are using so-called "internal mutability" which should better be avoided unless you do need it for something. If you want to create a Box with mutable interior only to keep mutability properties, you really shouldn't. It isn't idiomatic and will only result in a syntactic and semantic burden.
You can find a lot of useful information here:
Ownership
References and borrowing
Mutability
std::cell - internal mutability types
In fact, if you have a question about such fundamental things as mutability, it is probably already explained in the book :)

How to return reference to locally allocated struct/object? AKA error: `foo` does not live long enough

Here's a simplified example of what I'm doing:
struct Foo ...
impl io::Read for Foo ...
fn problem<'a>() -> io::Result<&'a mut io::Read> {
// foo does not live long enough, because it gets allocated on the stack
let mut foo = Foo{ v: 42 };
Ok(&mut foo)
}
Rust playground is here.
Obviously, the problem is that foo is allocated on the stack, so if we return a reference to it, the reference outlives the object.
In C, you'd get around this by using malloc to allocate the object on the heap, and the caller would need to know to call free when appropriate. In a GCed language, this would just work since foo would stick around until there are no references to it. Rust is really clever, and kind of in-between, so I'm not sure what my options are.
I think one option would be to return a managed pointer type. Is Box the most appropriate? (I found a guide to pointers in rust, but it is way outdated.)
The reason I'm returning a reference is that in reality I need to return any of several structs which implement Read. I suppose another option would be to create an enum to wrap each of the possible structs. That would avoid heap allocation, but seems needlessly awkward.
Are there other options I haven't thought of?
Replacing the reference with a Box compiles successfully:
fn problem<'a>() -> io::Result<Box<io::Read>> {
let mut foo = Foo{ v: 42 };
Ok(Box::new(foo))
}
Can you use static type? Looks like in either C or rust, static variable lasts as long as the program does - even if it's a static local.
http://rustbyexample.com/scope/lifetime/static_lifetime.html

Resources