So, I'm having a hell of a time trying to get this audio decoding module to work.
My audio decoder has various functions for decoding various audio formats (right now its Ogg/Vorbis, CAF/ALAC and FLAC). I'm trying to make each function return a Result<>. My custom error type looks like this:
type Result<T> = std::result::Result<T, AudioError>;
#[derive(Debug, Clone, Copy)]
pub struct AudioError(&'static str);
impl fmt::Display for AudioError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.0)?;
Ok(())
}
}
impl error::Error for AudioError {
fn source(&self) -> Option<&(dyn error::Error + 'static)> {
None
}
}
I'm trying to do something like the following:
fn decode_flac(filename: &'static str) -> Result<Arc<StaticSource>> {
use claxon::FlacReader;
let mut reader = match FlacReader::open(filename) {
Ok(r) => r,
Err(e) => {
return Err(AudioError(
format!("Could not open {}: {}", filename, e).as_str(),
))
}
};
let bps = reader.streaminfo().bits_per_sample as f32;
let mut samples: Vec<f32> = Vec::new();
for sample in reader.samples() {
match sample {
Ok(s) => {
// We need to dequantize the sample to get its 32-bit floating point equivalent
let dequantized_sample = {
let range = bps.exp2();
((2.0 * (s as f32) + range) / (range - 1.0)) - 1.0
};
samples.push(dequantized_sample);
}
Err(e) => {
return Err(AudioError(
format!("Audio: flac: decoding error: {}: {}", filename, e,).as_str(),
))
}
}
}
let src = match create_source(
samples,
reader.streaminfo().sample_rate,
reader.streaminfo().channels,
) {
Ok(s) => s,
Err(e) => {
return Err(AudioError(
format!("Cannot generate source: {}", e).as_str(),
))
}
};
let src = Arc::new(src);
match SRCS.write() {
Ok(mut s) => s.push((filename, src.clone())),
_ => panic!("Internal data storage for sources is poisoned!"),
}
Ok(src.clone())
}
However, the borrow checker is claiming that one of the variables is dropped (when I'm really returning it). This is probably because of how I'm declaring my storage mechanism. As a side note, I want to store an internal list of filenames and sources without having to either create new internal lists every time I need to do that or passing all of these around. So if someone could point me to a more idiomatic way of doing this, please do. This is how I'm creating the Vec<>:
use alto::*;
use lazy_static::*;
use std::convert::TryInto;
use std::error;
use std::fmt;
use std::fs::File;
use std::path::Path;
use std::sync::{Arc, RwLock};
lazy_static! {
static ref SRCS: RwLock<Vec<(&'static str, Arc<StaticSource>)>> = RwLock::new(Vec::new());
// ...
}
So:
- how would I fix this &'static lifetime problem when storing a Vec<> like this?
- Is there a more idiomatic way of storing an internal list like this without having to pass all sorts of copies around? Even if its "zero-cost," I would rather avoid it, especially since its not meant to be accessed publicly.