Skip to main content

media_format/
format.rs

1//! Format
2
3use std::{
4    collections::HashMap,
5    sync::{Arc, LazyLock, RwLock},
6};
7
8use media_core::{invalid_error, not_found_error, Result};
9use media_format_types::FormatBuilder;
10
11pub struct FormatList<T: ?Sized + FormatBuilder> {
12    format_builders: Vec<Arc<T>>,
13    extension_map: HashMap<String, Arc<T>>,
14}
15
16impl<T: ?Sized + FormatBuilder> FormatList<T> {
17    pub fn new() -> Self {
18        Self {
19            format_builders: Vec::new(),
20            extension_map: HashMap::new(),
21        }
22    }
23
24    /// Returns an iterator over all registered format builders
25    pub fn iter(&self) -> impl Iterator<Item = &Arc<T>> {
26        self.format_builders.iter()
27    }
28
29    /// Returns the number of registered format builders
30    pub fn len(&self) -> usize {
31        self.format_builders.len()
32    }
33
34    /// Returns true if no format builders are registered
35    pub fn is_empty(&self) -> bool {
36        self.format_builders.is_empty()
37    }
38}
39
40impl<B: ?Sized + FormatBuilder> Default for FormatList<B> {
41    fn default() -> Self {
42        Self::new()
43    }
44}
45
46/// Lazy-initialized format list with RwLock for thread safety
47pub type LazyFormatList<T> = LazyLock<RwLock<FormatList<T>>>;
48
49/// Registers a format builder in the format list
50pub fn register_format<T>(format_list: &LazyFormatList<T>, builder: Arc<T>) -> Result<()>
51where
52    T: ?Sized + FormatBuilder,
53{
54    let mut list = format_list.write().map_err(|err| invalid_error!(err.to_string()))?;
55
56    list.format_builders.push(Arc::clone(&builder));
57
58    // Register by extensions
59    for &ext in builder.extensions() {
60        let ext = ext.to_lowercase();
61        list.extension_map.insert(ext, Arc::clone(&builder));
62    }
63
64    Ok(())
65}
66
67/// Find a format builder by file extension
68pub fn find_format_by_extension<T: ?Sized + FormatBuilder>(format_list: &LazyFormatList<T>, ext: &str) -> Result<Arc<T>> {
69    let list = format_list.read().map_err(|err| invalid_error!(err.to_string()))?;
70
71    let ext = ext.to_lowercase();
72    list.extension_map.get(&ext).cloned().ok_or_else(|| not_found_error!("format for extension", ext))
73}