Skip to main content

honzo_chunks/extra/
mod.rs

1use honzo_core::HonzoError;
2use std::any::Any;
3use std::collections::HashMap;
4use std::sync::{Arc, OnceLock, RwLock};
5
6pub const ANNO_NAMESPACE: &str = "org.nisoku.anno";
7pub const DRM_NAMESPACE: &str = "org.nisoku.drm";
8pub const SYNC_NAMESPACE: &str = "org.nisoku.sync";
9
10pub mod anno;
11pub mod drm;
12pub mod sync;
13
14pub type RegisteredExtraValue = Box<dyn Any + Send + Sync>;
15pub type RegisteredExtraParser =
16    dyn Fn(&[u8]) -> Result<RegisteredExtraValue, HonzoError> + Send + Sync + 'static;
17
18static EXTRA_REGISTRY: OnceLock<RwLock<HashMap<String, Arc<RegisteredExtraParser>>>> =
19    OnceLock::new();
20
21fn registry() -> &'static RwLock<HashMap<String, Arc<RegisteredExtraParser>>> {
22    EXTRA_REGISTRY.get_or_init(|| RwLock::new(HashMap::new()))
23}
24
25pub fn boxed_extra<T: Any + Send + Sync>(value: T) -> RegisteredExtraValue {
26    Box::new(value)
27}
28
29pub struct RegisteredExtra {
30    namespace: String,
31    value: RegisteredExtraValue,
32}
33
34impl core::fmt::Debug for RegisteredExtra {
35    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
36        f.debug_struct("RegisteredExtra")
37            .field("namespace", &self.namespace)
38            .field("value_type", &std::any::type_name_of_val(&*self.value))
39            .finish()
40    }
41}
42
43impl RegisteredExtra {
44    pub fn namespace(&self) -> &str {
45        &self.namespace
46    }
47
48    pub fn downcast_ref<T: Any>(&self) -> Option<&T> {
49        self.value.downcast_ref()
50    }
51
52    pub fn into_downcast<T: Any>(self) -> Result<Box<T>, Self> {
53        match self.value.downcast::<T>() {
54            Ok(value) => Ok(value),
55            Err(value) => Err(Self {
56                namespace: self.namespace,
57                value,
58            }),
59        }
60    }
61}
62
63#[derive(Debug)]
64pub enum ParsedExtra {
65    Known(KnownExtra),
66    Registered(RegisteredExtra),
67}
68
69#[derive(Debug, Clone, PartialEq, Eq)]
70pub enum KnownExtra {
71    Anno(Vec<anno::Annotation>),
72    Drm(drm::DrmEnvelope),
73    Sync(Vec<sync::SyncCue>),
74}
75
76impl KnownExtra {
77    pub fn namespace(&self) -> &'static str {
78        match self {
79            Self::Anno(_) => ANNO_NAMESPACE,
80            Self::Drm(_) => DRM_NAMESPACE,
81            Self::Sync(_) => SYNC_NAMESPACE,
82        }
83    }
84}
85
86pub fn is_known_namespace(namespace: &str) -> bool {
87    if matches!(namespace, ANNO_NAMESPACE | DRM_NAMESPACE | SYNC_NAMESPACE) {
88        return true;
89    }
90    registry()
91        .read()
92        .expect("extra registry poisoned")
93        .contains_key(namespace)
94}
95
96pub fn parse_known(namespace: &str, body: &[u8]) -> Option<Result<KnownExtra, HonzoError>> {
97    match namespace {
98        ANNO_NAMESPACE => Some(anno::parse_anno(body).map(KnownExtra::Anno)),
99        DRM_NAMESPACE => Some(drm::parse_drm(body).map(KnownExtra::Drm)),
100        SYNC_NAMESPACE => Some(sync::parse_sync(body).map(KnownExtra::Sync)),
101        _ => None,
102    }
103}
104
105pub fn register_extra_parser(
106    namespace: impl Into<String>,
107    parser: impl Fn(&[u8]) -> Result<RegisteredExtraValue, HonzoError> + Send + Sync + 'static,
108) -> Option<Arc<RegisteredExtraParser>> {
109    registry()
110        .write()
111        .expect("extra registry poisoned")
112        .insert(namespace.into(), Arc::new(parser))
113}
114
115pub fn parse_registered(
116    namespace: &str,
117    body: &[u8],
118) -> Option<Result<RegisteredExtra, HonzoError>> {
119    let parser = registry()
120        .read()
121        .expect("extra registry poisoned")
122        .get(namespace)
123        .cloned()?;
124
125    Some(parser(body).map(|value| RegisteredExtra {
126        namespace: namespace.to_string(),
127        value,
128    }))
129}
130
131pub fn parse_extra(namespace: &str, body: &[u8]) -> Option<Result<ParsedExtra, HonzoError>> {
132    if let Some(parsed) = parse_known(namespace, body) {
133        return Some(parsed.map(ParsedExtra::Known));
134    }
135
136    parse_registered(namespace, body).map(|parsed| parsed.map(ParsedExtra::Registered))
137}