rodio::sink error detaching sound: detach is giving me move error anywhere I put it - audio

I am trying to make a simple game in Rust. Playing sound with rodio.
But when I run detach, I get an error:
error[E0507]: cannot move out of `self.sinks[_]` which is behind a mutable reference
--> src\sound.rs:48:3
|
48 | self.sinks[trk].detach();
| ^^^^^^^^^^^^^^^ -------- `self.sinks[_]` moved due to this method call
| |
| move occurs because `self.sinks[_]` has type `rodio::Sink`, which does not implement the `Copy` trait
|
note: this function takes ownership of the receiver `self`, which moves `self.sinks[_]`
--> C:\Users\dsinc\.cargo\registry\src\github.com-1ecc6299db9ec823\rodio-0.16.0\src\sink.rs:163:23
|
163 | pub fn detach(mut self) {
| ^^^^
For more information about this error.
I will put a sample of my code now:
use std::{io::BufReader, path::Path};
use rodio::Source;
pub struct Audio {
pub stream: rodio::OutputStream,
pub handle: rodio::OutputStreamHandle,
pub sinks: [rodio::Sink; 4],
}
impl Audio {
pub fn new() -> Audio {
let (stream, handle) = rodio::OutputStream::try_default().unwrap();
let sinks = [
rodio::Sink::try_new(&handle).unwrap(),
rodio::Sink::try_new(&handle).unwrap(),
rodio::Sink::try_new(&handle).unwrap(),
rodio::Sink::try_new(&handle).unwrap(),
];
Audio {
stream,
handle,
sinks,
}
}
pub fn load(
&mut self,
filename: &Path,
) -> rodio::source::Buffered<rodio::Decoder<BufReader<std::fs::File>>> {
let file = std::fs::File::open(filename).unwrap();
rodio::Decoder::new(BufReader::new(file))
.unwrap()
.buffered()
}
pub fn load_looped(
&mut self,
filename: &Path,
) -> rodio::source::Buffered<rodio::source::Repeat<rodio::Decoder<BufReader<std::fs::File>>>>
{
let file = std::fs::File::open(filename).unwrap();
rodio::Decoder::new(BufReader::new(file))
.unwrap()
.repeat_infinite()
.buffered()
}
pub fn play(
&mut self,
src: rodio::source::Buffered<rodio::Decoder<BufReader<std::fs::File>>>,
trk: usize,
) {
self.sinks[trk].append(src);
}
pub fn play_looped(
&mut self,
src: rodio::source::Buffered<
rodio::source::Repeat<rodio::Decoder<BufReader<std::fs::File>>>,
>,
trk: usize,
) {
self.sinks[trk].append(src);
}
pub fn stop(&mut self, trk: usize) -> &mut Self {
self.sinks[trk].detach(); // this gives me an error!
self
}
}
This file is a module, not main.

Related

Ensure that one lifetime outlives another in tree

I'm having a hard time figuring out the lifetime syntax that I need for the following code, which does not compile. The basic idea is that I'm creating an Abstract Syntax Tree, and each node must have a different type. Some node types must hold a reference to an external value. It's not possible to make this external value an owned type; it's actually a reference to disk file that must be shared by a number of nodes. Here's the code, as simple as I can make it:
trait Node {
fn init(&mut self, my_str: &str);
}
struct NodeParent {
pub children: Vec<Box<dyn Node>>,
}
impl Node for NodeParent {
fn init(&mut self, my_str: &str) {
for child in self.children.iter_mut() {
child.init(my_str);
}
}
}
struct NodeLeaf<'a> {
pub my_str: Option<&'a str>,
}
impl Node for NodeLeaf<'_> {
fn init(&mut self, my_str: &str) {
self.my_str = Some(my_str);
}
}
impl NodeLeaf<'_> {
pub fn new() -> Box<dyn Node> {
Box::new(NodeLeaf { my_str: None })
}
}
pub fn make_ast() {
let mut parent = NodeParent { children: vec![] };
let leaf = NodeLeaf::new();
parent.children.push(leaf);
let some_string = String::from("foo");
let my_str = some_string.as_str();
parent.init(my_str);
}
The error is:
error: lifetime may not live long enough
--> src/query/lifetime_test.rs:23:9
|
22 | fn init(&mut self, my_str: &str) {
| --------- - let's call the lifetime of this reference `'1`
| |
| has type `&mut NodeLeaf<'2>`
23 | self.my_str = Some(my_str);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment requires that `'1` must outlive `'2`
I know I need some kind of lifetime on &my_str everywhere it appears, but once I start taking the compiler's suggestion to start adding lifetimes here and there they proliferate, and I never get to code that compiles. I've also tried to Rc<>, but the code to make that work eludes me as well.
How do I specify that &my_str outlives the whole Node tree?
Link to the code on Rust Playground
Add a lifetime to Node:
trait Node<'a> {
fn init(&mut self, my_str: &'a str);
}
struct NodeParent<'a> {
pub children: Vec<Box<dyn Node<'a>>>,
}
impl<'a> Node<'a> for NodeParent<'a> {
fn init(&mut self, my_str: &'a str) {
for child in self.children.iter_mut() {
child.init(my_str);
}
}
}
struct NodeLeaf<'a> {
pub my_str: Option<&'a str>,
}
impl<'a> Node<'a> for NodeLeaf<'a> {
fn init(&mut self, my_str: &'a str) {
self.my_str = Some(my_str);
}
}
impl<'a> NodeLeaf<'a> {
pub fn new() -> Box<dyn Node<'a>> {
Box::new(NodeLeaf { my_str: None })
}
}
But this is not enough, because Box<dyn Node<'a>> is actually Box<dyn Node<'a> + 'static>, that is, it cannot contain any non-'static lifetime. You need to specify that it can contain lifetime 'a:
struct NodeParent<'a> {
pub children: Vec<Box<dyn Node<'a> + 'a>>,
}
impl<'a> NodeLeaf<'a> {
pub fn new() -> Box<dyn Node<'a> + 'a> {
Box::new(NodeLeaf { my_str: None })
}
}
Now you will get a different error:
error[E0597]: `some_string` does not live long enough
--> src/lib.rs:39:18
|
39 | let my_str = some_string.as_str();
| ^^^^^^^^^^^^^^^^^^^^ borrowed value does not live long enough
40 | parent.init(my_str);
41 | }
| -
| |
| `some_string` dropped here while still borrowed
| borrow might be used here, when `parent` is dropped and runs the destructor for type `NodeParent<'_>`
|
= note: values in a scope are dropped in the opposite order they are defined
Because Box<dyn Node> may have an arbitrary destructor, and it may access the stored string, we need to make sure it is still alive when the value is dropped. Do that by moving the string creation before the nodes:
pub fn make_ast() {
let some_string = String::from("foo");
let mut parent = NodeParent { children: vec![] };
let leaf = NodeLeaf::new();
parent.children.push(leaf);
let my_str = some_string.as_str();
parent.init(my_str);
}
Playground.

