Skip to content

Commit

Permalink
start on adding data adapters to macro
Browse files Browse the repository at this point in the history
  • Loading branch information
wilyle committed Jan 19, 2024
1 parent fdf8454 commit 1c1c838
Show file tree
Hide file tree
Showing 8 changed files with 99 additions and 14 deletions.
7 changes: 7 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ strum_macros = "0.25.3"
syn = { version = "2.0.40", features = ["extra-traits", "full"] }
tempfile = "3.9.0"
time = "0.3.31"
tuple_list = "0.1.3"
tokio = { version = "1.35", features = ["macros", "rt-multi-thread", "time", "sync", "test-util"] }
tokio-stream = { version = "0.1.8", features = ["net"] }
tonic = "0.10.0"
Expand Down
2 changes: 2 additions & 0 deletions freyja/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ freyja-common = { workspace = true }
log = { workspace = true }
proc-macros = { workspace = true }
time = { workspace = true }
tuple_list = { workspace = true }
tokio = { workspace = true }

grpc-data-adapter = { workspace = true }
Expand All @@ -34,3 +35,4 @@ in-memory-mock-digital-twin-adapter = { workspace = true }
in-memory-mock-mapping-adapter = { workspace = true }
mock-digital-twin-adapter = { workspace = true }
mock-mapping-service-adapter = { workspace = true }
grpc-data-adapter = { workspace = true }
8 changes: 7 additions & 1 deletion freyja/examples/in-memory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,11 @@
use in_memory_mock_cloud_adapter::in_memory_mock_cloud_adapter::InMemoryMockCloudAdapter;
use in_memory_mock_digital_twin_adapter::in_memory_mock_digital_twin_adapter::InMemoryMockDigitalTwinAdapter;
use in_memory_mock_mapping_adapter::in_memory_mock_mapping_adapter::InMemoryMockMappingAdapter;
use grpc_data_adapter::grpc_data_adapter_factory::GRPCDataAdapterFactory;

freyja::freyja_main! {InMemoryMockDigitalTwinAdapter, InMemoryMockCloudAdapter, InMemoryMockMappingAdapter}
freyja::freyja_main! {
InMemoryMockDigitalTwinAdapter,
InMemoryMockCloudAdapter,
InMemoryMockMappingAdapter,
[GRPCDataAdapterFactory],
}
8 changes: 7 additions & 1 deletion freyja/examples/mocks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,11 @@
use in_memory_mock_cloud_adapter::in_memory_mock_cloud_adapter::InMemoryMockCloudAdapter;
use mock_digital_twin_adapter::mock_digital_twin_adapter::MockDigitalTwinAdapter;
use mock_mapping_service_adapter::mock_mapping_service_adapter::MockMappingServiceAdapter;
use grpc_data_adapter::grpc_data_adapter_factory::GRPCDataAdapterFactory;

freyja::freyja_main! {MockDigitalTwinAdapter, InMemoryMockCloudAdapter, MockMappingServiceAdapter}
freyja::freyja_main! {
MockDigitalTwinAdapter,
InMemoryMockCloudAdapter,
MockMappingServiceAdapter,
[GRPCDataAdapterFactory],
}
1 change: 1 addition & 0 deletions proc_macros/src/freyja_main/generate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ pub(crate) fn generate(ir: FreyjaMainOutput) -> TokenStream {
dt_adapter_type,
cloud_adapter_type,
mapping_adapter_type,
data_adapter_factory_types,
},
} = ir;

Expand Down
74 changes: 64 additions & 10 deletions proc_macros/src/freyja_main/parse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
// SPDX-License-Identifier: MIT

use proc_macro2::TokenStream;
use syn::bracketed;
use syn::parse::{Parse, ParseStream};
use syn::{punctuated::Punctuated, Ident, Token};

Expand All @@ -21,6 +22,7 @@ pub(crate) struct FreyjaMainArgs {
pub dt_adapter_type: Ident,
pub cloud_adapter_type: Ident,
pub mapping_adapter_type: Ident,
pub data_adapter_factory_types: Vec<Ident>,
}

