mirror of
https://github.com/l1npengtul/nokhwa.git
synced 2026-07-04 02:27:26 +00:00
new controls
This commit is contained in:
@@ -40,7 +40,7 @@ version = "22"
|
||||
optional = true
|
||||
|
||||
[dependencies.opencv]
|
||||
version = "0.92"
|
||||
version = "0.93"
|
||||
default-features = false
|
||||
optional = true
|
||||
|
||||
@@ -57,8 +57,11 @@ version = "0.6"
|
||||
optional = true
|
||||
|
||||
[dependencies.yuvutils-rs]
|
||||
version = "0.3"
|
||||
version = "0.4"
|
||||
optional = true
|
||||
|
||||
[dependencies.rgb]
|
||||
version = "0.8"
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
features = ["docs-features"]
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -49,10 +49,12 @@ impl<D> Decoder for GeneralPurposeDecoder<D> where D: PixelWithColorType {
|
||||
// already decoded
|
||||
FrameFormat::Rgb8 => PixelFormat::Rgb,
|
||||
FrameFormat::RgbA8 => {
|
||||
PixelFormat::Rgba
|
||||
PixelFormat::Rgb
|
||||
}
|
||||
_ => return Err(()),
|
||||
};
|
||||
|
||||
dcv_color_primitives::convert_image(buffer.resolution().width(), buffer.resolution().height(), )
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
use crate::{frame_format::FrameFormat, types::ApiBackend};
|
||||
use thiserror::Error;
|
||||
use crate::ranges::RangeValidationResult;
|
||||
|
||||
/// All errors in `nokhwa`.
|
||||
#[allow(clippy::module_name_repetitions)]
|
||||
|
||||
@@ -4,9 +4,10 @@ use std::{
|
||||
};
|
||||
use crate::{
|
||||
frame_format::FrameFormat,
|
||||
types::{CameraFormat, Resolution, FrameRate, Range},
|
||||
traits::Distance
|
||||
traits::Distance,
|
||||
types::{CameraFormat, FrameRate, Resolution}
|
||||
};
|
||||
use crate::ranges::Range;
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialOrd, PartialEq)]
|
||||
enum ClosestType {
|
||||
|
||||
@@ -30,3 +30,5 @@ pub mod traits;
|
||||
pub mod types;
|
||||
pub mod decoders;
|
||||
pub mod utils;
|
||||
pub mod ranges;
|
||||
pub mod controls;
|
||||
|
||||
@@ -0,0 +1,516 @@
|
||||
use std::collections::HashMap;
|
||||
use core::fmt::{ Debug, Display, Formatter};
|
||||
use std::collections::hash_map::Keys;
|
||||
use std::hash::Hash;
|
||||
use std::ops::{Div, Sub};
|
||||
use crate::error::NokhwaError;
|
||||
|
||||
/// Failed to validate.
|
||||
#[derive(Copy, Clone, Debug, Default, Hash, Ord, PartialOrd, Eq, PartialEq)]
|
||||
pub struct RangeValidationFailure;
|
||||
|
||||
/// A range type that can be validated.
|
||||
pub trait ValidatableRange {
|
||||
/// Input type to validate.
|
||||
type Validation;
|
||||
|
||||
/// Validates the value.
|
||||
fn validate(&self, value: Self::Validation) -> Result<(), RangeValidationFailure>;
|
||||
}
|
||||
|
||||
/// Creates a range of values.
|
||||
///
|
||||
/// Inclusive by default.
|
||||
#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
|
||||
pub struct Range<T>
|
||||
{
|
||||
minimum: Option<T>,
|
||||
lower_inclusive: bool,
|
||||
maximum: Option<T>,
|
||||
upper_inclusive: bool,
|
||||
preferred: T,
|
||||
}
|
||||
|
||||
impl<T> Range<T>
|
||||
where
|
||||
T: Copy + Clone + Debug + PartialOrd + PartialEq,
|
||||
{
|
||||
/// Create an upper and lower inclusive [`Range`]
|
||||
pub fn new(preferred: T, min: Option<T>, max: Option<T>) -> Self {
|
||||
Self {
|
||||
minimum: min,
|
||||
lower_inclusive: true,
|
||||
maximum: max,
|
||||
upper_inclusive: true,
|
||||
preferred,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn with_inclusive(
|
||||
preferred: T,
|
||||
min: Option<T>,
|
||||
lower_inclusive: bool,
|
||||
max: Option<T>,
|
||||
upper_inclusive: bool,
|
||||
) -> Self {
|
||||
Self {
|
||||
minimum: min,
|
||||
lower_inclusive,
|
||||
maximum: max,
|
||||
upper_inclusive,
|
||||
preferred,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn exact(preferred: T) -> Self {
|
||||
Self {
|
||||
minimum: None,
|
||||
lower_inclusive: true,
|
||||
maximum: None,
|
||||
upper_inclusive: true,
|
||||
preferred,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_minimum(&mut self, minimum: Option<T>) {
|
||||
self.minimum = minimum;
|
||||
}
|
||||
pub fn set_lower_inclusive(&mut self, lower_inclusive: bool) {
|
||||
self.lower_inclusive = lower_inclusive;
|
||||
}
|
||||
pub fn set_maximum(&mut self, maximum: Option<T>) {
|
||||
self.maximum = maximum;
|
||||
}
|
||||
pub fn set_upper_inclusive(&mut self, upper_inclusive: bool) {
|
||||
self.upper_inclusive = upper_inclusive;
|
||||
}
|
||||
pub fn set_preferred(&mut self, preferred: T) {
|
||||
self.preferred = preferred;
|
||||
}
|
||||
pub fn minimum(&self) -> Option<T> {
|
||||
self.minimum
|
||||
}
|
||||
pub fn lower_inclusive(&self) -> bool {
|
||||
self.lower_inclusive
|
||||
}
|
||||
pub fn maximum(&self) -> Option<T> {
|
||||
self.maximum
|
||||
}
|
||||
pub fn upper_inclusive(&self) -> bool {
|
||||
self.upper_inclusive
|
||||
}
|
||||
pub fn preferred(&self) -> T {
|
||||
self.preferred
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> ValidatableRange for Range<T> where T: PartialEq + PartialOrd {
|
||||
type Validation = T;
|
||||
|
||||
fn validate(&self, value: Self::Validation) -> Result<(), RangeValidationFailure> {
|
||||
num_range_validate(self.minimum.as_ref(), self.maximum.as_ref(), &self.preferred, self.lower_inclusive, self.upper_inclusive, &value)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Default for Range<T>
|
||||
where
|
||||
T: Default,
|
||||
{
|
||||
fn default() -> Self {
|
||||
Range {
|
||||
minimum: None,
|
||||
lower_inclusive: true,
|
||||
maximum: None,
|
||||
upper_inclusive: true,
|
||||
preferred: T::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Display for Range<T> where T: Debug {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
let lower_inclusive_char = bool_to_inclusive_char(self.lower_inclusive, false);
|
||||
let upper_inclusive_char = bool_to_inclusive_char(self.upper_inclusive, true);
|
||||
let default = default_to_string(&self.preferred);
|
||||
|
||||
write!(f, "Range: {lower_inclusive_char}{}, {}{upper_inclusive_char}, Preferred: {default}", self.minimum, self.maximum)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialOrd, PartialEq)]
|
||||
pub struct IndicatedRange<T> where T: Copy + Clone + Debug + PartialOrd + PartialEq {
|
||||
minimum: T,
|
||||
lower_inclusive: bool,
|
||||
maximum: T,
|
||||
upper_inclusive: bool,
|
||||
step: Option<T>,
|
||||
default: Option<T>,
|
||||
}
|
||||
|
||||
impl<T> IndicatedRange<T>
|
||||
where
|
||||
T: Copy + Clone + Debug + PartialOrd + PartialEq
|
||||
{
|
||||
pub fn new(minimum: T, lower_inclusive: bool, maximum: T, upper_inclusive: bool, step: Option<T>, default: Option<T>) -> Self {
|
||||
Self { minimum, lower_inclusive, maximum, upper_inclusive, step, default }
|
||||
}
|
||||
|
||||
pub fn minimum(&self) -> T {
|
||||
self.minimum
|
||||
}
|
||||
|
||||
pub fn lower_inclusive(&self) -> bool {
|
||||
self.lower_inclusive
|
||||
}
|
||||
|
||||
pub fn maximum(&self) -> T {
|
||||
self.maximum
|
||||
}
|
||||
|
||||
pub fn upper_inclusive(&self) -> bool {
|
||||
self.upper_inclusive
|
||||
}
|
||||
|
||||
pub fn step(&self) -> Option<T> {
|
||||
self.step
|
||||
}
|
||||
|
||||
pub fn default_value(&self) -> Option<T> {
|
||||
self.default
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> ValidatableRange for IndicatedRange<T> where T: Copy + PartialEq + PartialOrd + Div<Output = T> + Sub<Output = T> + Number {
|
||||
type Validation = T;
|
||||
|
||||
fn validate(&self, value: Self::Validation) -> Result<(), RangeValidationFailure> {
|
||||
if let Some(step) = &self.step {
|
||||
let prepared_value = value - &self.minimum;
|
||||
// We can check the step if we subtract the value from the minimum value
|
||||
// then see if the remainder of prepared value and step is zero.
|
||||
// e.g. 4, 12, value is 7, step is 3
|
||||
// 7 - 4 = 3
|
||||
// 3 % 3 = 0 Valid!
|
||||
if prepared_value % step != 0 {
|
||||
return Err(RangeValidationFailure::default())
|
||||
}
|
||||
}
|
||||
|
||||
num_range_validate(self.minimum.as_ref(), self.maximum.as_ref(), &self.default, self.lower_inclusive, self.upper_inclusive, &value)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Display for IndicatedRange<T> where T: Debug {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
let lower_inclusive_char = bool_to_inclusive_char(self.lower_inclusive, false);
|
||||
let upper_inclusive_char = bool_to_inclusive_char(self.upper_inclusive, true);
|
||||
let default = default_to_string(&self.default);
|
||||
let step = default_to_string(&self.step);
|
||||
|
||||
// Ex) IndicatedRange: (5, 19], Step: 3, Default: 8
|
||||
write!(f, "IndicatedRange: {lower_inclusive_char}{}, {}{upper_inclusive_char}, Step: {step}, Default: {default}", self.minimum, self.maximum)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialOrd, PartialEq)]
|
||||
pub struct NonCopyRange<T> where T: Clone + Debug + PartialOrd + PartialEq {
|
||||
minimum: T,
|
||||
lower_inclusive: bool,
|
||||
maximum: T,
|
||||
upper_inclusive: bool,
|
||||
step: Option<T>,
|
||||
default: Option<T>,
|
||||
}
|
||||
|
||||
impl<T> NonCopyRange<T>
|
||||
where
|
||||
T: Clone + Debug + PartialOrd + PartialEq
|
||||
{
|
||||
pub fn new(minimum: T, lower_inclusive: bool, maximum: T, upper_inclusive: bool, step: Option<T>, default: Option<T>) -> Self {
|
||||
Self { minimum, lower_inclusive, maximum, upper_inclusive, step, default }
|
||||
}
|
||||
|
||||
pub fn minimum(&self) -> &T {
|
||||
&self.minimum
|
||||
}
|
||||
|
||||
pub fn lower_inclusive(&self) -> bool {
|
||||
self.lower_inclusive
|
||||
}
|
||||
|
||||
pub fn maximum(&self) -> &T {
|
||||
&self.maximum
|
||||
}
|
||||
|
||||
pub fn upper_inclusive(&self) -> bool {
|
||||
self.upper_inclusive
|
||||
}
|
||||
|
||||
pub fn step(&self) -> Option<&T> {
|
||||
self.step.as_ref()
|
||||
}
|
||||
|
||||
pub fn default_value(&self) -> Option<&T> {
|
||||
self.default.as_ref()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> ValidatableRange for NonCopyRange<T> where T: Clone + PartialEq + PartialOrd + Div<Output = T> + Sub<Output = T> {
|
||||
type Validation = T;
|
||||
|
||||
fn validate(&self, value: Self::Validation) -> Result<(), RangeValidationFailure> {
|
||||
if let Some(step) = &self.step {
|
||||
let prepared_value = value.clone() - &self.minimum;
|
||||
// We can check the step if we subtract the value from the minimum value
|
||||
// then see if the remainder of prepared value and step is zero.
|
||||
// e.g. 4, 12, value is 7, step is 3
|
||||
// 7 - 4 = 3
|
||||
// 3 % 3 = 0 Valid!
|
||||
if prepared_value % step != 0 {
|
||||
return Err(RangeValidationFailure::default())
|
||||
}
|
||||
}
|
||||
|
||||
num_range_validate(self.minimum.as_ref(), self.maximum.as_ref(), &self.default, self.lower_inclusive, self.upper_inclusive, &value)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Display for IndicatedRange<T> where T: Debug {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
let lower_inclusive_char = bool_to_inclusive_char(self.lower_inclusive, false);
|
||||
let upper_inclusive_char = bool_to_inclusive_char(self.upper_inclusive, true);
|
||||
let default = default_to_string(&self.default);
|
||||
let step = default_to_string(&self.step);
|
||||
|
||||
// Ex) IndicatedRange: (5, 19], Step: 3, Default: 8
|
||||
write!(f, "IndicatedRange: {lower_inclusive_char}{}, {}{upper_inclusive_char}, Step: {step}, Default: {default}", self.minimum, self.maximum)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Options<T> where T: Clone + Debug {
|
||||
default: Option<T>,
|
||||
available: Vec<T>,
|
||||
}
|
||||
|
||||
impl<T> Options<T>
|
||||
where
|
||||
T: Clone + Debug + PartialEq
|
||||
{
|
||||
pub fn new(values: Vec<T>, default_value: T) -> Self {
|
||||
Self {
|
||||
default: default_value,
|
||||
available: values,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn default_value(&self) -> Option<&T> {
|
||||
self.default.as_ref()
|
||||
}
|
||||
|
||||
pub fn available(&self) -> &[T] {
|
||||
&self.available
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> ValidatableRange for Options<T> where T: PartialEq {
|
||||
type Validation = T;
|
||||
|
||||
fn validate(&self, value: Self::Validation) -> Result<(), RangeValidationFailure> {
|
||||
if self.available.contains(value) {
|
||||
return Ok(());
|
||||
}
|
||||
Err(RangeValidationFailure::default())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Display for Options<T> where T: Debug {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
let default = default_to_string(&self.default);
|
||||
|
||||
write!(f, "Options: Available {:?}, Default: {default}", self.available)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct KeyValue<K, V> where K: Clone + Debug + Hash + Eq, V: Clone + Debug {
|
||||
defaults: HashMap<K, V>,
|
||||
}
|
||||
|
||||
impl<K, V> KeyValue<K, V>
|
||||
where
|
||||
K: Clone + Debug + Hash + Eq,
|
||||
V: Clone + Debug
|
||||
{
|
||||
pub fn new(default: HashMap<K, V>) -> Self {
|
||||
Self {
|
||||
defaults: default,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn available_keys(&self) -> &Keys<'_, K, V> {
|
||||
&self.defaults.keys()
|
||||
}
|
||||
|
||||
pub fn by_key(&self, key: &K) -> Option<&V> {
|
||||
self.defaults.get(key)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> ValidatableRange for KeyValue<T, _> where T: Eq + Hash {
|
||||
type Validation = T;
|
||||
|
||||
fn validate(&self, value: Self::Validation) -> Result<(), RangeValidationFailure> {
|
||||
if self.defaults.contains_key(&value) {
|
||||
return Ok(())
|
||||
}
|
||||
Err(RangeValidationFailure::default())
|
||||
}
|
||||
}
|
||||
|
||||
impl<K, V> Display for KeyValue<K, V> where K: Debug, V: Debug {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
// TODO: pretty print?
|
||||
write!(f, "Key Value Pairs: {:?}", self.defaults)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct ArrayRange<T> where T: Clone + Debug {
|
||||
appendable_options: Vec<T>,
|
||||
default_options: Vec<T>,
|
||||
}
|
||||
|
||||
impl<T> ArrayRange<T> where T: Clone + Debug + PartialEq {
|
||||
pub fn new(appendable: Vec<T>, default: Vec<T>) -> Result<Self, NokhwaError> {
|
||||
for option in &default {
|
||||
if !appendable.contains(option) {
|
||||
return Err(NokhwaError::StructureError { structure: "ArrayRange".to_string(), error: "Attempted to add an undependable option to default option - ILLEGAL! - If you got this while using a driver, this is a bug! Please report to https://github.com/l1npengtul/nokhwa/issues!".to_string() })
|
||||
}
|
||||
}
|
||||
|
||||
Ok(Self {
|
||||
appendable_options: appendable,
|
||||
default_options: default,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn appendable_options(&self) -> &[T] {
|
||||
&self.appendable_options
|
||||
}
|
||||
|
||||
pub fn default_options(&self) -> &[T] {
|
||||
&self.default_options
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> ValidatableRange for ArrayRange<T> where T: PartialEq {
|
||||
type Validation = T;
|
||||
|
||||
fn validate(&self, value: Self::Validation) -> Result<(), RangeValidationFailure> {
|
||||
if self.appendable_options.contains(value) {
|
||||
return Ok(());
|
||||
}
|
||||
Err(RangeValidationFailure::default())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Display for ArrayRange<T> where T: Debug {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "ArrayRange: Available Options: {:?}, Default: {:?}", self.appendable_options, self.default_options)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Simple<T> where T: Clone + Debug {
|
||||
default: Option<T>
|
||||
}
|
||||
|
||||
impl<T> Simple<T> where T: Clone + Debug {
|
||||
pub fn new(default: Option<T>) -> Self {
|
||||
Self {
|
||||
default,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn default_value(&self) -> Option<&T> {
|
||||
self.default.as_ref()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> ValidatableRange for Simple<T> {
|
||||
type Validation = T;
|
||||
|
||||
fn validate(&self, _: Self::Validation) -> Result<(), RangeValidationFailure> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Display for Simple<T> where T: Debug {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
let default = default_to_string(&self.default);
|
||||
write!(f, "Simple (Any Value): Default Value: {default}")
|
||||
}
|
||||
}
|
||||
|
||||
fn bool_to_inclusive_char(inclusive: bool, upper: bool) -> char {
|
||||
match inclusive {
|
||||
true => if upper { ']' } else { '[' },
|
||||
false => if upper { ')' } else { '(' },
|
||||
}
|
||||
}
|
||||
|
||||
fn default_to_string<T>(default: &Option<T>) -> String where T: Debug {
|
||||
match default {
|
||||
Some(v) => {
|
||||
format!("{v:?}")
|
||||
}
|
||||
None => String::from("None"),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fn num_range_validate<T>(minimum: Option<&T>, maximum: Option<&T>, default: &T, lower_inclusive: bool, upper_inclusive: bool, value: &T) -> Result<(), RangeValidationFailure> where T: PartialEq + PartialOrd {
|
||||
if value == default {
|
||||
return Ok(())
|
||||
}
|
||||
|
||||
if let Some(min) = minimum {
|
||||
let test = if lower_inclusive {
|
||||
min <= value
|
||||
} else {
|
||||
min < value
|
||||
};
|
||||
if test {
|
||||
return Err(RangeValidationFailure::default());
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(max) = maximum {
|
||||
let test = if upper_inclusive {
|
||||
max >= value
|
||||
} else {
|
||||
max > value
|
||||
};
|
||||
if test {
|
||||
return Err(RangeValidationFailure::default());
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
trait Number {}
|
||||
|
||||
macro_rules! impl_num {
|
||||
( $($n:ty, )* ) => {
|
||||
{
|
||||
$(
|
||||
impl Number for $n {}
|
||||
)*
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
impl_num!( i8, u8, i16, u16, i32, u32, i64, u64, i128, u128, f32, f64, );
|
||||
@@ -16,10 +16,11 @@
|
||||
|
||||
use crate::{
|
||||
buffer::Buffer, error::NokhwaError, format_request::FormatRequest, types::{
|
||||
ApiBackend, CameraControl, CameraFormat, CameraIndex, CameraInfo, ControlValueSetter, KnownCameraControl, Resolution
|
||||
ApiBackend, CameraFormat, CameraIndex, CameraInfo, Resolution
|
||||
}
|
||||
};
|
||||
use std::{borrow::Cow, collections::HashMap};
|
||||
use crate::controls::{CameraControl, ControlValueSetter, KnownCameraControl};
|
||||
use crate::frame_format::FrameFormat;
|
||||
use crate::types::FrameRate;
|
||||
|
||||
|
||||
+4
-823
@@ -5,147 +5,17 @@ use crate::{
|
||||
#[cfg(feature = "serialize")]
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::{
|
||||
borrow::Borrow, cmp::Ordering, fmt::{
|
||||
borrow::Borrow, cmp::Ordering, collections::HashSet, fmt::{
|
||||
Debug,
|
||||
Display,
|
||||
Formatter
|
||||
}, hash::{Hash, Hasher}, ops::{Add, Deref, DerefMut, Sub}
|
||||
};
|
||||
use std::collections::HashMap;
|
||||
use crate::controls::{CameraControl, CameraPropertyFlag, KnownCameraControl};
|
||||
use crate::ranges::Range;
|
||||
use crate::traits::Distance;
|
||||
|
||||
/// Creates a range of values.
|
||||
///
|
||||
/// Inclusive by default.
|
||||
#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
|
||||
pub struct Range<T>
|
||||
{
|
||||
minimum: Option<T>,
|
||||
lower_inclusive: bool,
|
||||
maximum: Option<T>,
|
||||
upper_inclusive: bool,
|
||||
preferred: T,
|
||||
}
|
||||
|
||||
impl<T> Range<T>
|
||||
where
|
||||
T: Copy + Clone + Debug + PartialOrd + PartialEq,
|
||||
{
|
||||
/// Create an upper and lower inclusive [`Range`]
|
||||
pub fn new(preferred: T, min: Option<T>, max: Option<T>) -> Self {
|
||||
Self {
|
||||
minimum: min,
|
||||
lower_inclusive: true,
|
||||
maximum: max,
|
||||
upper_inclusive: true,
|
||||
preferred,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn with_inclusive(
|
||||
preferred: T,
|
||||
min: Option<T>,
|
||||
lower_inclusive: bool,
|
||||
max: Option<T>,
|
||||
upper_inclusive: bool,
|
||||
) -> Self {
|
||||
Self {
|
||||
minimum: min,
|
||||
lower_inclusive,
|
||||
maximum: max,
|
||||
upper_inclusive,
|
||||
preferred,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn exact(preferred: T) -> Self {
|
||||
Self {
|
||||
minimum: None,
|
||||
lower_inclusive: true,
|
||||
maximum: None,
|
||||
upper_inclusive: true,
|
||||
preferred,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn in_range(&self, item: T) -> bool {
|
||||
if item == self.preferred {
|
||||
return true
|
||||
}
|
||||
|
||||
if let Some(min) = self.minimum {
|
||||
let test = if self.lower_inclusive {
|
||||
min >= item
|
||||
} else {
|
||||
min > item
|
||||
};
|
||||
if test {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(max) = self.maximum {
|
||||
let test = if self.lower_inclusive {
|
||||
max <= item
|
||||
} else {
|
||||
max < item
|
||||
};
|
||||
if test {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
|
||||
pub fn set_minimum(&mut self, minimum: Option<T>) {
|
||||
self.minimum = minimum;
|
||||
}
|
||||
pub fn set_lower_inclusive(&mut self, lower_inclusive: bool) {
|
||||
self.lower_inclusive = lower_inclusive;
|
||||
}
|
||||
pub fn set_maximum(&mut self, maximum: Option<T>) {
|
||||
self.maximum = maximum;
|
||||
}
|
||||
pub fn set_upper_inclusive(&mut self, upper_inclusive: bool) {
|
||||
self.upper_inclusive = upper_inclusive;
|
||||
}
|
||||
pub fn set_preferred(&mut self, preferred: T) {
|
||||
self.preferred = preferred;
|
||||
}
|
||||
pub fn minimum(&self) -> Option<T> {
|
||||
self.minimum
|
||||
}
|
||||
pub fn lower_inclusive(&self) -> bool {
|
||||
self.lower_inclusive
|
||||
}
|
||||
pub fn maximum(&self) -> Option<T> {
|
||||
self.maximum
|
||||
}
|
||||
pub fn upper_inclusive(&self) -> bool {
|
||||
self.upper_inclusive
|
||||
}
|
||||
pub fn preferred(&self) -> T {
|
||||
self.preferred
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Default for Range<T>
|
||||
where
|
||||
T: Default,
|
||||
{
|
||||
fn default() -> Self {
|
||||
Range {
|
||||
minimum: None,
|
||||
lower_inclusive: true,
|
||||
maximum: None,
|
||||
upper_inclusive: true,
|
||||
preferred: T::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// Describes the index of the camera.
|
||||
/// - Index: A numbered index
|
||||
@@ -626,456 +496,6 @@ impl Display for CameraInfo {
|
||||
}
|
||||
}
|
||||
|
||||
/// The list of known camera controls to the library. <br>
|
||||
/// These can control the picture brightness, etc. <br>
|
||||
/// Note that not all backends/devices support all these. Run [`supported_camera_controls()`](crate::traits::CaptureTrait::camera_controls) to see which ones can be set.
|
||||
#[derive(Copy, Clone, Debug, Hash, Ord, PartialOrd, Eq, PartialEq)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
|
||||
pub enum KnownCameraControl {
|
||||
Brightness,
|
||||
Contrast,
|
||||
Hue,
|
||||
Saturation,
|
||||
Sharpness,
|
||||
Gamma,
|
||||
WhiteBalance,
|
||||
BacklightComp,
|
||||
Gain,
|
||||
Pan,
|
||||
Tilt,
|
||||
Zoom,
|
||||
Exposure,
|
||||
Iris,
|
||||
Focus,
|
||||
Facing,
|
||||
/// Other camera control. Listed is the ID.
|
||||
/// Wasteful, however is needed for a unified API across Windows, Linux, and MacOSX due to Microsoft's usage of GUIDs.
|
||||
///
|
||||
/// THIS SHOULD ONLY BE USED WHEN YOU KNOW THE PLATFORM THAT YOU ARE RUNNING ON.
|
||||
Other(u128),
|
||||
}
|
||||
|
||||
/// All camera controls in an array.
|
||||
#[must_use]
|
||||
pub const fn all_known_camera_controls() -> &'static [KnownCameraControl] {
|
||||
&[
|
||||
KnownCameraControl::Brightness,
|
||||
KnownCameraControl::Contrast,
|
||||
KnownCameraControl::Hue,
|
||||
KnownCameraControl::Saturation,
|
||||
KnownCameraControl::Sharpness,
|
||||
KnownCameraControl::Gamma,
|
||||
KnownCameraControl::WhiteBalance,
|
||||
KnownCameraControl::BacklightComp,
|
||||
KnownCameraControl::Gain,
|
||||
KnownCameraControl::Pan,
|
||||
KnownCameraControl::Tilt,
|
||||
KnownCameraControl::Zoom,
|
||||
KnownCameraControl::Exposure,
|
||||
KnownCameraControl::Iris,
|
||||
KnownCameraControl::Focus,
|
||||
KnownCameraControl::Facing,
|
||||
]
|
||||
}
|
||||
|
||||
impl Display for KnownCameraControl {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{:?}", &self)
|
||||
}
|
||||
}
|
||||
|
||||
/// This tells you weather a [`KnownCameraControl`] is automatically managed by the OS/Driver
|
||||
/// or manually managed by you, the programmer.
|
||||
#[derive(Copy, Clone, Debug, Hash, Ord, PartialOrd, Eq, PartialEq)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
|
||||
pub enum KnownCameraControlFlag {
|
||||
Automatic,
|
||||
Manual,
|
||||
Continuous,
|
||||
ReadOnly,
|
||||
WriteOnly,
|
||||
Volatile,
|
||||
Disabled,
|
||||
}
|
||||
|
||||
impl Display for KnownCameraControlFlag {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{self:?}")
|
||||
}
|
||||
}
|
||||
|
||||
/// The values for a [`CameraControl`].
|
||||
///
|
||||
/// This provides a wide range of values that can be used to control a camera.
|
||||
#[derive(Clone, Debug, PartialEq, PartialOrd)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
|
||||
pub enum ControlValueDescription {
|
||||
None,
|
||||
Integer {
|
||||
value: i64,
|
||||
default: i64,
|
||||
step: i64,
|
||||
},
|
||||
IntegerRange {
|
||||
min: i64,
|
||||
max: i64,
|
||||
value: i64,
|
||||
step: i64,
|
||||
default: i64,
|
||||
},
|
||||
Float {
|
||||
value: f64,
|
||||
default: f64,
|
||||
step: f64,
|
||||
},
|
||||
FloatRange {
|
||||
min: f64,
|
||||
max: f64,
|
||||
value: f64,
|
||||
step: f64,
|
||||
default: f64,
|
||||
},
|
||||
Boolean {
|
||||
value: bool,
|
||||
default: bool,
|
||||
},
|
||||
String {
|
||||
value: String,
|
||||
default: Option<String>,
|
||||
},
|
||||
Bytes {
|
||||
value: Vec<u8>,
|
||||
default: Vec<u8>,
|
||||
},
|
||||
KeyValuePair {
|
||||
key: i128,
|
||||
value: i128,
|
||||
default: (i128, i128),
|
||||
},
|
||||
Point {
|
||||
value: (f64, f64),
|
||||
default: (f64, f64),
|
||||
},
|
||||
Enum {
|
||||
value: i64,
|
||||
possible: Vec<i64>,
|
||||
default: i64,
|
||||
},
|
||||
RGB {
|
||||
value: (f64, f64, f64),
|
||||
max: (f64, f64, f64),
|
||||
default: (f64, f64, f64),
|
||||
},
|
||||
StringList {
|
||||
value: String,
|
||||
availible: Vec<String>,
|
||||
},
|
||||
}
|
||||
|
||||
impl ControlValueDescription {
|
||||
/// Get the value of this [`ControlValueDescription`]
|
||||
#[must_use]
|
||||
pub fn value(&self) -> ControlValueSetter {
|
||||
match self {
|
||||
ControlValueDescription::None => ControlValueSetter::None,
|
||||
ControlValueDescription::Integer { value, .. }
|
||||
| ControlValueDescription::IntegerRange { value, .. } => {
|
||||
ControlValueSetter::Integer(*value)
|
||||
}
|
||||
ControlValueDescription::Float { value, .. }
|
||||
| ControlValueDescription::FloatRange { value, .. } => {
|
||||
ControlValueSetter::Float(*value)
|
||||
}
|
||||
ControlValueDescription::Boolean { value, .. } => ControlValueSetter::Boolean(*value),
|
||||
ControlValueDescription::String { value, .. } => {
|
||||
ControlValueSetter::String(value.clone())
|
||||
}
|
||||
ControlValueDescription::Bytes { value, .. } => {
|
||||
ControlValueSetter::Bytes(value.clone())
|
||||
}
|
||||
ControlValueDescription::KeyValuePair { key, value, .. } => {
|
||||
ControlValueSetter::KeyValue(*key, *value)
|
||||
}
|
||||
ControlValueDescription::Point { value, .. } => {
|
||||
ControlValueSetter::Point(value.0, value.1)
|
||||
}
|
||||
ControlValueDescription::Enum { value, .. } => ControlValueSetter::EnumValue(*value),
|
||||
ControlValueDescription::RGB { value, .. } => {
|
||||
ControlValueSetter::RGB(value.0, value.1, value.2)
|
||||
}
|
||||
ControlValueDescription::StringList { value, .. } => {
|
||||
ControlValueSetter::StringList(value.clone())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Verifies if the [setter](ControlValueSetter) is valid for the provided [`ControlValueDescription`].
|
||||
/// - `true` => Is valid.
|
||||
/// - `false` => Is not valid.
|
||||
///
|
||||
/// If the step is 0, it will automatically return `true`.
|
||||
#[must_use]
|
||||
pub fn verify_setter(&self, setter: &ControlValueSetter) -> bool {
|
||||
match self {
|
||||
ControlValueDescription::None => setter.as_none().is_some(),
|
||||
ControlValueDescription::Integer {
|
||||
value,
|
||||
default,
|
||||
step,
|
||||
} => {
|
||||
if *step == 0 {
|
||||
return true;
|
||||
}
|
||||
match setter.as_integer() {
|
||||
Some(i) => (i + default) % step == 0 || (i + value) % step == 0,
|
||||
None => false,
|
||||
}
|
||||
}
|
||||
ControlValueDescription::IntegerRange {
|
||||
min,
|
||||
max,
|
||||
value,
|
||||
step,
|
||||
default,
|
||||
} => {
|
||||
if *step == 0 {
|
||||
return true;
|
||||
}
|
||||
match setter.as_integer() {
|
||||
Some(i) => {
|
||||
((i + default) % step == 0 || (i + value) % step == 0)
|
||||
&& i >= min
|
||||
&& i <= max
|
||||
}
|
||||
None => false,
|
||||
}
|
||||
}
|
||||
ControlValueDescription::Float {
|
||||
value,
|
||||
default,
|
||||
step,
|
||||
} => {
|
||||
if step.abs() == 0_f64 {
|
||||
return true;
|
||||
}
|
||||
match setter.as_float() {
|
||||
Some(f) => (f - default).abs() % step == 0_f64 || (f - value) % step == 0_f64,
|
||||
None => false,
|
||||
}
|
||||
}
|
||||
ControlValueDescription::FloatRange {
|
||||
min,
|
||||
max,
|
||||
value,
|
||||
step,
|
||||
default,
|
||||
} => {
|
||||
if step.abs() == 0_f64 {
|
||||
return true;
|
||||
}
|
||||
|
||||
match setter.as_float() {
|
||||
Some(f) => {
|
||||
((f - default).abs() % step == 0_f64 || (f - value) % step == 0_f64)
|
||||
&& f >= min
|
||||
&& f <= max
|
||||
}
|
||||
None => false,
|
||||
}
|
||||
}
|
||||
ControlValueDescription::Boolean { .. } => setter.as_boolean().is_some(),
|
||||
ControlValueDescription::String { .. } => setter.as_str().is_some(),
|
||||
ControlValueDescription::Bytes { .. } => setter.as_bytes().is_some(),
|
||||
ControlValueDescription::KeyValuePair { .. } => setter.as_key_value().is_some(),
|
||||
ControlValueDescription::Point { .. } => match setter.as_point() {
|
||||
Some(pt) => {
|
||||
!pt.0.is_nan() && !pt.1.is_nan() && pt.0.is_finite() && pt.1.is_finite()
|
||||
}
|
||||
None => false,
|
||||
},
|
||||
ControlValueDescription::Enum { possible, .. } => match setter.as_enum() {
|
||||
Some(e) => possible.contains(e),
|
||||
None => false,
|
||||
},
|
||||
ControlValueDescription::RGB { max, .. } => match setter.as_rgb() {
|
||||
Some(v) => *v.0 >= max.0 && *v.1 >= max.1 && *v.2 >= max.2,
|
||||
None => false,
|
||||
},
|
||||
ControlValueDescription::StringList { availible, .. } => {
|
||||
availible.contains(&(setter.as_str().unwrap_or("").to_string())) // what the fuck??
|
||||
}
|
||||
}
|
||||
|
||||
// match setter {
|
||||
// ControlValueSetter::None => {
|
||||
// matches!(self, ControlValueDescription::None)
|
||||
// }
|
||||
// ControlValueSetter::Integer(i) => match self {
|
||||
// ControlValueDescription::Integer {
|
||||
// value,
|
||||
// default,
|
||||
// step,
|
||||
// } => (i - default).abs() % step == 0 || (i - value) % step == 0,
|
||||
// ControlValueDescription::IntegerRange {
|
||||
// min,
|
||||
// max,
|
||||
// value,
|
||||
// step,
|
||||
// default,
|
||||
// } => {
|
||||
// if value > max || value < min {
|
||||
// return false;
|
||||
// }
|
||||
//
|
||||
// (i - default) % step == 0 || (i - value) % step == 0
|
||||
// }
|
||||
// _ => false,
|
||||
// },
|
||||
// ControlValueSetter::Float(f) => match self {
|
||||
// ControlValueDescription::Float {
|
||||
// value,
|
||||
// default,
|
||||
// step,
|
||||
// } => (f - default).abs() % step == 0_f64 || (f - value) % step == 0_f64,
|
||||
// ControlValueDescription::FloatRange {
|
||||
// min,
|
||||
// max,
|
||||
// value,
|
||||
// step,
|
||||
// default,
|
||||
// } => {
|
||||
// if value > max || value < min {
|
||||
// return false;
|
||||
// }
|
||||
//
|
||||
// (f - default) % step == 0_f64 || (f - value) % step == 0_f64
|
||||
// }
|
||||
// _ => false,
|
||||
// },
|
||||
// ControlValueSetter::Boolean(b) => {
|
||||
//
|
||||
// }
|
||||
// ControlValueSetter::String(_) => {
|
||||
// matches!(self, ControlValueDescription::String { .. })
|
||||
// }
|
||||
// ControlValueSetter::Bytes(_) => {
|
||||
// matches!(self, ControlValueDescription::Bytes { .. })
|
||||
// }
|
||||
// ControlValueSetter::KeyValue(_, _) => {
|
||||
// matches!(self, ControlValueDescription::KeyValuePair { .. })
|
||||
// }
|
||||
// ControlValueSetter::Point(_, _) => {
|
||||
// matches!(self, ControlValueDescription::Point { .. })
|
||||
// }
|
||||
// ControlValueSetter::EnumValue(_) => {
|
||||
// matches!(self, ControlValueDescription::Enum { .. })
|
||||
// }
|
||||
// ControlValueSetter::RGB(_, _, _) => {
|
||||
// matches!(self, ControlValueDescription::RGB { .. })
|
||||
// }
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for ControlValueDescription {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
ControlValueDescription::None => {
|
||||
write!(f, "(None)")
|
||||
}
|
||||
ControlValueDescription::Integer {
|
||||
value,
|
||||
default,
|
||||
step,
|
||||
} => {
|
||||
write!(f, "(Current: {value}, Default: {default}, Step: {step})",)
|
||||
}
|
||||
ControlValueDescription::IntegerRange {
|
||||
min,
|
||||
max,
|
||||
value,
|
||||
step,
|
||||
default,
|
||||
} => {
|
||||
write!(
|
||||
f,
|
||||
"(Current: {value}, Default: {default}, Step: {step}, Range: ({min}, {max}))",
|
||||
)
|
||||
}
|
||||
ControlValueDescription::Float {
|
||||
value,
|
||||
default,
|
||||
step,
|
||||
} => {
|
||||
write!(f, "(Current: {value}, Default: {default}, Step: {step})",)
|
||||
}
|
||||
ControlValueDescription::FloatRange {
|
||||
min,
|
||||
max,
|
||||
value,
|
||||
step,
|
||||
default,
|
||||
} => {
|
||||
write!(
|
||||
f,
|
||||
"(Current: {value}, Default: {default}, Step: {step}, Range: ({min}, {max}))",
|
||||
)
|
||||
}
|
||||
ControlValueDescription::Boolean { value, default } => {
|
||||
write!(f, "(Current: {value}, Default: {default})")
|
||||
}
|
||||
ControlValueDescription::String { value, default } => {
|
||||
write!(f, "(Current: {value}, Default: {default:?})")
|
||||
}
|
||||
ControlValueDescription::Bytes { value, default } => {
|
||||
write!(f, "(Current: {value:x?}, Default: {default:x?})")
|
||||
}
|
||||
ControlValueDescription::KeyValuePair {
|
||||
key,
|
||||
value,
|
||||
default,
|
||||
} => {
|
||||
write!(
|
||||
f,
|
||||
"Current: ({key}, {value}), Default: ({}, {})",
|
||||
default.0, default.1
|
||||
)
|
||||
}
|
||||
ControlValueDescription::Point { value, default } => {
|
||||
write!(
|
||||
f,
|
||||
"Current: ({}, {}), Default: ({}, {})",
|
||||
value.0, value.1, default.0, default.1
|
||||
)
|
||||
}
|
||||
ControlValueDescription::Enum {
|
||||
value,
|
||||
possible,
|
||||
default,
|
||||
} => {
|
||||
write!(
|
||||
f,
|
||||
"Current: {value}, Possible Values: {possible:?}, Default: {default}",
|
||||
)
|
||||
}
|
||||
ControlValueDescription::RGB {
|
||||
value,
|
||||
max,
|
||||
default,
|
||||
} => {
|
||||
write!(
|
||||
f,
|
||||
"Current: ({}, {}, {}), Max: ({}, {}, {}), Default: ({}, {}, {})",
|
||||
value.0, value.1, value.2, max.0, max.1, max.2, default.0, default.1, default.2
|
||||
)
|
||||
}
|
||||
ControlValueDescription::StringList { value, availible } => {
|
||||
write!(f, "Current: {value}, Availible: {availible:?}")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// fn step_chk(val: i64, default: i64, step: i64) -> Result<(), NokhwaError> {
|
||||
// if (val - default) % step != 0 {
|
||||
// return Err(NokhwaError::StructureError {
|
||||
@@ -1086,245 +506,6 @@ impl Display for ControlValueDescription {
|
||||
// Ok(())
|
||||
// }
|
||||
|
||||
/// This struct tells you everything about a particular [`KnownCameraControl`].
|
||||
///
|
||||
/// However, you should never need to instantiate this struct, since its usually generated for you by `nokhwa`.
|
||||
/// The only time you should be modifying this struct is when you need to set a value and pass it back to the camera.
|
||||
/// NOTE: Assume the values for `min` and `max` as **non-inclusive**!.
|
||||
/// E.g. if the [`CameraControl`] says `min` is 100, the minimum is actually 101.
|
||||
#[derive(Clone, Debug, PartialOrd, PartialEq)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
|
||||
pub struct CameraControl {
|
||||
control: KnownCameraControl,
|
||||
name: String,
|
||||
description: ControlValueDescription,
|
||||
flag: Vec<KnownCameraControlFlag>,
|
||||
active: bool,
|
||||
}
|
||||
|
||||
impl CameraControl {
|
||||
/// Creates a new [`CameraControl`]
|
||||
#[must_use]
|
||||
pub fn new(
|
||||
control: KnownCameraControl,
|
||||
name: String,
|
||||
description: ControlValueDescription,
|
||||
flag: Vec<KnownCameraControlFlag>,
|
||||
active: bool,
|
||||
) -> Self {
|
||||
CameraControl {
|
||||
control,
|
||||
name,
|
||||
description,
|
||||
flag,
|
||||
active,
|
||||
}
|
||||
}
|
||||
|
||||
/// Gets the name of this [`CameraControl`]
|
||||
#[must_use]
|
||||
pub fn name(&self) -> &str {
|
||||
&self.name
|
||||
}
|
||||
|
||||
/// Gets the [`ControlValueDescription`] of this [`CameraControl`]
|
||||
#[must_use]
|
||||
pub fn description(&self) -> &ControlValueDescription {
|
||||
&self.description
|
||||
}
|
||||
|
||||
/// Gets the [`ControlValueSetter`] of the [`ControlValueDescription`] of this [`CameraControl`]
|
||||
#[must_use]
|
||||
pub fn value(&self) -> ControlValueSetter {
|
||||
self.description.value()
|
||||
}
|
||||
|
||||
/// Gets the [`KnownCameraControl`] of this [`CameraControl`]
|
||||
#[must_use]
|
||||
pub fn control(&self) -> KnownCameraControl {
|
||||
self.control
|
||||
}
|
||||
|
||||
/// Gets the [`KnownCameraControlFlag`] of this [`CameraControl`],
|
||||
/// telling you weather this control is automatically set or manually set.
|
||||
#[must_use]
|
||||
pub fn flag(&self) -> &[KnownCameraControlFlag] {
|
||||
&self.flag
|
||||
}
|
||||
|
||||
/// Gets `active` of this [`CameraControl`],
|
||||
/// telling you weather this control is currently active(in-use).
|
||||
#[must_use]
|
||||
pub fn active(&self) -> bool {
|
||||
self.active
|
||||
}
|
||||
|
||||
/// Gets `active` of this [`CameraControl`],
|
||||
/// telling you weather this control is currently active(in-use).
|
||||
pub fn set_active(&mut self, active: bool) {
|
||||
self.active = active;
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for CameraControl {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"Control: {}, Name: {}, Value: {}, Flag: {:?}, Active: {}",
|
||||
self.control, self.name, self.description, self.flag, self.active
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/// The setter for a control value
|
||||
#[derive(Clone, Debug, PartialEq, PartialOrd)]
|
||||
#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
|
||||
pub enum ControlValueSetter {
|
||||
None,
|
||||
Integer(i64),
|
||||
Float(f64),
|
||||
Boolean(bool),
|
||||
String(String),
|
||||
Bytes(Vec<u8>),
|
||||
KeyValue(i128, i128),
|
||||
Point(f64, f64),
|
||||
EnumValue(i64),
|
||||
RGB(f64, f64, f64),
|
||||
StringList(String),
|
||||
}
|
||||
|
||||
impl ControlValueSetter {
|
||||
#[must_use]
|
||||
pub fn as_none(&self) -> Option<()> {
|
||||
if let ControlValueSetter::None = self {
|
||||
Some(())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
#[must_use]
|
||||
|
||||
pub fn as_integer(&self) -> Option<&i64> {
|
||||
if let ControlValueSetter::Integer(i) = self {
|
||||
Some(i)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
#[must_use]
|
||||
|
||||
pub fn as_float(&self) -> Option<&f64> {
|
||||
if let ControlValueSetter::Float(f) = self {
|
||||
Some(f)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
#[must_use]
|
||||
|
||||
pub fn as_boolean(&self) -> Option<&bool> {
|
||||
if let ControlValueSetter::Boolean(f) = self {
|
||||
Some(f)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
#[must_use]
|
||||
|
||||
pub fn as_str(&self) -> Option<&str> {
|
||||
if let ControlValueSetter::String(s) = self {
|
||||
Some(s)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
#[must_use]
|
||||
|
||||
pub fn as_bytes(&self) -> Option<&[u8]> {
|
||||
if let ControlValueSetter::Bytes(b) = self {
|
||||
Some(b)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
#[must_use]
|
||||
|
||||
pub fn as_key_value(&self) -> Option<(&i128, &i128)> {
|
||||
if let ControlValueSetter::KeyValue(k, v) = self {
|
||||
Some((k, v))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
#[must_use]
|
||||
|
||||
pub fn as_point(&self) -> Option<(&f64, &f64)> {
|
||||
if let ControlValueSetter::Point(x, y) = self {
|
||||
Some((x, y))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
#[must_use]
|
||||
|
||||
pub fn as_enum(&self) -> Option<&i64> {
|
||||
if let ControlValueSetter::EnumValue(e) = self {
|
||||
Some(e)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
#[must_use]
|
||||
|
||||
pub fn as_rgb(&self) -> Option<(&f64, &f64, &f64)> {
|
||||
if let ControlValueSetter::RGB(r, g, b) = self {
|
||||
Some((r, g, b))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for ControlValueSetter {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
ControlValueSetter::None => {
|
||||
write!(f, "Value: None")
|
||||
}
|
||||
ControlValueSetter::Integer(i) => {
|
||||
write!(f, "IntegerValue: {i}")
|
||||
}
|
||||
ControlValueSetter::Float(d) => {
|
||||
write!(f, "FloatValue: {d}")
|
||||
}
|
||||
ControlValueSetter::Boolean(b) => {
|
||||
write!(f, "BoolValue: {b}")
|
||||
}
|
||||
ControlValueSetter::String(s) => {
|
||||
write!(f, "StrValue: {s}")
|
||||
}
|
||||
ControlValueSetter::Bytes(b) => {
|
||||
write!(f, "BytesValue: {b:x?}")
|
||||
}
|
||||
ControlValueSetter::KeyValue(k, v) => {
|
||||
write!(f, "KVValue: ({k}, {v})")
|
||||
}
|
||||
ControlValueSetter::Point(x, y) => {
|
||||
write!(f, "PointValue: ({x}, {y})")
|
||||
}
|
||||
ControlValueSetter::EnumValue(v) => {
|
||||
write!(f, "EnumValue: {v}")
|
||||
}
|
||||
ControlValueSetter::RGB(r, g, b) => {
|
||||
write!(f, "RGBValue: ({r}, {g}, {b})")
|
||||
}
|
||||
ControlValueSetter::StringList(s) => {
|
||||
write!(f, "StringListValue: {s}")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The list of known capture backends to the library. <br>
|
||||
/// - `Auto` - Use automatic selection.
|
||||
/// - `AVFoundation` - Uses `AVFoundation` on `MacOSX`
|
||||
|
||||
@@ -15,4 +15,24 @@ pub fn min_max_range<N: Copy + PartialOrd + AddAssign<N> + Sized>(min: N, max: N
|
||||
}
|
||||
|
||||
nums
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Default)]
|
||||
pub struct FailedMathOp;
|
||||
|
||||
pub(crate) trait FallibleDiv {
|
||||
type Output;
|
||||
|
||||
type Error: Default;
|
||||
|
||||
fn fallible_div(&self, other: &Self) -> Result<Self::Output, Self::Error>;
|
||||
}
|
||||
|
||||
pub(crate) trait FallibleSub {
|
||||
type Output;
|
||||
|
||||
type Error: Default;
|
||||
|
||||
fn fallible_sub(&self, other: &Self) -> Result<Self::Output, Self::Error>;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user