Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement FromAbbrevStr derive macro #62

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 10 additions & 10 deletions gribberish/src/templates/product/parameters/meteorological.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use gribberish_macros::{DisplayDescription, FromValue, ToParameter};
use gribberish_macros::{DisplayDescription, FromAbbrevStr, FromValue, ToParameter};
use gribberish_types::Parameter;

#[repr(u8)]
#[derive(Eq, PartialEq, Debug, DisplayDescription, FromValue, ToParameter)]
#[derive(Eq, PartialEq, Debug, DisplayDescription, FromValue, ToParameter, FromAbbrevStr)]
pub enum TemperatureProduct {
#[abbrev = "TMP"]
#[unit = "K"]
Expand Down Expand Up @@ -55,7 +55,7 @@ pub enum TemperatureProduct {
}

#[repr(u8)]
#[derive(Eq, PartialEq, Debug, DisplayDescription, FromValue, ToParameter)]
#[derive(Eq, PartialEq, Debug, DisplayDescription, FromValue, ToParameter, FromAbbrevStr)]
pub enum MoistureProduct {
#[description = "specific humidity"]
#[abbrev = "SPFH"]
Expand Down Expand Up @@ -143,7 +143,7 @@ pub enum MoistureProduct {
}

#[repr(u8)]
#[derive(Eq, PartialEq, Debug, DisplayDescription, FromValue, ToParameter)]
#[derive(Eq, PartialEq, Debug, DisplayDescription, FromValue, ToParameter, FromAbbrevStr)]
pub enum MomentumProduct {
#[description = "wind direction"]
#[abbrev = "WDIR"]
Expand Down Expand Up @@ -212,7 +212,7 @@ pub enum MomentumProduct {
}

#[repr(u8)]
#[derive(Eq, PartialEq, Debug, DisplayDescription, FromValue, ToParameter)]
#[derive(Eq, PartialEq, Debug, DisplayDescription, FromValue, ToParameter, FromAbbrevStr)]
pub enum CloudProduct {
#[description = "total cloud cover"]
#[abbrev = "TCDC"]
Expand All @@ -238,7 +238,7 @@ pub enum CloudProduct {
}

#[repr(u8)]
#[derive(Eq, PartialEq, Debug, DisplayDescription, FromValue, ToParameter)]
#[derive(Eq, PartialEq, Debug, DisplayDescription, FromValue, ToParameter, FromAbbrevStr)]
pub enum MassProduct {
#[abbrev = "PRES"]
#[unit = "pa"]
Expand All @@ -263,7 +263,7 @@ pub enum MassProduct {
}

#[repr(u8)]
#[derive(Eq, PartialEq, Debug, DisplayDescription, FromValue, ToParameter)]
#[derive(Eq, PartialEq, Debug, DisplayDescription, FromValue, ToParameter, FromAbbrevStr)]
pub enum RadarProduct {
#[description = "base spectrum width"]
#[abbrev = "BSWID"]
Expand All @@ -285,7 +285,7 @@ pub enum RadarProduct {
}

#[repr(u8)]
#[derive(Eq, PartialEq, Debug, DisplayDescription, FromValue, ToParameter)]
#[derive(Eq, PartialEq, Debug, DisplayDescription, FromValue, ToParameter, FromAbbrevStr)]
pub enum ForecastRadarImagery {
#[description = "echo top"]
#[abbrev = "RETOP"]
Expand All @@ -303,7 +303,7 @@ pub enum ForecastRadarImagery {
}

#[repr(u8)]
#[derive(Eq, PartialEq, Debug, DisplayDescription, FromValue, ToParameter)]
#[derive(Eq, PartialEq, Debug, DisplayDescription, FromValue, ToParameter, FromAbbrevStr)]
pub enum Electromagnetics {
#[abbrev = "LTNGSD"]
#[unit = "m-2 s-1"]
Expand Down Expand Up @@ -331,7 +331,7 @@ pub enum Electromagnetics {
}

#[repr(u8)]
#[derive(Eq, PartialEq, Debug, DisplayDescription, FromValue, ToParameter)]
#[derive(Eq, PartialEq, Debug, DisplayDescription, FromValue, ToParameter, FromAbbrevStr)]
pub enum PhysicalAtmosphericProperties {
#[description = "visibility"]
#[abbrev = "VIS"]
Expand Down
55 changes: 55 additions & 0 deletions macros/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -185,3 +185,58 @@ fn generate_parameter_attributes(enum_data: &ItemEnum) -> TokenStream {
}
}).into()
}


#[proc_macro_derive(FromAbbrevStr, attributes(name, abbrev))]
pub fn from_abbrev_str(input: TokenStream) -> TokenStream {
// Parse the input tokens into a syntax tree
let input = parse_macro_input!(input as DeriveInput);
let item: Item = input.into();

if let Item::Enum(e) = item {
// Build the output, possibly using quasi-quotation
let expanded = generate_from_abbrev_str(&e);

// Hand the output tokens back to the compiler
TokenStream::from(expanded)
} else {
panic!("Only Enums are supported for DisplayDescription!");
}
}

fn generate_from_abbrev_str(enum_data: &ItemEnum) -> TokenStream {
let name: &syn::Ident = &enum_data.ident;
let variants: &syn::punctuated::Punctuated<syn::Variant, syn::token::Comma> =
&enum_data.variants;
let variant_names = variants.into_iter().map(|v| v.ident.clone());

let variant_abbreviations = variants.into_iter().map(|v| {
let abbrev_attribute = v.attrs.iter().find(|a| a.path.is_ident("abbrev"));
match abbrev_attribute {
Some(a) => a
.tokens
.to_string()
.replace("=", "")
.replace("\"", "")
.trim()
.to_string(),
None => v.ident.to_string().to_lowercase(),
}
});

(quote! {
impl std::str::FromStr for #name {
type Err = gribberish_types::ParseAbbrevError;

fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
#(
#variant_abbreviations => Ok(#name::#variant_names),
)*
_ => Err(gribberish_types::ParseAbbrevError(format!("Unrecognised abbreviation: {s}"))),
}
}
}
})
.into()
}
15 changes: 12 additions & 3 deletions macros/tests/enum.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
use gribberish_macros::{DisplayDescription, FromValue, ToParameter};
use gribberish_macros::{DisplayDescription, FromAbbrevStr, FromValue, ToParameter};
use gribberish_types::Parameter;
use std::str::FromStr;

#[derive(Eq, PartialEq, Debug, DisplayDescription, FromValue, ToParameter)]
#[derive(Eq, PartialEq, Debug, DisplayDescription, FromValue, ToParameter, FromAbbrevStr)]
enum Shape {
#[description = "rectangle"]
#[abbrev = "rect"]
Expand Down Expand Up @@ -52,4 +53,12 @@ fn shape_parameter_attributes() {
let circle: Shape = 2u8.into();
assert_eq!(circle.unit(), "radius");
assert_eq!(circle.name(), "round one");
}
}

#[test]
fn shape_from_abbrev_str() {
assert_eq!(Shape::from_str("rect"), Ok(Shape::Rectangle));
assert_eq!(Shape::from_str("tri"), Ok(Shape::Triangle));
assert_eq!(Shape::from_str("cir"), Ok(Shape::Circle));
assert!(Shape::from_str("foo").is_err());
}
8 changes: 6 additions & 2 deletions types/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@

pub struct Parameter {
pub name: String,
pub unit: String,
pub abbrev: String,
}
}


#[derive(Debug, PartialEq, Eq)]
pub struct ParseAbbrevError(pub String);

Loading