use super::*;
pub trait FwIsoCtxImpl: ObjectImpl {
fn create_source(&self, ctx: &Self::Type) -> Result<Source, Error>;
fn flush_completions(&self, ctx: &Self::Type) -> Result<(), Error>;
fn get_cycle_timer(
&self,
ctx: &Self::Type,
clock_id: i32,
cycle_timer: &mut CycleTimer,
) -> Result<(), Error>;
fn release(&self, ctx: &Self::Type);
fn stop(&self, ctx: &Self::Type);
fn unmap_buffer(&self, ctx: &Self::Type);
fn stopped(&self, ctx: &Self::Type, error: Option<&Error>);
}
pub trait FwIsoCtxImplExt: ObjectSubclass {
fn parent_create_source(&self, ctx: &Self::Type) -> Result<Source, Error>;
fn parent_flush_completions(&self, ctx: &Self::Type) -> Result<(), Error>;
fn parent_get_cycle_timer(
&self,
ctx: &Self::Type,
clock_id: i32,
cycle_timer: &mut CycleTimer,
) -> Result<(), Error>;
fn parent_release(&self, ctx: &Self::Type);
fn parent_stop(&self, ctx: &Self::Type);
fn parent_unmap_buffer(&self, ctx: &Self::Type);
fn parent_stopped(&self, ctx: &Self::Type, error: Option<&Error>);
}
impl<T: FwIsoCtxImpl> FwIsoCtxImplExt for T {
fn parent_create_source(&self, ctx: &Self::Type) -> Result<Source, Error> {
unsafe {
let data = T::type_data();
let parent_class = data.as_ref().parent_class() as *mut ffi::HinokoFwIsoCtxInterface;
let f = (*parent_class)
.create_source
.expect("No parent \"create_source\" implementation");
let mut source = std::ptr::null_mut();
let mut error = std::ptr::null_mut();
let is_ok = f(
ctx.unsafe_cast_ref::<FwIsoCtx>().to_glib_none().0,
&mut source,
&mut error,
);
assert_eq!(is_ok == glib::ffi::GFALSE, !error.is_null());
if error.is_null() {
Ok(from_glib_full(source))
} else {
Err(from_glib_full(error))
}
}
}
fn parent_flush_completions(&self, ctx: &Self::Type) -> Result<(), Error> {
unsafe {
let data = T::type_data();
let parent_class = data.as_ref().parent_class() as *mut ffi::HinokoFwIsoCtxInterface;
let f = (*parent_class)
.flush_completions
.expect("No parent \"flush_completions\" implementation");
let mut error = std::ptr::null_mut();
let is_ok = f(
ctx.unsafe_cast_ref::<FwIsoCtx>().to_glib_none().0,
&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_cycle_timer(
&self,
ctx: &Self::Type,
clock_id: i32,
cycle_timer: &mut CycleTimer,
) -> Result<(), Error> {
unsafe {
let data = T::type_data();
let parent_class = data.as_ref().parent_class() as *mut ffi::HinokoFwIsoCtxInterface;
let f = (*parent_class)
.get_cycle_timer
.expect("No parent \"flush_completions\" implementation");
let mut error = std::ptr::null_mut();
let is_ok = f(
ctx.unsafe_cast_ref::<FwIsoCtx>().to_glib_none().0,
clock_id.into(),
&mut cycle_timer.to_glib_none_mut().0,
&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_release(&self, ctx: &Self::Type) {
unsafe {
let data = T::type_data();
let parent_class = data.as_ref().parent_class() as *mut ffi::HinokoFwIsoCtxInterface;
let f = (*parent_class)
.release
.expect("No parent \"release\" implementation");
f(ctx.unsafe_cast_ref::<FwIsoCtx>().to_glib_none().0)
}
}
fn parent_stop(&self, ctx: &Self::Type) {
unsafe {
let data = T::type_data();
let parent_class = data.as_ref().parent_class() as *mut ffi::HinokoFwIsoCtxInterface;
let f = (*parent_class)
.stop
.expect("No parent \"stop\" implementation");
f(ctx.unsafe_cast_ref::<FwIsoCtx>().to_glib_none().0)
}
}
fn parent_unmap_buffer(&self, ctx: &Self::Type) {
unsafe {
let data = T::type_data();
let parent_class = data.as_ref().parent_class() as *mut ffi::HinokoFwIsoCtxInterface;
let f = (*parent_class)
.unmap_buffer
.expect("No parent \"unmap_buffer\" implementation");
f(ctx.unsafe_cast_ref::<FwIsoCtx>().to_glib_none().0)
}
}
fn parent_stopped(&self, ctx: &Self::Type, error: Option<&Error>) {
unsafe {
let data = T::type_data();
let parent_class = data.as_ref().parent_class() as *mut ffi::HinokoFwIsoCtxInterface;
let f = (*parent_class)
.stopped
.expect("No parent \"stopped\" implementation");
f(
ctx.unsafe_cast_ref::<FwIsoCtx>().to_glib_none().0,
error.to_glib_none().0,
)
}
}
}
unsafe impl<T: FwIsoCtxImpl> IsImplementable<T> for FwIsoCtx {
fn interface_init(iface: &mut Interface<Self>) {
let iface = iface.as_mut();
iface.create_source = Some(fw_iso_ctx_create_source::<T>);
iface.flush_completions = Some(fw_iso_ctx_flush_completions::<T>);
iface.get_cycle_timer = Some(fw_iso_ctx_get_cycle_timer::<T>);
iface.release = Some(fw_iso_ctx_release::<T>);
iface.stop = Some(fw_iso_ctx_stop::<T>);
iface.unmap_buffer = Some(fw_iso_ctx_unmap_buffer::<T>);
iface.stopped = Some(fw_iso_ctx_stopped::<T>);
}
}
unsafe extern "C" fn fw_iso_ctx_create_source<T: FwIsoCtxImpl>(
ctx: *mut ffi::HinokoFwIsoCtx,
source: *mut *mut glib::ffi::GSource,
error: *mut *mut glib::ffi::GError,
) -> glib::ffi::gboolean {
let instance = &*(ctx as *mut T::Instance);
let imp = instance.imp();
let wrap: Borrowed<FwIsoCtx> = from_glib_borrow(ctx);
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_raw();
}
glib::ffi::GFALSE
}
}
}
unsafe extern "C" fn fw_iso_ctx_flush_completions<T: FwIsoCtxImpl>(
ctx: *mut ffi::HinokoFwIsoCtx,
error: *mut *mut glib::ffi::GError,
) -> glib::ffi::gboolean {
let instance = &*(ctx as *mut T::Instance);
let imp = instance.imp();
let wrap: Borrowed<FwIsoCtx> = from_glib_borrow(ctx);
match imp.flush_completions(wrap.unsafe_cast_ref()) {
Ok(_) => glib::ffi::GTRUE,
Err(err) => {
if !error.is_null() {
*error = err.into_raw();
}
glib::ffi::GFALSE
}
}
}
unsafe extern "C" fn fw_iso_ctx_get_cycle_timer<T: FwIsoCtxImpl>(
ctx: *mut ffi::HinokoFwIsoCtx,
clock_id: c_int,
cycle_timer: *const *mut ffi::HinokoCycleTimer,
error: *mut *mut glib::ffi::GError,
) -> glib::ffi::gboolean {
let instance = &*(ctx as *mut T::Instance);
let imp = instance.imp();
let wrap: Borrowed<FwIsoCtx> = from_glib_borrow(ctx);
match imp.get_cycle_timer(
wrap.unsafe_cast_ref(),
clock_id.into(),
&mut from_glib_none(*cycle_timer),
) {
Ok(_) => glib::ffi::GTRUE,
Err(err) => {
if !error.is_null() {
*error = err.into_raw();
}
glib::ffi::GFALSE
}
}
}
unsafe extern "C" fn fw_iso_ctx_release<T: FwIsoCtxImpl>(ctx: *mut ffi::HinokoFwIsoCtx) {
let instance = &*(ctx as *mut T::Instance);
let imp = instance.imp();
let wrap: Borrowed<FwIsoCtx> = from_glib_borrow(ctx);
imp.release(wrap.unsafe_cast_ref())
}
unsafe extern "C" fn fw_iso_ctx_stop<T: FwIsoCtxImpl>(ctx: *mut ffi::HinokoFwIsoCtx) {
let instance = &*(ctx as *mut T::Instance);
let imp = instance.imp();
let wrap: Borrowed<FwIsoCtx> = from_glib_borrow(ctx);
imp.stop(wrap.unsafe_cast_ref())
}
unsafe extern "C" fn fw_iso_ctx_unmap_buffer<T: FwIsoCtxImpl>(ctx: *mut ffi::HinokoFwIsoCtx) {
let instance = &*(ctx as *mut T::Instance);
let imp = instance.imp();
let wrap: Borrowed<FwIsoCtx> = from_glib_borrow(ctx);
imp.unmap_buffer(wrap.unsafe_cast_ref())
}
unsafe extern "C" fn fw_iso_ctx_stopped<T: FwIsoCtxImpl>(
ctx: *mut ffi::HinokoFwIsoCtx,
error: *const glib::ffi::GError,
) {
let instance = &*(ctx as *mut T::Instance);
let imp = instance.imp();
let wrap: Borrowed<FwIsoCtx> = from_glib_borrow(ctx);
imp.stopped(
wrap.unsafe_cast_ref(),
Option::<Error>::from_glib_none(error).as_ref(),
)
}
#[cfg(test)]
mod test {
use crate::{prelude::*, subclass::prelude::*, *};
use glib::{subclass::prelude::*, Error, ParamSpec, ParamSpecOverride, Source, ToValue, Value};
pub mod imp {
use super::*;
pub struct FwIsoCtxTest;
impl Default for FwIsoCtxTest {
fn default() -> Self {
Self {}
}
}
#[glib::object_subclass]
impl ObjectSubclass for FwIsoCtxTest {
const NAME: &'static str = "FwIsoCtxTest";
type Type = super::FwIsoCtxTest;
type Interfaces = (FwIsoCtx,);
fn new() -> Self {
Default::default()
}
}
impl ObjectImpl for FwIsoCtxTest {
fn properties() -> &'static [ParamSpec] {
use once_cell::sync::Lazy;
static PROPERTIES: Lazy<Vec<ParamSpec>> = Lazy::new(|| {
vec![
ParamSpecOverride::for_interface::<FwIsoCtx>("bytes-per-chunk"),
ParamSpecOverride::for_interface::<FwIsoCtx>("chunks-per-buffer"),
]
});
PROPERTIES.as_ref()
}
fn property(&self, _obj: &Self::Type, _id: usize, pspec: &ParamSpec) -> Value {
match pspec.name() {
"bytes-per-chunk" => 1u32.to_value(),
"chunks-per-buffer" => 2u32.to_value(),
_ => unimplemented!(),
}
}
}
impl FwIsoCtxImpl for FwIsoCtxTest {
fn create_source(&self, _ctx: &Self::Type) -> Result<Source, Error> {
Err(Error::new(FwIsoCtxError::Failed, "expected failure"))
}
fn flush_completions(&self, _ctx: &Self::Type) -> Result<(), Error> {
Ok(())
}
fn get_cycle_timer(
&self,
_ctx: &Self::Type,
_clock_id: i32,
_cycle_timer: &mut CycleTimer,
) -> Result<(), Error> {
Ok(())
}
fn release(&self, _ctx: &Self::Type) {}
fn stop(&self, _ctx: &Self::Type) {}
fn unmap_buffer(&self, _ctx: &Self::Type) {}
fn stopped(&self, _ctx: &Self::Type, error: Option<&Error>) {
assert_eq!(error, None);
}
}
}
glib::wrapper! {
pub struct FwIsoCtxTest(ObjectSubclass<imp::FwIsoCtxTest>)
@implements FwIsoCtx;
}
#[allow(clippy::new_without_default)]
impl FwIsoCtxTest {
pub fn new() -> Self {
glib::Object::new(&[]).expect("Failed creation/initialization of FwIsoCtxTest object")
}
}
#[test]
fn fw_iso_ctx_iface() {
let ctx = FwIsoCtxTest::new();
assert!(ctx.create_source().is_err());
assert_eq!(ctx.flush_completions(), Ok(()));
assert_eq!(ctx.release(), (()));
assert_eq!(ctx.stop(), (()));
assert_eq!(ctx.unmap_buffer(), (()));
let mut cycle_timer = CycleTimer::new();
assert_eq!(ctx.get_cycle_timer(0, &mut cycle_timer), Ok(()));
assert_eq!(ctx.bytes_per_chunk(), 1);
assert_eq!(ctx.chunks_per_buffer(), 2);
ctx.emit_stopped(None);
}
}