Skip to main content

essentia_core/pool/
pool.rs

1use cxx::UniquePtr;
2use essentia_sys::ffi;
3use thiserror::Error;
4
5use crate::data::types::HasDataType;
6use crate::data::{
7    ConversionError, DataContainer, DataType, GetFromDataContainer, PoolData, TryIntoDataContainer,
8};
9
10pub struct Pool {
11    inner: UniquePtr<ffi::PoolBridge>,
12}
13
14impl Default for Pool {
15    fn default() -> Self {
16        Self::new()
17    }
18}
19
20impl Pool {
21    pub fn new() -> Self {
22        Self {
23            inner: ffi::create_pool_bridge(),
24        }
25    }
26
27    pub(crate) fn new_from_bridge(bridge: UniquePtr<ffi::PoolBridge>) -> Self {
28        Self { inner: bridge }
29    }
30
31    pub fn set<T>(
32        &mut self,
33        key: &str,
34        value: impl TryIntoDataContainer<T>,
35    ) -> Result<(), PoolError>
36    where
37        T: PoolData + HasDataType,
38    {
39        let data_container =
40            value
41                .try_into_data_container()
42                .map_err(|error| PoolError::DataConversion {
43                    key: key.to_string(),
44                    source: error,
45                })?;
46
47        self.inner
48            .pin_mut()
49            .set(key, data_container.into_owned_ptr());
50
51        Ok(())
52    }
53
54    pub fn get<T, R>(&self, key: &str) -> Result<R, PoolError>
55    where
56        T: PoolData + HasDataType,
57        for<'a> DataContainer<'a, T>: GetFromDataContainer<R>,
58    {
59        if !self.contains(key) {
60            return Err(PoolError::KeyNotFound {
61                key: key.to_string(),
62            });
63        }
64
65        let data_container_ffi =
66            self.inner
67                .as_ref()
68                .unwrap()
69                .get(key)
70                .map_err(|exception| PoolError::Internal {
71                    key: key.to_string(),
72                    source: exception,
73                })?;
74
75        let data_container = DataContainer::new_borrowed(data_container_ffi.as_ref().unwrap());
76
77        // Verify type safety at runtime (backup to compile-time checks)
78        let expected_type = T::data_type();
79        let actual_type = data_container.data_type();
80
81        if actual_type != expected_type {
82            return Err(PoolError::TypeMismatch {
83                key: key.to_string(),
84                expected: expected_type,
85                actual: actual_type,
86            });
87        }
88
89        Ok(data_container.get())
90    }
91
92    pub fn get_container<T>(&self, key: &str) -> Result<DataContainer<'static, T>, PoolError>
93    where
94        T: PoolData + HasDataType,
95    {
96        if !self.contains(key) {
97            return Err(PoolError::KeyNotFound {
98                key: key.to_string(),
99            });
100        }
101
102        let data_container_ffi =
103            self.inner
104                .as_ref()
105                .unwrap()
106                .get(key)
107                .map_err(|exception| PoolError::Internal {
108                    key: key.to_string(),
109                    source: exception,
110                })?;
111
112        let data_container = DataContainer::new_owned(data_container_ffi);
113
114        // Verify type safety
115        let expected_type = T::data_type();
116        let actual_type = data_container.data_type();
117
118        if actual_type != expected_type {
119            return Err(PoolError::TypeMismatch {
120                key: key.to_string(),
121                expected: expected_type,
122                actual: actual_type,
123            });
124        }
125
126        Ok(data_container)
127    }
128
129    pub fn contains(&self, key: &str) -> bool {
130        self.inner.as_ref().unwrap().contains(key)
131    }
132
133    pub fn keys(&self) -> Vec<String> {
134        self.inner.as_ref().unwrap().keys()
135    }
136
137    pub fn len(&self) -> usize {
138        self.keys().len()
139    }
140
141    pub fn is_empty(&self) -> bool {
142        self.len() == 0
143    }
144
145    pub(crate) fn into_owned_ptr(self) -> UniquePtr<ffi::PoolBridge> {
146        self.inner
147    }
148}
149
150#[derive(Debug, Error)]
151pub enum PoolError {
152    #[error("Key '{key}' not found in pool")]
153    KeyNotFound { key: String },
154
155    #[error("Type mismatch for key '{key}': expected {expected}, found {actual}")]
156    TypeMismatch {
157        key: String,
158        expected: DataType,
159        actual: DataType,
160    },
161
162    #[error("Failed to convert data for key '{key}': {source}")]
163    DataConversion {
164        key: String,
165        #[source]
166        source: ConversionError,
167    },
168
169    #[error("Internal error for key '{key}': {source}")]
170    Internal {
171        key: String,
172        #[source]
173        source: cxx::Exception,
174    },
175}