use std::os::raw::c_void;
use std::ptr::null_mut;
use std::mem;
use capi::pa_ext_device_restore_info as InfoInternal;
use super::{ContextInternal, Context};
use crate::{def, format};
use crate::callbacks::{ListResult, box_closure_get_capi_ptr, callback_for_list_instance, ListInstanceCallback, MultiUseCallback};
use crate::operation::Operation;
#[derive(Debug)]
pub struct Info {
pub dtype: def::Device,
pub index: u32,
pub formats: Vec<format::Info>,
}
impl Info {
fn new_from_raw(p: *const InfoInternal) -> Self {
assert!(!p.is_null());
let src = unsafe { p.as_ref().unwrap() };
let mut formats_vec = Vec::with_capacity(src.n_formats as usize);
assert!(src.n_formats == 0 || !src.formats.is_null());
for i in 0..src.n_formats as isize {
let indexed_ptr = unsafe { (*src.formats.offset(i)) as *mut format::InfoInternal };
if !indexed_ptr.is_null() {
formats_vec.push(format::Info::from_raw_weak(indexed_ptr));
}
}
Info {
dtype: src.dtype,
index: src.index,
formats: formats_vec,
}
}
}
pub struct DeviceRestore {
context: *mut ContextInternal,
cb_ptrs: CallbackPointers,
}
unsafe impl Send for DeviceRestore {}
unsafe impl Sync for DeviceRestore {}
#[derive(Default)]
struct CallbackPointers {
subscribe: SubscribeCb,
}
type SubscribeCb = MultiUseCallback<dyn FnMut(def::Device, u32),
extern "C" fn(*mut ContextInternal, def::Device, u32, *mut c_void)>;
impl Context {
pub fn device_restore(&self) -> DeviceRestore {
unsafe { capi::pa_context_ref(self.ptr) };
DeviceRestore::from_raw(self.ptr)
}
}
impl DeviceRestore {
fn from_raw(context: *mut ContextInternal) -> Self {
Self { context: context, cb_ptrs: Default::default() }
}
pub fn test<F>(&mut self, callback: F) -> Operation<dyn FnMut(u32)>
where F: FnMut(u32) + 'static
{
let cb_data = box_closure_get_capi_ptr::<dyn FnMut(u32)>(Box::new(callback));
let ptr = unsafe { capi::pa_ext_device_restore_test(self.context,
Some(super::ext_test_cb_proxy), cb_data) };
assert!(!ptr.is_null());
Operation::from_raw(ptr, cb_data as *mut Box<dyn FnMut(u32)>)
}
pub fn subscribe<F>(&mut self, enable: bool, callback: F) -> Operation<dyn FnMut(bool)>
where F: FnMut(bool) + 'static
{
let cb_data = box_closure_get_capi_ptr::<dyn FnMut(bool)>(Box::new(callback));
let ptr = unsafe { capi::pa_ext_device_restore_subscribe(self.context, enable as i32,
Some(super::success_cb_proxy), cb_data) };
assert!(!ptr.is_null());
Operation::from_raw(ptr, cb_data as *mut Box<dyn FnMut(bool)>)
}
pub fn set_subscribe_cb<F>(&mut self, callback: F)
where F: FnMut(def::Device, u32) + 'static
{
let saved = &mut self.cb_ptrs.subscribe;
*saved = SubscribeCb::new(Some(Box::new(callback)));
let (cb_fn, cb_data) = saved.get_capi_params(ext_subscribe_cb_proxy);
unsafe { capi::pa_ext_device_restore_set_subscribe_cb(self.context, cb_fn, cb_data); }
}
pub fn read_formats_all<F>(&mut self, callback: F) -> Operation<dyn FnMut(ListResult<&Info>)>
where F: FnMut(ListResult<&Info>) + 'static
{
let cb_data = box_closure_get_capi_ptr::<dyn FnMut(ListResult<&Info>)>(Box::new(callback));
let ptr = unsafe { capi::pa_ext_device_restore_read_formats_all(self.context,
Some(read_list_cb_proxy), cb_data) };
assert!(!ptr.is_null());
Operation::from_raw(ptr, cb_data as *mut Box<dyn FnMut(ListResult<&Info>)>)
}
pub fn read_formats<F>(&mut self, type_: def::Device, index: u32, callback: F)
-> Operation<dyn FnMut(ListResult<&Info>)>
where F: FnMut(ListResult<&Info>) + 'static
{
let cb_data = box_closure_get_capi_ptr::<dyn FnMut(ListResult<&Info>)>(Box::new(callback));
let ptr = unsafe { capi::pa_ext_device_restore_read_formats(self.context, type_, index,
Some(read_list_cb_proxy), cb_data) };
assert!(!ptr.is_null());
Operation::from_raw(ptr, cb_data as *mut Box<dyn FnMut(ListResult<&Info>)>)
}
pub fn save_formats<F>(&mut self, type_: def::Device, index: u32,
formats: &mut [&mut format::Info], callback: F) -> Operation<dyn FnMut(bool)>
where F: FnMut(bool) + 'static
{
let mut format_ptrs: Vec<*mut capi::pa_format_info> = Vec::with_capacity(formats.len());
for format in formats {
format_ptrs.push(unsafe { mem::transmute(&format.ptr) });
}
let cb_data = box_closure_get_capi_ptr::<dyn FnMut(bool)>(Box::new(callback));
let ptr = unsafe {
capi::pa_ext_device_restore_save_formats(self.context, type_, index,
format_ptrs.len() as u8, format_ptrs.as_ptr(), Some(super::success_cb_proxy),
cb_data)
};
assert!(!ptr.is_null());
Operation::from_raw(ptr, cb_data as *mut Box<dyn FnMut(bool)>)
}
}
impl Drop for DeviceRestore {
fn drop(&mut self) {
unsafe { capi::pa_context_unref(self.context) };
self.context = null_mut::<ContextInternal>();
}
}
extern "C"
fn ext_subscribe_cb_proxy(_: *mut ContextInternal, type_: def::Device, index: u32,
userdata: *mut c_void)
{
let _ = std::panic::catch_unwind(|| {
let callback = SubscribeCb::get_callback(userdata);
(callback)(type_, index);
});
}
extern "C"
fn read_list_cb_proxy(_: *mut ContextInternal, i: *const InfoInternal, eol: i32,
userdata: *mut c_void)
{
let _ = std::panic::catch_unwind(|| {
match callback_for_list_instance::<dyn FnMut(ListResult<&Info>)>(eol, userdata) {
ListInstanceCallback::Entry(callback) => {
assert!(!i.is_null());
let obj = Info::new_from_raw(i);
(callback)(ListResult::Item(&obj));
},
ListInstanceCallback::End(mut callback) => { (callback)(ListResult::End); },
ListInstanceCallback::Error(mut callback) => { (callback)(ListResult::Error); },
}
});
}