1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
use {
	crate::{
		error,
		plugin::{ComponentLoader, PluginImpl},
		prelude::*,
	},
	glib::subclass::prelude::*,
	std::ptr,
};

impl ComponentLoader {
	pub const TYPE_LUA_SCRIPT: &'static str = "script/lua";
	pub const TYPE_LUA_CONFIG: &'static str = "config/lua";
	pub const TYPE_WIREPLUMBER_MODULE: &'static str = "module";
	pub const TYPE_PIPEWIRE_MODULE: &'static str = "pw_module";

	pub const DIR_WIREPLUMBER_MODULE: &'static str = "WIREPLUMBER_MODULE_DIR";
	pub const DIR_PIPEWIRE_MODULE: &'static str = "PIPEWIRE_MODULE_DIR";

	pub const MODULE_LOADER_LUA: &'static str = "libwireplumber-module-lua-scripting";

	pub const PLUGIN_LOADER_LUA: &'static str = "lua-scripting";
}

pub trait ComponentLoaderImpl: ObjectImpl + ComponentLoaderImplExt {
	fn supports_type(&self, loader: &Self::Type, type_: String) -> bool {
		self.parent_supports_type(loader, type_)
	}

	fn load(&self, loader: &Self::Type, component: String, type_: String, args: Option<Variant>) -> Result<(), Error> {
		self.parent_load(loader, component, type_, args)
	}
}

pub trait ComponentLoaderImplExt: ObjectSubclass {
	fn parent_class(&self) -> &ffi::WpComponentLoaderClass;
	fn parent_supports_type(&self, loader: &Self::Type, type_: String) -> bool;
	fn parent_load(
		&self,
		loader: &Self::Type,
		component: String,
		type_: String,
		args: Option<Variant>,
	) -> Result<(), Error>;
}

impl<T: ComponentLoaderImpl> ComponentLoaderImplExt for T {
	fn parent_class(&self) -> &ffi::WpComponentLoaderClass {
		unsafe {
			let data = T::type_data();
			let parent_class = data.as_ref().parent_class() as *mut _;
			&*parent_class
		}
	}

	fn parent_supports_type(&self, loader: &Self::Type, type_: String) -> bool {
		let parent = ComponentLoaderImplExt::parent_class(self);
		let f = parent
			.supports_type
			.expect("No parent class implementation for \"supports_type\"");
		unsafe {
			from_glib(f(
				loader.unsafe_cast_ref::<ComponentLoader>().to_glib_none().0,
				type_.to_glib_none().0,
			))
		}
	}

	fn parent_load(
		&self,
		loader: &Self::Type,
		component: String,
		type_: String,
		args: Option<Variant>,
	) -> Result<(), Error> {
		let parent = ComponentLoaderImplExt::parent_class(self);
		let f = parent.load.expect("No parent class implementation for \"load\"");
		unsafe {
			let mut error = ptr::null_mut();
			let res = from_glib(f(
				loader.unsafe_cast_ref::<ComponentLoader>().to_glib_none().0,
				component.to_glib_none().0,
				type_.to_glib_none().0,
				args.to_glib_none().0,
				&mut error,
			));
			match (res, error.is_null()) {
				(true, _) => Ok(()),
				(false, false) => Err(from_glib_full(error)),
				(false, true) => Err(error::invariant("GError NULL")),
			}
		}
	}
}

unsafe impl<T: ComponentLoaderImpl + PluginImpl> IsSubclassable<T> for ComponentLoader {
	fn class_init(class: &mut glib::Class<Self>) {
		Self::parent_class_init::<T>(class);

		unsafe extern "C" fn supports_type<T: ComponentLoaderImpl>(
			loader: *mut ffi::WpComponentLoader,
			type_: *const libc::c_char,
		) -> glib::ffi::gboolean {
			let this = &*(loader as *mut T::Instance);
			let this = this.imp();
			let loader: Borrowed<ComponentLoader> = from_glib_borrow(loader);

			this
				.supports_type(loader.unsafe_cast_ref(), from_glib_none(type_))
				.into_glib()
		}

		unsafe extern "C" fn load<T: ComponentLoaderImpl>(
			loader: *mut ffi::WpComponentLoader,
			component: *const libc::c_char,
			type_: *const libc::c_char,
			args: *mut glib::ffi::GVariant,
			error: *mut *mut glib::ffi::GError,
		) -> glib::ffi::gboolean {
			let this = &*(loader as *mut T::Instance);
			let this = this.imp();
			let loader: Borrowed<ComponentLoader> = from_glib_borrow(loader);

			match this.load(
				loader.unsafe_cast_ref(),
				from_glib_none(component),
				from_glib_none(type_),
				from_glib_none(args),
			) {
				Ok(()) => true,
				Err(e) => {
					*error = e.into_glib_ptr();
					false
				},
			}
			.into_glib()
		}

		let klass = class.as_mut();
		klass.supports_type = Some(supports_type::<T>);
		klass.load = Some(load::<T>);
	}
}