1use 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 pub fn iter(&self) -> impl Iterator<Item = &Arc<T>> {
26 self.format_builders.iter()
27 }
28
29 pub fn len(&self) -> usize {
31 self.format_builders.len()
32 }
33
34 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
46pub type LazyFormatList<T> = LazyLock<RwLock<FormatList<T>>>;
48
49pub 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 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
67pub 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}