How to clone async_std::path::PathBuf in v0.99.10? - rust

I have a scenario whereby I want to store the value of a PathBuf in two different collections, in a HashSet<PathBuf> and as a field in a vector of structs Vec<Contract> (Contract is a custom struct defined in my project).
I looked at the docs but I couldn't find a clone functionality for PathBuf.
I know that there are alternative solutions, such as converting the PathBuf to a String or generating a unique hash for the PathBuf, but I would prefer to use the same type.
Is it possible to clone PathBuf?
Update: as pointed out by #vallenting in the comments, I was looking at an old version of PathBuf. In v1.8.0 and above, clone is available.

In v0.99.10 you can use to_path_buf().
let p = PathBuf::from("...");
let p_clone = p.to_path_buf();
However, in v1.8.0 you can use clone() as you'd expect.
let p = PathBuf::from("...");
let p_clone = p.clone();

Related

How can I make Rust, with the Rodio crate, load multiple sources in a Vec, so I can play them later as needed without having to load them every time?

I am using Rust with the Rodio crate and I wanted to make a Vec of loaded sources to use whenever they are needed, so that the program doesn't need to load it every time. I've made a SoundHandler class that contains an OutputStream, an OutputStreamHandle and a Vec<Decoder<BufReader<File>>>. The first two are instanced by using OutputStream::try_default(), which returns both in a tuple. The Vec is a vector of loaded sources. Its content are, as I understand it, loaded and then pushed in the following SoundHandler method:
pub fn load_source(&mut self, file_path: PathBuf) -> SoundId {
let id = self.sources.len();
self.sources.push(
Decoder::new(
BufReader::new(
File::open(file_path).expect("file not found")
)
).expect("could not load source")
);
SoundId(id)
}
Next, the source should be played by calling the play_sound() method.
Previously, it directly loaded and played the sound:
pub fn play_sound(file_path: PathBuf) {
self.stream_handle.play_raw(
Decoder::new(
BufReader::new(
File::open(file_path).expect("file not found")
)
).expect("could not load source")
);
}
But now it must handle the sources that come from the Vec. I had trouble while trying to do that. I need help with that. I am pretty new to the language so knowing how to solve that problem in more than one way would be even better, but my priority is really the path I've chosen to do it, because knowing how to solve that would undoubtedly increase my Rust problem solving skills. Keep in mind my main goal here is to learn the language, and the snippets below are not at all an urgent problem to be solved for a company.
Ok, so I tried the most straightforward thing possible. I directly changed the old method to do the same thing but with the Vec:
pub fn play_sound(&self, sound_id: SoundId) {
self.stream_handle
.play_raw(self.sources.get(sound_id.0).unwrap().convert_samples()).unwrap();
}
But the compiler won't compile that method, because, according to it,
error[E0507]: cannot move out of a shared reference
self.stream_handle.play_raw(self.sources.get(sound_id.0).unwrap().convert_samples()).unwrap();
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-----------------
| |
| value moved due to this method call
move occurs because value has type `rodio::Decoder<std::io::BufReader<std::fs::File>>`, which does not implement the `Copy` trait
note: this function takes ownership of the receiver `self`, which moves value
I understand what the compiler is saying. Of course that can't be possible. convert_samples() tries to make the value inside the Vec invalid, and thus it could make the Vec unsafe. So I naively tried to clone the Decoder, but the struct does not implement the Clone trait, and apparently does not have any method to do so. Finally, I found a way to get the value and own it through the Vec::remove() method, but I do not want to remove it, and I do want it to be fallible.
So my question is: in this situation, how can I make that Vec of loaded sources? Maybe I could even make a Vec out of SamplesConverter. But then the name of the type gets huge, so that is probably not an intended way to do it: Vec<SamplesConverter<Decoder<BufReader<File>>, f32>>. But it has the same problems of the other implementation.
Decoders can't be cloned because the underlying data source may not be clonable (and in fact BufReader isn't). So in order to clone the audio sources you will need to ensure that the data is stored in memory. This can be accomplished by the buffered method, which returns a Buffered source, which can be cloned. So something like this should work:
pub fn load_source(&mut self, file_path: PathBuf) -> SoundId {
let id = self.sources.len();
self.sources.push(
Decoder::new(
BufReader::new(
File::open(file_path).expect("file not found")
)
).expect("could not load source")
.buffered()
);
SoundId(id)
}
pub fn play_sound(&self, sound_id: SoundId) {
self.stream_handle.play_raw(
self.sources.get(sound_id.0).unwrap().clone().convert_samples()).unwrap();
}

How to connect values inside two RefCells

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<_>>

Solana Rust program BTreeMap

