use super::*;
pub trait DeviceCommonImpl: ObjectImpl + ObjectSubclass {
fn open(&self, device: &Self::Type, path: &str, open_flag: i32) -> Result<(), glib::Error>;
fn get_protocol_version(
&self,
device: &Self::Type,
proto_ver_triplet: &mut [u16; 3],
) -> Result<(), glib::Error>;
fn get_device_info(&self, device: &Self::Type) -> Result<DeviceInfo, glib::Error>;
fn create_source(&self, device: &Self::Type) -> Result<glib::Source, glib::Error>;
fn handle_disconnection(&self, device: &Self::Type);
}
pub trait DeviceCommonImplExt: ObjectSubclass {
fn parent_open(
&self,
device: &Self::Type,
path: &str,
open_flag: i32,
) -> Result<(), glib::Error>;
fn parent_get_protocol_version(
&self,
device: &Self::Type,
proto_ver_triplet: &mut [u16; 3],
) -> Result<(), glib::Error>;
fn parent_get_device_info(&self, device: &Self::Type) -> Result<DeviceInfo, glib::Error>;
fn parent_create_source(&self, device: &Self::Type) -> Result<glib::Source, glib::Error>;
fn parent_handle_disconnection(&self, device: &Self::Type);
}
impl<T: DeviceCommonImpl> DeviceCommonImplExt for T {
fn parent_open(
&self,
device: &Self::Type,
path: &str,
open_flag: i32,
) -> Result<(), glib::Error> {
unsafe {
let data = T::type_data();
let parent_class =
data.as_ref().parent_class() as *mut ffi::ALSAHwdepDeviceCommonInterface;
let f = (*parent_class)
.open
.expect("No parent \"open\" implementation");
let mut error = std::ptr::null_mut();
let is_ok = f(
device.unsafe_cast_ref::<DeviceCommon>().to_glib_none().0,
path.to_glib_none().0,
open_flag.into(),
&mut error,
);
assert_eq!(is_ok == glib::ffi::GFALSE, !error.is_null());
if error.is_null() {
Ok(())
} else {
Err(from_glib_full(error))
}
}
}
fn parent_get_protocol_version(
&self,
device: &Self::Type,
proto_ver_triplet: &mut [u16; 3],
) -> Result<(), glib::Error> {
unsafe {
let data = T::type_data();
let parent_class =
data.as_ref().parent_class() as *mut ffi::ALSAHwdepDeviceCommonInterface;
let f = (*parent_class)
.get_protocol_version
.expect("No parent \"get_protocol_version\" implementation");
let ptr: *mut [u16; 3] = proto_ver_triplet;
let mut error = std::ptr::null_mut();
let is_ok = f(
device.unsafe_cast_ref::<DeviceCommon>().to_glib_none().0,
&ptr,
&mut error,
);
assert_eq!(is_ok == glib::ffi::GFALSE, !error.is_null());
if error.is_null() {
Ok(())
} else {
Err(from_glib_full(error))
}
}
}
fn parent_get_device_info(&self, device: &Self::Type) -> Result<DeviceInfo, glib::Error> {
unsafe {
let data = T::type_data();
let parent_class =
data.as_ref().parent_class() as *mut ffi::ALSAHwdepDeviceCommonInterface;
let f = (*parent_class)
.get_device_info
.expect("No parent \"get_device_info\" implementation");
let mut info = std::ptr::null_mut();
let mut error = std::ptr::null_mut();
let is_ok = f(
device.unsafe_cast_ref::<DeviceCommon>().to_glib_none().0,
&mut info,
&mut error,
);
assert_eq!(is_ok == glib::ffi::GFALSE, !error.is_null());
if error.is_null() {
Ok(from_glib_full(info))
} else {
Err(from_glib_full(error))
}
}
}
fn parent_create_source(&self, device: &Self::Type) -> Result<glib::Source, glib::Error> {
unsafe {
let data = T::type_data();
let parent_class =
data.as_ref().parent_class() as *mut ffi::ALSAHwdepDeviceCommonInterface;
let f = (*parent_class)
.create_source
.expect("No parent \"create_source\" implementation");
let mut src = std::ptr::null_mut();
let mut error = std::ptr::null_mut();
let is_ok = f(
device.unsafe_cast_ref::<DeviceCommon>().to_glib_none().0,
&mut src,
&mut error,
);
assert_eq!(is_ok == glib::ffi::GFALSE, !error.is_null());
if error.is_null() {
Ok(from_glib_full(src))
} else {
Err(from_glib_full(error))
}
}
}
fn parent_handle_disconnection(&self, device: &Self::Type) {
unsafe {
let data = T::type_data();
let parent_class =
data.as_ref().parent_class() as *mut ffi::ALSAHwdepDeviceCommonInterface;
let f = (*parent_class)
.handle_disconnection
.expect("No parent \"handle_disconnection\" implementation");
f(device.unsafe_cast_ref::<DeviceCommon>().to_glib_none().0);
}
}
}
unsafe impl<T: DeviceCommonImpl> IsImplementable<T> for DeviceCommon {
fn interface_init(iface: &mut glib::Interface<Self>) {
let iface = iface.as_mut();
iface.open = Some(device_common_open::<T>);
iface.get_protocol_version = Some(device_common_get_protocol_version::<T>);
iface.get_device_info = Some(device_common_get_device_info::<T>);
iface.create_source = Some(device_common_create_source::<T>);
iface.handle_disconnection = Some(device_common_handle_disconnection::<T>);
}
}
unsafe extern "C" fn device_common_open<T: DeviceCommonImpl>(
device: *mut ffi::ALSAHwdepDeviceCommon,
path: *const std::ffi::c_char,
open_flag: std::ffi::c_int,
error: *mut *mut glib::ffi::GError,
) -> glib::ffi::gboolean {
let instance = &*(device as *mut T::Instance);
let imp = instance.imp();
let wrap: Borrowed<DeviceCommon> = from_glib_borrow(device);
match imp.open(
wrap.unsafe_cast_ref(),
std::ffi::CStr::from_ptr(path).to_str().unwrap(),
open_flag,
) {
Ok(()) => glib::ffi::GTRUE,
Err(err) => {
if !error.is_null() {
*error = err.into_glib_ptr();
}
glib::ffi::GFALSE
}
}
}
unsafe extern "C" fn device_common_get_protocol_version<T: DeviceCommonImpl>(
device: *mut ffi::ALSAHwdepDeviceCommon,
proto_ver_triplet: *const *mut [u16; 3],
error: *mut *mut glib::ffi::GError,
) -> glib::ffi::gboolean {
let instance = &*(device as *mut T::Instance);
let imp = instance.imp();
let wrap: Borrowed<DeviceCommon> = from_glib_borrow(device);
match imp.get_protocol_version(wrap.unsafe_cast_ref(), &mut (**proto_ver_triplet)) {
Ok(()) => glib::ffi::GTRUE,
Err(err) => {
if !error.is_null() {
*error = err.into_glib_ptr();
}
glib::ffi::GFALSE
}
}
}
unsafe extern "C" fn device_common_get_device_info<T: DeviceCommonImpl>(
device: *mut ffi::ALSAHwdepDeviceCommon,
device_info: *mut *mut ffi::ALSAHwdepDeviceInfo,
error: *mut *mut glib::ffi::GError,
) -> glib::ffi::gboolean {
let instance = &*(device as *mut T::Instance);
let imp = instance.imp();
let wrap: Borrowed<DeviceCommon> = from_glib_borrow(device);
match imp.get_device_info(wrap.unsafe_cast_ref()) {
Ok(info) => {
*device_info = info.to_glib_full();
glib::ffi::GTRUE
}
Err(err) => {
if !error.is_null() {
*error = err.into_glib_ptr();
}
glib::ffi::GFALSE
}
}
}
unsafe extern "C" fn device_common_create_source<T: DeviceCommonImpl>(
device: *mut ffi::ALSAHwdepDeviceCommon,
source: *mut *mut glib::ffi::GSource,
error: *mut *mut glib::ffi::GError,
) -> glib::ffi::gboolean {
let instance = &*(device as *mut T::Instance);
let imp = instance.imp();
let wrap: Borrowed<DeviceCommon> = from_glib_borrow(device);
match imp.create_source(wrap.unsafe_cast_ref()) {
Ok(src) => {
*source = src.to_glib_none().0;
glib::ffi::GTRUE
}
Err(err) => {
if !error.is_null() {
*error = err.into_glib_ptr();
}
glib::ffi::GFALSE
}
}
}
unsafe extern "C" fn device_common_handle_disconnection<T: DeviceCommonImpl>(
device: *mut ffi::ALSAHwdepDeviceCommon,
) {
let instance = &*(device as *mut T::Instance);
let imp = instance.imp();
let wrap: Borrowed<DeviceCommon> = from_glib_borrow(device);
imp.handle_disconnection(wrap.unsafe_cast_ref())
}
#[cfg(test)]
mod test {
use crate::{prelude::*, subclass::prelude::*, *};
use glib::{prelude::ObjectExt, subclass::prelude::*, Object, Properties};
const NAME: &str = "MyName";
mod imp {
use super::*;
use std::cell::RefCell;
#[derive(Properties)]
#[properties(wrapper_type = super::DeviceCommonTest)]
pub struct DeviceCommonTestPrivate {
#[property(get, set)]
name: RefCell<String>,
#[property(get)]
handled: RefCell<bool>,
}
#[glib::object_subclass]
impl ObjectSubclass for DeviceCommonTestPrivate {
const NAME: &'static str = "DeviceCommonTest";
type Type = super::DeviceCommonTest;
type Interfaces = (DeviceCommon,);
fn new() -> Self {
Self {
name: Default::default(),
handled: Default::default(),
}
}
}
#[glib::derived_properties]
impl ObjectImpl for DeviceCommonTestPrivate {}
impl DeviceCommonImpl for DeviceCommonTestPrivate {
fn open(&self, _: &Self::Type, _: &str, _: i32) -> Result<(), glib::Error> {
Ok(())
}
fn get_protocol_version(
&self,
_: &Self::Type,
proto_ver_triplet: &mut [u16; 3],
) -> Result<(), glib::Error> {
proto_ver_triplet.copy_from_slice(&[1, 2, 3]);
Ok(())
}
fn get_device_info(&self, _: &Self::Type) -> Result<DeviceInfo, glib::Error> {
let device_info = Object::builder::<DeviceInfo>()
.property("name", NAME)
.build();
Ok(device_info)
}
fn create_source(&self, _: &Self::Type) -> Result<glib::Source, glib::Error> {
Err(glib::Error::new(DeviceCommonError::IsOpened, "expected"))
}
fn handle_disconnection(&self, _: &Self::Type) {
*self.handled.borrow_mut() = true;
}
}
}
glib::wrapper! {
pub struct DeviceCommonTest(ObjectSubclass<imp::DeviceCommonTestPrivate>)
@implements DeviceCommon;
}
#[test]
fn device_common_iface() {
let device = Object::builder::<DeviceCommonTest>().build();
assert!(device.open(10000, 10000, 0).is_err());
assert_eq!(device.protocol_version(), Ok([1, 2, 3]));
let device_info = device.device_info().unwrap();
assert_eq!(device_info.name().unwrap(), NAME);
assert!(device.create_source().is_err());
assert_eq!(device.handled(), false);
device.emit_handle_disconnection();
assert_eq!(device.handled(), true);
}
}