How to connect values inside two RefCells - rust

Sample code :
use serde_json::{json, Value};
fn main() {
let a: Rc<RefCell<Value>> = Rc::new(RefCell::new(json!({"a": "value"})));
let v: Rc<RefCell<Vec<Value>>> = Rc::new(RefCell::new(vec![]));
// How to push a into v, but keep `a` and `v` for future uses
}
I want to push Value a into vector v (link pointer), but still be able to use a later on.
I've tried the following:
1.
v.borrow_mut().push(*a.borrow_mut());
This does not work, as Value does not implement Copy trait, thus could not be dereferenced
2.
v.borrow_mut().push(RefCell::take(&a));
This works, however a has now lost the contents. I do understand that there should only be one owner, but I'm not sure how to achieve what I need.
The Why
I have a Value which I need to modify depending on some other data which is in a tree structure. I want to recursively walk through that other data tree, and pass along this Value to be modified.
In my function, I have this Value signature as Rc<RefCell<Value>>, and depending on the case I sometimes need to add nested properties, so I may need to add a property containing a vector with a new json!({}), and pass it as a new Rc<RefCell<Value>> to sub-iterations to append data to this specific subtree.
So, if you have any advice - maybe I need to change the recursive function's signature to have this data as Rc<RefCell<&Value>> instead, to have only one owner ? That seems like an awful lot of all sorts of references stacked upon one another, not sure which is the good way
Edit1: Updated sample to include Rc<RefCell<_>>

Related

Replacing a static Enum with a HashMap or similar

