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::control::{ControlId, ControlValue, Controls};
use crate::types::{CameraFormat, FrameRate, Resolution};
use std::collections::HashMap;
use crate::stream::Stream;
use crate::types::{CameraFormat, FrameRate, Resolution};
use std::collections::hash_map::{Keys, Values};
use std::collections::HashMap;
pub trait Setting {
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 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 set_control(
&mut self,
property: &ControlId,
value: ControlValue,
) -> Result<(), NokhwaError>;
}
#[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::fmt::{Display, Formatter};
use std::hash::{Hash, Hasher};
use ordered_float::OrderedFloat;
use crate::error::{NokhwaError, NokhwaResult};
use crate::ranges::{Range, ValidatableRange};
pub type PlatformSpecificControlId = u64;
@@ -42,7 +43,7 @@ pub enum ControlId {
Orientation,
PlatformSpecific(PlatformSpecificControlId)
PlatformSpecific(PlatformSpecificControlId),
}
impl Display for ControlId {
@@ -53,49 +54,125 @@ impl Display for ControlId {
#[derive(Clone, Debug, Default, PartialEq)]
pub struct Controls {
controls: HashMap<ControlId, ControlBody>,
values: HashMap<ControlId, ControlId>,
descriptions: HashMap<ControlId, ControlDescription>,
values: HashMap<ControlId, ControlValue>,
}
impl Controls {
pub fn new(device_controls: HashMap<ControlId, ControlBody>) -> Self {
Self {
controls: device_controls,
/// INVARIANTS: All `ControlId` in `device_values` MUST exist in `device_controls`
pub fn new(
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 {
Self::default()
}
pub fn control_value(&self, control_id: &ControlId) -> Option<&ControlBody> {
self.controls.get(control_id)
pub fn unchecked_new(
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
if let Some(control) = self.controls.get_mut(control_id) {
// FIXME: Remove this clone one day!
control.set_value(value.clone())?;
if let None = self.descriptions.get(control_id) {
return Err(NokhwaError::SetPropertyError {
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)]
pub struct ControlBody {
pub struct ControlDescription {
flags: HashSet<ControlFlags>,
descriptor: ControlValueDescriptor,
default_value: Option<ControlValue>,
}
impl ControlBody {
pub fn new(control_flags: HashSet<ControlFlags>, control_value_descriptor: ControlValueDescriptor, default_value: Option<ControlValue>) -> Self {
impl ControlDescription {
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 {
flags: control_flags,
descriptor: control_value_descriptor,
@@ -122,6 +199,10 @@ impl ControlBody {
pub fn remove_flag(&mut self, flag: ControlFlags) -> bool {
self.flags.remove(&flag)
}
pub fn validate(&self, value: &ControlValue) -> bool {
self.descriptor.validate(value)
}
}
#[derive(Copy, Clone, Debug, Hash, Ord, PartialOrd, Eq, PartialEq)]
@@ -160,6 +241,10 @@ pub enum ControlValueDescriptor {
width_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 {
@@ -167,166 +252,66 @@ impl ControlValueDescriptor {
match self {
ControlValueDescriptor::Null => {
if let &ControlValue::Null = value {
return false
return false;
}
}
ControlValueDescriptor::Integer(int_range) => {
if let ControlValue::Integer(i) = value {
return int_range.validate(i)
return int_range.validate(i);
}
}
ControlValueDescriptor::BitMask => {
if let &ControlValue::BitMask(_) = value {
return true
return true;
}
}
ControlValueDescriptor::Float(float_range) => {
if let ControlValue::Float(i) = value {
return float_range.validate(i)
return float_range.validate(i);
}
}
ControlValueDescriptor::String => {
if let &ControlValue::String(_) = value {
return true
return true;
}
}
ControlValueDescriptor::Boolean => {
if let &ControlValue::Boolean(_) = value {
return true
return true;
}
}
ControlValueDescriptor::Array(arr) => {
if let &ControlValue::Array(_) = value {
return arr.is_valid_value(value)
return arr.is_valid_value(value);
}
}
ControlValueDescriptor::Binary(size_limits) => {
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) => {
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 {
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
}
}
//
// #[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)]
pub enum ControlValue {
@@ -339,23 +324,22 @@ pub enum ControlValue {
Array(Vec<ControlValue>),
Binary(Vec<u8>),
EnumPick(Box<ControlValue>),
Area {
width: i64,
height: i64,
}
Area { width: i64, height: i64 },
Orientation(Orientation),
}
impl ControlValue {
pub fn is_primitive(&self) -> bool {
match self {
ControlValue::Null |
ControlValue::Integer(_) |
ControlValue::BitMask(_) |
ControlValue::Float(_) |
ControlValue::String(_)|
ControlValue::Boolean(_) |
ControlValue::Binary(_) |
ControlValue::Area { .. } => true,
ControlValue::Null
| ControlValue::Integer(_)
| ControlValue::BitMask(_)
| ControlValue::Float(_)
| ControlValue::String(_)
| ControlValue::Boolean(_)
| ControlValue::Binary(_)
| ControlValue::Area { .. }
| ControlValue::Orientation(_) => true,
_ => false,
}
}
@@ -383,39 +367,61 @@ impl ControlValue {
return true;
}
}
ControlValue::Integer(_) => {if let ControlValue::Integer(_) = other {
return true;
}}
ControlValue::BitMask(_) => {if let ControlValue::BitMask(_) = other {
return true;
}}
ControlValue::Float(_) => {if let ControlValue::Float(_) = other {
return true;
}}
ControlValue::String(_) => {if let ControlValue::String(_) = other {
return true;
}}
ControlValue::Boolean(_) => {if let ControlValue::Boolean(_) = 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::Integer(_) => {
if let ControlValue::Integer(_) = other {
return true;
}
}
ControlValue::BitMask(_) => {
if let ControlValue::BitMask(_) = other {
return true;
}
}
ControlValue::Float(_) => {
if let ControlValue::Float(_) = other {
return true;
}
}
ControlValue::String(_) => {
if let ControlValue::String(_) = other {
return true;
}
}
ControlValue::Boolean(_) => {
if let ControlValue::Boolean(_) = 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
}
}
impl Display for ControlValue {
@@ -423,3 +429,25 @@ impl Display for ControlValue {
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::error::NokhwaResult;
use crate::types::{CameraIndex, CameraInformation};
use std::fmt::{Display, Formatter};
#[derive(Copy, Clone, Debug, Ord, PartialOrd, Eq, PartialEq)]
pub enum Backends {
@@ -10,7 +10,7 @@ pub enum Backends {
AVFoundation,
MicrosoftMediaFoundation,
OpenCV,
Custom(&'static str)
Custom(&'static str),
}
impl Display for Backends {
@@ -23,16 +23,15 @@ pub trait PlatformTrait {
const PLATFORM: Backends;
type Camera: Camera;
fn block_on_permission(&mut self) -> NokhwaResult<()>;
fn check_permission_given(&mut self) -> bool;
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))
}
}
@@ -43,15 +42,13 @@ pub trait AsyncPlatformTrait {
const PLATFORM: Backends;
type AsyncCamera: AsyncCamera;
async fn await_permission(&mut self) -> NokhwaResult<()>;
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>> {
self.open_async(index).await.map(|cam| Box::new(cam))
}
}
}