use std::ffi::CString;
use std::ptr::NonNull;
use std::slice;
use std::str;
use crate::{MaaError, MaaResult, sys};
macro_rules! impl_buffer_lifecycle {
($name:ident, $sys_type:ty, $create_fn:path, $destroy_fn:path) => {
unsafe impl Send for $name {}
impl $name {
pub fn new() -> MaaResult<Self> {
let handle = unsafe { $create_fn() };
NonNull::new(handle)
.map(|ptr| Self {
handle: ptr,
own: true,
})
.ok_or(MaaError::NullPointer)
}
pub unsafe fn from_raw(handle: *mut $sys_type) -> Self {
Self {
handle: unsafe { NonNull::new_unchecked(handle) },
own: false,
}
}
pub fn from_handle(handle: *mut $sys_type) -> Option<Self> {
NonNull::new(handle).map(|ptr| Self {
handle: ptr,
own: false,
})
}
#[inline]
pub fn as_ptr(&self) -> *mut $sys_type {
self.handle.as_ptr()
}
#[inline]
pub fn raw(&self) -> *mut $sys_type {
self.handle.as_ptr()
}
}
impl Drop for $name {
fn drop(&mut self) {
if self.own {
unsafe { $destroy_fn(self.handle.as_ptr()) }
}
}
}
impl Default for $name {
fn default() -> Self {
Self::new().expect(concat!("Failed to create ", stringify!($name)))
}
}
impl std::fmt::Debug for $name {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct(stringify!($name))
.field("handle", &self.handle)
.field("own", &self.own)
.finish()
}
}
};
}
pub struct MaaStringBuffer {
handle: NonNull<sys::MaaStringBuffer>,
own: bool,
}
impl_buffer_lifecycle!(
MaaStringBuffer,
sys::MaaStringBuffer,
sys::MaaStringBufferCreate,
sys::MaaStringBufferDestroy
);
impl MaaStringBuffer {
pub fn set<S: AsRef<str>>(&mut self, content: S) -> MaaResult<()> {
let s = content.as_ref();
let c_str = CString::new(s)?;
let ret = unsafe { sys::MaaStringBufferSet(self.handle.as_ptr(), c_str.as_ptr()) };
crate::common::check_bool(ret)
}
pub fn set_ex<B: AsRef<[u8]>>(&mut self, content: B) -> MaaResult<()> {
let bytes = content.as_ref();
let ret = unsafe {
sys::MaaStringBufferSetEx(
self.handle.as_ptr(),
bytes.as_ptr() as *const _,
bytes.len() as u64,
)
};
crate::common::check_bool(ret)
}
pub fn as_str(&self) -> &str {
let bytes = self.as_bytes();
if bytes.is_empty() {
""
} else {
str::from_utf8(bytes).unwrap_or("")
}
}
pub fn as_bytes(&self) -> &[u8] {
unsafe {
let ptr = sys::MaaStringBufferGet(self.handle.as_ptr());
let size = sys::MaaStringBufferSize(self.handle.as_ptr()) as usize;
if ptr.is_null() || size == 0 {
&[]
} else {
slice::from_raw_parts(ptr as *const u8, size)
}
}
}
pub fn is_empty(&self) -> bool {
unsafe { sys::MaaStringBufferIsEmpty(self.handle.as_ptr()) != 0 }
}
pub fn clear(&mut self) -> MaaResult<()> {
let ret = unsafe { sys::MaaStringBufferClear(self.handle.as_ptr()) };
crate::common::check_bool(ret)
}
pub fn len(&self) -> usize {
unsafe { sys::MaaStringBufferSize(self.handle.as_ptr()) as usize }
}
}
impl std::fmt::Display for MaaStringBuffer {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(self.as_str())
}
}
impl From<&str> for MaaStringBuffer {
fn from(s: &str) -> Self {
let mut buf = Self::new().expect("Failed to create MaaStringBuffer");
buf.set(s).expect("Failed to set string buffer content");
buf
}
}
impl AsRef<str> for MaaStringBuffer {
fn as_ref(&self) -> &str {
self.as_str()
}
}
pub struct MaaImageBuffer {
handle: NonNull<sys::MaaImageBuffer>,
own: bool,
}
impl_buffer_lifecycle!(
MaaImageBuffer,
sys::MaaImageBuffer,
sys::MaaImageBufferCreate,
sys::MaaImageBufferDestroy
);
impl MaaImageBuffer {
pub fn is_empty(&self) -> bool {
unsafe { sys::MaaImageBufferIsEmpty(self.handle.as_ptr()) != 0 }
}
pub fn clear(&mut self) -> MaaResult<()> {
let ret = unsafe { sys::MaaImageBufferClear(self.handle.as_ptr()) };
crate::common::check_bool(ret)
}
pub fn width(&self) -> i32 {
unsafe { sys::MaaImageBufferWidth(self.handle.as_ptr()) }
}
pub fn height(&self) -> i32 {
unsafe { sys::MaaImageBufferHeight(self.handle.as_ptr()) }
}
pub fn channels(&self) -> i32 {
unsafe { sys::MaaImageBufferChannels(self.handle.as_ptr()) }
}
pub fn image_type(&self) -> i32 {
unsafe { sys::MaaImageBufferType(self.handle.as_ptr()) }
}
pub fn to_vec(&self) -> Option<Vec<u8>> {
unsafe {
let ptr = sys::MaaImageBufferGetEncoded(self.handle.as_ptr());
let size = sys::MaaImageBufferGetEncodedSize(self.handle.as_ptr());
if !ptr.is_null() && size > 0 {
let slice = slice::from_raw_parts(ptr, size as usize);
Some(slice.to_vec())
} else {
None
}
}
}
pub fn raw_data(&self) -> Option<&[u8]> {
unsafe {
let ptr = sys::MaaImageBufferGetRawData(self.handle.as_ptr());
if ptr.is_null() {
return None;
}
let w = self.width() as usize;
let h = self.height() as usize;
let c = self.channels() as usize;
if w == 0 || h == 0 || c == 0 {
return None;
}
Some(slice::from_raw_parts(ptr as *const u8, w * h * c))
}
}
pub fn set_raw_data(
&mut self,
data: &[u8],
width: i32,
height: i32,
img_type: i32,
) -> MaaResult<()> {
let ret = unsafe {
sys::MaaImageBufferSetRawData(
self.handle.as_ptr(),
data.as_ptr() as *mut std::ffi::c_void,
width,
height,
img_type,
)
};
crate::common::check_bool(ret)
}
pub fn set(&mut self, data: &[u8], width: i32, height: i32) -> MaaResult<()> {
self.set_raw_data(data, width, height, 16)
}
pub fn set_encoded(&mut self, data: &[u8]) -> MaaResult<()> {
let ret = unsafe {
sys::MaaImageBufferSetEncoded(
self.handle.as_ptr(),
data.as_ptr() as *mut u8,
data.len() as u64,
)
};
crate::common::check_bool(ret)
}
pub fn resize(&mut self, width: i32, height: i32) -> MaaResult<()> {
let ret = unsafe { sys::MaaImageBufferResize(self.handle.as_ptr(), width, height) };
crate::common::check_bool(ret)
}
#[cfg(feature = "image")]
pub fn to_dynamic_image(&self) -> MaaResult<image::DynamicImage> {
let encoded = self.to_vec().ok_or(MaaError::ImageConversionError)?;
image::load_from_memory(&encoded).map_err(|_| MaaError::ImageConversionError)
}
#[cfg(feature = "image")]
pub fn from_dynamic_image(img: &image::DynamicImage) -> MaaResult<Self> {
use std::io::Cursor;
let mut bytes = Vec::new();
img.write_to(&mut Cursor::new(&mut bytes), image::ImageFormat::Png)
.map_err(|_| MaaError::ImageConversionError)?;
let mut buffer = Self::new()?;
buffer.set_encoded(&bytes)?;
Ok(buffer)
}
#[cfg(feature = "image")]
pub fn from_rgb_image(img: &image::RgbImage) -> MaaResult<Self> {
Self::from_dynamic_image(&image::DynamicImage::ImageRgb8(img.clone()))
}
#[cfg(feature = "image")]
pub fn from_rgba_image(img: &image::RgbaImage) -> MaaResult<Self> {
Self::from_dynamic_image(&image::DynamicImage::ImageRgba8(img.clone()))
}
}
pub struct MaaImageListBuffer {
handle: NonNull<sys::MaaImageListBuffer>,
own: bool,
}
impl_buffer_lifecycle!(
MaaImageListBuffer,
sys::MaaImageListBuffer,
sys::MaaImageListBufferCreate,
sys::MaaImageListBufferDestroy
);
impl MaaImageListBuffer {
pub fn len(&self) -> usize {
unsafe { sys::MaaImageListBufferSize(self.handle.as_ptr()) as usize }
}
pub fn is_empty(&self) -> bool {
unsafe { sys::MaaImageListBufferIsEmpty(self.handle.as_ptr()) != 0 }
}
pub fn at(&self, index: usize) -> Option<MaaImageBuffer> {
unsafe {
let ptr = sys::MaaImageListBufferAt(self.handle.as_ptr(), index as u64);
MaaImageBuffer::from_handle(ptr as *mut sys::MaaImageBuffer)
}
}
pub fn append(&self, image: &MaaImageBuffer) -> MaaResult<()> {
let ret = unsafe { sys::MaaImageListBufferAppend(self.handle.as_ptr(), image.as_ptr()) };
crate::common::check_bool(ret)
}
pub fn set(&self, data: &[&MaaImageBuffer]) -> MaaResult<()> {
self.clear()?;
for img in data {
self.append(img)?;
}
Ok(())
}
pub fn remove(&self, index: usize) -> MaaResult<()> {
let ret = unsafe { sys::MaaImageListBufferRemove(self.handle.as_ptr(), index as u64) };
crate::common::check_bool(ret)
}
pub fn clear(&self) -> MaaResult<()> {
let ret = unsafe { sys::MaaImageListBufferClear(self.handle.as_ptr()) };
crate::common::check_bool(ret)
}
pub fn to_vec(&self) -> Vec<MaaImageBuffer> {
(0..self.len()).filter_map(|i| self.at(i)).collect()
}
pub fn iter(&self) -> impl Iterator<Item = MaaImageBuffer> + '_ {
(0..self.len()).filter_map(move |i| self.at(i))
}
pub fn to_vec_of_vec(&self) -> Vec<Vec<u8>> {
self.iter().filter_map(|img| img.to_vec()).collect()
}
pub fn to_raw_vecs(&self) -> Vec<(Vec<u8>, i32, i32, i32, i32)> {
self.iter()
.filter_map(|img| {
img.raw_data().map(|data| {
(
data.to_vec(),
img.width(),
img.height(),
img.channels(),
img.image_type(),
)
})
})
.collect()
}
}
pub struct MaaStringListBuffer {
handle: NonNull<sys::MaaStringListBuffer>,
own: bool,
}
impl_buffer_lifecycle!(
MaaStringListBuffer,
sys::MaaStringListBuffer,
sys::MaaStringListBufferCreate,
sys::MaaStringListBufferDestroy
);
impl MaaStringListBuffer {
pub fn len(&self) -> usize {
unsafe { sys::MaaStringListBufferSize(self.handle.as_ptr()) as usize }
}
pub fn is_empty(&self) -> bool {
unsafe { sys::MaaStringListBufferIsEmpty(self.handle.as_ptr()) != 0 }
}
pub fn append(&self, s: &str) -> MaaResult<()> {
let mut str_buf = MaaStringBuffer::new()?;
str_buf.set(s)?;
let ret = unsafe { sys::MaaStringListBufferAppend(self.handle.as_ptr(), str_buf.as_ptr()) };
crate::common::check_bool(ret)
}
pub fn set<S: AsRef<str>>(&self, data: &[S]) -> MaaResult<()> {
self.clear()?;
for s in data {
self.append(s.as_ref())?;
}
Ok(())
}
pub fn remove(&self, index: usize) -> MaaResult<()> {
let ret = unsafe { sys::MaaStringListBufferRemove(self.handle.as_ptr(), index as u64) };
crate::common::check_bool(ret)
}
pub fn clear(&self) -> MaaResult<()> {
let ret = unsafe { sys::MaaStringListBufferClear(self.handle.as_ptr()) };
crate::common::check_bool(ret)
}
pub fn iter(&self) -> impl Iterator<Item = &str> + '_ {
(0..self.len()).map(move |i| unsafe {
let ptr = sys::MaaStringListBufferAt(self.handle.as_ptr(), i as u64);
if ptr.is_null() {
return "";
}
let str_ptr = sys::MaaStringBufferGet(ptr as *mut sys::MaaStringBuffer);
let size = sys::MaaStringBufferSize(ptr as *mut sys::MaaStringBuffer) as usize;
if str_ptr.is_null() || size == 0 {
""
} else {
let slice = slice::from_raw_parts(str_ptr as *const u8, size);
str::from_utf8(slice).unwrap_or("")
}
})
}
pub fn to_vec(&self) -> Vec<String> {
self.iter().map(|s| s.to_string()).collect()
}
}
pub struct MaaRectBuffer {
handle: NonNull<sys::MaaRect>,
own: bool,
}
impl_buffer_lifecycle!(
MaaRectBuffer,
sys::MaaRect,
sys::MaaRectCreate,
sys::MaaRectDestroy
);
impl MaaRectBuffer {
pub fn get(&self) -> crate::common::Rect {
unsafe {
crate::common::Rect {
x: sys::MaaRectGetX(self.handle.as_ptr()),
y: sys::MaaRectGetY(self.handle.as_ptr()),
width: sys::MaaRectGetW(self.handle.as_ptr()),
height: sys::MaaRectGetH(self.handle.as_ptr()),
}
}
}
pub fn set(&mut self, rect: &crate::common::Rect) -> MaaResult<()> {
let ret = unsafe {
sys::MaaRectSet(
self.handle.as_ptr(),
rect.x,
rect.y,
rect.width,
rect.height,
)
};
crate::common::check_bool(ret)
}
}
impl From<crate::common::Rect> for MaaRectBuffer {
fn from(rect: crate::common::Rect) -> Self {
let mut buf = Self::new().expect("Failed to create MaaRectBuffer");
buf.set(&rect).expect("Failed to set rect buffer");
buf
}
}
impl From<MaaRectBuffer> for crate::common::Rect {
fn from(buf: MaaRectBuffer) -> Self {
buf.get()
}
}
impl From<&MaaRectBuffer> for crate::common::Rect {
fn from(buf: &MaaRectBuffer) -> Self {
buf.get()
}
}