Skip to content

Commit

Permalink
Add "impl bridges" to Component derive macro
Browse files Browse the repository at this point in the history
  • Loading branch information
jarrodldavis committed Mar 20, 2022
1 parent 5179721 commit 840b980
Show file tree
Hide file tree
Showing 2 changed files with 86 additions and 6 deletions.
40 changes: 38 additions & 2 deletions core/tests/component.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,10 @@
mod example_app;

use self::example_app::{ExampleApp, ExampleConfig};
use abscissa_core::{component, Component, FrameworkError, FrameworkErrorKind::ComponentError};
use abscissa_core::{
component, Application, Component, FrameworkError, FrameworkErrorKind::ComponentError, Shutdown,
};
use std::sync::atomic::{AtomicBool, Ordering};

/// ID for `FoobarComponent` (example component #1)
const FOOBAR_COMPONENT_ID: component::Id = component::Id::new("component::FoobarComponent");
Expand All @@ -30,7 +33,23 @@ impl FoobarComponent {

/// Example component #2
#[derive(Component, Debug, Default)]
pub struct BazComponent {}
#[component(after_config, before_shutdown)]
pub struct BazComponent {
pub after_config_run: bool,
pub before_shutdown_run: AtomicBool,
}

impl BazComponent {
fn after_config<A: Application>(&mut self, _config: &A::Cfg) -> Result<(), FrameworkError> {
self.after_config_run = true;
Ok(())
}

fn before_shutdown(&self, _kind: Shutdown) -> Result<(), FrameworkError> {
self.before_shutdown_run.store(true, Ordering::Relaxed);
Ok(())
}
}

/// Example component #3
#[derive(Component, Debug, Default)]
Expand Down Expand Up @@ -148,3 +167,20 @@ fn dependency_injection() {
let quux = registry.get_downcast_ref::<QuuxComponent>().unwrap();
assert_eq!(quux.foobar_state.as_ref().unwrap(), "original foobar state");
}

#[test]
fn impl_bridges() {
let mut registry = component::Registry::default();
let components = init_components();

registry.register(components).unwrap();
registry.after_config(&ExampleConfig::default()).unwrap();

let baz = registry.get_downcast_ref::<BazComponent>().unwrap();
assert!(baz.after_config_run);

registry
.shutdown(&ExampleApp::default(), Shutdown::Graceful)
.unwrap();
assert!(baz.before_shutdown_run.load(Ordering::Relaxed));
}
52 changes: 48 additions & 4 deletions derive/src/component.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ pub fn derive_component(s: Structure<'_>) -> TokenStream {
let attrs = ComponentAttributes::from_derive_input(s.ast());
let name = &s.ast().ident;
let abscissa_core = attrs.abscissa_core_crate();
let after_config = attrs.after_config();
let before_shutdown = attrs.before_shutdown();
let dependency_methods = attrs.dependency_methods();

s.gen_impl(quote! {
Expand All @@ -29,13 +31,21 @@ pub fn derive_component(s: Structure<'_>) -> TokenStream {
}

#dependency_methods

#after_config

#before_shutdown
}
})
}

/// Parsed `#[component(...)]` attribute fields
#[derive(Debug)]
struct ComponentAttributes {
after_config: bool,

before_shutdown: bool,

/// Special attribute used by `abscissa_core` to `derive(Component)`.
///
/// Workaround for using custom derive on traits defined in the same crate:
Expand All @@ -49,6 +59,8 @@ struct ComponentAttributes {
impl ComponentAttributes {
/// Parse component attributes from custom derive input.
pub fn from_derive_input(input: &DeriveInput) -> Self {
let mut after_config = false;
let mut before_shutdown = false;
let mut core = false;
let mut inject = Vec::new();

Expand All @@ -61,9 +73,12 @@ impl ComponentAttributes {
Meta::List(MetaList { nested, .. }) => {
for meta in &nested {
match meta {
NestedMeta::Meta(Meta::Path(path)) if path.is_ident("core") => {
core = true
}
NestedMeta::Meta(Meta::Path(path)) => match path.get_ident() {
Some(id) if id == "after_config" => after_config = true,
Some(id) if id == "before_shutdown" => before_shutdown = true,
Some(id) if id == "core" => core = true,
_ => panic!("malformed `component` attribute: {:?}", meta),
},
NestedMeta::Meta(Meta::NameValue { .. }) => {
inject.push(InjectAttribute::from_nested_meta(meta))
}
Expand All @@ -75,7 +90,12 @@ impl ComponentAttributes {
};
}

Self { core, inject }
Self {
after_config,
before_shutdown,
core,
inject,
}
}

/// Ident for the `abscissa_core` crate.
Expand All @@ -88,6 +108,30 @@ impl ComponentAttributes {
Ident::new(crate_name, Span::call_site())
}

pub fn after_config(&self) -> TokenStream {
if !self.after_config {
return quote!();
}

quote! {
fn after_config(&mut self, config: &A::Cfg) -> Result<(), FrameworkError> {
self.after_config::<A>(config)
}
}
}

pub fn before_shutdown(&self) -> TokenStream {
if !self.before_shutdown {
return quote!();
}

quote! {
fn before_shutdown(&self, kind: Shutdown) -> Result<(), FrameworkError> {
self.before_shutdown(kind)
}
}
}

/// Generate `Component::dependencies()` and `register_dependencies()`
pub fn dependency_methods(&self) -> TokenStream {
if self.inject.is_empty() {
Expand Down

0 comments on commit 840b980

Please sign in to comment.