I have read this article here and I understood that HashMap is not usable in Solana, thus, I need to use BTreeMap.
I am a beginner in Rust and I am having an error with the following code when trying to move from Ethereum to Solana :
pub fn constructor (
let mut DomainsToIndex = BTreeMap::new();
Domains[] pub DomainList;
contractOwner = msg.sender;
firstDomain.name = "empty";
firstDomain.IP = "n/a";
firstDomain.owner = 0;
firstDomain.lockTime = 0;
firstDomain.infoDocumentHash = "n/a";
DomainsToIndex.insert(String::from(firstDomain.name), 0);
DomainList.push(firstDomain);
) -> ProgramResult {
msg!("First domain was added by default");
Ok(())
}
I of course added the import in the top of the file with:
use std::collections::BTreeMap;
The error I receive when using cargo build is the following as per the image presented below:
I presume that I am not doing something right, as I am a newbie in Rust, can you please help out ?
Thanks.
There are a couple of syntactical issues with the code.
Application arguments should be separate from the body and pub without a struct doesn't make sense either.
Unfortunately the documentation of their Rust interface is quite lacking (seems to be mostly "have a look at some examples then find out the rest through trial-and-error"). So I was unable to look up enough information to suggest a reasonably correct version.
Here are a couple of more pointers:
it's not clear what the input to this function is. You're referencing a msg object with a sender member there, but the only equivalent I could identify was the &[AccountInfo] argument which identifies the invoking account.
Alternatively, Solana programs receive a byte array of instruction data which apparently can have any content encoded within them.
I would suggest starting with their Hello World example, playing around with it a bit and continue with your own app once you're more familiar with Rust syntax and Solana best practices.

Sharing weak trait object references

I'm trying to provide "views" of non-owned structs to separate components of a system.
Assume a set of traits with distinct methods: Drawable, Modifiable and a number of structs which implement at least one of the traits - SimpleBox, Panel, Expression.
Different components of the system will need to frequently access sequences of these objects, using methods of specific traits; consider a DrawingManager or a ModifyManager:
struct DrawingManager {
items: Vec<Weak<Drawable>>,
}
struct ModifyManager {
items: Vec<Weak<Modifiable>>
}
While a single object may be referenced in both managers, assume that there is a separate single owner of all structs:
struct ObjectManager {
boxes: Vec<Rc<Box>>,
panels: Vec<Rc<Panel>>,
expressions: Vec<Rc<Expression>>,
}
Ideally, it would be useful to be able to manage deleting structs from one place - i.e simply removing it from the ObjectManager being enough to invalidate references in all other components (hence the use of Weak).
Is there a way of doing this?
Is this the correct way to achieve this?
Is there a more idiomatic way of implementing this functionality?
The system contains several traits, so making a single trait using methods of all the other traits seems like a bad idea. Several traits have more than one method, so replacing them with closures is not possible.
What I have tried
As one object may produce one or more Rc<Trait>, we might envision implementing this with a HashMap<ID, Vec<Rc<Any>>> whereby we make each struct have a unique ID, which maps to a list of all Rc that have been made for it.
When we want to remove an object, we remove it from the corresponding list, and remove the entry in the hashmap, invalidating all Weak references.
However, implementing this fails, as to insert into the HashMap, one must upcast a Rc<Trait> -> Rc<Any>, only to downcast it later.
I'm not sure if this is the idiomatic way of doing this, but I've since developed a crate providing this functionality - dependent_view.
Using the crate, the initial problem can be solved by using DependentRc instead of plain Rc's:
struct ObjectManager {
boxes: Vec<DependentRc<Box>>,
panels: Vec<DependentRc<Panel>>,
expressions: Vec<DependentRc<Expression>>
}
let object_manager : ObjectManager = ObjectManager::new();
Then using macros provided by the crate, we can obtain Weak<> references to these structs:
let box_view : Weak<Drawable> = to_view!(object_manager.boxes[0]);
let panel_view : Weak<Drawable> = to_view!(object_manager.panels[0]);
let expression_view : Weak<Drawable> = to_view!(object_manager.expressions[0]);
With this, dropping the corresponding DependentRc<> will invalidate all Weak<> references that have been made of it.

Differences in syntax for invoking trait method on generic type

I'm trying to understand the need for the Trait:: and <T as Trait>:: method invocation syntax. In particular, I'm looking at the following function from this answer:
fn clone_into_array<A, T>(slice: &[T]) -> A
where
A: Default + AsMut<[T]>,
T: Clone,
{
assert_eq!(
slice.len(),
std::mem::size_of::<A>() / std::mem::size_of::<T>()
);
let mut a = Default::default();
<A as AsMut<[T]>>::as_mut(&mut a).clone_from_slice(slice);
a
}
It seems that the middle two method invocation lines can be rewritten as:
let mut a = A::default();
a.as_mut().clone_from_slice(slice);
I believe this is more readable, as we already know that A implements Default and AsMut<[T]> and we can invoke as_mut directly as a method instead of having to pass a to it explicitly.
However, am I missing a good reason for the linked answer to have written it more verbosely? Is it considered good style? Are the two semantically different under certain conditions?
I agree with your rewrites — they are more clear and are what I would recommend for that function.
am I missing a good reason for the linked answer to have written it more verbosely?
My guess is that the author simply was tired of writing that function and stopped. If they took a look at it again, they might refine it to be shorter.
Is it considered good style?
I don't think there's a general community stylistic preference around this yet, other than the general "shorter is better until it isn't".
Are the two semantically different under certain conditions?
They shouldn't be.
There are times where the <>:: syntax is needed because otherwise it would be ambiguous. One example from a recent question:
let array = <&mut [u8; 3]>::try_from(slice);
Another time is when you don't have a nicely-named intermediate type or the intermediate type is ambiguous across multiple traits. One gross example is from a where clause but shows the same issue as an expression would:
<<Tbl as OrderDsl<Desc<Expr>>>::Output as LimitDsl>::Output: QueryId,
See also:
How to call a method when a trait and struct use the same name?

Resources