use std::{
collections::HashMap,
sync::{Arc, LazyLock, RwLock},
};
use media_core::{invalid_error, not_found_error, Result};
use media_format_types::FormatBuilder;
pub struct FormatList<T: ?Sized + FormatBuilder> {
format_builders: Vec<Arc<T>>,
extension_map: HashMap<String, Arc<T>>,
}
impl<T: ?Sized + FormatBuilder> FormatList<T> {
pub fn new() -> Self {
Self {
format_builders: Vec::new(),
extension_map: HashMap::new(),
}
}
pub fn iter(&self) -> impl Iterator<Item = &Arc<T>> {
self.format_builders.iter()
}
pub fn len(&self) -> usize {
self.format_builders.len()
}
pub fn is_empty(&self) -> bool {
self.format_builders.is_empty()
}
}
impl<B: ?Sized + FormatBuilder> Default for FormatList<B> {
fn default() -> Self {
Self::new()
}
}
pub type LazyFormatList<T> = LazyLock<RwLock<FormatList<T>>>;
pub fn register_format<T>(format_list: &LazyFormatList<T>, builder: Arc<T>) -> Result<()>
where
T: ?Sized + FormatBuilder,
{
let mut list = format_list.write().map_err(|err| invalid_error!(err.to_string()))?;
list.format_builders.push(Arc::clone(&builder));
for &ext in builder.extensions() {
let ext = ext.to_lowercase();
list.extension_map.insert(ext, Arc::clone(&builder));
}
Ok(())
}
pub fn find_format_by_extension<T: ?Sized + FormatBuilder>(format_list: &LazyFormatList<T>, ext: &str) -> Result<Arc<T>> {
let list = format_list.read().map_err(|err| invalid_error!(err.to_string()))?;
let ext = ext.to_lowercase();
list.extension_map.get(&ext).cloned().ok_or_else(|| not_found_error!("format for extension", ext))
}