serenity-rs / songbird

An async Rust library for the Discord voice API
ISC License
391 stars 111 forks source link

How to get mutable state for buffer? #191

Closed w1nns closed 1 year ago

w1nns commented 1 year ago

Hi! I'm trying to create a discord voice recorder based on this example . How can I create a buffer in which I will put voice packets in order to write it all to a file in the future? I added the buf field to the Receiver structure.

struct Receiver {
    buf: Vec<i16>
}

impl Receiver {
    pub fn new() -> Self {
        // You can manage state here, such as a buffer of audio packet bytes soou can later store them in intervals.
        let buf = Vec::new();
        Self { buf }
    }
}

But I can't change buf field, because the reference to Receiver is not mutable in the act method. If I make this reference mutable, then there will be signature incompatibility.

error[E0053]: method `act` has an incompatible type for trait
  --> src/main.rs:66:18
   |
66 |     async fn act(&mut self, ctx: &EventContext<'_>) -> Option<Event> {
   |                  ^^^^^^^^^
   |                  |
   |                  types differ in mutability
   |                  help: change the self-receiver type to match the trait: `self: &'life0 Receiver`
   |
   = note: expected signature `fn(&'life0 Receiver, &'life1 EventContext<'life2>) -> std::pin::Pin<_>`
              found signature `fn(&'life0 mut Receiver, &'life1 EventContext<'life2>) -> std::pin::Pin<_>`

For more information about this error, try `rustc --explain E0053`.
error: could not compile `rust_discord_bot` due to previous error
FelixMcFelix commented 1 year ago

You can achieve this by using atomic types, concurrent data structures, or explicit locking using mutexes. Assuming you're only setting up one handler per call, mutexes will have practically no cost. The use of shared references is a 'training wheel' measure, since the API might move to spawned futures (all of which point to the same handler) down the line.