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? - audio

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();
}

Related

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).

Proper way to keep assets loaded in Bevy engine using Handle and using the assets later?

I am learning Rust and Bevy engine, and I want to keep certain assets (such as Fonts) loaded during the entire application life-time.
// Resource for fonts:
#[derive(Default, Clone)]
pub struct ResFont {
pub ui: Handle<Font>, // The font that will be used in this example.
pub dialog: Handle<Font>,
...
}
// Insert resource in main() during App building:
{
.insert_resource(ResFont::default())
}
// Load resource during startup:
pub fn startup(asset_server: Res<AssetServer>, mut res_font: ResMut<ResFont>)
{
res_font.ui = asset_server.load("font/Default.ttf");
}
// Use the font resource in a different place:
pub fn setup_ui(res_font: ResMut<ResFont>)
{
...
TextStyle {
font: res_font.ui.clone(),
font_size: 12.0,
color: Color::WHITE,
}
...
}
In the function setup_ui() at the bottom, I am using .clone() to copy that asset. If I don't use .clone(), I get the error:
cannot move out of dereference of `bevy::prelude::ResMut<'_, resource::text::ResFont>`
move occurs because value has type `bevy::prelude::Handle<bevy::prelude::Font>`, which does not implement the `Copy` traitrustc(E0507)
ui.rs(19, 27): move occurs because value has type `bevy::prelude::Handle<bevy::prelude::Font>`, which does not implement the `Copy` trait
I have two questions:
Am I copying the entire Font here during the .clone() operation?
Is this the "proper" way to keep resources loaded and for use later, or is there is a better way to achieve this that I don't know of?
Regarding your questions, I'd recommend you to give the (unofficial) bevy cheatbook's chapter on assets a read, it will answer most of your questions. I'm going to quote the parts relevant to your questions here:
No you're not copying the Font, just the Handle.
Handles have built-in reference counting (similar to Rc/Arc in Rust). This allows Bevy to track if an asset is still needed, and automatically unload it when it no longer is. You can use .clone() to create multiple handles to the same asset. The clone is a cheap operation, but it is explicit, to ensure that you are aware of the places in your code that create additional handles and may affect the lifetime of assets.
It is one of two suggested ways.
You could store your handles somewhere that is convenient for you (such as in resources).
If you don't have your handle stored anywhere, you can always generate one from a path by calling asset_server.load. You could simply do that whenever you need, and not bother storing handles.
Repeatedly calling asset_server.load works because internally, the function checks if the asset has already been loaded and reuses said asset. (This can be seen in the source code of the AssetServer::load_async method, specifically l. 246-252).
So when is storing handles in a resource superior to asset_server.load?
The asset server will unload an asset if no more handles to it exist.
This would usually be unlikely to happen for a font used in the UI, but could be more common for other types of assets you want to stay loaded at all times.
Storing the handle in a resource ensures it will never be unloaded.
Some other hints for your code:
instead of .insert_resource(ResFont::default()) you could just use .init_resource(ResFont), which would then call the Default implementation.
in pub fn setup_ui(res_font: ResMut<ResFont>), you can just use Res<ResFont> instead, as you're not mutating it.
For future reference, this reply applies for Bevy 0.5.

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.

How can I split up a large impl over multiple files?

