use crate::{
context::Context,
helper::{chars_to_cow, uninit},
try_gp_internal, Result,
};
use std::{borrow::Cow, ffi, fmt, marker::PhantomData, os::raw::c_int};
pub(crate) struct AbilitiesList<'a> {
pub(crate) inner: *mut libgphoto2_sys::CameraAbilitiesList,
_phantom: PhantomData<&'a ffi::c_void>,
}
pub struct Abilities {
pub(crate) inner: libgphoto2_sys::CameraAbilities,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct UsbInfo {
pub vendor: usize,
pub product: usize,
pub class: usize,
pub subclass: usize,
pub protocol: usize,
}
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub enum CameraDriverStatus {
Production,
Testing,
Experimental,
Deprecated,
}
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub enum DeviceType {
Camera,
AudioPlayer,
}
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub struct CameraOperations(c_int);
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub struct FileOperations(c_int);
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub struct FolderOperations(c_int);
impl Drop for AbilitiesList<'_> {
fn drop(&mut self) {
unsafe {
libgphoto2_sys::gp_abilities_list_free(self.inner);
}
}
}
impl From<libgphoto2_sys::CameraOperation> for CameraOperations {
fn from(op: libgphoto2_sys::CameraOperation) -> Self {
Self(op as c_int)
}
}
impl From<libgphoto2_sys::CameraFileOperation> for FileOperations {
fn from(op: libgphoto2_sys::CameraFileOperation) -> Self {
Self(op as c_int)
}
}
impl From<libgphoto2_sys::CameraFolderOperation> for FolderOperations {
fn from(op: libgphoto2_sys::CameraFolderOperation) -> Self {
Self(op as c_int)
}
}
impl From<libgphoto2_sys::GphotoDeviceType> for DeviceType {
fn from(device_type: libgphoto2_sys::GphotoDeviceType) -> Self {
use libgphoto2_sys::GphotoDeviceType;
match device_type {
GphotoDeviceType::GP_DEVICE_STILL_CAMERA => Self::Camera,
GphotoDeviceType::GP_DEVICE_AUDIO_PLAYER => Self::AudioPlayer,
}
}
}
impl From<libgphoto2_sys::CameraDriverStatus> for CameraDriverStatus {
fn from(status: libgphoto2_sys::CameraDriverStatus) -> Self {
use libgphoto2_sys::CameraDriverStatus as GPDriverStatus;
match status {
GPDriverStatus::GP_DRIVER_STATUS_PRODUCTION => Self::Production,
GPDriverStatus::GP_DRIVER_STATUS_TESTING => Self::Testing,
GPDriverStatus::GP_DRIVER_STATUS_EXPERIMENTAL => Self::Experimental,
GPDriverStatus::GP_DRIVER_STATUS_DEPRECATED => Self::Deprecated,
}
}
}
impl From<libgphoto2_sys::CameraAbilities> for Abilities {
fn from(abilities: libgphoto2_sys::CameraAbilities) -> Self {
Self { inner: abilities }
}
}
impl fmt::Debug for Abilities {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Abilities")
.field("id", &self.id())
.field("model", &self.model())
.field("driver_status", &self.driver_status())
.field("camera_operations", &self.camera_operations())
.field("file_operations", &self.file_operations())
.field("folder_operations", &self.folder_operations())
.field("device_type", &self.device_type())
.field("usb_info", &self.usb_info())
.finish()
}
}
impl<'a> AbilitiesList<'a> {
pub(crate) fn new(context: &Context) -> Result<Self> {
let mut abilities_inner = unsafe { uninit() };
try_gp_internal!(libgphoto2_sys::gp_abilities_list_new(&mut abilities_inner))?;
try_gp_internal!(libgphoto2_sys::gp_abilities_list_load(abilities_inner, context.inner))?;
Ok(Self { inner: abilities_inner, _phantom: PhantomData })
}
}
impl Abilities {
pub fn id(&self) -> Cow<str> {
chars_to_cow(self.inner.id.as_ptr())
}
pub fn model(&self) -> Cow<str> {
chars_to_cow(self.inner.model.as_ptr())
}
pub fn driver_status(&self) -> CameraDriverStatus {
self.inner.status.into()
}
pub fn camera_operations(&self) -> CameraOperations {
self.inner.operations.into()
}
pub fn file_operations(&self) -> FileOperations {
self.inner.file_operations.into()
}
pub fn folder_operations(&self) -> FolderOperations {
self.inner.folder_operations.into()
}
pub fn device_type(&self) -> DeviceType {
self.inner.device_type.into()
}
pub fn usb_info(&self) -> UsbInfo {
UsbInfo {
vendor: self.inner.usb_vendor as usize,
product: self.inner.usb_product as usize,
class: self.inner.usb_class as usize,
subclass: self.inner.usb_subclass as usize,
protocol: self.inner.usb_protocol as usize,
}
}
}
macro_rules! impl_bitmask_check {
($(#[$meta:meta])*, $name:ident, $op:expr) => {
$(#[$meta])*
#[inline]
pub fn $name(&self) -> bool {
self.0 & $op as c_int != 0
}
};
}
impl CameraOperations {
impl_bitmask_check!(
,capture_image,
libgphoto2_sys::CameraOperation::GP_OPERATION_CAPTURE_IMAGE
);
impl_bitmask_check!(
,capture_video,
libgphoto2_sys::CameraOperation::GP_OPERATION_CAPTURE_VIDEO
);
impl_bitmask_check!(
,capture_audio,
libgphoto2_sys::CameraOperation::GP_OPERATION_CAPTURE_AUDIO
);
impl_bitmask_check!(
,capture_preview,
libgphoto2_sys::CameraOperation::GP_OPERATION_CAPTURE_PREVIEW
);
impl_bitmask_check!(
,config,
libgphoto2_sys::CameraOperation::GP_OPERATION_CONFIG
);
impl_bitmask_check!(
,trigger_capture,
libgphoto2_sys::CameraOperation::GP_OPERATION_TRIGGER_CAPTURE
);
}
impl FileOperations {
impl_bitmask_check!(
,delete,
libgphoto2_sys::CameraFileOperation::GP_FILE_OPERATION_DELETE
);
impl_bitmask_check!(
,preview,
libgphoto2_sys::CameraFileOperation::GP_FILE_OPERATION_PREVIEW
);
impl_bitmask_check!(
,raw,
libgphoto2_sys::CameraFileOperation::GP_FILE_OPERATION_RAW
);
impl_bitmask_check!(
,audio,
libgphoto2_sys::CameraFileOperation::GP_FILE_OPERATION_AUDIO
);
impl_bitmask_check!(
,exif,
libgphoto2_sys::CameraFileOperation::GP_FILE_OPERATION_EXIF
);
}
impl FolderOperations {
impl_bitmask_check!(
,delete_all,
libgphoto2_sys::CameraFolderOperation::GP_FOLDER_OPERATION_DELETE_ALL
);
impl_bitmask_check!(
,put_file,
libgphoto2_sys::CameraFolderOperation::GP_FOLDER_OPERATION_PUT_FILE
);
impl_bitmask_check!(
,make_dir,
libgphoto2_sys::CameraFolderOperation::GP_FOLDER_OPERATION_MAKE_DIR
);
impl_bitmask_check!(
,remove_dir,
libgphoto2_sys::CameraFolderOperation::GP_FOLDER_OPERATION_REMOVE_DIR
);
}