Skip to main content

basisu_c_sys/extra/
mod.rs

1#[cfg(feature = "encoder")]
2#[cfg_attr(docsrs, doc(cfg(feature = "encoder")))]
3mod encoder;
4mod transcoder;
5
6use bytemuck::NoUninit;
7#[cfg(feature = "encoder")]
8#[cfg_attr(docsrs, doc(cfg(feature = "encoder")))]
9pub use encoder::*;
10pub use transcoder::*;
11
12use crate::transcoder as trans_sys;
13use alloc::vec::Vec;
14use core::num::NonZero;
15use core::ops::{Bound, Range, RangeBounds};
16
17#[derive(Debug, thiserror::Error)]
18pub(crate) enum BuHeapAccessError {
19    #[error("Invalid {range:?}, end < start")]
20    InvalidRange { range: Range<u64> },
21    #[error("Read/Write out of bounds, the capacity is {capacity} but the end is {end}")]
22    OutOfBounds { end: u64, capacity: u64 },
23}
24
25/// Safe wrapper of basisu memory allocation ([`trans_sys::bt_alloc`] and [`trans_sys::bt_free`]).
26///
27// Note: This is used for both transcoder and encoder and assumes their `alloc` and `free` are the same. If not (though it's unlikely), this should be changed.
28pub(crate) struct BuHeap {
29    ptr: NonZero<u64>,
30    capacity: NonZero<u64>,
31}
32
33impl BuHeap {
34    pub fn new_uninit(capacity: NonZero<u64>) -> Self {
35        unsafe {
36            let ptr = trans_sys::bt_alloc(capacity.into());
37            Self {
38                ptr: NonZero::new(ptr).expect("basisu alloc failed"),
39                capacity,
40            }
41        }
42    }
43    pub fn new<T: NoUninit>(data: &[T]) -> Option<Self> {
44        let data = bytemuck::must_cast_slice(data);
45        let capacity = NonZero::new(data.len() as u64)?;
46        let mut bt = Self::new_uninit(capacity);
47        bt.try_write(0, data).unwrap();
48        Some(bt)
49    }
50    #[inline]
51    pub fn ptr(&self) -> NonZero<u64> {
52        self.ptr
53    }
54    #[inline]
55    pub fn capacity(&self) -> NonZero<u64> {
56        self.capacity
57    }
58    pub fn try_read<S: RangeBounds<u64>>(&self, range: S) -> Result<Vec<u8>, BuHeapAccessError> {
59        let capacity = u64::from(self.capacity());
60        let mut r = 0..capacity;
61        match range.start_bound() {
62            Bound::Included(&start_idx) => {
63                r.start = start_idx;
64            }
65            Bound::Excluded(&start) => {
66                r.start = start + 1;
67            }
68            Bound::Unbounded => {}
69        }
70        match range.end_bound() {
71            Bound::Included(&end_idx) => {
72                r.end = end_idx + 1;
73            }
74            Bound::Excluded(&end) => {
75                r.end = end;
76            }
77            Bound::Unbounded => {}
78        }
79        if r.end < r.start {
80            return Err(BuHeapAccessError::InvalidRange { range: r });
81        }
82        if r.end > capacity {
83            return Err(BuHeapAccessError::OutOfBounds {
84                end: r.end,
85                capacity,
86            });
87        }
88
89        if r.end == r.start {
90            return Ok(Vec::new());
91        }
92
93        Ok(unsafe {
94            crate::copy_basisu_memory_to_host(u64::from(self.ptr()) + r.start, r.end - r.start)
95        })
96    }
97    pub fn try_write(&mut self, offset: u64, data: &[u8]) -> Result<(), BuHeapAccessError> {
98        let capacity = u64::from(self.capacity());
99        let end = offset + data.len() as u64;
100        if end > capacity {
101            return Err(BuHeapAccessError::OutOfBounds { end, capacity });
102        }
103
104        unsafe { crate::copy_host_memory_to_basisu(data, u64::from(self.ptr()) + offset) };
105        Ok(())
106    }
107}
108impl Drop for BuHeap {
109    fn drop(&mut self) {
110        unsafe {
111            trans_sys::bt_free(u64::from(self.ptr()));
112        }
113    }
114}