ergonomic changes to trait

This commit is contained in:
l1npengtul
2025-02-08 12:32:55 +09:00
parent ec30a63f66
commit 334fd27b0f
3 changed files with 235 additions and 204 deletions
+17 -11
View File
@@ -1,9 +1,10 @@
use crate::error::{NokhwaError}; use crate::control::{ControlDescription, ControlId, ControlValue, Controls};
use crate::error::NokhwaError;
use crate::frame_format::FrameFormat; use crate::frame_format::FrameFormat;
use crate::control::{ControlId, ControlValue, Controls};
use crate::types::{CameraFormat, FrameRate, Resolution};
use std::collections::HashMap;
use crate::stream::Stream; use crate::stream::Stream;
use crate::types::{CameraFormat, FrameRate, Resolution};
use std::collections::hash_map::{Keys, Values};
use std::collections::HashMap;
pub trait Setting { pub trait Setting {
fn enumerate_formats(&self) -> Result<Vec<CameraFormat>, NokhwaError>; fn enumerate_formats(&self) -> Result<Vec<CameraFormat>, NokhwaError>;
@@ -15,15 +16,20 @@ pub trait Setting {
fn set_format(&self, camera_format: CameraFormat) -> Result<(), NokhwaError>; fn set_format(&self, camera_format: CameraFormat) -> Result<(), NokhwaError>;
fn controls(&self) -> &Controls; fn control_ids(&self) -> Keys<ControlId, ControlDescription>;
fn control_descriptions(&self) -> Values<ControlId, ControlDescription>;
fn control_values(&self) -> Values<ControlId, ControlValue>;
fn control_value(&self, id: &ControlId) -> Option<&ControlValue>;
fn control_description(&self, id: &ControlId) -> Option<&ControlDescription>;
fn set_control(&mut self, property: &ControlId, value: ControlValue)
-> Result<(), NokhwaError>;
fn refresh_controls(&mut self) -> Result<(), NokhwaError>; fn refresh_controls(&mut self) -> Result<(), NokhwaError>;
fn set_control(
&mut self,
property: &ControlId,
value: ControlValue,
) -> Result<(), NokhwaError>;
} }
#[cfg(feature = "async")] #[cfg(feature = "async")]
+212 -184
View File
@@ -1,9 +1,10 @@
use crate::error::{NokhwaError, NokhwaResult};
use crate::ranges::{Range, ValidatableRange};
use ordered_float::OrderedFloat;
use std::collections::hash_map::{Keys, Values};
use std::collections::{HashMap, HashSet}; use std::collections::{HashMap, HashSet};
use std::fmt::{Display, Formatter}; use std::fmt::{Display, Formatter};
use std::hash::{Hash, Hasher}; use std::hash::{Hash, Hasher};
use ordered_float::OrderedFloat;
use crate::error::{NokhwaError, NokhwaResult};
use crate::ranges::{Range, ValidatableRange};
pub type PlatformSpecificControlId = u64; pub type PlatformSpecificControlId = u64;
@@ -42,7 +43,7 @@ pub enum ControlId {
Orientation, Orientation,
PlatformSpecific(PlatformSpecificControlId) PlatformSpecific(PlatformSpecificControlId),
} }
impl Display for ControlId { impl Display for ControlId {
@@ -53,49 +54,125 @@ impl Display for ControlId {
#[derive(Clone, Debug, Default, PartialEq)] #[derive(Clone, Debug, Default, PartialEq)]
pub struct Controls { pub struct Controls {
controls: HashMap<ControlId, ControlBody>, descriptions: HashMap<ControlId, ControlDescription>,
values: HashMap<ControlId, ControlId>, values: HashMap<ControlId, ControlValue>,
} }
impl Controls { impl Controls {
pub fn new(device_controls: HashMap<ControlId, ControlBody>) -> Self { /// INVARIANTS: All `ControlId` in `device_values` MUST exist in `device_controls`
Self { pub fn new(
controls: device_controls, device_controls: HashMap<ControlId, ControlDescription>,
device_values: HashMap<ControlId, ControlValue>,
) -> Option<Self> {
for (id, value) in device_values.iter() {
if let Some(description) = device_controls.get(id) {
if !description.validate(value) {
return None;
}
}
} }
Some(Self {
descriptions: device_controls,
values: device_values,
})
} }
pub fn empty() -> Self { pub fn empty() -> Self {
Self::default() Self::default()
} }
pub fn control_value(&self, control_id: &ControlId) -> Option<&ControlBody> { pub fn unchecked_new(
self.controls.get(control_id) device_controls: HashMap<ControlId, ControlDescription>,
device_values: HashMap<ControlId, ControlValue>,
) -> Self {
Self {
descriptions: device_controls,
values: device_values,
}
} }
pub fn set_control_value(&mut self, control_id: &ControlId, value: ControlValue) -> NokhwaResult<()> { pub fn description(&self, control_id: &ControlId) -> Option<&ControlDescription> {
self.descriptions.get(control_id)
}
pub fn value(&self, control_id: &ControlId) -> Option<&ControlValue> {
self.values.get(control_id)
}
pub fn descriptions(&self) -> Values<ControlId, ControlDescription> {
self.descriptions.values()
}
pub fn values(&self) -> Values<ControlId, ControlValue> {
self.values.values()
}
pub fn ids(&self) -> Keys<ControlId, ControlDescription> {
self.descriptions.keys()
}
pub fn set_control_value(
&mut self,
control_id: &ControlId,
value: ControlValue,
) -> NokhwaResult<()> {
// see if it exists // see if it exists
if let Some(control) = self.controls.get_mut(control_id) { if let None = self.descriptions.get(control_id) {
// FIXME: Remove this clone one day! return Err(NokhwaError::SetPropertyError {
control.set_value(value.clone())?; property: control_id.to_string(),
value: value.to_string(),
error: "ID Not Found".to_string(),
});
}
match self.values.get_mut(control_id) {
Some(old) => {
*old = value;
Ok(())
}
// this should not happen,
None => Err(NokhwaError::SetPropertyError {
property: control_id.to_string(),
value: value.to_string(),
error: "If you got this, its probably a bug or your camera is _horribly_ bugged :>"
.to_string(),
}),
} }
Err(NokhwaError::SetPropertyError {
property: control_id.to_string(),
value: value.to_string(),
error: "Not Found/Not Supported".to_string(),
})
} }
} }
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub struct ControlBody { pub struct ControlDescription {
flags: HashSet<ControlFlags>, flags: HashSet<ControlFlags>,
descriptor: ControlValueDescriptor, descriptor: ControlValueDescriptor,
default_value: Option<ControlValue>, default_value: Option<ControlValue>,
} }
impl ControlBody { impl ControlDescription {
pub fn new(control_flags: HashSet<ControlFlags>, control_value_descriptor: ControlValueDescriptor, default_value: Option<ControlValue>) -> Self { pub fn new(
control_flags: HashSet<ControlFlags>,
control_value_descriptor: ControlValueDescriptor,
default_value: Option<ControlValue>,
) -> Option<Self> {
if let Some(default) = &default_value {
if !control_value_descriptor.validate(default) {
return None;
}
}
Some(Self {
flags: control_flags,
descriptor: control_value_descriptor,
default_value,
})
}
pub fn new_unchecked(
control_flags: HashSet<ControlFlags>,
control_value_descriptor: ControlValueDescriptor,
default_value: Option<ControlValue>,
) -> Self {
Self { Self {
flags: control_flags, flags: control_flags,
descriptor: control_value_descriptor, descriptor: control_value_descriptor,
@@ -122,6 +199,10 @@ impl ControlBody {
pub fn remove_flag(&mut self, flag: ControlFlags) -> bool { pub fn remove_flag(&mut self, flag: ControlFlags) -> bool {
self.flags.remove(&flag) self.flags.remove(&flag)
} }
pub fn validate(&self, value: &ControlValue) -> bool {
self.descriptor.validate(value)
}
} }
#[derive(Copy, Clone, Debug, Hash, Ord, PartialOrd, Eq, PartialEq)] #[derive(Copy, Clone, Debug, Hash, Ord, PartialOrd, Eq, PartialEq)]
@@ -160,6 +241,10 @@ pub enum ControlValueDescriptor {
width_limits: Range<i64>, width_limits: Range<i64>,
height_limits: Range<i64>, height_limits: Range<i64>,
}, },
// An Orientation
// Usually, this is a read-only value.
// An empty vec indicates any allowed value.
Orientation(Vec<Orientation>),
} }
impl ControlValueDescriptor { impl ControlValueDescriptor {
@@ -167,166 +252,66 @@ impl ControlValueDescriptor {
match self { match self {
ControlValueDescriptor::Null => { ControlValueDescriptor::Null => {
if let &ControlValue::Null = value { if let &ControlValue::Null = value {
return false return false;
} }
} }
ControlValueDescriptor::Integer(int_range) => { ControlValueDescriptor::Integer(int_range) => {
if let ControlValue::Integer(i) = value { if let ControlValue::Integer(i) = value {
return int_range.validate(i) return int_range.validate(i);
} }
} }
ControlValueDescriptor::BitMask => { ControlValueDescriptor::BitMask => {
if let &ControlValue::BitMask(_) = value { if let &ControlValue::BitMask(_) = value {
return true return true;
} }
} }
ControlValueDescriptor::Float(float_range) => { ControlValueDescriptor::Float(float_range) => {
if let ControlValue::Float(i) = value { if let ControlValue::Float(i) = value {
return float_range.validate(i) return float_range.validate(i);
} }
} }
ControlValueDescriptor::String => { ControlValueDescriptor::String => {
if let &ControlValue::String(_) = value { if let &ControlValue::String(_) = value {
return true return true;
} }
} }
ControlValueDescriptor::Boolean => { ControlValueDescriptor::Boolean => {
if let &ControlValue::Boolean(_) = value { if let &ControlValue::Boolean(_) = value {
return true return true;
} }
} }
ControlValueDescriptor::Array(arr) => { ControlValueDescriptor::Array(arr) => {
if let &ControlValue::Array(_) = value { if let &ControlValue::Array(_) = value {
return arr.is_valid_value(value) return arr.is_valid_value(value);
} }
} }
ControlValueDescriptor::Binary(size_limits) => { ControlValueDescriptor::Binary(size_limits) => {
if let ControlValue::Binary(bin) = value { if let ControlValue::Binary(bin) = value {
return size_limits.validate(bin.len() as u64) return size_limits.validate(bin.len() as u64);
} }
} }
ControlValueDescriptor::Menu(choices) => { ControlValueDescriptor::Menu(choices) => {
if let ControlValue::EnumPick(choice) = value { if let ControlValue::EnumPick(choice) = value {
return choices.contains_key(choice) return choices.contains_key(choice);
} }
} }
ControlValueDescriptor::Area { width_limits, height_limits } => { ControlValueDescriptor::Area {
width_limits,
height_limits,
} => {
if let ControlValue::Area { width, height } = &value { if let ControlValue::Area { width, height } = &value {
return width_limits.validate(width) && height_limits.validate(height) return width_limits.validate(width) && height_limits.validate(height);
}
}
ControlValueDescriptor::Orientation(orientations) => {
if let ControlValue::Orientation(orientation) = &value {
return orientations.contains(orientation) || orientations.is_empty();
} }
} }
} }
false false
} }
} }
//
// #[derive(Clone, Debug, PartialEq)]
// pub enum ControlValuePrimitiveDescriptor {
// Null,
// Integer(Range<i64>),
// BitMask,
// Float(Range<f64>),
// String,
// Binary,
// Boolean,
// }
//
// impl ControlValuePrimitiveDescriptor {
// pub fn is_valid_primitive_value(&self, other: &ControlValuePrimitive) -> bool {
// match self {
// ControlValuePrimitiveDescriptor::Null => {
// if let ControlValuePrimitive::Null = other {
// return true
// }
// }
// ControlValuePrimitiveDescriptor::Integer(i) => {
// if let ControlValuePrimitive::Integer(v) = other {
// return i.validate(v)
// }
// }
// ControlValuePrimitiveDescriptor::BitMask => {
// if let ControlValuePrimitive::BitMask(_) = other {
// return true
// }
// }
// ControlValuePrimitiveDescriptor::Float(f) => {
// if let ControlValuePrimitive::Float(v) = other {
// return f.validate(v)
// }
// }
// ControlValuePrimitiveDescriptor::String => {
// if let ControlValuePrimitive::String(_) = other {
// return true
// }
// }
// ControlValuePrimitiveDescriptor::Boolean => {
// 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
// }
// }
// }
// false
// }
// }
//
// #[derive(Clone, Debug, Hash, Ord, PartialOrd, Eq, PartialEq)]
// pub enum ControlValuePrimitive {
// Null,
// Integer(i64),
// BitMask(i64),
// Float(OrderedFloat<f64>),
// String(String),
// Boolean(bool),
// }
//
// 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),
// }
// }
// }
#[derive(Clone, Debug, Hash, Eq, PartialEq, PartialOrd)] #[derive(Clone, Debug, Hash, Eq, PartialEq, PartialOrd)]
pub enum ControlValue { pub enum ControlValue {
@@ -339,23 +324,22 @@ pub enum ControlValue {
Array(Vec<ControlValue>), Array(Vec<ControlValue>),
Binary(Vec<u8>), Binary(Vec<u8>),
EnumPick(Box<ControlValue>), EnumPick(Box<ControlValue>),
Area { Area { width: i64, height: i64 },
width: i64, Orientation(Orientation),
height: i64,
}
} }
impl ControlValue { impl ControlValue {
pub fn is_primitive(&self) -> bool { pub fn is_primitive(&self) -> bool {
match self { match self {
ControlValue::Null | ControlValue::Null
ControlValue::Integer(_) | | ControlValue::Integer(_)
ControlValue::BitMask(_) | | ControlValue::BitMask(_)
ControlValue::Float(_) | | ControlValue::Float(_)
ControlValue::String(_)| | ControlValue::String(_)
ControlValue::Boolean(_) | | ControlValue::Boolean(_)
ControlValue::Binary(_) | | ControlValue::Binary(_)
ControlValue::Area { .. } => true, | ControlValue::Area { .. }
| ControlValue::Orientation(_) => true,
_ => false, _ => false,
} }
} }
@@ -383,39 +367,61 @@ impl ControlValue {
return true; return true;
} }
} }
ControlValue::Integer(_) => {if let ControlValue::Integer(_) = other { ControlValue::Integer(_) => {
return true; if let ControlValue::Integer(_) = other {
}} return true;
ControlValue::BitMask(_) => {if let ControlValue::BitMask(_) = other { }
return true; }
}} ControlValue::BitMask(_) => {
ControlValue::Float(_) => {if let ControlValue::Float(_) = other { if let ControlValue::BitMask(_) = other {
return true; return true;
}} }
ControlValue::String(_) => {if let ControlValue::String(_) = other { }
return true; ControlValue::Float(_) => {
}} if let ControlValue::Float(_) = other {
ControlValue::Boolean(_) => {if let ControlValue::Boolean(_) = other { return true;
return true; }
}} }
ControlValue::Array(_) => {if let ControlValue::Array(_) = other { ControlValue::String(_) => {
return true; if let ControlValue::String(_) = other {
}} return true;
ControlValue::EnumPick(_) => {if let ControlValue::EnumPick(_) = other { }
return true; }
}} ControlValue::Boolean(_) => {
ControlValue::Binary(_) => {if let ControlValue::Binary(_) = other { if let ControlValue::Boolean(_) = other {
return true; return true;
}} }
ControlValue::Area { .. } => {if let ControlValue::Area { .. } = other { }
return true; ControlValue::Array(_) => {
}} if let ControlValue::Array(_) = other {
return true;
}
}
ControlValue::EnumPick(_) => {
if let ControlValue::EnumPick(_) = other {
return true;
}
}
ControlValue::Binary(_) => {
if let ControlValue::Binary(_) = other {
return true;
}
}
ControlValue::Area { .. } => {
if let ControlValue::Area { .. } = other {
return true;
}
}
ControlValue::Orientation(_) => {
if let ControlValue::Orientation(_) = other {
return true;
}
}
_ => return false,
} }
false false
} }
} }
impl Display for ControlValue { impl Display for ControlValue {
@@ -423,3 +429,25 @@ impl Display for ControlValue {
write!(f, "Control Value: {self:?}") write!(f, "Control Value: {self:?}")
} }
} }
#[derive(Copy, Clone, Debug, Hash, Ord, PartialOrd, Eq, PartialEq)]
#[non_exhaustive]
pub enum Orientation {
User,
Environment,
Up,
Down,
Left,
Right,
Center,
Near,
Far,
Other,
Custom(i64),
}
impl Display for Orientation {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "Orientation {self:?}")
}
}
+6 -9
View File
@@ -1,7 +1,7 @@
use std::fmt::{Display, Formatter};
use crate::camera::{AsyncCamera, Camera}; use crate::camera::{AsyncCamera, Camera};
use crate::error::NokhwaResult; use crate::error::NokhwaResult;
use crate::types::{CameraIndex, CameraInformation}; use crate::types::{CameraIndex, CameraInformation};
use std::fmt::{Display, Formatter};
#[derive(Copy, Clone, Debug, Ord, PartialOrd, Eq, PartialEq)] #[derive(Copy, Clone, Debug, Ord, PartialOrd, Eq, PartialEq)]
pub enum Backends { pub enum Backends {
@@ -10,7 +10,7 @@ pub enum Backends {
AVFoundation, AVFoundation,
MicrosoftMediaFoundation, MicrosoftMediaFoundation,
OpenCV, OpenCV,
Custom(&'static str) Custom(&'static str),
} }
impl Display for Backends { impl Display for Backends {
@@ -23,16 +23,15 @@ pub trait PlatformTrait {
const PLATFORM: Backends; const PLATFORM: Backends;
type Camera: Camera; type Camera: Camera;
fn block_on_permission(&mut self) -> NokhwaResult<()>; fn block_on_permission(&mut self) -> NokhwaResult<()>;
fn check_permission_given(&mut self) -> bool; fn check_permission_given(&mut self) -> bool;
fn query(&mut self) -> NokhwaResult<Vec<CameraInformation>>; fn query(&mut self) -> NokhwaResult<Vec<CameraInformation>>;
fn open(&mut self, index: &CameraIndex) -> NokhwaResult<Self::Camera>; fn open(&mut self, index: CameraIndex) -> NokhwaResult<Self::Camera>;
fn open_dynamic(&mut self, index: &CameraIndex) -> NokhwaResult<Box<dyn Camera>> { fn open_dynamic(&mut self, index: CameraIndex) -> NokhwaResult<Box<dyn Camera>> {
self.open(index).map(|cam| Box::new(cam)) self.open(index).map(|cam| Box::new(cam))
} }
} }
@@ -43,15 +42,13 @@ pub trait AsyncPlatformTrait {
const PLATFORM: Backends; const PLATFORM: Backends;
type AsyncCamera: AsyncCamera; type AsyncCamera: AsyncCamera;
async fn await_permission(&mut self) -> NokhwaResult<()>; async fn await_permission(&mut self) -> NokhwaResult<()>;
async fn query_async(&mut self) -> NokhwaResult<Vec<CameraInformation>>; async fn query_async(&mut self) -> NokhwaResult<Vec<CameraInformation>>;
async fn open_async (&mut self, index: &CameraIndex) -> NokhwaResult<Self::AsyncCamera>; async fn open_async(&mut self, index: &CameraIndex) -> NokhwaResult<Self::AsyncCamera>;
async fn open_dynamic_async(&mut self, index: &CameraIndex) -> NokhwaResult<Box<dyn Camera>> { async fn open_dynamic_async(&mut self, index: &CameraIndex) -> NokhwaResult<Box<dyn Camera>> {
self.open_async(index).await.map(|cam| Box::new(cam)) self.open_async(index).await.map(|cam| Box::new(cam))
} }
} }