Poll changes
This commit is contained in:
@ -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<Path> = None;
|
||||
const ERROR_T_NAME: &str = "error_type";
|
||||
let mut value_type: Option<Type> = None;
|
||||
let mut error_type: Option<Type> = 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<PathSegment, PathSep> = 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<Self::Value, #error_path> {
|
||||
async fn poll(&self) -> Result<Self::Value, Self::Error> {
|
||||
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<Self::Value> {
|
||||
@ -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<Self::Value, #error_path> {
|
||||
async fn poll(&self) -> Result<Self::Value, Self::Error> {
|
||||
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<Self::Value, #error_path> {
|
||||
async fn poll(&self) -> Result<Self::Value, Self::Error> {
|
||||
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<Self::Value> {
|
||||
@ -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)]
|
||||
|
@ -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<Self::Value, CriticalError> {
|
||||
async fn poll(&self) -> Result<Self::Value, Self::Error> {
|
||||
Ok(self.second)
|
||||
}
|
||||
}
|
||||
|
@ -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<Self::Value, CriticalError> {
|
||||
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
|
||||
|
31
src/error.rs
31
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<T: Copy> CriticalErrResult for Result<T, CriticalError> {
|
||||
type Value = T;
|
||||
|
||||
fn err_emproc(self, procedure: impl FnOnce(CriticalError) -> !) -> Self::Value {
|
||||
match self {
|
||||
Ok(val) => val,
|
||||
Err(error) => error.emergency_procedure(procedure),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
#![no_std]
|
||||
#![feature(async_fn_in_trait)]
|
||||
#![feature(async_fn_in_trait, never_type)]
|
||||
|
||||
pub mod transducer;
|
||||
pub mod cell;
|
||||
|
@ -1,7 +1,6 @@
|
||||
use crate::CriticalError;
|
||||
|
||||
pub trait Poll {
|
||||
type Value: Copy;
|
||||
type Error: Copy;
|
||||
|
||||
async fn poll(&self) -> Result<Self::Value, CriticalError>;
|
||||
async fn poll(&self) -> Result<Self::Value, Self::Error>;
|
||||
}
|
||||
|
@ -51,3 +51,10 @@ impl<T: Copy> From<Cell<T>> for State<T> {
|
||||
State::new(state_cell)
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------------------------------------------------
|
||||
// ----- Error ------------------------
|
||||
// ---------------------------------------------------------------------------------------------------------------------
|
||||
/// Indicates the transducer value is statically known to be impossible.
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||
pub struct InvalidValue;
|
||||
|
@ -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;
|
Reference in New Issue
Block a user