cobia/
cobia_collection.rs

1use crate::C;
2use crate::*;
3use std::marker::PhantomData;
4use cape_smart_pointer::CapeSmartPointer;
5
6const ICOBIACOLLECTION_UUID:CapeUUID=CapeUUID::from_slice(&[0xdeu8,0xafu8,0xeau8,0x79u8,0xd3u8,0x49u8,0x4du8,0x03u8,0xbbu8,0x05u8,0x37u8,0x7cu8,0x0du8,0x3eu8,0x47u8,0x8bu8]);
7
8/// CobiaCollectionBase wraps an collection interface
9/// 
10/// The collection interface is returned in case muliple objects
11/// are returned by a method. 
12/// 
13/// Collection items each must have a unique name, and the name
14/// is exposed from the approproate identification interface.
15/// 
16/// Collection items are accessed by index or by name.
17///
18/// #Example
19///
20/// ```
21/// use cobia;
22/// use cobia::prelude::*;
23/// cobia::cape_open_initialize().unwrap();
24/// let library_enumerator = cobia::CapeTypeLibraries::new().unwrap();
25/// let libraries = library_enumerator.libraries().unwrap(); //this is a CobiaCollection smart pointer
26/// assert!(libraries.size() > 0); //normally the CAPE-OPEN type libraries are registered
27/// cobia::cape_open_cleanup();
28/// ```
29
30#[cape_smart_pointer(ICOBIACOLLECTION_UUID)]
31pub struct CobiaCollectionBase<Element:CapeSmartPointer> {
32	interface: *mut C::ICobiaCollection, //the interface is cast to ICapeCollection - function signatures are identical
33	element_type : PhantomData<Element>
34}
35
36impl<Element:CapeSmartPointer> CobiaCollectionBase<Element> {
37
38	/// Create a new CobiaCollectionBase from an interface pointer
39	///
40	/// This member is not typically called. Instead, the CobiaCollectionBase is created by the API functions that return it.
41	///
42	/// # Safety
43	///
44	/// The interface pointer must be valid and must point to an object that implements the ICobiaCollection interface.
45	///
46	/// # Panics
47	///
48	/// This function panics if the interface pointer is null.
49
50	pub(crate) fn from_interface_pointer(interface: *mut C::ICobiaCollection) ->  Self {
51		if interface.is_null() {
52			panic!("Null pointer in creation of CobiaCollectionBase<Element>");
53		}
54		unsafe {((*(*interface).vTbl).base.addReference.unwrap())((*interface).me)};
55		Self {
56			interface,
57			element_type: PhantomData,
58		}
59	}
60
61	/// Create a new CobiaCollectionBase from an interface pointer without adding a reference
62	///
63	/// This member is not typically called. Instead, the CobiaCollectionBase is created by the API functions that return it.
64	///
65	/// # Safety
66	///
67	/// The interface pointer must be valid and must point to an object that implements the ICobiaCollection interface.
68	///
69	/// # Panics
70	///
71	/// This function panics if the interface pointer is null.
72
73	pub(crate) fn attach(interface: *mut C::ICobiaCollection) ->  Self {
74		if interface.is_null() {
75			panic!("Null pointer in creation of CobiaCollectionBase<Element>");
76		}
77		Self {
78			interface,
79			element_type: PhantomData,
80		}
81	}
82
83	/// Get the number of elements in the collection
84	///
85	/// # Examples
86	///
87	/// ```
88	/// use cobia;
89	/// use cobia::prelude::*;
90	/// cobia::cape_open_initialize().unwrap();
91	/// let library_enumerator = cobia::CapeTypeLibraries::new().unwrap();
92	/// let libraries = library_enumerator.libraries().unwrap(); //this is a CobiaCollection smart pointer
93	/// assert!(libraries.size() > 0); //normally the CAPE-OPEN type libraries are registered
94	/// cobia::cape_open_cleanup();
95	/// ```
96
97	pub fn size(&self) -> usize {
98		let mut size: C::CapeInteger = 0;
99		let res=unsafe { (*(*self.interface).vTbl).getCount.unwrap()((*self.interface).me, &mut size as *mut C::CapeInteger) };
100		if res == COBIAERR_NOERROR { 
101			size as usize
102		} else {
103			//getCount should not fail... if it does, assume that 0 is a reasonable default
104			debug_assert!(false);
105			0
106		}
107	}
108
109	/// Get a collection item by index in the collection
110	///
111	/// The index is zero-based, and must be 0 <= index < size().
112	///
113	/// Note that the collection implements iterators, but not the Index
114	/// or IndexMut trait, as both these traits require returning the 
115	/// item by reference, which is not possible in this context, as 
116	/// the returned object owns the interface pointer.
117	///
118	/// # Examples
119	///
120	/// ```
121	/// use cobia;
122	/// use cobia::prelude::*;
123	/// cobia::cape_open_initialize().unwrap();
124	/// let library_enumerator = cobia::CapeTypeLibraries::new().unwrap();
125	/// let libraries = library_enumerator.libraries().unwrap(); //this is a CobiaCollection smart pointer
126	/// assert!(libraries.size() > 0); //normally the CAPE-OPEN type libraries are registered
127	/// let library = libraries.at(0).unwrap();
128	/// cobia::cape_open_cleanup();
129	/// ```
130
131	pub fn at(&self,index : usize) -> Result<Element, COBIAError> {
132		let mut el : *mut C::ICapeInterface=std::ptr::null_mut();
133		let index = index as C::CapeInteger;
134		let res=unsafe { (*(*self.interface).vTbl).ItemByIndex.unwrap()((*self.interface).me,index,&mut el as *mut *mut C::ICapeInterface) };
135		if res == COBIAERR_NOERROR {
136			let el=el as *mut C::ICapeInterface as *mut Element::Interface;
137			if el.is_null() {
138				Err(COBIAError::Code(COBIAERR_NULLPOINTER))
139			} else {
140				Ok(Element::attach(unsafe{&mut*el as &mut Element::Interface}))
141			}
142		} else {
143			Err(COBIAError::from_object(res,self))
144		}
145	}
146
147	/// Get a collection item by name
148	///
149	/// The name is case insentive, but must correspond to one of the items
150	/// in the collection.
151	///
152	/// # Examples
153	///
154	/// ```
155	/// use cobia;
156	/// use cobia::prelude::*;
157	/// cobia::cape_open_initialize().unwrap();
158	/// let library_enumerator = cobia::CapeTypeLibraries::new().unwrap();
159	/// let libraries = library_enumerator.libraries().unwrap(); //this is a CobiaCollection smart pointer
160	/// assert!(libraries.size() > 0); //normally the CAPE-OPEN type libraries are registered
161	/// let library = libraries.at(0).unwrap();
162	/// let lib_name = library.get_name().unwrap();
163	/// let library1 = libraries.get(&lib_name).unwrap();
164	/// assert_eq!(library.get_uuid().unwrap(),library1.get_uuid().unwrap());
165	/// cobia::cape_open_cleanup();
166	/// ```
167
168	pub fn get(&self,id : &str) -> Result<Element, COBIAError> {
169		let mut el : *mut C::ICapeInterface=std::ptr::null_mut();
170		let id=CapeStringImpl::from_string(id);
171		let res=unsafe { (*(*self.interface).vTbl).ItemByName.unwrap()((*self.interface).me,(&id.as_cape_string_in() as *const C::ICapeString).cast_mut(),&mut el as *mut *mut C::ICapeInterface) };
172		if res == COBIAERR_NOERROR {
173			let el=el as *mut C::ICapeInterface as *mut Element::Interface;
174			if el.is_null() {
175				Err(COBIAError::Code(COBIAERR_NULLPOINTER))
176			} else {
177				Ok(Element::attach(unsafe{&mut*el as &mut Element::Interface}))
178			}
179		} else {
180			Err(COBIAError::from_object(res,self))
181		}
182	}
183
184	///Get an iterator for the collection by reference
185	///
186	///This iterator does not consume the collection.
187	///
188	/// # Examples
189	///
190	/// ```
191	/// use cobia;
192	/// use cobia::prelude::*;
193	/// cobia::cape_open_initialize().unwrap();
194	/// let library_enumerator = cobia::CapeTypeLibraries::new().unwrap();
195	/// let libraries = library_enumerator.libraries().unwrap(); //this is a CobiaCollection smart pointer
196	/// let mut found=false;
197	/// for library in libraries.iter() {
198	///     let lib_name = library.get_name().unwrap();
199	///     if lib_name=="CAPEOPEN_1_2" { //performance note: this is not efficient, but it is an example
200	///         found=true;
201	///			break;
202	///     }
203	/// }
204	/// assert!(found);
205	/// cobia::cape_open_cleanup();
206	/// ```
207
208	pub fn iter(&self) -> CobiaCollectionBaseRefIterator<'_,Element> {
209		CobiaCollectionBaseRefIterator {
210			collection:self,
211			index:0
212		}
213	}
214
215}
216
217/// Iterator that consumes a CobiaCollectionBase
218///
219/// This iterator consumes the collection and returns the elements.
220///
221/// # Examples
222///
223/// ```
224/// use cobia;
225/// use cobia::prelude::*;
226/// cobia::cape_open_initialize().unwrap();
227/// let library_enumerator = cobia::CapeTypeLibraries::new().unwrap();
228/// let libraries = library_enumerator.libraries().unwrap(); //this is a CobiaCollection smart pointer
229/// let mut found=false;
230/// for library in libraries {
231///     let lib_name = library.get_name().unwrap();
232///     if lib_name=="CAPEOPEN_1_2" { //performance note: this is not efficient, but it is an example
233///         found=true;
234///			break;
235///     }
236/// }
237/// assert!(found);
238/// cobia::cape_open_cleanup();
239/// ```
240
241pub struct CobiaCollectionBaseIterator<Element:CapeSmartPointer> {
242	collection:CobiaCollectionBase<Element>,
243	index:usize
244}
245
246impl<Element:CapeSmartPointer> Iterator for CobiaCollectionBaseIterator<Element> {
247	type Item=Element;
248	fn next(&mut self) -> Option<Self::Item> {
249		if self.index < self.collection.size() {
250			let res=self.collection.at(self.index);
251			self.index+=1;
252			match res {
253				Ok(el) => Some(el),
254				Err(_) => None
255			}
256		} else {
257			None
258		}
259	}
260}
261
262impl<Element:CapeSmartPointer> IntoIterator for CobiaCollectionBase<Element> {
263	type Item=Element;
264	type IntoIter=CobiaCollectionBaseIterator<Element>;
265	fn into_iter(self) -> Self::IntoIter {
266		CobiaCollectionBaseIterator {
267			collection:self,
268			index:0
269		}
270	}
271}
272
273/// Iterator that using a reference to CobiaCollectionBase
274///
275/// This iterator returns the elements and does not consume the collection.
276///
277/// # Examples
278///
279/// ```
280/// use cobia;
281/// use cobia::prelude::*;
282/// cobia::cape_open_initialize().unwrap();
283/// let library_enumerator = cobia::CapeTypeLibraries::new().unwrap();
284/// let libraries = library_enumerator.libraries().unwrap(); //this is a CobiaCollection smart pointer
285/// let mut found=false;
286/// for library in &libraries {
287///     let lib_name = library.get_name().unwrap();
288///     if lib_name=="CAPEOPEN_1_2" { //performance note: this is not efficient, but it is an example
289///         found=true;
290///			break;
291///     }
292/// }
293/// assert!(found);
294/// cobia::cape_open_cleanup();
295/// ```
296
297pub struct CobiaCollectionBaseRefIterator<'a,Element:CapeSmartPointer> {
298	collection:&'a CobiaCollectionBase<Element>,
299	index:usize
300}
301
302impl<'a,Element:CapeSmartPointer> Iterator for CobiaCollectionBaseRefIterator<'a,Element> {
303	type Item=Element;
304	fn next(&mut self) -> Option<Self::Item> {
305		if self.index < self.collection.size() {
306			let res=self.collection.at(self.index);
307			self.index+=1;
308			match res {
309				Ok(el) => Some(el),
310				Err(_) => None
311			}
312		} else {
313			None
314		}
315	}
316}
317
318impl<'a,Element:CapeSmartPointer> IntoIterator for &'a CobiaCollectionBase<Element> {
319	type Item=Element;
320	type IntoIter=CobiaCollectionBaseRefIterator<'a,Element>;
321	fn into_iter(self) -> Self::IntoIter {
322		CobiaCollectionBaseRefIterator {
323			collection:&self,
324			index:0
325		}
326	}
327}
328
329/// CobiaCollection wraps an ICobiaCollection interface
330///
331/// This interface is returned by API functions that return multiple objects.
332///
333/// #Example
334///
335/// ```
336/// use cobia;
337/// use cobia::prelude::*;
338/// cobia::cape_open_initialize().unwrap();
339/// let library_enumerator = cobia::CapeTypeLibraries::new().unwrap();
340/// let libraries = library_enumerator.libraries().unwrap(); //this is a CobiaCollection smart pointer
341/// assert!(libraries.size() > 0); //normally the CAPE-OPEN type libraries are registered
342/// cobia::cape_open_cleanup();
343/// ```
344
345pub type CobiaCollection<Element> = CobiaCollectionBase<Element>;
346