I have a simple Enum used to map to hardcoded strings:
Think:
enum SomeThing {
A, B, C
}
These values are shown in a UI as RadioButtons so the user can pick one and these options are mapped to a string (the name of a file I don't control).
The way this is done at runtime time is (pseudo-code):
let xxx: HashMap::from([
(
SomeThing::A.to_string(),
"value_for_a".to_string(),
),
(
SomeThing::B.to_string(),
"value_for_b".to_string(),
),
etc...
This is done at runtime and later used to retrieve the value for the chosen option. The fact that it's an Enum has the type safety in mind. But...
I'd like to change this code to make it user-configurable, and allow the user to specify those values themselves; since it's a runtime-constructed HashMap, I could imagine a config file (of any format like YAML) having:
---
xxx:
A: value_for_a
B: value_for_b
C: value_for_c
And parsed into "the same" HashMap (without the benefits of the Enum type safety).
The questions are:
I suppose creating an Enum at runtime would not be possible right? I'd imagine the user could create a new D key/value and or remove an existing one.
What would be another way to do this instead? Keep/Use a HashMap of some sort to store the Key (A,B,C) and their values after they were parsed?
(worth mentioning: the Enum is convenient because it's used by structopt for a command line parameter via the provided arg_enum! macro, so you can specify the posible_values as &YourEnum::variants() but this is less important to keep)
Is there a "better" way to do this that you can think of?

use the iteration object multiple times (Rust)

I'm new to rust. I need to get a list of files and directories in a folder, however I can't access the iteration object more than once.
Of course, this can be done using else, but I would like to know what to do in such a situation.
for d in fs::read_dir("./").unwrap() {
if d.unwrap().path().is_dir() {
continue;
} else if d.unwrap().path().is_file() { //except here
continue;
}
I'm new to rust. I need to get a list of files and directories in a folder, however I can't access the iteration object more than once.
You can understand why, and how to fix it, by looking at the documentation. Specifically the self types:
read_dir returns an iterator of Result<DirEntry>, so that's what d is.
Result::unwrap takes self, so it consumes the result itself, meaning after the first call to d.unwrap() there is no d anymore.
Your solutions then are:
since path, is_dir, and is_file all take &self as ShadowRanger notes you can just store the unwrapped DirEntry, or the paths
alternatively, you can use Result::as_ref to get a Result<&DirEntry>, which you can then unwrap to get an &DirEntry of which you can get the path, this only needs a &Result, so it does not consume the Result itself

Must a captured variable type implement Copy trait when closure returned as output parameter?

Question is general, no particular example.
If we have a function that returns a closure and closure itself returns some captured variable, does that variable type have to implement Copy˙trait?
From documentation:
https://doc.rust-lang.org/rust-by-example/fn/closures/output_parameters.html
fn create_fn() -> impl Fn() {
let text = "Fn".to_owned();
move || println!("This is a: {}", text)
}
this works, but for some types this solution give error. For example, if a text would be of type Option<T> it returns error saying something like:
`move occurs because `text` has type `std::option::Option<Box<dyn Something>>`, which does not implement the `Copy` trait
captured by this `Fn` closure`
One solution to solve the error is either to change closure trait to FnOnce but that introduces restriction that closure can be called only once.
But, if we want to call it multiple times, does that necessarily means that text must implement Copy trait?
I thought that move keyword does exactly that but i'm obviously wrong so if someone could explain details about how this moving captured variables actually works?
No, the type must not necessarily implement Copy. The thing is, when you have a Fn, it must be callable several times. If you actually move out something, then it's not going to work unless you're not actually moving it but just copying it (thus the error). But, the important thing is, you're not necessarily moving something out. You could also, for instance, create it on the fly (well, technically speaking, you'd still be moving it out, but maybe the example will help).
fn create_fn() -> impl Fn() -> String {
let text = "something";
move || text.to_string()
}
(see the playground)
Note that, here, String does not implement Copy (and it could also not implement Clone). What makes it work is that this function can be called over and over again, because each time it won't move out something it will need in a future call (here, by creating a brand new String to be given out).
But, if you're moving out a captured variable, you won't be able to do that twice. In that specific case, it would have to implement Copy (or just Clone and then you'd have to .clone() it).

Is unsafe my only option to pass a reference to this method expecting a closure?

I'm using the cursive_table_view crate, and the table has a set_on_submit method to which you pass a closure to be executed when the user press over a selected row in the table. The signature of said method is:
pub fn set_on_submit<F>(&mut self, cb: F)
where
F: Fn(&mut Cursive, usize, usize) + 'static,
Inside the closure, I'm trying to use something that actually comes as a parameter in the function that contains this code. I simply declare that parameter as &'static, and that's all good and expected. Now of course, I've just moved the problem to the caller of my function.
fn my_function(param: &'static MyType) {
let table = TableView::new();
table.set_on_sumbit(|cur, row, index| {
do_something_with(param);
}
}
Eventually I get to a point where I have to declare my variable as static to pass it as a parameter to that function, but because I need to modify this variable before the call (and after declaration), it needs to be static mutable. Now the problem is, when I try to modify the variable, the compiler says that I can only do that with unsafe.
I believe I understand the why of everything above. The closure is going to be called upon some event in the UI, so it makes sense that this lives for as long as the entire program.
I've tried several options with Rc and read a ton about lifetimes and even threads and messages, but I felt I was blindly trying things without really understanding at some point. Where I'm at now is that I believe I understand, but I'm uncomfortable with having to go the unsafe route suggestion.
Is it avoidable? Is my pattern wrong to begin with?
I didn't want to add more code to keep the explanation agnostic to everything else, but of course I'm happy to edit if more code helps understand the issue. Also, I don't really need to modify the struct any longer by the time I've passed the reference to the closure, in case that helps find a solution down that path.
Think of references as mostly (excluding &'static and a few other cases) being for temporary things, especially temporary things that live only as long as a stack frame. Therefore, don't try to use references for things like user interface callbacks.
Here's how to use std::rc::Rc instead, which ensures that the data lives as long as needed.
use std::rc::Rc;
fn my_function(param: Rc<MyType>) { // changed parameter type
let table = TableView::new();
table.set_on_submit(|cur, row, index| {
do_something_with(&param); // & enables conversion to &MyType
}
}
Now, in order to use this, you need to arrange so your data is owned by the Rc. It is not possible to have the above sort of callback and also have let data = MyType {...} directly, because the data must be owned by the Rc. (However, if useful, you can initialize it and then later put it in the Rc.)
fn main() {
// Wrap it as soon as you construct it.
// (Or at least before you start using callbacks.)
let my_app_data = Rc::new(MyType {
// whatever fields or constructor...
});
// Call the function. `.clone()` here makes a copy of the `Rc` refcounted pointer,
// not the underlying data.
my_function(my_app_data.clone());
}
If your program uses threads, then you must use the thread-safe reference counter std::sync::Arc instead of Rc.
If you want to modify the data while the callback exists — whether in a callback or elsewhere — you need to also use RefCell (or thread-safe std::sync::Mutex / RwLock) inside the Rc, which adds a few complications.

Why can't I use C#9's "with" keyword to create a copy of structs (like with records)

C# 9 has a new feature. A record type. The record is just a class, but with a bunch of automatically created functions and properties. But basically the idea (as I undstand it) was, a class that behaves like structs, for things like copying, coimparison with Equals, immutibility and so on.
Also with the record type was a new feature with the keyword "with". To create a copy of a record, you can write something like that: var copy = original with { Property = new_value, };
Now I wondered, if records were designt to behave like structs (but are classes). Why doesn't the new "with" keyword works also with structs. I mean, as far as I can tell, structs have all features, that are necessary for this feature. Like they are copied by value.
Instead to use similar features for structs, I have to write a copy constructor and can then write: var copy = new StructType(original) { Property = new_value, };
Short answer:
That's how the feature was designed.
Long answer:
The compiler creates a synthesized clone method with a reserved name <Clone>$, when you use with keyword, the compiler calls this clone method, and then modifies whatever properties you want to modify.
structs or classes doesn't have a synthesized clone method. Hence, with can't be used with them.
You may want to write a language proposal to extend the usage of with keyword.
Edit:
Currently, there is a proposal for allowing record structs. See Proposal: record structs for more information. This is what you may want.

Resources