From 9902369de2203b760b5fb4cbdc48cc151f221f44 Mon Sep 17 00:00:00 2001 From: Yoshitomo Nakanishi Date: Tue, 22 Aug 2023 22:47:39 +0200 Subject: [PATCH] Allow cast between int, float, and enum value --- device/src/u3v/async_read.rs | 2 +- genapi/src/boolean.rs | 6 +- genapi/src/command.rs | 15 +- genapi/src/elem_type.rs | 11 +- genapi/src/enumeration.rs | 4 +- genapi/src/float.rs | 4 +- genapi/src/integer.rs | 4 +- genapi/src/ivalue.rs | 281 ++++++++++++++++++++++++++++------- genapi/src/store.rs | 31 ++-- 9 files changed, 271 insertions(+), 87 deletions(-) diff --git a/device/src/u3v/async_read.rs b/device/src/u3v/async_read.rs index b87c6f13..921dbd02 100644 --- a/device/src/u3v/async_read.rs +++ b/device/src/u3v/async_read.rs @@ -217,7 +217,7 @@ impl Drop for AsyncTransfer { /// timeout, or error, instead of potentially returning early. /// /// This design is based on -/// https://libusb.sourceforge.io/api-1.0/libusb_mtasync.html#threadwait +/// fn poll_completed( ctx: &impl UsbContext, timeout: Duration, diff --git a/genapi/src/boolean.rs b/genapi/src/boolean.rs index 1d8bd4c4..316b9d91 100644 --- a/genapi/src/boolean.rs +++ b/genapi/src/boolean.rs @@ -65,7 +65,7 @@ impl IBoolean for BooleanNode { store: &impl NodeStore, cx: &mut ValueCtxt, ) -> GenApiResult { - let value = self.value.value(device, store, cx)?; + let value: i64 = self.value.value(device, store, cx)?; if value == self.on_value { Ok(true) } else if value == self.off_value { @@ -102,7 +102,7 @@ impl IBoolean for BooleanNode { cx: &mut ValueCtxt, ) -> GenApiResult { Ok(self.elem_base.is_readable(device, store, cx)? - && self.value.is_readable(device, store, cx)?) + && IValue::::is_readable(&self.value, device, store, cx)?) } #[tracing::instrument(skip(self, device, store, cx), @@ -115,7 +115,7 @@ impl IBoolean for BooleanNode { cx: &mut ValueCtxt, ) -> GenApiResult { Ok(self.elem_base.is_writable(device, store, cx)? - && self.value.is_writable(device, store, cx)?) + && IValue::::is_writable(&self.value, device, store, cx)?) } } diff --git a/genapi/src/command.rs b/genapi/src/command.rs index 0db00eb9..b84768da 100644 --- a/genapi/src/command.rs +++ b/genapi/src/command.rs @@ -4,7 +4,7 @@ use super::{ elem_type::ImmOrPNode, - interface::{ICommand, IInteger, INode}, + interface::{ICommand, INode}, ivalue::IValue, node_base::{NodeAttributeBase, NodeBase, NodeElementBase}, store::{CacheStore, IntegerId, NodeStore, ValueStore}, @@ -59,7 +59,7 @@ impl ICommand for CommandNode { ) -> GenApiResult<()> { cx.invalidate_cache_by(self.node_base().id()); - let value = self.command_value.value(device, store, cx)?; + let value: i64 = self.command_value.value(device, store, cx)?; self.value.set_value(value, device, store, cx) } @@ -71,15 +71,14 @@ impl ICommand for CommandNode { store: &impl NodeStore, cx: &mut ValueCtxt, ) -> GenApiResult { - let nid = match self.value { + let node = match self.value { ImmOrPNode::Imm(..) => return Ok(true), ImmOrPNode::PNode(nid) => nid, }; - cx.invalidate_cache_of(nid); - let node = nid.expect_iinteger_kind(store)?; - if node.is_readable(device, store, cx)? { - let command_value = self.command_value.value(device, store, cx)?; + cx.invalidate_cache_of(node); + if IValue::::is_readable(&node, device, store, cx)? { + let command_value: i64 = self.command_value.value(device, store, cx)?; let reg_value = node.value(device, store, cx)?; Ok(command_value != reg_value) } else { @@ -97,6 +96,6 @@ impl ICommand for CommandNode { cx: &mut ValueCtxt, ) -> GenApiResult { Ok(self.elem_base.is_writable(device, store, cx)? - && self.value.is_writable(device, store, cx)?) + && IValue::::is_writable(&self.value, device, store, cx)?) } } diff --git a/genapi/src/elem_type.rs b/genapi/src/elem_type.rs index f204933e..83a252be 100644 --- a/genapi/src/elem_type.rs +++ b/genapi/src/elem_type.rs @@ -6,7 +6,6 @@ use std::marker::PhantomData; use super::{ - interface::IInteger, ivalue::IValue, store::{CacheStore, NodeId, NodeStore, ValueStore}, Device, GenApiResult, ValueCtxt, @@ -281,7 +280,7 @@ impl AddressKind { ) -> GenApiResult { match self { Self::Address(i) => i.value(device, store, cx), - Self::IntSwissKnife(nid) => nid.expect_iinteger_kind(store)?.value(device, store, cx), + Self::IntSwissKnife(nid) => nid.value(device, store, cx), Self::PIndex(p_index) => p_index.value(device, store, cx), } } @@ -310,12 +309,10 @@ impl RegPIndex { store: &impl NodeStore, cx: &mut ValueCtxt, ) -> GenApiResult { - let base = self - .p_index - .expect_iinteger_kind(store)? - .value(device, store, cx)?; + let base = self.p_index.value(device, store, cx)?; if let Some(offset) = &self.offset { - Ok(base + offset.value(device, store, cx)?) + let offset: i64 = offset.value(device, store, cx)?; + Ok(base + offset) } else { Ok(base) } diff --git a/genapi/src/enumeration.rs b/genapi/src/enumeration.rs index 6427746e..0b3ea4d6 100644 --- a/genapi/src/enumeration.rs +++ b/genapi/src/enumeration.rs @@ -152,7 +152,7 @@ impl IEnumeration for EnumerationNode { cx: &mut ValueCtxt, ) -> GenApiResult { Ok(self.elem_base.is_readable(device, store, cx)? - && self.value.is_readable(device, store, cx)?) + && IValue::::is_readable(&self.value, device, store, cx)?) } #[tracing::instrument(skip(self, device, store, cx), @@ -165,7 +165,7 @@ impl IEnumeration for EnumerationNode { cx: &mut ValueCtxt, ) -> GenApiResult { Ok(self.elem_base.is_writable(device, store, cx)? - && self.value.is_writable(device, store, cx)?) + && IValue::::is_writable(&self.value, device, store, cx)?) } } diff --git a/genapi/src/float.rs b/genapi/src/float.rs index c5a6721e..4d666214 100644 --- a/genapi/src/float.rs +++ b/genapi/src/float.rs @@ -198,7 +198,7 @@ impl IFloat for FloatNode { cx: &mut ValueCtxt, ) -> GenApiResult { Ok(self.elem_base.is_readable(device, store, cx)? - && self.value_kind.is_readable(device, store, cx)?) + && IValue::::is_readable(&self.value_kind, device, store, cx)?) } #[tracing::instrument(skip(self, device, store, cx), @@ -211,6 +211,6 @@ impl IFloat for FloatNode { cx: &mut ValueCtxt, ) -> GenApiResult { Ok(self.elem_base.is_writable(device, store, cx)? - && self.value_kind.is_writable(device, store, cx)?) + && IValue::::is_writable(&self.value_kind, device, store, cx)?) } } diff --git a/genapi/src/integer.rs b/genapi/src/integer.rs index 10e6e473..40b27c6d 100644 --- a/genapi/src/integer.rs +++ b/genapi/src/integer.rs @@ -188,7 +188,7 @@ impl IInteger for IntegerNode { cx: &mut ValueCtxt, ) -> GenApiResult { Ok(self.elem_base.is_readable(device, store, cx)? - && self.value_kind.is_readable(device, store, cx)?) + && IValue::::is_readable(&self.value_kind, device, store, cx)?) } #[tracing::instrument(skip(self, device, store, cx), @@ -201,7 +201,7 @@ impl IInteger for IntegerNode { cx: &mut ValueCtxt, ) -> GenApiResult { Ok(self.elem_base.is_writable(device, store, cx)? - && self.value_kind.is_writable(device, store, cx)?) + && IValue::::is_writable(&self.value_kind, device, store, cx)?) } } diff --git a/genapi/src/ivalue.rs b/genapi/src/ivalue.rs index a41c1bab..05062f7c 100644 --- a/genapi/src/ivalue.rs +++ b/genapi/src/ivalue.rs @@ -6,7 +6,7 @@ use ambassador::delegatable_trait; use super::{ elem_type::{ImmOrPNode, PIndex, PValue, ValueKind}, - interface::{IFloat, IInteger, IString}, + interface::{IEnumeration, IFloat, IInteger, IString}, store::{CacheStore, FloatId, IntegerId, NodeId, NodeStore, StringId, ValueStore}, Device, GenApiError, GenApiResult, ValueCtxt, }; @@ -44,20 +44,20 @@ pub(super) trait IValue { } macro_rules! impl_ivalue_for_imm { - ($ty:ty) => { - impl IValue<$ty> for $ty { + ($imm_ty:ty, $result_ty:ty) => { + impl IValue<$result_ty> for $imm_ty { fn value( &self, _: &mut impl Device, _: &impl NodeStore, _: &mut ValueCtxt, - ) -> GenApiResult<$ty> { - Ok(*self) + ) -> GenApiResult<$result_ty> { + Ok(*self as $result_ty) } fn set_value( &self, - _: $ty, + _: $result_ty, _: &mut impl Device, _: &impl NodeStore, _: &mut ValueCtxt, @@ -85,8 +85,10 @@ macro_rules! impl_ivalue_for_imm { } }; } -impl_ivalue_for_imm!(i64); -impl_ivalue_for_imm!(f64); +impl_ivalue_for_imm!(i64, i64); +impl_ivalue_for_imm!(i64, f64); +impl_ivalue_for_imm!(f64, i64); +impl_ivalue_for_imm!(f64, f64); macro_rules! impl_ivalue_for_vid { ($ty:ty, $vid:ty, $f:ident) => { @@ -97,7 +99,7 @@ macro_rules! impl_ivalue_for_vid { _: &impl NodeStore, cx: &mut ValueCtxt, ) -> GenApiResult<$ty> { - Ok(cx.value_store.$f(*self).unwrap().into()) + Ok(cx.value_store.$f(*self).unwrap() as $ty) } fn set_value( @@ -132,55 +134,232 @@ macro_rules! impl_ivalue_for_vid { }; } impl_ivalue_for_vid!(i64, IntegerId, integer_value); +impl_ivalue_for_vid!(f64, IntegerId, integer_value); impl_ivalue_for_vid!(f64, FloatId, float_value); -impl_ivalue_for_vid!(String, StringId, str_value); +impl_ivalue_for_vid!(i64, FloatId, float_value); +impl IValue for StringId { + fn value( + &self, + _: &mut impl Device, + _: &impl NodeStore, + cx: &mut ValueCtxt, + ) -> GenApiResult { + Ok(cx.value_store.str_value(*self).unwrap().into()) + } -macro_rules! impl_ivalue_for_node_id { - ($ty:ty, $expect_kind:ident) => { - impl IValue<$ty> for NodeId { - fn value( - &self, - device: &mut impl Device, - store: &impl NodeStore, - cx: &mut ValueCtxt, - ) -> GenApiResult<$ty> { - self.$expect_kind(store)?.value(device, store, cx) - } + fn set_value( + &self, + value: String, + _: &mut impl Device, + _: &impl NodeStore, + cx: &mut ValueCtxt, + ) -> GenApiResult<()> { + cx.value_store_mut().update(*self, value); + Ok(()) + } - fn set_value( - &self, - value: $ty, - device: &mut impl Device, - store: &impl NodeStore, - cx: &mut ValueCtxt, - ) -> GenApiResult<()> { - self.$expect_kind(store)? - .set_value(value, device, store, cx) - } + fn is_readable( + &self, + _: &mut impl Device, + _: &impl NodeStore, + _: &mut ValueCtxt, + ) -> GenApiResult { + Ok(true) + } - fn is_readable( - &self, - device: &mut impl Device, - store: &impl NodeStore, - cx: &mut ValueCtxt, - ) -> GenApiResult { - self.$expect_kind(store)?.is_readable(device, store, cx) - } + fn is_writable( + &self, + _: &mut impl Device, + _: &impl NodeStore, + _: &mut ValueCtxt, + ) -> GenApiResult { + Ok(true) + } +} - fn is_writable( - &self, - device: &mut impl Device, - store: &impl NodeStore, - cx: &mut ValueCtxt, - ) -> GenApiResult { - self.$expect_kind(store)?.is_writable(device, store, cx) - } +impl IValue for NodeId { + fn value( + &self, + device: &mut impl Device, + store: &impl NodeStore, + cx: &mut ValueCtxt, + ) -> GenApiResult { + if let Some(i) = self.as_iinteger_kind(store) { + i.value(device, store, cx) + } else if let Some(f) = self.as_ifloat_kind(store) { + f.value(device, store, cx).map(|f| f as i64) + } else if let Some(e) = self.as_ienumeration_kind(store) { + e.current_value(device, store, cx) + } else { + Err(GenApiError::invalid_node( + format!("Node {:?} is not an integer, float, or enumeration", self).into(), + )) } - }; + } + + fn set_value( + &self, + value: i64, + device: &mut impl Device, + store: &impl NodeStore, + cx: &mut ValueCtxt, + ) -> GenApiResult<()> { + if let Some(i) = self.as_iinteger_kind(store) { + i.set_value(value, device, store, cx) + } else if let Some(f) = self.as_ifloat_kind(store) { + f.set_value(value as f64, device, store, cx) + } else if let Some(e) = self.as_ienumeration_kind(store) { + e.set_entry_by_value(value, device, store, cx) + } else { + Err(GenApiError::not_writable()) + } + } + + fn is_readable( + &self, + device: &mut impl Device, + store: &impl NodeStore, + cx: &mut ValueCtxt, + ) -> GenApiResult { + if let Some(i) = self.as_iinteger_kind(store) { + i.is_readable(device, store, cx) + } else if let Some(f) = self.as_ifloat_kind(store) { + f.is_readable(device, store, cx) + } else if let Some(e) = self.as_ienumeration_kind(store) { + e.is_readable(device, store, cx) + } else { + Ok(false) + } + } + + fn is_writable( + &self, + device: &mut impl Device, + store: &impl NodeStore, + cx: &mut ValueCtxt, + ) -> GenApiResult { + if let Some(i) = self.as_iinteger_kind(store) { + i.is_writable(device, store, cx) + } else if let Some(f) = self.as_ifloat_kind(store) { + f.is_writable(device, store, cx) + } else { + Ok(false) + } + } +} + +impl IValue for NodeId { + fn value( + &self, + device: &mut impl Device, + store: &impl NodeStore, + cx: &mut ValueCtxt, + ) -> GenApiResult { + if let Some(i) = self.as_iinteger_kind(store) { + i.value(device, store, cx).map(|i| i as f64) + } else if let Some(f) = self.as_ifloat_kind(store) { + f.value(device, store, cx) + } else if let Some(e) = self.as_ienumeration_kind(store) { + e.current_value(device, store, cx).map(|i| i as f64) + } else { + Err(GenApiError::invalid_node( + format!("Node {:?} is not an integer, float, or enumeration", self).into(), + )) + } + } + + fn set_value( + &self, + value: f64, + device: &mut impl Device, + store: &impl NodeStore, + cx: &mut ValueCtxt, + ) -> GenApiResult<()> { + if let Some(i) = self.as_iinteger_kind(store) { + i.set_value(value as i64, device, store, cx) + } else if let Some(f) = self.as_ifloat_kind(store) { + f.set_value(value, device, store, cx) + } else if let Some(e) = self.as_ienumeration_kind(store) { + e.set_entry_by_value(value as i64, device, store, cx) + } else { + Err(GenApiError::not_writable()) + } + } + + fn is_readable( + &self, + device: &mut impl Device, + store: &impl NodeStore, + cx: &mut ValueCtxt, + ) -> GenApiResult { + if let Some(i) = self.as_iinteger_kind(store) { + i.is_readable(device, store, cx) + } else if let Some(f) = self.as_ifloat_kind(store) { + f.is_readable(device, store, cx) + } else if let Some(e) = self.as_ienumeration_kind(store) { + e.is_readable(device, store, cx) + } else { + Ok(false) + } + } + + fn is_writable( + &self, + device: &mut impl Device, + store: &impl NodeStore, + cx: &mut ValueCtxt, + ) -> GenApiResult { + if let Some(i) = self.as_iinteger_kind(store) { + i.is_writable(device, store, cx) + } else if let Some(f) = self.as_ifloat_kind(store) { + f.is_writable(device, store, cx) + } else { + Ok(false) + } + } +} + +impl IValue for NodeId { + fn value( + &self, + device: &mut impl Device, + store: &impl NodeStore, + cx: &mut ValueCtxt, + ) -> GenApiResult { + self.expect_istring_kind(store)?.value(device, store, cx) + } + + fn set_value( + &self, + value: String, + device: &mut impl Device, + store: &impl NodeStore, + cx: &mut ValueCtxt, + ) -> GenApiResult<()> { + self.expect_istring_kind(store)? + .set_value(value, device, store, cx) + } + + fn is_readable( + &self, + device: &mut impl Device, + store: &impl NodeStore, + cx: &mut ValueCtxt, + ) -> GenApiResult { + self.expect_istring_kind(store)? + .is_readable(device, store, cx) + } + + fn is_writable( + &self, + device: &mut impl Device, + store: &impl NodeStore, + cx: &mut ValueCtxt, + ) -> GenApiResult { + self.expect_istring_kind(store)? + .is_writable(device, store, cx) + } } -impl_ivalue_for_node_id!(f64, expect_ifloat_kind); -impl_ivalue_for_node_id!(i64, expect_iinteger_kind); -impl_ivalue_for_node_id!(String, expect_istring_kind); impl IValue for ImmOrPNode where diff --git a/genapi/src/store.rs b/genapi/src/store.rs index baf30a3c..9a1410ca 100644 --- a/genapi/src/store.rs +++ b/genapi/src/store.rs @@ -87,23 +87,32 @@ pub trait ValueStore { self.value_opt(id).unwrap() } - fn integer_value(&self, id: IntegerId) -> Option { - if let ValueData::Integer(i) = self.value_opt(id)? { - Some(*i) - } else { - None + fn integer_value(&self, id: T) -> Option + where + T: Into, + { + match self.value_opt(id)? { + ValueData::Integer(i) => Some(*i), + ValueData::Float(f) => Some(*f as i64), + _ => None, } } - fn float_value(&self, id: FloatId) -> Option { - if let ValueData::Float(f) = self.value_opt(id)? { - Some(*f) - } else { - None + fn float_value(&self, id: T) -> Option + where + T: Into, + { + match self.value_opt(id)? { + ValueData::Integer(i) => Some(*i as f64), + ValueData::Float(f) => Some(*f), + _ => None, } } - fn str_value(&self, id: StringId) -> Option<&String> { + fn str_value(&self, id: T) -> Option<&String> + where + T: Into, + { if let ValueData::Str(s) = self.value_opt(id)? { Some(s) } else {