From 1c25e51a8a04d4a86e25a12bb03a771015318677 Mon Sep 17 00:00:00 2001 From: Zachary Sunforge Date: Mon, 26 Jun 2023 13:54:00 -0700 Subject: [PATCH] Poll changes --- macros/node-poll-variants/src/lib.rs | 88 ++++++++++++------- macros/node-poll-variants/tests/generate.rs | 7 +- .../src/standard/multiplexer/sync/poll.rs | 4 +- src/error.rs | 31 ++++++- src/lib.rs | 2 +- src/transducer/input.rs | 5 +- src/transducer/mod.rs | 7 ++ src/transducer/output.rs | 7 +- 8 files changed, 105 insertions(+), 46 deletions(-) diff --git a/macros/node-poll-variants/src/lib.rs b/macros/node-poll-variants/src/lib.rs index 92c5a7e..242c1cf 100644 --- a/macros/node-poll-variants/src/lib.rs +++ b/macros/node-poll-variants/src/lib.rs @@ -1,16 +1,13 @@ use proc_macro::TokenStream; use quote::quote; use std::ops::Deref; -use syn::__private::Span; +use quote::__private::parse_spanned; +use syn::__private::{str, Span}; use syn::punctuated::Punctuated; use syn::token::{Colon, Comma, PathSep, Plus}; -use syn::{ - parse_macro_input, parse_quote, parse_quote_spanned, parse_str, Data, DeriveInput, Expr, - GenericParam, Generics, Ident, Lit, Meta, Path, PathSegment, Token, TraitBound, - TraitBoundModifier, TypeParam, TypeParamBound, -}; +use syn::{parse_macro_input, parse_quote, parse_quote_spanned, parse_str, Data, DeriveInput, Expr, GenericParam, Generics, Ident, Lit, LitStr, Meta, Path, PathSegment, Token, TraitBound, TraitBoundModifier, TypeParam, TypeParamBound, Type}; -#[proc_macro_derive(PollVariants, attributes(value_type))] +#[proc_macro_derive(PollVariants, attributes(value_type, error_type))] pub fn poll_variant_macro(input: TokenStream) -> TokenStream { // ----- Parse input ---------------------------------- let input = parse_macro_input!(input as DeriveInput); @@ -28,13 +25,15 @@ pub fn poll_variant_macro(input: TokenStream) -> TokenStream { Data::Union(_) => panic!("Stateful struct cannot be derived from a union."), }; - // ----- Extract value type attribute ---------------------------------- + // ----- Extract attribute information ---------------------------------- const VALUE_T_NAME: &str = "value_type"; - let mut value_type_path: Option = None; + const ERROR_T_NAME: &str = "error_type"; + let mut value_type: Option = None; + let mut error_type: Option = None; for attribute in attrs.iter() { // if the attribute is a named value if let Meta::NameValue(meta) = &attribute.meta { - // if the name of the attribute is value_t + // if the name of the attribute is value_type if meta.path.segments[0].ident == VALUE_T_NAME { // if the value of the attribute is a literal if let Expr::Lit(lit) = &meta.value { @@ -42,15 +41,12 @@ pub fn poll_variant_macro(input: TokenStream) -> TokenStream { if let Lit::Str(lit) = &lit.lit { let span = lit.span(); let string = lit.token().to_string(); - let mut segments: Punctuated = Punctuated::new(); - string - .trim_matches('"') - .split("::") - .map(|segment| Ident::new(segment, span)) - .for_each(|ident| segments.push(parse_quote_spanned!(span=> #ident))); + let string = string.trim_matches('"').to_string(); + let _value_type: Type = parse_str(string.deref()).unwrap(); + let _value_type: Type = parse_quote_spanned!(span=> #_value_type); + + value_type = Some(_value_type); - let path: Path = parse_quote_spanned!(span=> #segments); - value_type_path = Some(path); } else { panic!("{VALUE_T_NAME} must be set with a string literal.") } @@ -58,10 +54,33 @@ pub fn poll_variant_macro(input: TokenStream) -> TokenStream { panic!("{VALUE_T_NAME} must be set with a literal.") } } + + // if the name of the attribute is error_type + if meta.path.segments[0].ident == ERROR_T_NAME { + // if the value of the attribute is a literal + if let Expr::Lit(lit) = &meta.value { + // if the literal is a string + if let Lit::Str(lit) = &lit.lit { + let span = lit.span(); + let string = lit.token().to_string(); + let string = string.trim_matches('"').to_string(); + let _error_type: Type = parse_str(string.deref()).unwrap(); + let _error_type: Type = parse_quote_spanned!(span=> #_error_type); + + error_type = Some(_error_type); + } else { + panic!("{ERROR_T_NAME} must be set with a string literal.") + } + } else { + panic!("{ERROR_T_NAME} must be set with a literal.") + } + } } } - let value_type_path = value_type_path + let value_type = value_type .expect(format!("Need attribute {VALUE_T_NAME}: #[{VALUE_T_NAME} = \"type\"]").deref()); + let error_type = error_type + .expect(format!("Need attribute {ERROR_T_NAME}: #[{ERROR_T_NAME} = \"type\"]").deref()); // ----- Add publisher generics ---------------------------------- // MutexT @@ -148,15 +167,16 @@ pub fn poll_variant_macro(input: TokenStream) -> TokenStream { // ----- Stateful struct ---------------------------------- #vis struct #stateful_variant_ident #og_generics #og_where_clause { pub poll: #ident #og_type_generics, - pub state: #state_path<#value_type_path>, + pub state: #state_path<#value_type>, } // ----- Stateful impls ---------------------------------- impl #og_impl_generics #poll_path for #stateful_variant_ident #og_type_generics #og_where_clause { - type Value = #value_type_path; + type Value = #value_type; + type Error = #error_type; #[inline] - async fn poll(&self) -> Result { + async fn poll(&self) -> Result { let result = self.poll.poll().await; if let Ok(value) = result { self.state.update(value); @@ -166,7 +186,7 @@ pub fn poll_variant_macro(input: TokenStream) -> TokenStream { } impl #og_impl_generics #stateful_path for #stateful_variant_ident #og_type_generics #og_where_clause { - type Value = #value_type_path; + type Value = #value_type; #[inline(always)] fn state_cell(&self) -> #cellview_path { @@ -183,16 +203,17 @@ pub fn poll_variant_macro(input: TokenStream) -> TokenStream { #[cfg(feature = "embassy-sync")] #vis struct #publish_variant_ident #publish_generics #publ_where_clause { pub poll: #ident #og_type_generics, - pub publisher: #publisher_path<#value_type_path, #mutex_t_ident, #capacity_ident, #num_subs_ident>, + pub publisher: #publisher_path<#value_type, #mutex_t_ident, #capacity_ident, #num_subs_ident>, } // ----- Publish impl ---------------------------------- #[cfg(feature = "embassy-sync")] impl #publ_impl_generics #poll_path for #publish_variant_ident #publ_type_generics #publ_where_clause { - type Value = #value_type_path; + type Value = #value_type; + type Error = #error_type; #[inline] - async fn poll(&self) -> Result { + async fn poll(&self) -> Result { let result = self.poll.poll().await; if let Ok(value) = result { self.publisher.update(value); @@ -203,7 +224,7 @@ pub fn poll_variant_macro(input: TokenStream) -> TokenStream { #[cfg(feature = "embassy-sync")] impl #publ_impl_generics #publish_path<#capacity_ident, #num_subs_ident> for #publish_variant_ident #publ_type_generics #publ_where_clause { - type Value = #value_type_path; + type Value = #value_type; type Mutex = #mutex_t_ident; #[inline(always)] @@ -218,16 +239,17 @@ pub fn poll_variant_macro(input: TokenStream) -> TokenStream { #[cfg(feature = "embassy-sync")] #vis struct #state_pub_variant_ident #publish_generics #publ_where_clause { pub poll: #ident #og_type_generics, - pub state: #state_path<#value_type_path>, - pub publisher: #publisher_path<#value_type_path, #mutex_t_ident, #capacity_ident, #num_subs_ident>, + pub state: #state_path<#value_type>, + pub publisher: #publisher_path<#value_type, #mutex_t_ident, #capacity_ident, #num_subs_ident>, } #[cfg(feature = "embassy-sync")] impl #publ_impl_generics #poll_path for #state_pub_variant_ident #publ_type_generics #publ_where_clause { - type Value = #value_type_path; + type Value = #value_type; + type Error = #error_type; #[inline] - async fn poll(&self) -> Result { + async fn poll(&self) -> Result { let result = self.poll.poll().await; if let Ok(value) = result { self.state.update(value); @@ -239,7 +261,7 @@ pub fn poll_variant_macro(input: TokenStream) -> TokenStream { #[cfg(feature = "embassy-sync")] impl #publ_impl_generics #stateful_path for #state_pub_variant_ident #publ_type_generics #publ_where_clause { - type Value = #value_type_path; + type Value = #value_type; #[inline(always)] fn state_cell(&self) -> #cellview_path { @@ -254,7 +276,7 @@ pub fn poll_variant_macro(input: TokenStream) -> TokenStream { #[cfg(feature = "embassy-sync")] impl #publ_impl_generics #publish_path<#capacity_ident, #num_subs_ident> for #state_pub_variant_ident #publ_type_generics #publ_where_clause { - type Value = #value_type_path; + type Value = #value_type; type Mutex = #mutex_t_ident; #[inline(always)] diff --git a/macros/node-poll-variants/tests/generate.rs b/macros/node-poll-variants/tests/generate.rs index 73c119a..98df1d5 100644 --- a/macros/node-poll-variants/tests/generate.rs +++ b/macros/node-poll-variants/tests/generate.rs @@ -1,11 +1,11 @@ -#![feature(async_fn_in_trait, impl_trait_projections)] +#![feature(async_fn_in_trait, impl_trait_projections, never_type)] use node_poll_variants::PollVariants; -use physical_node::CriticalError; use physical_node::transducer::input::Poll; #[derive(PollVariants)] #[value_type = "SecondT"] +#[error_type = "!"] struct ExamplePoll<'a, FirstT, SecondT> where SecondT: Copy, @@ -21,8 +21,9 @@ where SecondT: Copy, { type Value = SecondT; + type Error = !; - async fn poll(&self) -> Result { + async fn poll(&self) -> Result { Ok(self.second) } } diff --git a/peripheral-components/ads1256/node/src/standard/multiplexer/sync/poll.rs b/peripheral-components/ads1256/node/src/standard/multiplexer/sync/poll.rs index d5f0f1a..d180353 100644 --- a/peripheral-components/ads1256/node/src/standard/multiplexer/sync/poll.rs +++ b/peripheral-components/ads1256/node/src/standard/multiplexer/sync/poll.rs @@ -11,6 +11,7 @@ use uom::si::f32; #[derive(PollVariants)] #[value_type = "f32::ElectricPotential"] +#[error_type = "CriticalError"] pub struct AutocalPoll<'a, DeviceMutexT, ModInT, DelayerT, SST, DrdyT, SpiT> where DeviceMutexT: RawMutex, @@ -60,11 +61,12 @@ where SpiT: SpiBus, { type Value = f32::ElectricPotential; + type Error = CriticalError; async fn poll(&self) -> Result { let mut ads1256_guard = self.ads1256.lock().await; let ads1256 = ads1256_guard.deref_mut(); - //TODO: ADS1256 documentation seems to say we should be waiting for drdy low after putting + //TODO: ADS1256 documentation seems to say we should be waiting for drdy low after // issuing standby command but it never goes low. let result = ads1256 diff --git a/src/error.rs b/src/error.rs index ca1d807..096e009 100644 --- a/src/error.rs +++ b/src/error.rs @@ -1,4 +1,6 @@ -/// An error that it is likely impossible to recover. This error should only be created in +use crate::transducer::InvalidValue; + +/// An error that it is likely impossible to recover from. This error should only be created in /// situations where attempts to recover have already been attempted and have failed. Error handling /// should consist of attempting to alert another system for maintenance and attempting to shut down /// any systems that depend on the correct functionality of the component having errors. @@ -9,4 +11,31 @@ pub enum CriticalError { /// Critical communication failed and retries are either impossible or also failed. Communication, + InvalidValue(InvalidValue), +} + +impl CriticalError { + pub fn emergency_procedure(self, procedure: impl FnOnce(CriticalError) -> !) -> ! { + procedure(self); + } +} + +/// [Result] where error type is [CriticalError]. +pub trait CriticalErrResult: Copy { + type Value: Copy; + + /// Execute emergency procedure in the event of a critical, the emergency procedure cannot + /// return. It should usually terminate the program, potentially rebooting the device in some sort of recovery mode. + fn err_emproc(self, procedure: impl FnOnce(CriticalError) -> !) -> Self::Value; +} + +impl CriticalErrResult for Result { + type Value = T; + + fn err_emproc(self, procedure: impl FnOnce(CriticalError) -> !) -> Self::Value { + match self { + Ok(val) => val, + Err(error) => error.emergency_procedure(procedure), + } + } } diff --git a/src/lib.rs b/src/lib.rs index c8d494c..b064117 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,5 +1,5 @@ #![no_std] -#![feature(async_fn_in_trait)] +#![feature(async_fn_in_trait, never_type)] pub mod transducer; pub mod cell; diff --git a/src/transducer/input.rs b/src/transducer/input.rs index 4664d79..40e3cce 100644 --- a/src/transducer/input.rs +++ b/src/transducer/input.rs @@ -1,7 +1,6 @@ -use crate::CriticalError; - pub trait Poll { type Value: Copy; + type Error: Copy; - async fn poll(&self) -> Result; + async fn poll(&self) -> Result; } diff --git a/src/transducer/mod.rs b/src/transducer/mod.rs index 8948ca0..6f907f7 100644 --- a/src/transducer/mod.rs +++ b/src/transducer/mod.rs @@ -51,3 +51,10 @@ impl From> for State { State::new(state_cell) } } + +// --------------------------------------------------------------------------------------------------------------------- +// ----- Error ------------------------ +// --------------------------------------------------------------------------------------------------------------------- +/// Indicates the transducer value is statically known to be impossible. +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +pub struct InvalidValue; diff --git a/src/transducer/output.rs b/src/transducer/output.rs index eb43a0d..3512b8f 100644 --- a/src/transducer/output.rs +++ b/src/transducer/output.rs @@ -1,9 +1,8 @@ +use crate::transducer::InvalidValue; + pub trait Output { type Value: Copy; //TODO: Should this be maybe async? - fn output(&mut self, setting: Self::Value) -> Result<(), InvalidOutputSetting>; + fn output(&mut self, setting: Self::Value) -> Result<(), InvalidValue>; } - -/// Indicates the setting given for an [Output] is statically known to be an impossible setting to achieve. -pub struct InvalidOutputSetting; \ No newline at end of file