impl Parse for FreyjaMainArgs {
Expand All @@ -30,16 +32,35 @@ impl Parse for FreyjaMainArgs {
///
/// - `input`: the input stream
fn parse(input: ParseStream) -> syn::Result<Self> {
let mut args = Punctuated::<Ident, Token![,]>::parse_terminated(input)?.into_iter();

if args.len() != 3 {
panic!("Expected exactly three arguments to freyja_main");
let dt_adapter_type = input.parse::<Ident>().unwrap();
let _ = input.parse::<Token![,]>().unwrap();
let cloud_adapter_type = input.parse::<Ident>().unwrap();
let _ = input.parse::<Token![,]>().unwrap();
let mapping_adapter_type = input.parse::<Ident>().unwrap();
let _ = input.parse::<Token![,]>().unwrap();

let data_adapter_content;
let _ = bracketed!(data_adapter_content in input);
let data_adapter_factory_types = Punctuated::<Ident, Token![,]>::parse_terminated(&data_adapter_content)
.unwrap()
.into_iter()
.collect();

let trailing_comma_result = if !input.is_empty() {
Some(input.parse::<Token![,]>())
} else {
None
};

if !input.is_empty() || trailing_comma_result.is_some_and(|r| r.is_err()) {
panic!("Unexpected tokens at end of input");
}

Ok(FreyjaMainArgs {
dt_adapter_type: args.next().unwrap(),
cloud_adapter_type: args.next().unwrap(),
mapping_adapter_type: args.next().unwrap(),
dt_adapter_type,
cloud_adapter_type,
mapping_adapter_type,
data_adapter_factory_types,
})
}
}
Expand All @@ -56,25 +77,33 @@ mod freyja_main_parse_tests {
let foo_ident = format_ident!("Foo");
let bar_ident = format_ident!("Bar");
let baz_ident = format_ident!("Baz");
let factory_idents = vec![ format_ident!("DA1"), format_ident!("DA2") ];
let factory_idents_clone = factory_idents.clone();

let input = quote! { #foo_ident, #bar_ident, #baz_ident };
let input = quote! { #foo_ident, #bar_ident, #baz_ident, [#(#factory_idents),*] };
let output = parse(input);

assert_eq!(output.dt_adapter_type, foo_ident);
assert_eq!(output.cloud_adapter_type, bar_ident);
assert_eq!(output.mapping_adapter_type, baz_ident);
for ident in factory_idents.iter() {
assert!(output.data_adapter_factory_types.contains(&ident));
}

// Now try a different order
let input = quote! { #baz_ident, #foo_ident, #bar_ident };
let input = quote! { #baz_ident, #foo_ident, #bar_ident, [#(#factory_idents_clone),*] };
let output = parse(input);

assert_eq!(output.dt_adapter_type, baz_ident);
assert_eq!(output.cloud_adapter_type, foo_ident);
assert_eq!(output.mapping_adapter_type, bar_ident);
for ident in factory_idents {
assert!(output.data_adapter_factory_types.contains(&ident));
}
}

#[test]
fn parse_panics_with_incorrect_number_of_arguments() {
fn parse_panics_with_invalid_input() {
let foo_ident = format_ident!("Foo");
let bar_ident = format_ident!("Bar");
let baz_ident = format_ident!("Baz");
Expand All @@ -88,4 +117,29 @@ mod freyja_main_parse_tests {
let result = catch_unwind(|| parse(input));
assert!(result.is_err());
}

#[test]
fn parse_accepts_trailing_comma() {
let foo_ident = format_ident!("Foo");
let bar_ident = format_ident!("Bar");
let baz_ident = format_ident!("Baz");
let factory_idents = vec![ format_ident!("DA1"), format_ident!("DA2") ];

let input = quote! { #foo_ident, #bar_ident, #baz_ident, [#(#factory_idents),*], };
let result = catch_unwind(|| parse(input));
assert!(result.is_ok());
}

#[test]
fn parse_panics_with_invalid_trailing_content() {
let foo_ident = format_ident!("Foo");
let bar_ident = format_ident!("Bar");
let baz_ident = format_ident!("Baz");
let factory_idents = vec![ format_ident!("DA1"), format_ident!("DA2") ];
let qux_ident = format_ident!("Qux");

let input = quote! { #foo_ident, #bar_ident, #baz_ident, [#(#factory_idents),*], #qux_ident };
let result = catch_unwind(|| parse(input));
assert!(result.is_err());
}
}
12 changes: 10 additions & 2 deletions proc_macros/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ pub fn error(ts: TokenStream) -> TokenStream {
///
/// *FreyjaMainPredicate*:
///
/// &nbsp;&nbsp;&nbsp;&nbsp;*DigitalTwinAdapterType* `,` *CloudAdapterType* `,` *MappingClientType*
/// &nbsp;&nbsp;&nbsp;&nbsp;*DigitalTwinAdapterType* `,` *CloudAdapterType* `,` *MappingAdapterType* `, [` *DataAdapterTypeList* `]`
///
/// *DigitalTwinAdapterType*:
///
Expand All @@ -93,9 +93,17 @@ pub fn error(ts: TokenStream) -> TokenStream {
///
/// &nbsp;&nbsp;&nbsp;&nbsp;IDENTIFIER
///
/// *MappingClientType*:
/// *MappingAdapterType*:
///
/// &nbsp;&nbsp;&nbsp;&nbsp;IDENTIFIER
///
/// *DataAdapterTypeList*:
///
/// &nbsp;&nbsp;&nbsp;&nbsp;*DataAdapterType* (`,` *DataAdapterTypeList*)
///
/// *DataAdapterType*:
///
/// &nbsp;&nbsp;&nbsp;&nbsp;IDENTIFIER
///
/// Note that the accepted syntax for each of the adapter types is only an identifier.
/// This means that fully qualified types like `my_crate::MyAdapter`
Expand Down

0 comments on commit 1c1c838

Please sign in to comment.