libfprint_rs/device/
device_sync.rs

1use crate::device::{UserData, callback::fp_match_cb, fn_pointer};
2use crate::image::FpImage;
3use gio::Cancellable;
4use glib::object::ObjectExt;
5use glib::translate::FromGlibPtrNone;
6use glib::translate::{FromGlibPtrFull, ToGlibPtr};
7use std::sync::Arc;
8
9use crate::print::FpPrint;
10
11use super::FpDevice;
12
13/// This type represents the callback function for the `FpDevice::enroll` implementation and will be called for each stage of the enrollment process.
14pub type FpEnrollProgress<T> =
15    fn(&FpDevice, i32, Option<FpPrint>, Option<crate::GError>, &Option<T>) -> ();
16/// This type represents the callback function for the `FpDevice::verify` and `FpDevice::identify` implementations and will be called when a print is matched.
17pub type FpMatchCb<T> =
18    fn(&FpDevice, Option<FpPrint>, FpPrint, Option<crate::GError>, &Option<T>) -> ();
19
20impl FpDevice {
21    #[cfg(not(doctest))]
22    /// Open the device synchronously.
23    /// # Example:
24    /// ```no_run
25    /// use libfprint_rs::{FpDevice, FpContext};
26    ///
27    /// let ctx = FpContext::new();
28    /// let devices = ctx.devices();
29    /// let dev = devices.get(0).unwrap();
30    ///
31    /// dev.open_sync(None).unwrap();
32    /// ```
33    pub fn open_sync(&self, cancellable: Option<&Cancellable>) -> Result<(), crate::GError> {
34        let raw_cancel = match cancellable {
35            Some(p) => p.to_glib_none().0,
36            None => std::ptr::null_mut(),
37        };
38
39        let mut error = std::ptr::null_mut();
40
41        let res = unsafe {
42            libfprint_sys::fp_device_open_sync(
43                self.to_glib_none().0,
44                raw_cancel.cast(),
45                std::ptr::addr_of_mut!(error),
46            )
47        };
48        if res == glib::ffi::GFALSE {
49            return Err(unsafe { glib::Error::from_glib_full(error.cast()) });
50        }
51        Ok(())
52    }
53    #[cfg(not(doctest))]
54    /// Close the device synchronously.
55    /// # Example:
56    /// ```no_run
57    /// use libfprint_rs::{FpDevice, FpContext};
58    ///
59    /// let ctx = FpContext::new();
60    /// let devices = ctx.devices();
61    /// let dev = devices.get(0).unwrap();
62    ///
63    /// dev.open_sync(None).unwrap();
64    /// dev.close_sync(None).unwrap();
65    /// ```
66    pub fn close_sync(&self, cancellable: Option<&Cancellable>) -> Result<(), crate::GError> {
67        let raw_cancel = match cancellable {
68            Some(p) => p.to_glib_none().0,
69            None => std::ptr::null_mut(),
70        };
71
72        let mut error = std::ptr::null_mut();
73
74        let res = unsafe {
75            libfprint_sys::fp_device_close_sync(
76                self.to_glib_none().0,
77                raw_cancel.cast(),
78                std::ptr::addr_of_mut!(error),
79            )
80        };
81        if res == glib::ffi::GFALSE {
82            return Err(unsafe { glib::Error::from_glib_full(error.cast()) });
83        }
84        Ok(())
85    }
86
87    #[cfg(not(doctest))]
88    /// Enroll a new print.
89    /// Enrolls a print, `progress_cb` will be called for each stage of the enrollment process.
90    /// # Example:
91    /// ```no_run
92    /// use libfprint_rs::{FpDevice, FpContext, FpPrint};
93    ///
94    /// pub fn enroll_cb(device: &FpDevice,enroll_stage: i32, print: Option<FpPrint>, error: Option<libfprint_rs::GError>, data: &Option<i32>,) -> () {
95    ///     println!("Enroll stage: {}", enroll_stage);
96    /// }
97    ///
98    /// let ctx = FpContext::new();
99    /// let devices = ctx.devices();
100    /// let dev = devices.get(0).unwrap();
101    /// dev.open_sync(None).unwrap();
102    ///
103    /// let template = FpPrint::new(&dev);
104    /// let new_print = dev.enroll_sync(template, None, Some(enroll_cb), Some(10)).unwrap();
105    ///
106    /// dev.close_sync(None).unwrap();
107    /// ```
108    pub fn enroll_sync<T>(
109        &self,
110        template: FpPrint,
111        cancellable: Option<&Cancellable>,
112        progress_cb: Option<FpEnrollProgress<T>>,
113        progress_data: Option<T>,
114    ) -> Result<FpPrint, crate::GError> {
115        let mut error = std::ptr::null_mut();
116
117        let template = self.check_print(template);
118
119        let raw_dev = self.to_glib_none().0;
120        let raw_cancel = match cancellable {
121            Some(p) => p.to_glib_none().0,
122            None => std::ptr::null_mut(),
123        };
124
125        let user_ptr = fn_pointer!(progress_cb, progress_data);
126
127        // Raw template: transfer full
128        let raw_template: *mut libfprint_sys::FpPrint = template.to_glib_full();
129
130        let ptr = unsafe {
131            libfprint_sys::fp_device_enroll_sync(
132                raw_dev,
133                raw_template,
134                raw_cancel.cast(),
135                Some(crate::device::callback::fp_enroll_progress::<FpEnrollProgress<T>, T>),
136                user_ptr,
137                std::ptr::addr_of_mut!(error),
138            )
139        };
140
141        if !user_ptr.is_null() {
142            let _: Arc<UserData<FpEnrollProgress<T>, T>> =
143                unsafe { Arc::from_raw(user_ptr.cast()) };
144        }
145
146        if !ptr.is_null() {
147            let fp = unsafe { FpPrint::from_glib_full(ptr) };
148            unsafe {
149                fp.set_data("set", true);
150            }
151            Ok(fp)
152        } else {
153            Err(unsafe { glib::Error::from_glib_full(error.cast()) })
154        }
155    }
156
157    #[cfg(not(doctest))]
158    /// Verify a given print synchronously.
159    /// `match_cb` will be called when the verification is done.
160    /// # Example:
161    /// ```no_run
162    /// use libfprint_rs::{FpDevice, FpContext, FpPrint, GError};
163    ///
164    /// pub fn match_cb(device: &FpDevice, matched_print: Option<FpPrint>, enrolled_print: FpPrint,
165    /// error: Option<GError>, data: &Option<i32>) {
166    ///     if matched_print.is_some() {
167    ///         println!("Matched print: {:?}", matched_print);
168    ///     }
169    /// }
170    /// let ctx = FpContext::new();
171    /// let devices = ctx.devices();
172    /// let dev = devices.get(0).unwrap();
173    /// dev.open_sync(None).unwrap();
174    ///
175    /// let some_print: FpPrint = foreign_function_that_gets_print();
176    /// let mut new_print = FpPrint::new(&dev); // The variable that will hold the new print
177    /// let verified = dev.verify_sync(&some_print, None, Some(match_cb), Some(10), Some(&mut
178    /// new_print)).unwrap();
179    /// if verified {
180    ///    println!("Print verified");println
181    /// }
182    /// ```
183    pub fn verify_sync<T>(
184        &self,
185        enrolled_print: &FpPrint,
186        cancellable: Option<gio::Cancellable>,
187        match_cb: Option<FpMatchCb<T>>,
188        match_data: Option<T>,
189        print: Option<&mut FpPrint>, // TODO: Handle initialized
190    ) -> Result<bool, crate::GError> {
191        let ptr = fn_pointer!(match_cb, match_data);
192        let mut error = std::ptr::null_mut();
193        let mut matched = glib::ffi::GFALSE;
194
195        let mut new_print: libfprint_sys::FpPrint_autoptr = std::ptr::null_mut();
196        let new_print_ptr = match print {
197            Some(_) => std::ptr::addr_of_mut!(new_print),
198            None => std::ptr::null_mut(),
199        };
200
201        let raw_cancel = match cancellable {
202            Some(p) => p.to_glib_none().0,
203            None => std::ptr::null_mut(),
204        };
205
206        let res = unsafe {
207            libfprint_sys::fp_device_verify_sync(
208                self.to_glib_none().0,
209                enrolled_print.to_glib_none().0,
210                raw_cancel.cast(),
211                Some(fp_match_cb::<FpMatchCb<T>, T>),
212                ptr,
213                &mut matched,
214                new_print_ptr,
215                &mut error,
216            )
217        };
218        if let Some(p) = print
219            && !new_print.is_null()
220        {
221            *p = unsafe { FpPrint::from_glib_full(new_print) };
222        }
223
224        // If res is false, the operation failed, so the `error` pointer must be pointing
225        // to a valid error
226        if res == glib::ffi::GFALSE {
227            return Err(unsafe { glib::Error::from_glib_none(error.cast()) });
228        }
229        // Else there must be a response
230        Ok(matched == glib::ffi::GTRUE)
231    }
232    #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
233    /// Prepare device for suspend.
234    pub fn suspend_sync(&self, cancellable: Option<&Cancellable>) -> Result<(), crate::GError> {
235        let raw_cancel = match cancellable {
236            Some(p) => p.to_glib_none().0,
237            None => std::ptr::null_mut(),
238        };
239
240        let mut error = std::ptr::null_mut();
241
242        let res = unsafe {
243            libfprint_sys::fp_device_suspend_sync(
244                self.to_glib_none().0,
245                raw_cancel.cast(),
246                std::ptr::addr_of_mut!(error),
247            )
248        };
249        if res == glib::ffi::GFALSE {
250            return Err(unsafe { glib::Error::from_glib_full(error.cast()) });
251        }
252        Ok(())
253    }
254
255    #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
256    /// Resume device after suspend.
257    pub fn resume_sync(&self, cancellable: Option<&Cancellable>) -> Result<(), crate::GError> {
258        let raw_cancel = match cancellable {
259            Some(p) => p.to_glib_none().0,
260            None => std::ptr::null_mut(),
261        };
262
263        let mut error = std::ptr::null_mut();
264
265        let res = unsafe {
266            libfprint_sys::fp_device_resume_sync(
267                self.to_glib_none().0,
268                raw_cancel.cast(),
269                std::ptr::addr_of_mut!(error),
270            )
271        };
272        if res == glib::ffi::GFALSE {
273            return Err(unsafe { glib::Error::from_glib_full(error.cast()) });
274        }
275        Ok(())
276    }
277    #[cfg(not(doctest))]
278    /// Identify a print synchronously.
279    ///
280    /// `match_cb` will be called when a print matches or at the end of the operation.
281    /// # Example:
282    /// ```no_run
283    /// use libfprint_rs::{FpDevice, FpContext, FpPrint, GError};
284    ///
285    /// pub fn match_cb(device: &FpDevice, matched_print: Option<FpPrint>, enrolled_print: FpPrint,
286    /// error: Option<GError>, data: &Option<i32>) {
287    ///     if matched_print.is_some() {
288    ///         println!("Matched print: {:?}", matched_print);
289    ///     }
290    /// }
291    ///
292    /// let ctx = FpContext::new();
293    /// let devices = ctx.devices();
294    /// let dev = devices.get(0).unwrap();
295    /// dev.open_sync(None).unwrap();
296    ///
297    /// let vec_prints: Vec<FpPrint> = function_returning_Vec_prints();
298    /// let mut new_print = FpPrint::new(&dev); // The variable that will hold the new print
299    /// let print_identified = dev.identify_sync(&vec_prints, None, Some(match_cb), Some(10), Some(&mut
300    /// new_print)).unwrap();
301    /// if print_identified.is_some() {
302    ///     println!("Found matching print on vector passed");
303    /// }
304    /// ```
305    pub fn identify_sync<T>(
306        &self,
307        prints: &[FpPrint],
308        cancellable: Option<&Cancellable>,
309        match_cb: Option<FpMatchCb<T>>,
310        match_data: Option<T>,
311        print: Option<&mut FpPrint>, // TODO: Handle initialized
312    ) -> Result<Option<FpPrint>, crate::GError> {
313        // Arc the function content and the data, get the pointer. If no function is provided
314        // then a null pointer is returned.
315
316        use glib::translate::ToGlibContainerFromSlice;
317        let ptr = fn_pointer!(match_cb, match_data);
318
319        // Create a GPtrArray from the vector of prints
320        let raw_prints: (*mut glib::ffi::GPtrArray, _) =
321            ToGlibContainerFromSlice::to_glib_container_from_slice(prints);
322
323        let raw_cancel = match cancellable {
324            Some(p) => p.to_glib_none().0,
325            None => std::ptr::null_mut(),
326        };
327
328        let mut new_print: libfprint_sys::FpPrint_autoptr = std::ptr::null_mut();
329        let new_print_ptr = match print {
330            Some(_) => std::ptr::addr_of_mut!(new_print),
331            None => std::ptr::null_mut(),
332        };
333
334        let mut print_match = std::ptr::null_mut();
335
336        let mut error = std::ptr::null_mut();
337
338        let res = unsafe {
339            libfprint_sys::fp_device_identify_sync(
340                self.to_glib_none().0,
341                raw_prints.0.cast(),
342                raw_cancel.cast(),
343                Some(fp_match_cb::<FpMatchCb<T>, T>),
344                ptr,
345                new_print_ptr,
346                std::ptr::addr_of_mut!(print_match),
347                std::ptr::addr_of_mut!(error),
348            )
349        };
350        unsafe { libfprint_sys::g_ptr_array_free(raw_prints.0.cast(), 1) };
351
352        if let Some(p) = print
353            && !new_print.is_null()
354        {
355            *p = unsafe { FpPrint::from_glib_full(new_print) };
356        };
357
358        if res == glib::ffi::GFALSE {
359            return Err(unsafe { glib::Error::from_glib_full(error.cast()) });
360        }
361        if print_match.is_null() {
362            Ok(None)
363        } else {
364            Ok(Some(unsafe { FpPrint::from_glib_full(print_match) }))
365        }
366    }
367    #[cfg(not(doctest))]
368    /// Start an synchronous operation to capture an image.
369    /// # Example:
370    /// ```no_run
371    /// let ctx = FpContext::new();
372    /// let devices = ctx.devices();
373    /// let dev = devices.get(0).unwrap();
374    /// dev.open_sync(None).unwrap();
375    ///
376    /// let image = dev.capture_sync(true, None).unwrap();
377    /// ```
378    pub fn capture_sync(
379        &self,
380        wait_for_finger: bool,
381        cancellable: Option<&Cancellable>,
382    ) -> Result<FpImage, crate::GError> {
383        let raw_cancel = match cancellable {
384            Some(p) => p.to_glib_none().0,
385            None => std::ptr::null_mut(),
386        };
387
388        let mut raw_error = std::ptr::null_mut();
389
390        let raw_image = unsafe {
391            libfprint_sys::fp_device_capture_sync(
392                self.to_glib_none().0,
393                wait_for_finger as i32,
394                raw_cancel.cast(),
395                std::ptr::addr_of_mut!(raw_error),
396            )
397        };
398        if raw_image.is_null() {
399            return Err(unsafe { glib::Error::from_glib_full(raw_error.cast()) });
400        }
401        Ok(unsafe { FpImage::from_glib_full(raw_image) })
402    }
403
404    /// Delete a given print from the device.
405    pub fn delete_print_sync() {
406        unimplemented!()
407    }
408    /// List device stored prints synchronously.
409    pub fn list_prints_sync() {
410        unimplemented!()
411    }
412    /// Clear sensor storage.
413    pub fn clear_storage_sync() {
414        unimplemented!()
415    }
416
417    fn check_print(&self, template: FpPrint) -> FpPrint {
418        // This checks if the template was created with FpPrint::new() or not
419        let set: Option<bool> = unsafe { template.steal_data("set") };
420        if set == Some(true) {
421            let empty_template = FpPrint::new(self);
422            if let Some(username) = template.username() {
423                empty_template.set_username(&username);
424            }
425            if let Some(description) = template.description() {
426                empty_template.set_description(&description);
427            }
428            empty_template.set_finger(template.finger());
429            if let Some(date) = template.enroll_date() {
430                empty_template.set_enroll_date(date);
431            }
432            drop(template);
433            empty_template
434        } else {
435            template
436        }
437    }
438}