Let's say I have the following:
enum Item {
None,
Table(Table),
...
}
struct Table {
...
}
And let's say I have some table like this:
let t = &mut Table::new();
How would I go about upcasting t from a &mut Table into a &mut Item? If I try to convert directly like this:
let i = &mut Item::Table(t);
I get the error mismatched types expected struct Table, found &mut Table.
This is quite problematic.
If you don't need the same address, then you can wrap it in Item::Table. The problem is that you need to have an owned Table but you only have it borrowed. You can take it from there, but you need to leave something in its place so the reference is still valid. You can use std::mem::take() to put Default::default() inside or std::mem::replace() to put something else. You can also use the replace_with crate if you only need it temporarily.
let i = &mut Item::Table(std::mem::take(t));
let i = &mut Item::Table(std::mem::replace(t, Table::new()));
replace_with::replace_with_or_abort(t, |t| {
let mut i = Item::Table(t);
let i_ref = &mut i;
// Work with `i_ref`...
match i {
Item::Table(t) => t,
_ => unreachable!(),
}
}
If you do need it to have the same address, then you're out of luck. Item does not have the same layout as Table, and so you cannot do that.
Related
Imagine that you create a type, and for some reason, you don't want its user to be able to put it into a Vec, Rc, etc.
struct ImmovableObject<T>(T);
fn main() {
// Should cause an error, ImmovableObject can't be put in / owned by a Vec.
let mut x = vec![ImmovableObject(42)];
}
I looked into the various methods of pinning it, but they all require some form of reference. Is there a way to do this without any indirection?
I could only think of a runtime check, but it's ugly to use (basically need to check it everytime something is created). It would also have to be implemented for each type that should be banned from containing ImmovableObject, and it won't work if the ImmovableObject is contained in another object
#![feature(specialization)]
trait MaybePanic {
fn maybe_panic(&self);
}
struct ImmovableObject<T>(T);
impl<T> MaybePanic for T {
default fn maybe_panic(&self) { }
}
impl<T> MaybePanic for Vec<ImmovableObject<T>> {
fn maybe_panic(&self) { panic!("Mustn't store an ImmovableObject in a Vector"); }
}
fn main() {
let obj = ImmovableObject(42_usize);
obj.maybe_panic(); // ok
let tuple = (ImmovableObject(42_usize), );
let v = vec![tuple];
v.maybe_panic(); // ok
let v = vec![obj];
v.maybe_panic(); // runtime error
}
In Pin, we disable as_mut so we can not get a &mut for functions like std::mem::swap that will move the object.
However, somehow we need interior mutability without any moving. In the following code, SimpleNUnPin impls !Unpin so we can't move it. However, we can change its field a, this operator does not change address of the SimpleNUnPin instance.
struct SimpleNUnPin {
a: u64,
}
impl !Unpin for SimpleNUnPin {}
fn main()
{
let x = SimpleNUnPin { a: 1 };
pin_utils::pin_mut!(x);
x.as_mut().a = 2;
}
I want to find a way that enable interior mutability in Pin. I found pin-cell crate, which claims to be safer than RefCell. However, is that what I want? I find no example of it except from some API documentations. I tried to write some codes, but they can't compile.
use std::borrow::BorrowMut;
use pin_cell;
use pin_cell::{PinCell, PinMut};
fn main() {
let x = SimpleNUnPin { a: 1 };
let ptr1 = &x as *const _ as isize;
let xp = PinCell::new(x);
let mut b = xp.borrow_mut();
b.a = 2;
unsafe {
let n1 = &*(ptr1 as *const SimpleNUnPin);
assert_eq!(n1.a, 2);
}
The above code prints out error "error[E0609]: no field a on type &mut PinCell<SimpleNUnPin>". It is quite strange since my clion think it is a PinMut<SimpleNUnpin>.
Is there anyone can help? There are two questions:
Is pin-cell suitable in my case?
Why my code cam't compile, and has a contradict type dedution with clion?
Can someone explain which exact temporary value is dropped and what the recommended way to do this operation is?
fn main() {
let mut a = &mut String::from("Hello Ownership");
a = &mut a.replace("Ownership", "World");
println!("a is {}", a);
}
If you want to keep the &mut references (which are generally not needed in your case, of course), you can do something like this:
fn main() {
let a = &mut String::from("Hello Ownership");
let a = &mut a.replace("Ownership", "World");
println!("a is {}", a);
}
The type of a would by &mut String. In the second line we do what's known as variable shadowing (not that it's needed) and the type is still &mut String.
That doesn't quite answer your question. I don't know why exactly your version doesn't compile, but at least I thought this info might be useful. (see below)
Update
Thanks to Solomon's findings, I wanted to add that apparently in this case:
let a = &mut ...;
let b = &mut ...;
or this one (variable shadowing, basically the same as the above):
let a = &mut ...;
let a = &mut ...;
, the compiler will automatically extend the lifetime of each temporary until the end of the enclosing block. However, in the case of:
let mut a = &mut ...;
a = &mut ...;
, it seems the compiler simply doesn't do such lifetime extension, so that's why the OP's code doesn't compile, even though the code seems to be doing pretty much the same thing.
Why are you using &mut there? Try this:
fn main() {
let mut a = String::from("Hello Ownership");
a = a.replace("Ownership", "World");
println!("a is {}", a);
}
Aha, figured it out!
https://doc.rust-lang.org/nightly/error-index.html#E0716 says:
Temporaries are not always dropped at the end of the enclosing statement. In simple cases where the & expression is immediately stored into a variable, the compiler will automatically extend the lifetime of the temporary until the end of the enclosing block. Therefore, an alternative way to fix the original program is to write let tmp = &foo() and not let tmp = foo():
fn foo() -> i32 { 22 }
fn bar(x: &i32) -> &i32 { x }
let value = &foo();
let p = bar(value);
let q = *p;
Here, we are still borrowing foo(), but as the borrow is assigned directly into a variable, the temporary will not be dropped until the end of the enclosing block. Similar rules apply when temporaries are stored into aggregate structures like a tuple or struct:
// Here, two temporaries are created, but
// as they are stored directly into `value`,
// they are not dropped until the end of the
// enclosing block.
fn foo() -> i32 { 22 }
let value = (&foo(), &foo());
I have a struct Folder. I have a method called contents. I want that method to return an object that supports IntoIterator so that the caller can just go
for x in folder.contents(){
...
}
The Item type is (since this is what the hashmap iterator returns - see a little lower)
(&OsString, &FileOrFolder)
where FileOrFolder is an enum
enum FileOrFolder{
File(File),
Folder(Folder)
}
The iterator itself needs to first enumerate a HashMap<OSString, FileOrFolder> owned by the folder and then second, enumerate a Vec<File>. The Vec of files is created on the fly by the contents fn or by the IntoIterator call, whatever works. I tried simply using chain but quickly realized that wasn't going to work. So my rough sketch of what I am trying to do is this:
// the iterator
pub struct FFIter {
files: Vec<FileOrFolder>,
files_iter:Box<dyn Iterator<Item=FileOrFolder>>,
dirs: Box<dyn Iterator<Item = (&OsString, &FileOrFolder)>>,
dirs_done:bool
}
// the thing returned by the contents fn
struct FolderContents{
folder:&Folder
}
// make it iterable
impl IntoIterator for FolderContents {
type Item =(&OsString, &FileOrFolder);
type IntoIter = FFIter;
fn into_iter(self) -> Self::IntoIter {
let files = self.folder.make_the_files()
FFIter {
files: files, // to keep files 'alive'
files_iter: files.iter(),
dirs: Box::new(self.hashmap.iter()),
dirs_done:false
}
}
}
impl Iterator for FFIter {
type Item = (&OsString, &FileOrFolder);
fn next(&mut self) -> Option<(&OsString, &FileOrFolder)> {
None // return empty, lets just get the skeleton built
}
}
impl Folder{
pub fn contents(&self) -> FolderContents{
FolderContents{folder:&self}
}
}
I know this is full of errors, but I need to know if this is doable at all. As you can see I am not even trying to write the code that returns anything. I am just trying to get the basic outline to compile.
I started arm wrestling with the lifetime system and got to the point where I had this
error[E0658]: generic associated types are unstable
--> src\state\files\file_or_folder.rs:46:5
|
46 | type Item<'a> =(&'a OsString, &'a FileOrFolder);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: see issue #44265 <https://github.com/rust-lang/rust/issues/44265> for more information
Which kinda sucked as that is what the compiler said I should do.
I am happy to keep ploughing away at this following the suggestions from the compiler / reading / ... But in the past I have posted a question along these lines and been told - 'of course it can't be done'. So should I be able to make this work?
The Folder type is not Copy and expensive to clone. The File type is simple (string and i64), Copy and Clone
I know I could simply make the caller call two different iterations and merge them, but I am trying to write a transparent replacement module to drop into a large existing codebase.
If somebody says that chain() should work that's great, I will have another go at that.
EDIT Jmp said chain should work,
heres what I tried
pub fn contents(&self) -> Box<dyn Iterator<Item = (&OsString, &FileOrFolder)> + '_> {
let mut files = vec![];
if self.load_done {
for entry in WalkDir::new(&self.full_path)
.max_depth(1)
.skip_hidden(false)
.follow_links(false)
.into_iter()
{
let ent = entry.unwrap();
if ent.file_type().is_file() {
if let Some(name) = ent.path().file_name() {
files.push((
name.to_os_string(),
FileOrFolder::File(File {
name: name.to_os_string(),
size: ent.metadata().unwrap().len() as u128,
}),
));
}
}
}
};
Box::new(
self.contents
.iter()
.map(|(k, v)| (k, v))
.chain(files.iter().map(|x| (&x.0, &x.1))),
)
}
but the compiler complains, correctly, that 'files' get destroyed at the end of the call. What I need is for the vec to be held by the iterator and then dropped at the end of the iteration. Folder itself cannot hold the files - the whole point here is to populate files on the fly, its too expensive, memory wise to hold them.
You claim that files is populated on the fly, but that's precisely what your code is not doing: your code precomputes files before attempting to return it. The solution is to really compute files on the fly, something like this:
pub fn contents(&self) -> Box<dyn Iterator<Item = (&OsString, &FileOrFolder)> + '_> {
let files = WalkDir::new(&self.full_path)
.max_depth(1)
.skip_hidden(false)
.follow_links(false)
.into_iter()
.filter_map (|entry| {
let ent = entry.unwrap;
if ent.file_type().is_file() {
if let Some(name) = ent.path().file_name() {
Some((
name.to_os_string(),
FileOrFolder::File(File {
name: name.to_os_string(),
size: ent.metadata().unwrap().len() as u128,
}),
))
} else None
} else None
});
self.contents
.iter()
.chain (files)
}
Since you haven't given us an MRE, I haven't tested the above, but I think it will fail because self.contents.iter() returns references, whereas files returns owned values. Fixing this requires changing the prototype of the function to return some form of owned values since files cannot be made to return references. I see two ways to do this:
Easiest is to make FileOrFolder clonable and get rid of the references in the prototype:
pub fn contents(&self) -> Box<dyn Iterator<Item = (OsString, FileOrFolder)> + '_> {
let files = ...;
self.contents
.iter()
.cloned()
.chain (files)
Or you can make a wrapper type similar to Cow than can hold either a reference or an owned value:
enum OwnedOrRef<'a, T> {
Owned (T),
Ref (&'a T),
}
pub fn contents(&self) -> Box<dyn Iterator<Item = (OwnedOrRef::<OsString>, OwnedOrRef::<FileOrFolder>)> + '_> {
let files = ...;
self.contents
.iter()
.map (|(k, v)| (OwnedOrRef::Ref (k), OwnedOrRef::Ref (v))
.chain (files
.map (|(k, v)| (OwnedOrRef::Owned (k),
OwnedOrRef::Owned (v)))
}
You can even use Cow if FileOrFolder can implement ToOwned.
I'm writing a function that takes a reference to an integer and returns a vector of that integer times 2, 5 times. I think that'd look something like:
fn foo(x: &i64) -> Vec<&i64> {
let mut v = vec![];
for i in 0..5 {
let q = x * 2;
v.push(&q);
}
v
}
fn main() {
let x = 5;
let q = foo(&x);
println!("{:?}", q);
}
The borrow checker goes nuts because I define a new variable, it's allocated on the stack, and goes out of scope at the end of the function.
What do I do? Certainly I can't go through life without writing functions that create new data! I'm aware there's Box, and Copy-type workarounds, but I'm interested in an idiomatic Rust solution.
I realize I could return a Vec<i64> but I think that'd run into the same issues? Mainly trying to come up with an "emblematic" problem for the general issue :)
EDIT: I only just realized that you wrote "I'm aware there's Box, Copy etc type workaround but I'm mostly interested in an idiomatic rust solution", but I've already typed the whole answer. :P And the solutions below are idiomatic Rust, this is all just how memory works! Don't go trying to return pointers to stack-allocated data in C or C++, because even if the compiler doesn't stop you, that doesn't mean anything good will come of it. ;)
Any time that you return a reference, that reference must have been a parameter to the function. In other words, if you're returning references to data, all that data must have been allocated outside of the function. You seem to understand this, I just want to make sure it's clear. :)
There are many potential ways of solving this problem depending on what your use case is.
In this particular example, because you don't need x for anything afterward, you can just give ownership to foo without bothering with references at all:
fn foo(x: i64) -> Vec<i64> {
std::iter::repeat(x * 2).take(5).collect()
}
fn main() {
let x = 5;
println!("{:?}", foo(x));
}
But let's say that you don't want to pass ownership into foo. You could still return a vector of references as long as you didn't want to mutate the underlying value:
fn foo(x: &i64) -> Vec<&i64> {
std::iter::repeat(x).take(5).collect()
}
fn main() {
let x = 5;
println!("{:?}", foo(&x));
}
...and likewise you could mutate the underlying value as long as you didn't want to hand out new pointers to it:
fn foo(x: &mut i64) -> &mut i64 {
*x *= 2;
x
}
fn main() {
let mut x = 5;
println!("{:?}", foo(&mut x));
}
...but of course, you want to do both. So if you're allocating memory and you want to return it, then you need to do it somewhere other than the stack. One thing you can do is just stuff it on the heap, using Box:
// Just for illustration, see the next example for a better approach
fn foo(x: &i64) -> Vec<Box<i64>> {
std::iter::repeat(Box::new(x * 2)).take(5).collect()
}
fn main() {
let x = 5;
println!("{:?}", foo(&x));
}
...though with the above I just want to make sure you're aware of Box as a general means of using the heap. Truthfully, simply using a Vec means that your data will be placed on the heap, so this works:
fn foo(x: &i64) -> Vec<i64> {
std::iter::repeat(x * 2).take(5).collect()
}
fn main() {
let x = 5;
println!("{:?}", foo(&x));
}
The above is probably the most idiomatic example here, though as ever your use case might demand something different.
Alternatively, you could pull a trick from C's playbook and pre-allocate the memory outside of foo, and then pass in a reference to it:
fn foo(x: &i64, v: &mut [i64; 5]) {
for i in v {
*i = x * 2;
}
}
fn main() {
let x = 5;
let mut v = [0; 5]; // fixed-size array on the stack
foo(&x, &mut v);
println!("{:?}", v);
}
Finally, if the function must take a reference as its parameter and you must mutate the referenced data and you must copy the reference itself and you must return these copied references, then you can use Cell for this:
use std::cell::Cell;
fn foo(x: &Cell<i64>) -> Vec<&Cell<i64>> {
x.set(x.get() * 2);
std::iter::repeat(x).take(5).collect()
}
fn main() {
let x = Cell::new(5);
println!("{:?}", foo(&x));
}
Cell is both efficient and non-surprising, though note that Cell works only on types that implement the Copy trait (which all the primitive numeric types do). If your type doesn't implement Copy then you can still do this same thing with RefCell, but it imposes a slight runtime overhead and opens up the possibilities for panics at runtime if you get the "borrowing" wrong.