use cxx::UniquePtr;
use essentia_sys::ffi;
use thiserror::Error;
use crate::data::types::HasDataType;
use crate::data::{
ConversionError, DataContainer, DataType, GetFromDataContainer, PoolData, TryIntoDataContainer,
};
pub struct Pool {
inner: UniquePtr<ffi::PoolBridge>,
}
impl Default for Pool {
fn default() -> Self {
Self::new()
}
}
impl Pool {
pub fn new() -> Self {
Self {
inner: ffi::create_pool_bridge(),
}
}
pub(crate) fn new_from_bridge(bridge: UniquePtr<ffi::PoolBridge>) -> Self {
Self { inner: bridge }
}
pub fn set<T>(
&mut self,
key: &str,
value: impl TryIntoDataContainer<T>,
) -> Result<(), PoolError>
where
T: PoolData + HasDataType,
{
let data_container =
value
.try_into_data_container()
.map_err(|error| PoolError::DataConversion {
key: key.to_string(),
source: error,
})?;
self.inner
.pin_mut()
.set(key, data_container.into_owned_ptr());
Ok(())
}
pub fn get<T, R>(&self, key: &str) -> Result<R, PoolError>
where
T: PoolData + HasDataType,
for<'a> DataContainer<'a, T>: GetFromDataContainer<R>,
{
if !self.contains(key) {
return Err(PoolError::KeyNotFound {
key: key.to_string(),
});
}
let data_container_ffi =
self.inner
.as_ref()
.unwrap()
.get(key)
.map_err(|exception| PoolError::Internal {
key: key.to_string(),
source: exception,
})?;
let data_container = DataContainer::new_borrowed(data_container_ffi.as_ref().unwrap());
let expected_type = T::data_type();
let actual_type = data_container.data_type();
if actual_type != expected_type {
return Err(PoolError::TypeMismatch {
key: key.to_string(),
expected: expected_type,
actual: actual_type,
});
}
Ok(data_container.get())
}
pub fn get_container<T>(&self, key: &str) -> Result<DataContainer<'static, T>, PoolError>
where
T: PoolData + HasDataType,
{
if !self.contains(key) {
return Err(PoolError::KeyNotFound {
key: key.to_string(),
});
}
let data_container_ffi =
self.inner
.as_ref()
.unwrap()
.get(key)
.map_err(|exception| PoolError::Internal {
key: key.to_string(),
source: exception,
})?;
let data_container = DataContainer::new_owned(data_container_ffi);
let expected_type = T::data_type();
let actual_type = data_container.data_type();
if actual_type != expected_type {
return Err(PoolError::TypeMismatch {
key: key.to_string(),
expected: expected_type,
actual: actual_type,
});
}
Ok(data_container)
}
pub fn contains(&self, key: &str) -> bool {
self.inner.as_ref().unwrap().contains(key)
}
pub fn keys(&self) -> Vec<String> {
self.inner.as_ref().unwrap().keys()
}
pub fn len(&self) -> usize {
self.keys().len()
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
pub(crate) fn into_owned_ptr(self) -> UniquePtr<ffi::PoolBridge> {
self.inner
}
}
#[derive(Debug, Error)]
pub enum PoolError {
#[error("Key '{key}' not found in pool")]
KeyNotFound { key: String },
#[error("Type mismatch for key '{key}': expected {expected}, found {actual}")]
TypeMismatch {
key: String,
expected: DataType,
actual: DataType,
},
#[error("Failed to convert data for key '{key}': {source}")]
DataConversion {
key: String,
#[source]
source: ConversionError,
},
#[error("Internal error for key '{key}': {source}")]
Internal {
key: String,
#[source]
source: cxx::Exception,
},
}