cobia/
cape_object_impl.rs

1use crate::C;
2use crate::*;
3
4/// Internal data for CAPE-OPEN object implementations.
5///
6/// This structure holds the internal data for CAPE-OPEN object implementations,
7/// such as the interface pointer, last error information, reference count and
8/// the interface map.
9///
10/// This structure is not typically directly referenced, but rather a reference to it is
11/// generated by the `cape_object_implementation` macro.
12
13pub struct CapeObjectData {
14	/// Unique pointer to the ICapeInterface implementation.
15	interface: C::ICapeInterface,
16	/// Last error that occurred in the object.
17	last_error: Option<COBIAError>,
18	/// Scope of the last error
19	last_error_scope: Option<String>,
20	/// Reference count for the object.
21	ref_count: i32,
22	/// Interface map
23	interface_map: std::collections::HashMap<CapeUUID, *mut C::ICapeInterface>,
24}
25
26/// This trait is implemented by all CAPE-OPEN objects.
27///
28/// It is not typically needed to implement this trait directly, but rather to use the
29/// `cape_object_implementation` macro that generates this trait.
30
31pub trait ICapeInterfaceImpl: std::fmt::Display {
32	type T: ICapeInterfaceImpl;
33
34	/// Returns a mutable reference to the internal `CapeObjectData` structure.
35	fn get_object_data(&mut self) -> &mut CapeObjectData;
36	/// Returns a pointer to the implementing object.
37	fn get_self(&mut self) -> *mut Self::T;
38
39	/// the V-table for the ICapeInterface implementation.
40	const CAPEINTERFACE_VTABLE: C::ICapeInterface_VTable = C::ICapeInterface_VTable {
41		addReference: Some(Self::raw_add_reference),
42		release: Some(Self::raw_release),
43		queryInterface: Some(Self::raw_query_interface),
44		getLastError: Some(Self::raw_get_last_error),
45	};
46
47	/// Initializes the object, setting up the interface pointer and adding it to the interface map.
48	fn init(&mut self) -> *mut C::ICapeInterface {
49		//initialize interface pointer
50		self.get_object_data().interface.me =
51			self.get_self() as *const Self::T as *mut std::ffi::c_void;
52		//add to interface map
53		let icapeinterface = self.as_icapeinterface();
54		self.add_interface(
55			std::ptr::addr_of!(C::ICapeInterface_UUID),
56			icapeinterface,
57		);
58		self.as_icapeinterface()
59	}
60
61	/// Utility function for internal object setup
62	fn create_object_data<Timpl: ICapeInterfaceImpl>() -> CapeObjectData {
63		CapeObjectData {
64			interface: C::ICapeInterface {
65				me: std::ptr::null_mut(),
66				vTbl: (&Timpl::CAPEINTERFACE_VTABLE as *const C::ICapeInterface_VTable).cast_mut(),
67			},
68			last_error: None,
69			last_error_scope: None,
70			ref_count: 0,
71			interface_map: std::collections::HashMap::new(),
72		}
73	}
74
75	extern "C" fn raw_add_reference(me: *mut ::std::os::raw::c_void) {
76		let p = me as *mut Self::T;
77		assert!(unsafe { &mut *p }.get_object_data().ref_count >= 0);
78		unsafe { &mut *p }.get_object_data().ref_count += 1;
79	}
80
81	extern "C" fn raw_release(me: *mut ::std::os::raw::c_void) {
82		let p = me as *mut Self::T;
83		let ref_count: &mut i32 = &mut unsafe { (*p).get_object_data() }.ref_count;
84		*ref_count -= 1;
85		if *ref_count == 0 {
86			drop(unsafe { Box::from_raw(me as *mut Self::T) });
87		}
88	}
89
90	extern "C" fn raw_query_interface(
91		me: *mut ::std::os::raw::c_void,
92		uuid: *const C::CapeUUID,
93		interface: *mut *mut C::ICapeInterface,
94	) -> C::CapeResult {
95		let p = me as *mut Self::T;
96		let object_data: &mut CapeObjectData = unsafe { (*p).get_object_data() };
97		match object_data.interface_map.get(&(unsafe { *uuid }).clone()) {
98			Some(ptr) => {
99				unsafe { *interface = *ptr };
100				assert!(object_data.ref_count >= 0);
101				object_data.ref_count += 1;
102				COBIAERR_NOERROR
103			}
104			None => COBIAERR_NOSUCHINTERFACE,
105		}
106	}
107
108	extern "C" fn raw_get_last_error(
109		me: *mut ::std::os::raw::c_void,
110		error: *mut *mut C::ICapeError,
111	) -> C::CapeResult {
112		if error == std::ptr::null_mut() {
113			return COBIAERR_NULLPOINTER;
114		}
115		let p = me as *mut Self::T;
116		let object_data: &mut CapeObjectData = unsafe { (*p).get_object_data() };
117		let e = match &object_data.last_error {
118			Some(e) => &e,
119			None => &COBIAError::Code(COBIAERR_NOERROR),
120		};
121		let scope = match &object_data.last_error_scope {
122			Some(s) => &s,
123			None => "<unknown>",
124		};
125		unsafe {
126			*error = CapeErrorImpl::new(e, scope, &format!("{}",*p)) as *mut C::ICapeError
127		};
128		COBIAERR_NOERROR
129	}
130
131	/// Utility function to add an interface to the interface map.
132	///
133	/// # Arguments
134	/// * `uuid` - A pointer to the UUID of the interface.
135	/// * `interface` - A pointer to the ICapeInterface implementation of the interface.
136
137	fn add_interface(&mut self, uuid: *const C::CapeUUID, interface: *mut C::ICapeInterface) {
138		self.get_object_data().interface_map.insert((unsafe { *uuid }).clone(),interface);
139	}
140
141	/// Utility function to set the last error and scope.
142	///
143	/// # Arguments
144	/// * `error` - The error to set.
145	/// * `scope` - The scope of the error, typically a string describing where the error occurred.
146
147	fn set_last_error(&mut self, error: COBIAError, scope: &str) -> C::CapeResult {
148		let object_data = self.get_object_data();
149		object_data.last_error_scope = Some(scope.to_string());
150		let ret_code = match error {
151			COBIAError::Code(c) => c,
152			_ => COBIAERR_CAPEOPENERROR,
153		};
154		object_data.last_error = Some(error);
155		ret_code
156	}
157
158	/// Utility function to clear the last error and scope.
159
160	fn clear_last_error(&mut self) {
161		let obj = &mut self.get_object_data();
162		obj.last_error_scope = None;
163		obj.last_error = None;
164	}
165
166	/// Returns a unique pointer to the ICapeInterface implementation of the object.
167
168	fn as_icapeinterface(&mut self) -> *mut C::ICapeInterface {
169		&mut self.get_object_data().interface as *mut C::ICapeInterface
170	}
171}
172