I really don't like monolithic implementations of the functions for a class (in C++ speak). In that language I can split things up as I like; in Rust there are strict rules about what goes in what files.
I have about 2000 lines (no comments/ docs) of impl for a struct. Logically they can be broken up into different sets; functions for managing aspect A, functions for managing aspect B, ... They all noodle on the struct's data big time, so chopping the struct up further wont help.
I saw in one answer that you can have
// in thing.rs
struct Thing{
.......
}
impl Thing{
fn1
fn2
}
// in more_thing.rs
use crate::thing::*;
impl Thing{
fn3,
fn4
}
// in lib.rs
mod thing;
mod more_thing;
This works, almost (I was surprised it worked at all). Its a kind of half way house. The problem is that for the methods in more_thing.rs I have to declare the fields of Thing all pub. Which is doable but not great. Are there any other options?
I know I can limit the pub scope but still it blows encapsulation.
All non-pub items in a module are still visible in its submodules. Just make more_thing a submodule of thing instead of a sibling. You can do this by putting it in a directory named thing, and putting the mod declaration inside thing.rs:
// thing.rs (or thing/mod.rs; see below)
pub struct Thing {
field: i32,
}
// Note the lack of `pub`: `more` is only an implementation detail
mod more;
// thing/more.rs
use super::Thing;
impl Thing {
// Although it is defined in a non-`pub` module, this method will be visible anywhere
// `Thing` is because it is marked `pub` and is a member of `Thing`. You can use
// `pub(crate)` or `pub(super)` instead to get different levels of visibility, or
// leave it private and it will only be available in the current module (thing::more)
pub fn field(&self) -> i32 {
// because more is a submodule of thing, non-`pub` members are visible here.
self.field
}
}
If you wish to keep all the Thing-related files in the thing directory, you can rename thing.rs to the special filename thing/mod.rs and it will work in exactly the same way.
All methods are private by default in Rust, which means they are only accessible in the scope of their containing module (which is never larger than a file), in this case thing.rs. thing.rs is just as remote to more_thing.rs as any libraries and external code; it may as well be a separate crate. In essence, you are trying to declare a private method on an external item, which of course fails.
However, this can be a bit confusing because when it comes to orphan rules, you can always implement traits for any item in the same crate, not just the same module. This is because trait implementations are always public (as long as you can access both the trait and the item implementing it; the actual orphan rules are a bit more complicated but this is the basic idea).
In essence: trait implementations are public, but method implementations are private by default. In order to implement public things you need at least public access, and in order to implement private things you need private access.
Instead, one solution is to simply declare a function that takes your item as an argument. For example, in more_thing.rs:
use super::thing::Thing;
fn foo(thing: &Thing) {
// ...
}
Why not put impl blocks in the same file?
in thing.rs
struct Thing {
.......
}
impl Thing {
fn1
fn2
}
impl Thing {
fn3
fn4
}
The methods are splited though there is still a large file.

Method call on clap::App moving ownership more than once

Even after reading the chapters about reference ownership and borrowing, I cannot understand some things in the following code, effectively stopping me from calling more than one method from clap::App!
extern crate clap;
use clap::App;
fn main() {
let mut app =
App::new("name me").args_from_usage("<input_file> 'Sets the input file to use'");
let matches = app.get_matches();
app.print_help();
println!(
"Using input file: {}",
matches.value_of("input_file").unwrap()
);
}
Compiling this code leads to:
error[E0382]: use of moved value: `app`
--> src/main.rs:9:5
|
8 | let matches = app.get_matches();
| --- value moved here
9 | app.print_help();
| ^^^ value used here after move
|
= note: move occurs because `app` has type `clap::App<'_, '_>`, which does not implement the `Copy` trait
If I understand correctly, app.get_matches() asks to borrow the ownership, thus app must be mut. Where does the ownership go once the function returns?
I thought app would still have ownership of the object, yet the compiler has a different opinion.
How can I get the matches, and effectively still call another method, such as print_help on app then?
Read the function signature for App::get_matches:
fn get_matches(self) -> ArgMatches<'a>
This takes self by value, also said as it consumes the value; you cannot call any methods on it afterwards. There's nothing to be done about this; presumably the author has good rationale for this.
Now review App::print_help:
fn print_help(&mut self) -> ClapResult<()>
It takes a reference (which happens to be mutable). You do not have to transfer ownership to call this method.
If I understand correctly, app.get_matches() asks to borrow the ownership, thus app must be mut. Where does the ownership go once the function returns?
You do not understand correctly, in multiple dimensions.
get_matches consumes the value, it does not borrow anything.
A value does not need to be mutable to be borrowed.
When you do borrow something, the ownership doesn't "go" anywhere. The original owner continues to own it. That's why it's called borrowing.
How can I get the matches, and effectively still call another method, such as print_help on app then?
You don't. The obvious workaround is to clone the original object, producing a second value. Then you can consume one value and still call methods on the second value.
Basically, it sounds like you are trying to do something that the library is discouraging you from doing. Perhaps you should re-evaluate your goals and/or review the intended usage of the library. For example, get_matches will automatically display the help text when the user requests it, so why should your code try to do so?
From the Clap issue tracker:
You have a few options. You can either use AppSettings::ArgRequiredElseHelp or you can keep the move from happening by using App::get_matches_from_safe_borrow.

Resources