use super::super::virtual_block::{
VirtualAllocation, VirtualAllocationInfo, VirtualBlock, VirtualBlockDetails, VirtualBlockStats,
};
use super::super::{AllocError, AllocationAlgorithm, PlacementStrategy};
use crate as vk;
use std::sync::{Mutex, PoisonError};
pub struct SynchronizedVirtualBlock<'callbacks> {
inner: Mutex<Transferable<'callbacks>>,
}
struct Transferable<'callbacks>(VirtualBlock<'callbacks>);
unsafe impl Send for Transferable<'_> {}
impl<'callbacks> SynchronizedVirtualBlock<'callbacks> {
fn locked<R>(
&self,
operation: impl FnOnce(&mut VirtualBlock<'callbacks>) -> Result<R, AllocError>,
) -> Result<R, AllocError> {
let mut guard = self
.inner
.lock()
.map_err(|_| AllocError::SynchronizationPoisoned)?;
operation(&mut guard.0)
}
pub fn new(size: u64) -> Result<Self, AllocError> {
Self::new_with_algorithm(size, AllocationAlgorithm::Tlsf)
}
pub fn new_with_algorithm(size: u64, algorithm: AllocationAlgorithm) -> Result<Self, AllocError> {
Ok(Self {
inner: Mutex::new(Transferable(VirtualBlock::new_with_algorithm(
size, algorithm,
)?)),
})
}
pub unsafe fn new_with_callbacks(
size: u64,
algorithm: AllocationAlgorithm,
callbacks: &'callbacks vk::AllocationCallbacks,
) -> Result<Self, AllocError> {
let block = unsafe { VirtualBlock::new_with_callbacks(size, algorithm, callbacks)? };
Ok(Self {
inner: Mutex::new(Transferable(block)),
})
}
pub unsafe fn new_from_block(block: VirtualBlock<'callbacks>) -> Self {
Self {
inner: Mutex::new(Transferable(block)),
}
}
pub fn allocate(
&self,
size: u64,
alignment: u64,
strategy: PlacementStrategy,
) -> Result<VirtualAllocation, AllocError> {
self.locked(|block| block.allocate(size, alignment, strategy))
}
pub fn allocate_upper(&self, size: u64, alignment: u64) -> Result<VirtualAllocation, AllocError> {
self.locked(|block| block.allocate_upper(size, alignment))
}
pub fn free(&self, allocation: &mut VirtualAllocation) -> Result<(), AllocError> {
self.locked(|block| block.free(allocation))
}
pub fn allocation_info(
&self,
allocation: &VirtualAllocation,
) -> Result<VirtualAllocationInfo, AllocError> {
self.locked(|block| block.allocation_info(allocation))
}
pub fn set_user_data(
&self,
allocation: &VirtualAllocation,
data: usize,
) -> Result<(), AllocError> {
self.locked(|block| block.set_user_data(allocation, data))
}
pub fn is_empty(&self) -> Result<bool, AllocError> {
self.locked(|block| Ok(block.is_empty()))
}
pub fn clear(&self) -> Result<(), AllocError> {
self.locked(|block| {
block.clear();
Ok(())
})
}
pub fn statistics(&self) -> Result<VirtualBlockStats, AllocError> {
self.locked(|block| Ok(block.statistics()))
}
pub fn detailed_statistics(&self) -> Result<VirtualBlockDetails, AllocError> {
self.locked(|block| Ok(block.detailed_statistics()))
}
pub fn write_statistics_json(
&self,
output: &mut impl std::io::Write,
detailed: bool,
) -> Result<(), AllocError> {
self.locked(|block| block.write_statistics_json(output, detailed))
}
#[allow(clippy::result_large_err)]
pub fn into_inner(
self,
) -> Result<VirtualBlock<'callbacks>, PoisonError<VirtualBlock<'callbacks>>> {
match self.inner.into_inner() {
Ok(owner) => Ok(owner.0),
Err(error) => Err(PoisonError::new(error.into_inner().0)),
}
}
}