Returning traits with dyn

I've been trying to get this code to compile
pub trait Packet: PacketSerializer + ProtocolToID + Default {
fn serialize_with_id(&self, ver: &ProtocolVersion) -> Box<ByteBuf>;
fn deserialize_gen(buf: &mut ByteBuf) -> Box<Self>;
}
impl<T: PacketSerializer + ProtocolToID + PacketHandler + Default> Packet for T
{
fn serialize_with_id(&self, ver: &ProtocolVersion) -> Box<ByteBuf> {
let mut buf = Box::new(ByteBuf::new());
buf.write_var_int(self.resolve_id(ver));
self.serialize(&mut buf, &ver);
buf
}
fn deserialize_gen(buf: &mut ByteBuf) -> Box<T> {
let mut p: T = Default::default();
p.deserialize(buf);
Box::new(p)
}
}
pub fn invoke_packet_handler(id: i32, buf: &mut ByteBuf) -> Box<dyn Packet> {
Box::new(clientbound::SetCompression { threshold: 256 })
}
specifically invoke_packet_handler is supposed to return a Box<dyn Packet>
According to the docs, this should work https://doc.rust-lang.org/rust-by-example/trait/dyn.html if you "statically" define the trait so the compiler can see it.
I get the following error at runtime
error[E0038]: the trait `Packet` cannot be made into an object
--> src/serialize/packet.rs:43:61
|
43 | pub fn invoke_packet_handler(id: i32, buf: &mut ByteBuf) -> Box<dyn Packet> {
| ^^^^^^^^^^^^^^^ `Packet` cannot be made into an object
I'm assuming this is because of the implementation for Packet? It's generic on every type that implements PacketSerializer, ProtocolToID, PacketHandler and Default
However,
pub fn invoke_packet_handler(id: i32, buf: &mut ByteBuf) -> Box<dyn PacketHandler> {
Box::new(clientbound::SetCompression { threshold: 256 })
}
does compile if I specify a single trait

Borrowed value does not live long enough with an Arc<Mutex<T>>

In the example below, openvpn_client is created before the on_poll_read and on_poll_write. Therefore, it should be destructed after them (Playground):
use core::task::{Context, Poll};
use hyper::client::connect::{Connected, Connection};
use std::sync::{Arc, Mutex};
pub type OnPollRead = Arc<
dyn Fn(&mut Context<'_>, &mut tokio::io::ReadBuf<'_>) -> Poll<std::io::Result<()>>
+ Send
+ Sync,
>;
pub type OnPollWrite = Arc<
dyn Fn(&mut Context<'_>, &[u8]) -> Poll<core::result::Result<usize, std::io::Error>>
+ Send
+ Sync,
>;
#[derive(Clone)]
pub struct CustomTransporter {
on_poll_read: Option<OnPollRead>,
on_poll_write: Option<OnPollWrite>,
}
pub struct OVPNClient {}
impl OVPNClient {
pub fn send(&self, buffer: &[u8]) {}
}
unsafe impl Send for OVPNClient {}
unsafe impl Send for CustomTransporter {}
impl CustomTransporter {
pub fn new(
on_poll_read: Option<OnPollRead>,
on_poll_write: Option<OnPollWrite>,
) -> CustomTransporter {
CustomTransporter {
on_poll_read: on_poll_read,
on_poll_write: on_poll_write,
}
}
}
fn main() {
let openvpn_client = Arc::new(Mutex::new(OVPNClient {}));
let on_poll_read = Arc::new(
|context: &mut Context, buffer: &mut tokio::io::ReadBuf| -> Poll<std::io::Result<()>> {
Poll::Ready(Ok(()))
},
);
let on_poll_write = Arc::new(
|context: &mut Context,
buffer: &[u8]|
-> Poll<core::result::Result<usize, std::io::Error>> {
openvpn_client.lock().unwrap().send(buffer);
Poll::Ready(Ok(0))
},
);
let connector = CustomTransporter::new(Some(on_poll_read), Some(on_poll_write));
}
Error:
error[E0597]: `openvpn_client` does not live long enough
--> src/main.rs:57:13
|
54 | / |context: &mut Context,
55 | | buffer: &[u8]|
56 | | -> Poll<core::result::Result<usize, std::io::Error>> {
| |_____________________________________________________________- value captured here
57 | openvpn_client.lock().unwrap().send(buffer);
| ^^^^^^^^^^^^^^ borrowed value does not live long enough
...
62 | let connector = CustomTransporter::new(Some(on_poll_read), Some(on_poll_write));
| ------------- cast requires that `openvpn_client` is borrowed for `'static`
63 | }
| - `openvpn_client` dropped here while still borrowed
Why does this error happen?

Storing Fn types gives error: cast requires that ... is borrowed for 'static`

Here is a small code sample representing the problem I currently have. CmdMap stores some logic from Trait types that should be triggered by a String key. This logic requires a context that is provided with the Arg instance. In this Arg instance, we may need mutable references to some objects (represented here by Printer).
Here's the code:
use std::collections::HashMap;
struct Cmd {}
pub trait Trait<T> {
fn execute(args: T) -> Result<(), String>;
}
impl<'a> Trait<Arg<'a>> for Cmd {
fn execute(arg: Arg) -> Result<(), String> {
arg.printer.print("execute".to_string());
Ok(())
}
}
struct Printer {
name: String,
}
impl Printer {
pub fn print(&mut self, msg: String) {
self.name = "print".to_string();
println!("{}: {}", self.name, msg);
}
}
struct Arg<'a> {
pub printer: &'a mut Printer,
}
type Callback<T> = dyn Fn(T) -> Result<(), String>;
struct CmdMap<T> {
pub map: HashMap<String, Box<Callback<T>>>,
}
impl<T> CmdMap<T> {
pub fn try_execute(&self, name: String, arg: T) {
self.map[&name](arg);
}
}
fn test() {
let mut map: CmdMap<Arg> = CmdMap {
map: HashMap::new(),
};
map.map.insert("test".to_string(), Box::new(Cmd::execute));
let mut printer: Printer = Printer {
name: "".to_string(),
};
loop {
map.try_execute(
"test".to_string(),
Arg {
printer: &mut printer,
},
);
}
}
The compiler complains:
error[E0499]: cannot borrow `printer` as mutable more than once at a time
--> src/lib.rs:57:26
|
47 | map.map.insert("test".to_string(), Box::new(Cmd::execute));
| ---------------------- cast requires that `printer` is borrowed for `'static`
...
57 | printer: &mut printer,
| ^^^^^^^^^^^^ mutable borrow starts here in previous iteration of loop
...
58 | map.try_execute("test".to_string(), Arg { printer: &mut printer });
| ^^^^^^^^^^^^ mutable borrow starts here in previous iteration of loop
I don't undersand why the compiler complains here. The first error cast requires that printer is borrowed for 'static, doesn't make sense to me as I'm storing Fn types that need to borrow printer for the time of their execution only.
Am I missing something?

Struct containing reference to a file in Rust fails to borrow

Not sure what I am missing here, the lifetime is declared, therefore the struct should use the path to create the file and return a Struct with the mutable File reference for me to be able to call "write" wrapper later...
use std::path::Path;
use std::fs::File;
// use std::io::Write;
#[derive(Debug)]
pub struct Foo<'a> {
file: &'a mut File,
}
impl<'a> Foo<'a> {
pub fn new(path: &'a Path) -> Result<Self, std::io::Error> {
let mut f: &'a File = &File::create(path)?;
Ok(Self { file: &mut f })
}
//pub fn write(&self, b: [u8]) {
// self.file.write(b);
//}
}
Error:
| impl<'a> Foo<'a> {
| -- lifetime `'a` defined here
11 | pub fn new(path: &'a Path) -> Result<Self, std::io::Error> {
12 | let mut f: &'a File = &File::create(path)?;
| -------- ^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use
| |
| type annotation requires that borrow lasts for `'a`
...
15 | }
| - temporary value is freed at the end of this statement
As #E_net4 mentioned, I don't want a mutable reference, yet I want to own the value. Rather than trying to play with lifetimes, I can basically just own the file and handle the whole struct as mutable when trying to write to the file!
use std::path::{ PathBuf };
use std::fs::File;
use std::io::Write;
use std::env;
#[derive(Debug)]
pub struct Foo {
file: File,
}
impl Foo {
pub fn new(path: PathBuf) -> Self {
Self {
file: File::create(path).unwrap(),
}
}
pub fn write(&mut self, b: &[u8]) -> Result<usize, std::io::Error> {
self.file.write(b)
}
}
fn main() {
let mut tmp_dir = env::temp_dir();
tmp_dir.push("foo23");
let mut f = Foo::new(tmp_dir);
f.write(b"test2").unwrap();
}

Resources