Skip to content

Commit

Permalink
Merge pull request #241 from redbadger/viktor/relax-effect-macro
Browse files Browse the repository at this point in the history
Simplify construction of capabilities, so they don't require the app type
  • Loading branch information
StuartHarris authored May 20, 2024
2 parents 6993083 + 27eb671 commit f2bc473
Show file tree
Hide file tree
Showing 37 changed files with 54 additions and 82 deletions.
10 changes: 3 additions & 7 deletions crux_core/src/capability/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,6 @@
//! // Shell to dispatch side-effect requests to the right capability implementation
//! // (and, in some languages, checking that all necessary capabilities are implemented)
//! #[derive(Effect)]
//! #[effect(app = "MyApp")]
//! pub struct Capabilities {
//! pub render: Render<Event>
//! }
Expand Down Expand Up @@ -343,7 +342,7 @@ pub trait Capability<Ev> {
/// # }
/// # }
/// # }
/// impl crux_core::WithContext<App, Effect> for Capabilities {
/// impl crux_core::WithContext<Event, Effect> for Capabilities {
/// fn new_with_context(
/// context: crux_core::capability::ProtoContext<Effect, Event>,
/// ) -> Capabilities {
Expand All @@ -354,11 +353,8 @@ pub trait Capability<Ev> {
/// }
/// }
/// ```
pub trait WithContext<App, Ef>
where
App: crate::App,
{
fn new_with_context(context: ProtoContext<Ef, App::Event>) -> App::Capabilities;
pub trait WithContext<Ev, Ef> {
fn new_with_context(context: ProtoContext<Ef, Ev>) -> Self;
}

/// An interface for capabilities to interact with the app and the shell.
Expand Down
12 changes: 6 additions & 6 deletions crux_core/src/core/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,12 +44,12 @@ where
/// Create an instance of the Crux core to start a Crux application, e.g.
///
/// ```rust,ignore
/// let core: Core<HelloEffect, Hello> = Core::new::<HelloCapabilities>();
/// let core: Core<HelloEffect, Hello> = Core::new();
/// ```
///
pub fn new<Capabilities>() -> Self
pub fn new() -> Self
where
Capabilities: WithContext<A, Ef>,
A::Capabilities: WithContext<A::Event, Ef>,
{
let (request_sender, request_receiver) = capability::channel();
let (event_sender, event_receiver) = capability::channel();
Expand All @@ -60,7 +60,7 @@ where
model: Default::default(),
executor,
app: Default::default(),
capabilities: Capabilities::new_with_context(capability_context),
capabilities: <<A as App>::Capabilities>::new_with_context(capability_context),
requests: request_receiver,
capability_events: event_receiver,
}
Expand Down Expand Up @@ -128,9 +128,9 @@ impl<Ef, A> Default for Core<Ef, A>
where
Ef: Effect,
A: App,
A::Capabilities: WithContext<A, Ef>,
A::Capabilities: WithContext<A::Event, Ef>,
{
fn default() -> Self {
Self::new::<A::Capabilities>()
Self::new()
}
}
1 change: 0 additions & 1 deletion crux_core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,6 @@
//!// will use to request side effects from the Shell
//!#[cfg_attr(feature = "typegen", derive(crux_core::macros::Export))]
//!#[derive(Effect)]
//!#[effect(app = "Hello")]
//!pub struct Capabilities {
//! pub render: Render<Event>,
//!}
Expand Down
2 changes: 1 addition & 1 deletion crux_core/src/testing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ where
impl<App, Ef> Default for AppTester<App, Ef>
where
App: crate::App,
App::Capabilities: WithContext<App, Ef>,
App::Capabilities: WithContext<App::Event, Ef>,
App::Event: Send,
Ef: Send + 'static,
{
Expand Down
5 changes: 2 additions & 3 deletions crux_core/tests/capability_runtime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,6 @@ mod app {
}

#[derive(Effect)]
#[effect(app = "MyApp")]
pub struct Capabilities {
crawler: super::capability::Crawler<Event>,
render: crux_core::render::Render<Event>,
Expand Down Expand Up @@ -129,11 +128,11 @@ mod tests {
use crux_core::Core;
use rand::prelude::*;

use super::app::{Capabilities, Effect, Event, MyApp};
use super::app::{Effect, Event, MyApp};

#[test]
fn fetches_a_tree() {
let core: Core<Effect, MyApp> = Core::new::<Capabilities>();
let core: Core<Effect, MyApp> = Core::new();

let mut effects: VecDeque<Effect> = core.process_event(Event::Fetch).into();

Expand Down
6 changes: 2 additions & 4 deletions crux_macros/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,6 @@ than `App`, you can specify its name:

```rust
#[derive(Effect)]
#[effect(app = "MyApp")]
pub struct Capabilities {
pub render: Render<Event>,
}
Expand All @@ -68,7 +67,6 @@ this:
```rust
#[derive(Effect)]
#[effect(name = "MyEffect")]
#[effect(app = "MyApp")]
pub struct Capabilities {
pub render: Render<Event>,
}
Expand All @@ -78,7 +76,7 @@ Or, more idiomatically, combine them into one usage, like this:

```rust
#[derive(Effect)]
#[effect(name = "MyEffect", app = "MyApp")]
#[effect(name = "MyEffect")]
pub struct Capabilities {
pub render: Render<Event>,
}
Expand All @@ -88,7 +86,7 @@ Full usage might look something like this:

```rust
#[derive(Effect)]
#[effect(name = "MyEffect", app = "MyApp")]
#[effect(name = "MyEffect")]
pub struct CatFactCapabilities {
pub http: Http<MyEvent>,
pub key_value: KeyValue<MyEvent>,
Expand Down
21 changes: 6 additions & 15 deletions crux_macros/src/effect.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use darling::{ast, util, FromDeriveInput, FromField, FromMeta, ToTokens};
use darling::{ast, util, FromDeriveInput, FromField, ToTokens};
use proc_macro2::{Literal, TokenStream};
use proc_macro_error::{abort_call_site, OptionExt};
use quote::{format_ident, quote};
Expand All @@ -10,7 +10,6 @@ use syn::{DeriveInput, GenericArgument, Ident, PathArguments, Type};
struct EffectStructReceiver {
ident: Ident,
name: Option<Ident>,
app: Option<Type>,
data: ast::Data<util::Ignored, EffectFieldReceiver>,
}

Expand Down Expand Up @@ -56,14 +55,6 @@ impl ToTokens for EffectStructReceiver {
None => (quote!(Effect), quote!(EffectFfi), quote!("Effect")),
};

let app = match self.app {
Some(ref app) => quote!(#app),
None => {
let x = Type::from_string("App").unwrap();
quote!(#x)
}
};

let fields = self
.data
.as_ref()
Expand Down Expand Up @@ -166,7 +157,7 @@ impl ToTokens for EffectStructReceiver {
}
}

impl ::crux_core::WithContext<#app, #effect_name> for #ident {
impl ::crux_core::WithContext<#event, #effect_name> for #ident {
fn new_with_context(context: ::crux_core::capability::ProtoContext<#effect_name, #event>) -> #ident {
#ident {
#(#with_context_fields ,)*
Expand Down Expand Up @@ -262,7 +253,7 @@ mod tests {
}
}
}
impl ::crux_core::WithContext<App, Effect> for Capabilities {
impl ::crux_core::WithContext<Event, Effect> for Capabilities {
fn new_with_context(
context: ::crux_core::capability::ProtoContext<Effect, Event>,
) -> Capabilities {
Expand Down Expand Up @@ -325,7 +316,7 @@ mod tests {
}
}
}
impl ::crux_core::WithContext<App, Effect> for Capabilities {
impl ::crux_core::WithContext<Event, Effect> for Capabilities {
fn new_with_context(
context: ::crux_core::capability::ProtoContext<Effect, Event>,
) -> Capabilities {
Expand Down Expand Up @@ -363,7 +354,7 @@ mod tests {
fn full() {
let input = r#"
#[derive(Effect)]
#[effect(name = "MyEffect", app = "MyApp")]
#[effect(name = "MyEffect")]
pub struct MyCapabilities {
pub http: crux_http::Http<MyEvent>,
pub key_value: KeyValue<MyEvent>,
Expand Down Expand Up @@ -441,7 +432,7 @@ mod tests {
}
}
}
impl ::crux_core::WithContext<MyApp, MyEffect> for MyCapabilities {
impl ::crux_core::WithContext<MyEvent, MyEffect> for MyCapabilities {
fn new_with_context(
context: ::crux_core::capability::ProtoContext<MyEffect, MyEvent>,
) -> MyCapabilities {
Expand Down
2 changes: 0 additions & 2 deletions crux_macros/src/export.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,6 @@ use syn::{DeriveInput, GenericArgument, Ident, PathArguments, Type};
struct ExportStructReceiver {
ident: Ident,
name: Option<Ident>, // also used by the effect derive macro to name the effect
#[allow(dead_code)] // `app` is used by the effect derive macro only
app: Option<Type>,
data: ast::Data<util::Ignored, ExportFieldReceiver>,
}

Expand Down
2 changes: 1 addition & 1 deletion crux_macros/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ use syn::parse_macro_input;
/// # }
/// # }
/// #[derive(Effect)]
/// #[effect(name = "MyEffect", app = "MyApp")]
/// #[effect(name = "MyEffect")]
/// pub struct MyCapabilities {
/// pub http: crux_http::Http<MyEvent>,
/// pub render: Render<MyEvent>,
Expand Down
4 changes: 2 additions & 2 deletions docs/src/getting_started/core.md
Original file line number Diff line number Diff line change
Expand Up @@ -235,12 +235,12 @@ pub struct Capabilities {
}
```
The `Export` and `Effect` derive macros can be configured with the `effect` attribute if you need to specify the name of the effect type, and/or the name of your `App` e.g.:
The `Export` and `Effect` derive macros can be configured with the `effect` attribute if you need to specify a different name for the Effect type e.g.:
```rust,ignore
#[cfg_attr(feature = "typegen", derive(Export))]
#[derive(Effect)]
#[effect(name = "MyEffect", app = "MyApp")]
#[effect(name = "MyEffect")]
pub struct Capabilities {
render: Render<Event>,
pub_sub: PubSub<Event>,
Expand Down
2 changes: 0 additions & 2 deletions docs/src/guide/hello_world.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,6 @@ use crux_core::render::Render;
use crux_core::macros::Effect;
#[derive(Effect)]
#[effect(app = "Hello")]
pub struct Capabilities {
render: Render<Event>,
}
Expand All @@ -118,7 +117,6 @@ use serde::{Deserialize, Serialize};
#[cfg_attr(feature = "typegen", derive(crux_core::macros::Export))]
#[derive(Effect)]
#[effect(app = "Hello")]
pub struct Capabilities {
render: Render<Event>,
}
Expand Down
1 change: 0 additions & 1 deletion docs/src/guide/testing.md
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,6 @@ our `Capabilities` struct looked like this...
#[cfg_attr(feature = "typegen", derive(crux_core::macros::Export))]
#[derive(Effect)]
#[effect(app = "NoteEditor")]
pub struct Capabilities {
timer: Timer<Event>,
render: Render<Event>,
Expand Down
4 changes: 2 additions & 2 deletions examples/bridge_echo/cli/src/core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@ use crossbeam_channel::Sender;
use std::sync::Arc;
use tracing::debug;

use shared::{App, Capabilities, Effect, Event};
use shared::{App, Effect, Event};

pub type Core = Arc<shared::Core<Effect, App>>;

pub fn new() -> Core {
Arc::new(shared::Core::new::<Capabilities>())
Arc::new(shared::Core::new())
}

pub fn update(core: &Core, event: Event, tx: &Arc<Sender<Effect>>) -> Result<()> {
Expand Down
2 changes: 1 addition & 1 deletion examples/bridge_echo/shared/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ pub use app::*;
uniffi::include_scaffolding!("shared");

lazy_static! {
static ref CORE: Bridge<Effect, App> = Bridge::new(Core::new::<Capabilities>());
static ref CORE: Bridge<Effect, App> = Bridge::new(Core::new());
}

#[wasm_bindgen]
Expand Down
4 changes: 2 additions & 2 deletions examples/bridge_echo/web-leptos/src/core.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
use std::rc::Rc;

use leptos::{SignalUpdate, WriteSignal};
use shared::{App, Capabilities, Effect, Event, ViewModel};
use shared::{App, Effect, Event, ViewModel};

pub type Core = Rc<shared::Core<Effect, App>>;

pub fn new() -> Core {
Rc::new(shared::Core::new::<Capabilities>())
Rc::new(shared::Core::new())
}

pub fn update(core: &Core, event: Event, render: WriteSignal<ViewModel>) {
Expand Down
4 changes: 2 additions & 2 deletions examples/cat_facts/cli/src/core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,15 @@ use shared::{
},
platform::PlatformResponse,
time::{Instant, TimeResponse},
CatFactCapabilities, CatFacts, Effect, Event,
CatFacts, Effect, Event,
};

use crate::http;

pub type Core = Arc<shared::Core<Effect, CatFacts>>;

pub fn new() -> Core {
Arc::new(shared::Core::new::<CatFactCapabilities>())
Arc::new(shared::Core::new())
}

pub fn update(core: &Core, event: Event, tx: &Arc<Sender<Effect>>) -> Result<()> {
Expand Down
1 change: 0 additions & 1 deletion examples/cat_facts/shared/src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,6 @@ pub struct CatFacts {

#[cfg_attr(feature = "typegen", derive(crux_core::macros::Export))]
#[derive(crux_core::macros::Effect)]
#[effect(app = "CatFacts")]
pub struct CatFactCapabilities {
pub http: Http<Event>,
pub key_value: KeyValue<Event>,
Expand Down
2 changes: 1 addition & 1 deletion examples/cat_facts/shared/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ pub use app::*;
uniffi::include_scaffolding!("shared");

lazy_static! {
static ref CORE: Bridge<Effect, CatFacts> = Bridge::new(Core::new::<CatFactCapabilities>());
static ref CORE: Bridge<Effect, CatFacts> = Bridge::new(Core::new());
}

#[wasm_bindgen]
Expand Down
4 changes: 2 additions & 2 deletions examples/cat_facts/web-yew/src/core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use gloo_console::log;
use shared::{
platform::PlatformResponse,
time::{Instant, TimeResponse},
CatFactCapabilities, CatFacts, Effect, Event,
CatFacts, Effect, Event,
};
use std::rc::Rc;
use yew::{platform::spawn_local, Callback};
Expand All @@ -17,7 +17,7 @@ pub enum Message {
}

pub fn new() -> Core {
Rc::new(shared::Core::new::<CatFactCapabilities>())
Rc::new(shared::Core::new())
}

pub fn update(core: &Core, event: Event, callback: &Callback<Message>) {
Expand Down
4 changes: 2 additions & 2 deletions examples/counter/cli/src/core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,14 @@ use std::sync::Arc;
use tokio::spawn;
use tracing::debug;

use shared::{App, Capabilities, Effect, Event};
use shared::{App, Effect, Event};

use crate::{http, sse};

pub type Core = Arc<shared::Core<Effect, App>>;

pub fn new() -> Core {
Arc::new(shared::Core::new::<Capabilities>())
Arc::new(shared::Core::new())
}

pub fn update(core: &Core, event: Event, tx: &Arc<Sender<Effect>>) -> Result<()> {
Expand Down
2 changes: 1 addition & 1 deletion examples/counter/shared/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ pub use capabilities::sse;
uniffi::include_scaffolding!("shared");

lazy_static! {
static ref CORE: Bridge<Effect, App> = Bridge::new(Core::new::<Capabilities>());
static ref CORE: Bridge<Effect, App> = Bridge::new(Core::new());
}

#[wasm_bindgen]
Expand Down
Loading

0 comments on commit f2bc473

Please sign in to comment.