mirror of
https://github.com/l1npengtul/nokhwa.git
synced 2026-07-04 02:27:26 +00:00
v0.2.0 core
This commit is contained in:
Generated
-1
@@ -2518,7 +2518,6 @@ dependencies = [
|
||||
"num-rational 0.4.2",
|
||||
"num-traits",
|
||||
"opencv 0.93.1",
|
||||
"paste",
|
||||
"rgb",
|
||||
"serde",
|
||||
"thiserror 2.0.0",
|
||||
|
||||
@@ -23,7 +23,6 @@ test-fail-warnings = []
|
||||
[dependencies]
|
||||
thiserror = "2.0"
|
||||
bytes = "1.3"
|
||||
paste = "1.0"
|
||||
flume = "0.11"
|
||||
num-traits = "0.2"
|
||||
|
||||
|
||||
@@ -25,6 +25,7 @@ pub trait Setting {
|
||||
}
|
||||
|
||||
#[cfg(feature = "async")]
|
||||
#[cfg_attr(feature = "async", async_trait::async_trait)]
|
||||
pub trait AsyncSetting {
|
||||
async fn enumerate_formats_async(&self) -> Result<Vec<CameraFormat>, NokhwaError>;
|
||||
|
||||
@@ -53,6 +54,7 @@ pub trait Capture {
|
||||
}
|
||||
|
||||
#[cfg(feature = "async")]
|
||||
#[cfg_attr(feature = "async", async_trait::async_trait)]
|
||||
pub trait AsyncStream {
|
||||
async fn open_stream_async(&mut self) -> Result<Stream, NokhwaError>;
|
||||
|
||||
@@ -62,4 +64,5 @@ pub trait AsyncStream {
|
||||
pub trait Camera: Setting + Capture {}
|
||||
|
||||
#[cfg(feature = "async")]
|
||||
#[cfg_attr(feature = "async", async_trait::async_trait)]
|
||||
pub trait AsyncCamera: Camera + AsyncSetting + AsyncStream {}
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
use crate::{frame_format::FrameFormat, types::ApiBackend};
|
||||
use crate::{frame_format::FrameFormat};
|
||||
use std::fmt::{Debug};
|
||||
use thiserror::Error;
|
||||
use crate::platform::Backends;
|
||||
@@ -27,9 +27,9 @@ pub enum NokhwaError {
|
||||
#[error("Unitialized Camera. Call `init()` first!")]
|
||||
UnitializedError,
|
||||
#[error("Could not initialize {backend}: {error}")]
|
||||
InitializeError { backend: ApiBackend, error: String },
|
||||
InitializeError { backend: Backends, error: String },
|
||||
#[error("Could not shutdown {backend}: {error}")]
|
||||
ShutdownError { backend: ApiBackend, error: String },
|
||||
ShutdownError { backend: Backends, error: String },
|
||||
#[error("Error: {0}")]
|
||||
GeneralError(String),
|
||||
#[error("Could not generate required structure {structure}: {error}")]
|
||||
|
||||
@@ -4,139 +4,140 @@ use crate::{
|
||||
ranges::Range,
|
||||
types::{CameraFormat, FrameRate, Resolution},
|
||||
};
|
||||
use std::cmp::Ordering;
|
||||
use crate::ranges::ValidatableRange;
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialOrd, PartialEq)]
|
||||
enum ClosestType {
|
||||
Resolution,
|
||||
FrameRate,
|
||||
Both,
|
||||
None,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Hash, Ord, PartialOrd, Eq, PartialEq)]
|
||||
pub enum CustomFormatRequestType {
|
||||
HighestFrameRate,
|
||||
HighestResolution,
|
||||
Closest,
|
||||
Exact,
|
||||
}
|
||||
|
||||
/// A helper for choosing a [`CameraFormat`].
|
||||
/// The use of this is completely optional - for a simpler way try [`crate::camera::Camera::enumerate_formats`].
|
||||
///
|
||||
/// The `frame_format` field filters out the [`CameraFormat`]s by [`FrameFormat`].
|
||||
pub enum FormatRequest {
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub enum FormatRequestType {
|
||||
/// Pick the closest [`CameraFormat`] to the one requested
|
||||
Closest {
|
||||
resolution: Option<Range<Resolution>>,
|
||||
frame_rate: Option<Range<FrameRate>>,
|
||||
frame_format: Vec<FrameFormat>,
|
||||
},
|
||||
HighestFrameRate {
|
||||
frame_rate: Range<FrameRate>,
|
||||
frame_format: Vec<FrameFormat>,
|
||||
},
|
||||
HighestResolution {
|
||||
resolution: Range<Resolution>,
|
||||
frame_format: Vec<FrameFormat>,
|
||||
},
|
||||
Exact {
|
||||
resolution: Resolution,
|
||||
frame_rate: FrameRate,
|
||||
frame_format: Vec<FrameFormat>,
|
||||
},
|
||||
Any,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct FormatRequest {
|
||||
request_type: FormatRequestType,
|
||||
allowed_frame_formats: Vec<FrameFormat>,
|
||||
}
|
||||
|
||||
impl FormatRequest {
|
||||
pub fn sort_formats(&self, list_of_formats: &[CameraFormat]) -> Vec<CameraFormat> {
|
||||
if list_of_formats.is_empty() {
|
||||
return vec![];
|
||||
pub fn new(format_request_type: FormatRequestType, allowed_frame_formats: Vec<FrameFormat>) -> Self {
|
||||
Self {
|
||||
request_type: format_request_type,
|
||||
allowed_frame_formats,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn best<'a>(&self, camera_formats: &'a Vec<CameraFormat>) -> Option<&'a CameraFormat> {
|
||||
camera_formats.first()
|
||||
}
|
||||
|
||||
pub fn sort_foramts(&self, mut camera_formats: Vec<CameraFormat>) -> Vec<CameraFormat> {
|
||||
if camera_formats.is_empty() {
|
||||
return camera_formats;
|
||||
}
|
||||
|
||||
match self {
|
||||
FormatRequest::Closest {
|
||||
match self.request_type {
|
||||
FormatRequestType::Closest {
|
||||
resolution,
|
||||
frame_rate,
|
||||
frame_format,
|
||||
..
|
||||
} => {
|
||||
let resolution_point = resolution.map(|x| x.preferred());
|
||||
let frame_rate_point = frame_rate.map(|x| x.preferred());
|
||||
// lets calcuate distance in 3 dimensions (add both resolution and frame_rate together)
|
||||
|
||||
let mut distances = list_of_formats
|
||||
.iter()
|
||||
.filter(|x| frame_format.contains(&x.format()))
|
||||
.map(|fmt| {
|
||||
let frame_rate_distance = match frame_rate_point {
|
||||
Some(f_point) => (fmt.frame_rate() - f_point).approximate_float().unwrap_or(f32::INFINITY).abs(),
|
||||
None => 0_f32,
|
||||
};
|
||||
|
||||
let resolution_point_distance = match resolution_point {
|
||||
Some(res_pt) => fmt.resolution().distance_from(&res_pt) as f32,
|
||||
None => 0_f32,
|
||||
};
|
||||
|
||||
(frame_rate_distance + resolution_point_distance, fmt)
|
||||
})
|
||||
.collect::<Vec<(f32, &CameraFormat)>>();
|
||||
distances.sort_by(|a, b| a.0.partial_cmp(&b.0).unwrap_or(Ordering::Equal));
|
||||
distances.into_iter().map(|x| x.1).copied().collect()
|
||||
camera_formats.sort_by(|a, b| {
|
||||
let a_distance = format_distance_to_point(&resolution_point, &frame_rate_point, a);
|
||||
let b_distance = format_distance_to_point(&resolution_point, &frame_rate_point, b);
|
||||
|
||||
a_distance.total_cmp(&b_distance)
|
||||
});
|
||||
|
||||
camera_formats.into_iter().filter(|fmt| {
|
||||
self.allowed_frame_formats.contains(fmt.format())
|
||||
}).filter(|cam_fmt| {
|
||||
if let Some(res_range) = resolution {
|
||||
return res_range.validate(cam_fmt.resolution())
|
||||
}
|
||||
|
||||
if let Some(frame_rate_range) = frame_rate {
|
||||
return frame_rate_range.validate(&cam_fmt.frame_rate())
|
||||
}
|
||||
true
|
||||
}).collect()
|
||||
}
|
||||
FormatRequest::HighestFrameRate {
|
||||
frame_rate,
|
||||
frame_format,
|
||||
FormatRequestType::HighestFrameRate {
|
||||
frame_rate
|
||||
} => {
|
||||
let mut formats = list_of_formats
|
||||
.iter()
|
||||
.filter(|x| {
|
||||
frame_format.contains(&x.format()) && frame_rate.validate(&x.frame_rate()).is_ok()
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
formats.sort();
|
||||
formats.into_iter().copied().collect()
|
||||
camera_formats.sort_by(|a, b| {
|
||||
a.frame_rate().cmp(b.frame_rate())
|
||||
});
|
||||
|
||||
camera_formats.into_iter().filter(|fmt| {
|
||||
self.allowed_frame_formats.contains(fmt.format())
|
||||
}).filter(|a| {
|
||||
frame_rate.validate(a.frame_rate())
|
||||
}).collect()
|
||||
}
|
||||
FormatRequest::HighestResolution {
|
||||
resolution,
|
||||
frame_format,
|
||||
FormatRequestType::HighestResolution {
|
||||
resolution
|
||||
} => {
|
||||
let mut formats = list_of_formats
|
||||
.iter()
|
||||
.filter(|x| {
|
||||
frame_format.contains(&x.format()) && resolution.validate(&x.resolution()).is_ok()
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
formats.sort();
|
||||
formats.into_iter().copied().collect()
|
||||
camera_formats.sort_by(|a, b| {
|
||||
a.resolution().cmp(b.resolution())
|
||||
});
|
||||
|
||||
camera_formats.into_iter().filter(|fmt| {
|
||||
self.allowed_frame_formats.contains(fmt.format())
|
||||
}).filter(|a| {
|
||||
resolution.validate(a.resolution())
|
||||
}).collect()
|
||||
}
|
||||
FormatRequest::Exact {
|
||||
FormatRequestType::Exact {
|
||||
resolution,
|
||||
frame_rate,
|
||||
frame_format,
|
||||
} => {
|
||||
let mut formats = list_of_formats
|
||||
.iter()
|
||||
.filter(|x| {
|
||||
frame_format.contains(&x.format())
|
||||
&& resolution == &x.resolution()
|
||||
&& frame_rate == &x.frame_rate()
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
formats.sort();
|
||||
formats.into_iter().copied().collect()
|
||||
camera_formats.into_iter().filter(|fmt| {
|
||||
self.allowed_frame_formats.contains(fmt.format())
|
||||
}).filter(|a| {
|
||||
resolution.eq(a.resolution()) && frame_rate.eq(a.frame_rate())
|
||||
}).collect()
|
||||
}
|
||||
FormatRequestType::Any => {
|
||||
// return as-is
|
||||
camera_formats
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
#[must_use]
|
||||
pub fn resolve(&self, list_of_formats: &[CameraFormat]) -> Option<CameraFormat> {
|
||||
if list_of_formats.is_empty() {
|
||||
return None;
|
||||
}
|
||||
|
||||
Some(self.sort_formats(list_of_formats).remove(0))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn format_distance_to_point(resolution: &Option<Resolution>, frame_rate: &Option<FrameRate>, format: &CameraFormat) -> f32 {
|
||||
let frame_rate_distance = match frame_rate {
|
||||
Some(f_point) => (format.frame_rate() - f_point).approximate_float().unwrap_or(f32::INFINITY).abs(),
|
||||
None => 0_f32,
|
||||
};
|
||||
|
||||
let resolution_point_distance = match resolution {
|
||||
Some(res_pt) => format.resolution().distance_from(&res_pt) as f32,
|
||||
None => 0_f32,
|
||||
};
|
||||
|
||||
frame_rate_distance + resolution_point_distance
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#![allow(clippy::cast_sign_loss)]
|
||||
#![allow(clippy::cast_possible_truncation)]
|
||||
#![cfg_attr(feature = "test-fail-warning", deny(warnings))]
|
||||
#![cfg_attr(feature = "docs-features", feature(doc_cfg))]
|
||||
// #![cfg_attr(feature = "docs-features", feature(doc_cfg))]
|
||||
/*
|
||||
* Copyright 2022 l1npengtul <l1npengtul@protonmail.com> / The Nokhwa Contributors
|
||||
*
|
||||
@@ -29,10 +29,9 @@ pub mod format_request;
|
||||
pub mod frame_buffer;
|
||||
pub mod frame_format;
|
||||
pub mod properties;
|
||||
pub mod query;
|
||||
pub mod ranges;
|
||||
pub mod traits;
|
||||
pub mod types;
|
||||
pub mod utils;
|
||||
pub mod stream;
|
||||
mod platform;
|
||||
pub mod platform;
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
use std::fmt::{Display, Formatter};
|
||||
use crate::camera::{AsyncCamera, Camera};
|
||||
use crate::error::NokhwaResult;
|
||||
use crate::types::{CameraIndex, CameraInformation};
|
||||
@@ -8,9 +9,16 @@ pub enum Backends {
|
||||
WebWASM,
|
||||
AVFoundation,
|
||||
MicrosoftMediaFoundation,
|
||||
OpenCV,
|
||||
Custom(&'static str)
|
||||
}
|
||||
|
||||
impl Display for Backends {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{:?}", self)
|
||||
}
|
||||
}
|
||||
|
||||
pub trait PlatformTrait {
|
||||
const PLATFORM: Backends;
|
||||
type Camera: Camera;
|
||||
@@ -26,6 +34,7 @@ pub trait PlatformTrait {
|
||||
}
|
||||
|
||||
#[cfg(feature = "async")]
|
||||
#[cfg_attr(feature = "async", async_trait::async_trait)]
|
||||
pub trait AsyncPlatformTrait {
|
||||
const PLATFORM: Backends;
|
||||
type AsyncCamera: AsyncCamera;
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::fmt::{Display, Formatter};
|
||||
use std::ops::{ControlFlow};
|
||||
use crate::error::{NokhwaError, NokhwaResult};
|
||||
use crate::ranges::{Range, ValidatableRange};
|
||||
|
||||
@@ -122,7 +121,7 @@ impl ControlBody {
|
||||
}
|
||||
|
||||
pub fn set_value(&mut self, value: ControlValue) -> NokhwaResult<Option<ControlValue>> {
|
||||
if let ControlFlow::Break(()) = self.descriptor.validate(&value) {
|
||||
if self.descriptor.validate(&value) {
|
||||
return Err(NokhwaError::SetPropertyError {
|
||||
property: "Control Body".to_string(),
|
||||
value: value.to_string(),
|
||||
@@ -186,73 +185,68 @@ pub enum ControlValueDescriptor {
|
||||
}
|
||||
|
||||
impl ControlValueDescriptor {
|
||||
pub fn validate(&self, value: &ControlValue) -> ControlFlow<()> {
|
||||
pub fn validate(&self, value: &ControlValue) -> bool {
|
||||
match self {
|
||||
ControlValueDescriptor::Null => {
|
||||
if let &ControlValue::Null = value {
|
||||
return ControlFlow::Continue(())
|
||||
return false
|
||||
}
|
||||
}
|
||||
ControlValueDescriptor::Integer(int_range) => {
|
||||
if let ControlValue::Integer(i) = value {
|
||||
int_range.validate(i)?;
|
||||
return int_range.validate(i)
|
||||
}
|
||||
}
|
||||
ControlValueDescriptor::BitMask => {
|
||||
if let &ControlValue::BitMask(_) = value {
|
||||
return ControlFlow::Continue(())
|
||||
return true
|
||||
}
|
||||
}
|
||||
ControlValueDescriptor::Float(float_range) => {
|
||||
if let ControlValue::Float(i) = value {
|
||||
float_range.validate(i)?;
|
||||
return float_range.validate(i)
|
||||
}
|
||||
}
|
||||
ControlValueDescriptor::String => {
|
||||
if let &ControlValue::String(_) = value {
|
||||
return ControlFlow::Continue(())
|
||||
return true
|
||||
}
|
||||
}
|
||||
ControlValueDescriptor::Boolean => {
|
||||
if let &ControlValue::Boolean(_) = value {
|
||||
return ControlFlow::Continue(())
|
||||
return true
|
||||
}
|
||||
}
|
||||
ControlValueDescriptor::Array(arr) => {
|
||||
if arr.is_valid_value(value) {
|
||||
return ControlFlow::Continue(())
|
||||
if let &ControlValue::Array(_) = value {
|
||||
return arr.is_valid_value(value)
|
||||
}
|
||||
}
|
||||
ControlValueDescriptor::MultiChoice(choices) => {
|
||||
if let &ControlValue::Array(values) = value {
|
||||
if let ControlValue::Array(values) = value {
|
||||
for v in values {
|
||||
let mut contains = false;
|
||||
let vl: ControlValue = v.clone().into();
|
||||
for choice in choices {
|
||||
if choice.is_valid_value(v.as_ref()) {
|
||||
if choice.is_valid_value(&vl) {
|
||||
contains = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if !contains {
|
||||
return ControlFlow::Break(())
|
||||
}
|
||||
return contains
|
||||
}
|
||||
}
|
||||
}
|
||||
ControlValueDescriptor::Enum(choices) => {
|
||||
for choice in choices {
|
||||
if choice.is_valid_value(&value) {
|
||||
return ControlFlow::Continue(())
|
||||
}
|
||||
return choice.is_valid_value(&value)
|
||||
}
|
||||
}
|
||||
ControlValueDescriptor::Map(map) => {
|
||||
if let ControlValue::Map(setting_map) = &value {
|
||||
for (setting_key, setting_value) in setting_map {
|
||||
if let Some(descriptor) = map.get(setting_key) {
|
||||
if !descriptor.is_valid_value(setting_value.as_ref()) {
|
||||
return ControlFlow::Break(())
|
||||
}
|
||||
return !descriptor.is_valid_primitive_value(setting_value)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -260,15 +254,12 @@ impl ControlValueDescriptor {
|
||||
ControlValueDescriptor::Menu(menu) => {
|
||||
if let ControlValue::KeyValue(k, v) = &value {
|
||||
if let Some(descriptor) = menu.get(k) {
|
||||
if descriptor.is_valid_value(v.as_ref()) {
|
||||
return ControlFlow::Continue(())
|
||||
}
|
||||
return descriptor.is_valid_primitive_value(v)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ControlFlow::Break(())
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -283,35 +274,71 @@ pub enum ControlValuePrimitiveDescriptor {
|
||||
}
|
||||
|
||||
impl ControlValuePrimitiveDescriptor {
|
||||
pub fn is_valid_value(&self, other: &ControlValue) -> bool {
|
||||
pub fn is_valid_primitive_value(&self, other: &ControlValuePrimitive) -> bool {
|
||||
match self {
|
||||
ControlValuePrimitiveDescriptor::Null => {
|
||||
if let &ControlValue::Null = other {
|
||||
if let ControlValuePrimitive::Null = other {
|
||||
return true
|
||||
}
|
||||
}
|
||||
ControlValuePrimitiveDescriptor::Integer(int_range) => {
|
||||
if let ControlValue::Integer(i) = other {
|
||||
return int_range.validate(i).is_ok()
|
||||
ControlValuePrimitiveDescriptor::Integer(i) => {
|
||||
if let ControlValuePrimitive::Integer(v) = other {
|
||||
return i.validate(v)
|
||||
}
|
||||
}
|
||||
ControlValuePrimitiveDescriptor::BitMask => {
|
||||
if let &ControlValue::BitMask(_) = other {
|
||||
if let ControlValuePrimitive::BitMask(_) = other {
|
||||
return true
|
||||
}
|
||||
}
|
||||
ControlValuePrimitiveDescriptor::Float(float_range) => {
|
||||
if let ControlValue::Float(i) = other {
|
||||
return float_range.validate(i).is_ok()
|
||||
ControlValuePrimitiveDescriptor::Float(f) => {
|
||||
if let ControlValuePrimitive::Float(v) = other {
|
||||
return f.validate(v)
|
||||
}
|
||||
}
|
||||
ControlValuePrimitiveDescriptor::String => {
|
||||
if let &ControlValue::String(_) = other {
|
||||
if let ControlValuePrimitive::String(_) = other {
|
||||
return true
|
||||
}
|
||||
}
|
||||
ControlValuePrimitiveDescriptor::Boolean => {
|
||||
if let &ControlValue::Boolean(_) = other {
|
||||
if let ControlValuePrimitive::Boolean(_) = other {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
pub fn is_valid_value(&self, other: &ControlValue) -> bool {
|
||||
match self {
|
||||
ControlValuePrimitiveDescriptor::Null => {
|
||||
if let ControlValue::Null = other {
|
||||
return true
|
||||
}
|
||||
}
|
||||
ControlValuePrimitiveDescriptor::Integer(i) => {
|
||||
if let ControlValue::Integer(v) = other {
|
||||
return i.validate(v)
|
||||
}
|
||||
}
|
||||
ControlValuePrimitiveDescriptor::BitMask => {
|
||||
if let ControlValue::BitMask(_) = other {
|
||||
return true
|
||||
}
|
||||
}
|
||||
ControlValuePrimitiveDescriptor::Float(f) => {
|
||||
if let ControlValue::Float(v) = other {
|
||||
return f.validate(v)
|
||||
}
|
||||
}
|
||||
ControlValuePrimitiveDescriptor::String => {
|
||||
if let ControlValue::String(_) = other {
|
||||
return true
|
||||
}
|
||||
}
|
||||
ControlValuePrimitiveDescriptor::Boolean => {
|
||||
if let ControlValue::Boolean(_) = other {
|
||||
return true
|
||||
}
|
||||
}
|
||||
@@ -330,15 +357,15 @@ pub enum ControlValuePrimitive {
|
||||
Boolean(bool),
|
||||
}
|
||||
|
||||
impl AsRef<ControlValue> for ControlValuePrimitive {
|
||||
fn as_ref(&self) -> &ControlValue {
|
||||
match self {
|
||||
ControlValuePrimitive::Null => &ControlValue::Null,
|
||||
ControlValuePrimitive::Integer(i) => &ControlValue::Integer(*i),
|
||||
ControlValuePrimitive::BitMask(b) => &ControlValue::BitMask(*b),
|
||||
ControlValuePrimitive::Float(f) => &ControlValue::Float(*f),
|
||||
ControlValuePrimitive::String(s) => &ControlValue::String(s.clone()),
|
||||
ControlValuePrimitive::Boolean(b) => &ControlValue::Boolean(*b),
|
||||
impl From<ControlValuePrimitive> for ControlValue {
|
||||
fn from(value: ControlValuePrimitive) -> Self {
|
||||
match value {
|
||||
ControlValuePrimitive::Null => ControlValue::Null,
|
||||
ControlValuePrimitive::Integer(i) => ControlValue::Integer(i),
|
||||
ControlValuePrimitive::BitMask(b) => ControlValue::BitMask(b),
|
||||
ControlValuePrimitive::Float(f) => ControlValue::Float(f),
|
||||
ControlValuePrimitive::String(s) => ControlValue::String(s),
|
||||
ControlValuePrimitive::Boolean(b) => ControlValue::Boolean(b),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -357,6 +384,22 @@ pub enum ControlValue {
|
||||
}
|
||||
|
||||
impl ControlValue {
|
||||
pub fn primitive_same_type(&self, other: &ControlValuePrimitive) -> bool {
|
||||
match other {
|
||||
ControlValuePrimitive::Null => {
|
||||
if let ControlValue::Null = self {
|
||||
return true
|
||||
}
|
||||
}
|
||||
ControlValuePrimitive::Integer(_) => {if let ControlValue::Integer(_) = self {return true}}
|
||||
ControlValuePrimitive::BitMask(_) => {if let ControlValue::BitMask(_) = self {return true}}
|
||||
ControlValuePrimitive::Float(_) => {if let ControlValue::Float(_) = self {return true}}
|
||||
ControlValuePrimitive::String(_) => {if let ControlValue::String(_) = self {return true}}
|
||||
ControlValuePrimitive::Boolean(_) => {if let ControlValue::Boolean(_) = self {return true}}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
pub fn same_type(&self, other: &ControlValue) -> bool {
|
||||
match self {
|
||||
ControlValue::Null => {
|
||||
@@ -392,6 +435,8 @@ impl ControlValue {
|
||||
|
||||
false
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
impl Display for ControlValue {
|
||||
@@ -399,16 +444,3 @@ impl Display for ControlValue {
|
||||
write!(f, "Control Value: {self:?}")
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ControlValuePrimitive> for ControlValue {
|
||||
fn from(value: ControlValuePrimitive) -> Self {
|
||||
match value {
|
||||
ControlValuePrimitive::Null => ControlValue::Null,
|
||||
ControlValuePrimitive::Integer(i) => ControlValue::Integer(i),
|
||||
ControlValuePrimitive::BitMask(b) => ControlValue::BitMask(b),
|
||||
ControlValuePrimitive::Float(f) => ControlValue::Float(f),
|
||||
ControlValuePrimitive::String(s) => ControlValue::String(s),
|
||||
ControlValuePrimitive::Boolean(b) => ControlValue::Boolean(b),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+14
-20
@@ -15,7 +15,7 @@ pub trait ValidatableRange {
|
||||
type Validation;
|
||||
|
||||
/// Validates the value.
|
||||
fn validate(&self, value: &Self::Validation) -> Result<(), RangeValidationFailure>;
|
||||
fn validate(&self, value: &Self::Validation) -> bool;
|
||||
}
|
||||
|
||||
/// Creates a range of values.
|
||||
@@ -117,7 +117,7 @@ where
|
||||
{
|
||||
type Validation = T;
|
||||
|
||||
fn validate(&self, value: &T) -> Result<(), RangeValidationFailure> {
|
||||
fn validate(&self, value: &T) -> bool {
|
||||
num_range_validate(
|
||||
self.minimum,
|
||||
self.maximum,
|
||||
@@ -195,11 +195,8 @@ where
|
||||
{
|
||||
type Validation = T;
|
||||
|
||||
fn validate(&self, value: &Self::Validation) -> Result<(), RangeValidationFailure> {
|
||||
if self.available.contains(value) {
|
||||
return Ok(());
|
||||
}
|
||||
Err(RangeValidationFailure::default())
|
||||
fn validate(&self, value: &Self::Validation) -> bool {
|
||||
self.available.contains(value)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -294,11 +291,8 @@ where
|
||||
{
|
||||
type Validation = T;
|
||||
|
||||
fn validate(&self, value: &Self::Validation) -> Result<(), RangeValidationFailure> {
|
||||
if self.appendable_options.contains(value) {
|
||||
return Ok(());
|
||||
}
|
||||
Err(RangeValidationFailure::default())
|
||||
fn validate(&self, value: &Self::Validation) -> bool {
|
||||
self.appendable_options.contains(value)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -336,8 +330,8 @@ where
|
||||
impl<T> ValidatableRange for Simple<T> {
|
||||
type Validation = T;
|
||||
|
||||
fn validate(&self, _: &Self::Validation) -> Result<(), RangeValidationFailure> {
|
||||
Ok(())
|
||||
fn validate(&self, _: &Self::Validation) -> bool {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
@@ -390,7 +384,7 @@ fn num_range_validate<T>(
|
||||
upper_inclusive: bool,
|
||||
step: Option<T>,
|
||||
value: T,
|
||||
) -> Result<(), RangeValidationFailure>
|
||||
) -> bool
|
||||
where
|
||||
T: SimpleRangeItem,
|
||||
{
|
||||
@@ -403,12 +397,12 @@ where
|
||||
// 7 - 4 = 3
|
||||
// 3 % 3 = 0 Valid!
|
||||
if prepared_value % step != T::ZERO {
|
||||
return Err(RangeValidationFailure::default());
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
if value == default {
|
||||
return Ok(());
|
||||
return true
|
||||
}
|
||||
|
||||
if let Some(min) = minimum {
|
||||
@@ -418,7 +412,7 @@ where
|
||||
min < value
|
||||
};
|
||||
if test {
|
||||
return Err(RangeValidationFailure::default());
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -429,11 +423,11 @@ where
|
||||
max > value
|
||||
};
|
||||
if test {
|
||||
return Err(RangeValidationFailure::default());
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
true
|
||||
}
|
||||
|
||||
pub trait SimpleRangeItem: Copy + Clone + Debug + Div<Output = Self> + Sub<Output = Self> + Rem<Output = Self> + PartialOrd + PartialEq {
|
||||
|
||||
@@ -289,6 +289,14 @@ impl Sub for FrameRate {
|
||||
}
|
||||
}
|
||||
|
||||
impl Sub for &FrameRate {
|
||||
type Output = FrameRate;
|
||||
|
||||
fn sub(self, rhs: Self) -> Self::Output {
|
||||
(self.rational - rhs.rational).into()
|
||||
}
|
||||
}
|
||||
|
||||
impl Rem for FrameRate {
|
||||
type Output = FrameRate;
|
||||
|
||||
@@ -345,8 +353,8 @@ impl CameraFormat {
|
||||
|
||||
/// Get the resolution of the current [`CameraFormat`]
|
||||
#[must_use]
|
||||
pub fn resolution(&self) -> Resolution {
|
||||
self.resolution
|
||||
pub fn resolution(&self) -> &Resolution {
|
||||
&self.resolution
|
||||
}
|
||||
|
||||
/// Get the width of the resolution of the current [`CameraFormat`]
|
||||
@@ -368,8 +376,8 @@ impl CameraFormat {
|
||||
|
||||
/// Get the frame rate of the current [`CameraFormat`]
|
||||
#[must_use]
|
||||
pub fn frame_rate(&self) -> FrameRate {
|
||||
self.frame_rate
|
||||
pub fn frame_rate(&self) -> &FrameRate {
|
||||
&self.frame_rate
|
||||
}
|
||||
|
||||
/// Set the [`CameraFormat`]'s frame rate.
|
||||
@@ -379,8 +387,8 @@ impl CameraFormat {
|
||||
|
||||
/// Get the [`CameraFormat`]'s format.
|
||||
#[must_use]
|
||||
pub fn format(&self) -> FrameFormat {
|
||||
self.format
|
||||
pub fn format(&self) -> &FrameFormat {
|
||||
&self.format
|
||||
}
|
||||
|
||||
/// Set the [`CameraFormat`]'s format.
|
||||
|
||||
Reference in New Issue
Block a user