From 9360c8690ef0b576c52007f91a6bd3b7f0509314 Mon Sep 17 00:00:00 2001 From: Michael House Date: Mon, 1 Apr 2024 18:03:55 -0500 Subject: [PATCH] Update version (#74) Removed derive crate --- Cargo.toml | 2 +- crates/mil_std_1553b_derive/Cargo.lock | 46 ---- crates/mil_std_1553b_derive/Cargo.toml | 17 -- crates/mil_std_1553b_derive/README.md | 3 - crates/mil_std_1553b_derive/src/field.rs | 43 ---- crates/mil_std_1553b_derive/src/lib.rs | 180 ---------------- crates/mil_std_1553b_derive/src/word.rs | 257 ----------------------- examples/custom.rs | 2 +- 8 files changed, 2 insertions(+), 548 deletions(-) delete mode 100644 crates/mil_std_1553b_derive/Cargo.lock delete mode 100644 crates/mil_std_1553b_derive/Cargo.toml delete mode 100644 crates/mil_std_1553b_derive/README.md delete mode 100644 crates/mil_std_1553b_derive/src/field.rs delete mode 100644 crates/mil_std_1553b_derive/src/lib.rs delete mode 100644 crates/mil_std_1553b_derive/src/word.rs diff --git a/Cargo.toml b/Cargo.toml index e489ec0..0fe5fce 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,7 +25,7 @@ categories = [ derive = [ "dep:mil_std_1553b_derive" ] [dependencies] -mil_std_1553b_derive = { version = "0.5.0", path = "crates/mil_std_1553b_derive", optional = true } +mil_std_1553b_derive = { version = "0.5.0", optional = true } [[example]] name = "custom" diff --git a/crates/mil_std_1553b_derive/Cargo.lock b/crates/mil_std_1553b_derive/Cargo.lock deleted file mode 100644 index 81d8b51..0000000 --- a/crates/mil_std_1553b_derive/Cargo.lock +++ /dev/null @@ -1,46 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "derive" -version = "0.4.0" -dependencies = [ - "quote", - "syn", -] - -[[package]] -name = "proc-macro2" -version = "1.0.79" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "quote" -version = "1.0.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "syn" -version = "1.0.109" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "unicode-ident" -version = "1.0.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" diff --git a/crates/mil_std_1553b_derive/Cargo.toml b/crates/mil_std_1553b_derive/Cargo.toml deleted file mode 100644 index df4f86c..0000000 --- a/crates/mil_std_1553b_derive/Cargo.toml +++ /dev/null @@ -1,17 +0,0 @@ -[package] -name = "mil_std_1553b_derive" -version = "0.5.0" -edition = "2021" -license = "MIT" -readme = "README.md" -description = "MIL STD 1553B proc macros" -authors = ["Michael House "] - -[lib] -proc-macro = true - -[dependencies] -syn = { version = "1.0", features = ["full"]} -quote = "1.0" -proc-macro-error = "1.0.4" -proc-macro2 = "1.0.79" \ No newline at end of file diff --git a/crates/mil_std_1553b_derive/README.md b/crates/mil_std_1553b_derive/README.md deleted file mode 100644 index dbe135d..0000000 --- a/crates/mil_std_1553b_derive/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# MIL STD 1553B Derives - -Provides proc-macros for deriving mil_std_1553b types. \ No newline at end of file diff --git a/crates/mil_std_1553b_derive/src/field.rs b/crates/mil_std_1553b_derive/src/field.rs deleted file mode 100644 index 9b39cbc..0000000 --- a/crates/mil_std_1553b_derive/src/field.rs +++ /dev/null @@ -1,43 +0,0 @@ -use proc_macro::TokenStream; -use proc_macro_error::OptionExt; - -pub struct FieldArgs { - name: Option, - value: Option -} - -impl FieldArgs { - pub fn new(input: TokenStream) -> Self { - let mut items = input.into_iter(); - - let name = items - .next() - .map(|t| t.to_string()); - - // skip the comma - items.next(); - - let value = items - .next() - .map(|t| t - .to_string() - .trim_start_matches("0b") - .to_string()); - - Self { name, value } - } - - pub fn name(&self) -> String { - self.name - .clone() - .expect_or_abort("Need an identifier for the field") - } - - pub fn mask(&self) -> u16 { - self.value - .clone() - .and_then(|v| u16::from_str_radix(&v,2).ok()) - .expect_or_abort("Need a mask for the field") - } - -} \ No newline at end of file diff --git a/crates/mil_std_1553b_derive/src/lib.rs b/crates/mil_std_1553b_derive/src/lib.rs deleted file mode 100644 index 7989f12..0000000 --- a/crates/mil_std_1553b_derive/src/lib.rs +++ /dev/null @@ -1,180 +0,0 @@ -use proc_macro::{Span, TokenStream}; -use proc_macro_error::{abort, abort_call_site}; -use quote::{quote, ToTokens}; -use syn::{parse_macro_input, DeriveInput, Ident, ItemFn}; - -mod word; -mod field; - -use field::FieldArgs; -use word::FieldKind; - -/// Derive the `Word` trait and associated From implementations -/// -/// This trait requires that the `Default` trait is implemented -/// as well. To avoid this, implement the Word trait manually. -/// -/// ### Example -/// -/// ```rust -/// #[derive(Default, Word)] -/// struct MyWord { -/// -/// #[data] -/// buffer: [u8; 2], -/// -/// #[parity] -/// parity_bit: u8, -/// -/// // you can have any other -/// // fields you need -/// count: u8, -/// } -/// ``` -#[proc_macro_derive(Word, attributes(data,parity))] -#[proc_macro_error::proc_macro_error] -pub fn word_derive(input: TokenStream) -> TokenStream { - let input = parse_macro_input!(input as DeriveInput); - - let item = match input.data { - syn::Data::Struct(s) => s, - _ => abort_call_site!("Word derive is only valid on a struct") - }; - - let fields = match item.fields { - syn::Fields::Named(n) => n, - _ => abort_call_site!("Word derive requires named fields") - }; - - let mut data_field: FieldKind = FieldKind::None; - let mut parity_field: FieldKind = FieldKind::None; - - for named in fields.named { - match word::parse_field(&named) { - - word::FieldKind::Data(v) if data_field.is_some() => - abort!(v, "Duplicate #[data] fields"), - - word::FieldKind::Parity(v) if parity_field.is_some() => - abort!(v, "Duplicate #[parity] fields"), - - k if k.is_data() => data_field = k, - k if k.is_parity() => parity_field = k, - _ => continue - } - } - - if data_field.is_none() { - abort!(data_field.ident(),"Need a '#[data]' field with type '[u8;2]'"); - } - - if parity_field.is_none() { - abort!(parity_field.ident(),"Need a '#[parity]' field with type 'u8'"); - } - - let self_type = input.ident; - - let data_ident = data_field.ident(); - - - let word_impl = word::impl_word(&data_field, &parity_field, &self_type); - - quote!( - #word_impl - - impl From<&mil_std_1553b::DataWord> for #self_type { - fn from(word: &mil_std_1553b::DataWord) -> Self { - use mil_std_1553b::Word; - #self_type::new() - .with_bytes(word.as_bytes()) - .with_parity(word.parity()) - } - } - - impl From<&#self_type> for mil_std_1553b::DataWord { - fn from(word: &#self_type) -> Self { - use mil_std_1553b::Word; - mil_std_1553b::DataWord::new() - .with_bytes(word.as_bytes()) - .with_parity(word.parity()) - } - } - - impl From for #self_type { - fn from(word: mil_std_1553b::DataWord) -> Self { - Self::from(&word) - } - } - - impl From<#self_type> for mil_std_1553b::DataWord { - fn from(word: #self_type) -> Self { - Self::from(&word) - } - } - - impl From<&#self_type> for u16 { - fn from(word: &#self_type) -> Self { - u16::from_be_bytes(word.#data_ident) - } - } - - impl From<#self_type> for u16 { - fn from(word: #self_type) -> Self { - u16::from_be_bytes(word.#data_ident) - } - } - ).to_token_stream().into() -} - -/// Implement a parser for a word field -/// -/// ### Arguments -/// -/// * name - A const name for the field (e.g. 'MY_FIELD') -/// * mask - A u16 bit mask for the field (e.g. '0b10000000000000000') -/// -/// ### Example -/// -/// ```rust -/// -/// #[field(MY_FIELD, 0b1000000000000000)] -/// pub fn get_my_field_value(&self) -> u8 { -/// Self::MY_FIELD.get(self) -/// } -/// -/// ``` -/// -/// Will generate the following code: -/// -/// ```rust -/// -/// pub const MY_FIELD_MASK: u16 = 32768u16; -/// pub const MY_FIELD: Field = Field::from(Self::MY_FIELD_MASK); -/// pub fn get_my_field_value(&self) -> u8 { -/// Self::MY_FIELD.get(self) -/// } -/// -/// ``` -#[proc_macro_attribute] -#[proc_macro_error::proc_macro_error] -pub fn field(attr: TokenStream, item: TokenStream) -> TokenStream { - let args = FieldArgs::new(attr); - let item = parse_macro_input!(item as ItemFn); - - let name = args.name(); - let mask = args.mask(); - - let mask_label = format!("{}_MASK",name); - let mask_ident = Ident::new(&mask_label, Span::call_site().into()); - - let field_label = format!("{}",name); - let field_ident = Ident::new(&field_label, Span::call_site().into()); - - quote!( - pub const #mask_ident: u16 = #mask; - - pub const #field_ident: Field = Field::from(Self::#mask_ident); - - #item - ).to_token_stream().into() -} \ No newline at end of file diff --git a/crates/mil_std_1553b_derive/src/word.rs b/crates/mil_std_1553b_derive/src/word.rs deleted file mode 100644 index a0b581b..0000000 --- a/crates/mil_std_1553b_derive/src/word.rs +++ /dev/null @@ -1,257 +0,0 @@ -use syn::{Expr, ExprLit, Field, Ident, Lit}; -use proc_macro2::TokenStream; - -use proc_macro_error::{abort, OptionExt}; -use quote::quote; - -const DATA_LABEL: &str = "data"; -const PARITY_LABEL: &str = "parity"; - -const DATA_KIND: &str = "[u8;2]"; -const PARITY_KIND: &str = "u8"; - -#[derive(Eq,PartialEq,Debug)] -pub(crate) enum FieldLabel { - None, - Data(Ident), - Parity(Ident) -} - -#[derive(Eq,PartialEq,Debug)] -pub(crate) enum FieldKind { - None, - Data(Ident), - Parity(Ident) -} - -impl FieldLabel { - - pub(crate) fn is_some(&self) -> bool { - !matches!(self,FieldLabel::None) - } - - pub(crate) fn is_kind(&self, kind: &FieldKind) -> bool { - match (self,kind) { - (Self::None,FieldKind::None) => true, - (Self::Data(_),FieldKind::Data(_)) => true, - (Self::Parity(_),FieldKind::Parity(_)) => true, - _ => false - } - } - -} - -impl FieldKind { - - pub(crate) fn is_none(&self) -> bool { - matches!(self,FieldKind::None) - } - - pub(crate) fn is_some(&self) -> bool { - !matches!(self,FieldKind::None) - } - - pub(crate) fn ident(&self) -> Option { - match self { - Self::Data(v) => Some(v.clone()), - Self::Parity(v) => Some(v.clone()), - _ => None - } - } - - pub(crate) fn is_data(&self) -> bool { - matches!(self,Self::Data(_)) - } - - pub(crate) fn is_parity(&self) -> bool { - matches!(self,Self::Parity(_)) - } - -} - -pub(crate) fn parse_label(field: &Field) -> FieldLabel { - let mut kind = FieldLabel::None; - for attr in field.attrs.iter() { - let ident = attr.path.get_ident(); - - // get the attribute as a field type - let attr = match ident.map(Ident::to_string).as_deref() { - Some(DATA_LABEL) => FieldLabel::Data(ident.unwrap().clone()), - Some(PARITY_LABEL) => FieldLabel::Parity(ident.unwrap().clone()), - _ => FieldLabel::None, - }; - - if attr != FieldLabel::None { - - // found multiple labels on the same field - if kind != FieldLabel::None { - abort!(ident, "Multiple declarations of field"); - } - - kind = attr; - } - - } - kind -} - -pub(crate) fn parse_kind(field: &Field) -> FieldKind { - - let ident = field - .ident - .clone() - .expect_or_abort("Cannot derive for struct with unnamed field"); - - let kind = match &field.ty { - syn::Type::Path(v) => v - .path - .segments - .iter() - .next() - .map(|t| t.ident.to_string()) - .unwrap_or("".into()) - .to_string(), - syn::Type::Array(v) => { - - let t = match v.elem.as_ref() { - syn::Type::Path(s) => s.path.segments - .clone() - .into_iter() - .next() - .map(|t| t.ident.to_string()) - .unwrap_or("".into()) - .to_string(), - _ => String::new() - }; - - let l = match &v.len { - Expr::Lit(ExprLit { lit: Lit::Int(i), .. }) => i - .base10_parse::() - .unwrap_or(0), - _ => 0, - }; - - format!("[{};{}]",t,l) - }, - _ => String::new() - }; - - match kind.as_str() { - DATA_KIND => FieldKind::Data(ident), - PARITY_KIND => FieldKind::Parity(ident), - _ => FieldKind::None - } -} - -pub(crate) fn parse_field(field: &Field) -> FieldKind { - let field_label = parse_label(field); - - if field_label.is_some() { - let field_kind = parse_kind(field); - - if field_label.is_kind(&field_kind) { - return field_kind; - } - } - - FieldKind::None -} - -pub(crate) fn impl_new(data_ident: &Ident, parity_ident: &Ident) -> TokenStream { - quote!( - fn new() -> Self { - Self { - #data_ident: [0, 0], - #parity_ident: 1, - ..Default::default() - } - } - ) -} - -pub(crate) fn impl_word(data_field: &FieldKind, parity_field: &FieldKind, self_type: &Ident) -> TokenStream { - let data_ident = data_field.ident().expect_or_abort("No identifier for data field"); - let parity_ident = parity_field.ident().expect_or_abort("No identifier for parity field"); - - let new_impl = impl_new(&data_ident, &parity_ident); - - quote!( - impl mil_std_1553b::Word for #self_type { - - #new_impl - - fn with_value(mut self, data: u16) -> Self { - self.set_value(data); - self - } - - fn with_bytes(mut self, data: [u8; 2]) -> Self { - self.set_bytes(data); - self - } - - fn with_parity(mut self, parity: u8) -> Self { - self.set_parity(parity); - self - } - - fn with_calculated_parity(mut self) -> Self { - self.#parity_ident = self.calculate_parity(); - self - } - - fn build(self) -> mil_std_1553b::Result { - if self.check_parity() { - Ok(self) - } else { - Err(mil_std_1553b::Error::InvalidWord) - } - } - - fn from_value(data: u16) -> Self { - Self::new().with_value(data).with_calculated_parity() - } - - fn from_bytes(data: [u8; 2]) -> Self { - Self::new().with_bytes(data) - } - - fn as_bytes(&self) -> [u8; 2] { - self.#data_ident - } - - fn as_value(&self) -> u16 { - self.into() - } - - fn set_value(&mut self, data: u16) { - self.#data_ident = data.to_be_bytes(); - self.#parity_ident = self.calculate_parity(); - } - - fn set_bytes(&mut self, data: [u8; 2]) { - self.#data_ident = data; - self.#parity_ident = self.calculate_parity(); - } - - fn parity(&self) -> u8 { - self.#parity_ident - } - - fn set_parity(&mut self, parity: u8) { - self.#parity_ident = parity; - } - - fn calculate_parity(&self) -> u8 { - match self.as_value().count_ones() % 2 { - 0 => 1, - _ => 0, - } - } - - fn check_parity(&self) -> bool { - self.parity() == self.calculate_parity() - } - } - ) -} \ No newline at end of file diff --git a/examples/custom.rs b/examples/custom.rs index 1be8294..e50e82a 100644 --- a/examples/custom.rs +++ b/examples/custom.rs @@ -21,7 +21,7 @@ struct CustomWord { impl CustomWord { #[field(STATUS_LIGHT, 0b1000000000000000)] pub fn status_light_on(&self) -> bool { - Self::STATUS_LIGHT.get(self) == 1 + Self::STATUS_LIGHT.get::<_, u16>(self) == 1 } }