Skip to content

Commit

Permalink
Merge pull request #258 from redbadger/push-oxvxzmluqnsm
Browse files Browse the repository at this point in the history
Delegate type registration to capabilities
  • Loading branch information
StuartHarris authored Jul 12, 2024
2 parents 0efb48b + 6c451a2 commit 375ea1a
Show file tree
Hide file tree
Showing 4 changed files with 49 additions and 161 deletions.
10 changes: 10 additions & 0 deletions crux_core/src/capabilities/compose.rs
Original file line number Diff line number Diff line change
Expand Up @@ -157,4 +157,14 @@ impl<Ev> Capability<Ev> for Compose<Ev> {
{
Compose::new(self.context.map_event(f))
}

#[cfg(feature = "typegen")]
fn register_types(_generator: &mut crate::typegen::TypeGen) -> crate::typegen::Result {
panic!(
r#"
The Compose Capability should not be registered for type generation.
Instead, use #[effect(skip)] to skip the generation of an effect variant for the Compose Capability.
"#
)
}
}
21 changes: 14 additions & 7 deletions crux_core/src/capability/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,7 @@ mod shell_request;
mod shell_stream;

use futures::Future;
use serde::de::DeserializeOwned;
use std::sync::Arc;

pub(crate) use channel::channel;
Expand Down Expand Up @@ -237,7 +238,6 @@ pub trait Operation: serde::Serialize + PartialEq + Send + 'static {
/// # }
///
/// ```

#[derive(Debug, PartialEq, serde::Serialize, serde::Deserialize)]
pub enum Never {}

Expand All @@ -256,19 +256,19 @@ impl Operation for Never {
/// ```rust
/// # use crux_core::{Capability, capability::{CapabilityContext, Operation}};
/// # pub struct Http<Ev> {
/// # context: CapabilityContext<HttpOperation, Ev>,
/// # context: CapabilityContext<HttpRequest, Ev>,
/// # }
/// # #[derive(serde::Serialize, PartialEq, Eq)] pub struct HttpOperation;
/// # impl Operation for HttpOperation {
/// # #[derive(serde::Serialize, serde::Deserialize, PartialEq, Eq)] pub struct HttpRequest;
/// # impl Operation for HttpRequest {
/// # type Output = ();
/// # }
/// # impl<Ev> Http<Ev> where Ev: 'static, {
/// # pub fn new(context: CapabilityContext<HttpOperation, Ev>) -> Self {
/// # pub fn new(context: CapabilityContext<HttpRequest, Ev>) -> Self {
/// # Self { context }
/// # }
/// # }
/// impl<Ev> Capability<Ev> for Http<Ev> {
/// type Operation = HttpOperation;
/// type Operation = HttpRequest;
/// type MappedSelf<MappedEv> = Http<MappedEv>;
///
/// fn map_event<F, NewEvent>(&self, f: F) -> Self::MappedSelf<NewEvent>
Expand All @@ -282,7 +282,7 @@ impl Operation for Never {
/// }
/// ```
pub trait Capability<Ev> {
type Operation: Operation;
type Operation: Operation + DeserializeOwned;

type MappedSelf<MappedEv>;

Expand All @@ -291,6 +291,13 @@ pub trait Capability<Ev> {
F: Fn(NewEv) -> Ev + Send + Sync + 'static,
Ev: 'static,
NewEv: 'static + Send;

#[cfg(feature = "typegen")]
fn register_types(generator: &mut crate::typegen::TypeGen) -> crate::typegen::Result {
generator.register_type::<Self::Operation>()?;
generator.register_type::<<Self::Operation as Operation>::Output>()?;
Ok(())
}
}

/// Allows Crux to construct app's set of required capabilities, providing context
Expand Down
176 changes: 23 additions & 153 deletions crux_macros/src/export.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,14 +47,15 @@ impl ToTokens for ExportStructReceiver {

for (capability, event) in fields.iter().map(|f| split_on_generic(&f.ty)) {
output_type_exports.push(quote! {
generator.register_type::<<#capability<#event> as ::crux_core::capability::Capability<#event>>::Operation>()?;
generator
.register_type::<<<#capability<#event> as ::crux_core::capability::Capability<#event>>::Operation as ::crux_core::capability::Operation>::Output>()?;
#capability::<#event>::register_types(generator)?;
});
}

tokens.extend(quote! {
use ::crux_core::capability::Capability;

impl ::crux_core::typegen::Export for #ident {
#[cfg(feature = "typegen")]
fn register_types(generator: &mut ::crux_core::typegen::TypeGen) -> ::crux_core::typegen::Result {
#(#output_type_exports)*

Expand Down Expand Up @@ -129,22 +130,13 @@ mod tests {
let actual = quote!(#input);

insta::assert_snapshot!(pretty_print(&actual), @r###"
use ::crux_core::capability::Capability;
impl ::crux_core::typegen::Export for Capabilities {
#[cfg(feature = "typegen")]
fn register_types(
generator: &mut ::crux_core::typegen::TypeGen,
) -> ::crux_core::typegen::Result {
generator
.register_type::<
<Render<Event> as ::crux_core::capability::Capability<Event>>::Operation,
>()?;
generator
.register_type::<
<<Render<
Event,
> as ::crux_core::capability::Capability<
Event,
>>::Operation as ::crux_core::capability::Operation>::Output,
>()?;
Render::<Event>::register_types(generator)?;
generator.register_type::<EffectFfi>()?;
generator.register_type::<::crux_core::bridge::Request<EffectFfi>>()?;
Ok(())
Expand Down Expand Up @@ -186,66 +178,16 @@ mod tests {
let actual = quote!(#input);

insta::assert_snapshot!(pretty_print(&actual), @r###"
use ::crux_core::capability::Capability;
impl ::crux_core::typegen::Export for MyCapabilities {
#[cfg(feature = "typegen")]
fn register_types(
generator: &mut ::crux_core::typegen::TypeGen,
) -> ::crux_core::typegen::Result {
generator
.register_type::<
<crux_http::Http<
MyEvent,
> as ::crux_core::capability::Capability<MyEvent>>::Operation,
>()?;
generator
.register_type::<
<<crux_http::Http<
MyEvent,
> as ::crux_core::capability::Capability<
MyEvent,
>>::Operation as ::crux_core::capability::Operation>::Output,
>()?;
generator
.register_type::<
<KeyValue<
MyEvent,
> as ::crux_core::capability::Capability<MyEvent>>::Operation,
>()?;
generator
.register_type::<
<<KeyValue<
MyEvent,
> as ::crux_core::capability::Capability<
MyEvent,
>>::Operation as ::crux_core::capability::Operation>::Output,
>()?;
generator
.register_type::<
<Platform<
MyEvent,
> as ::crux_core::capability::Capability<MyEvent>>::Operation,
>()?;
generator
.register_type::<
<<Platform<
MyEvent,
> as ::crux_core::capability::Capability<
MyEvent,
>>::Operation as ::crux_core::capability::Operation>::Output,
>()?;
generator
.register_type::<
<Render<
MyEvent,
> as ::crux_core::capability::Capability<MyEvent>>::Operation,
>()?;
generator
.register_type::<
<<Render<
MyEvent,
> as ::crux_core::capability::Capability<
MyEvent,
>>::Operation as ::crux_core::capability::Operation>::Output,
>()?;
crux_http::Http::<MyEvent>::register_types(generator)?;
KeyValue::<MyEvent>::register_types(generator)?;
Platform::<MyEvent>::register_types(generator)?;
Render::<MyEvent>::register_types(generator)?;
generator.register_type::<EffectFfi>()?;
generator.register_type::<::crux_core::bridge::Request<EffectFfi>>()?;
Ok(())
Expand All @@ -272,80 +214,17 @@ mod tests {
let actual = quote!(#input);

insta::assert_snapshot!(pretty_print(&actual), @r###"
use ::crux_core::capability::Capability;
impl ::crux_core::typegen::Export for MyCapabilities {
#[cfg(feature = "typegen")]
fn register_types(
generator: &mut ::crux_core::typegen::TypeGen,
) -> ::crux_core::typegen::Result {
generator
.register_type::<
<crux_http::Http<
MyEvent,
> as ::crux_core::capability::Capability<MyEvent>>::Operation,
>()?;
generator
.register_type::<
<<crux_http::Http<
MyEvent,
> as ::crux_core::capability::Capability<
MyEvent,
>>::Operation as ::crux_core::capability::Operation>::Output,
>()?;
generator
.register_type::<
<KeyValue<
MyEvent,
> as ::crux_core::capability::Capability<MyEvent>>::Operation,
>()?;
generator
.register_type::<
<<KeyValue<
MyEvent,
> as ::crux_core::capability::Capability<
MyEvent,
>>::Operation as ::crux_core::capability::Operation>::Output,
>()?;
generator
.register_type::<
<Platform<
MyEvent,
> as ::crux_core::capability::Capability<MyEvent>>::Operation,
>()?;
generator
.register_type::<
<<Platform<
MyEvent,
> as ::crux_core::capability::Capability<
MyEvent,
>>::Operation as ::crux_core::capability::Operation>::Output,
>()?;
generator
.register_type::<
<Render<
MyEvent,
> as ::crux_core::capability::Capability<MyEvent>>::Operation,
>()?;
generator
.register_type::<
<<Render<
MyEvent,
> as ::crux_core::capability::Capability<
MyEvent,
>>::Operation as ::crux_core::capability::Operation>::Output,
>()?;
generator
.register_type::<
<Time<
MyEvent,
> as ::crux_core::capability::Capability<MyEvent>>::Operation,
>()?;
generator
.register_type::<
<<Time<
MyEvent,
> as ::crux_core::capability::Capability<
MyEvent,
>>::Operation as ::crux_core::capability::Operation>::Output,
>()?;
crux_http::Http::<MyEvent>::register_types(generator)?;
KeyValue::<MyEvent>::register_types(generator)?;
Platform::<MyEvent>::register_types(generator)?;
Render::<MyEvent>::register_types(generator)?;
Time::<MyEvent>::register_types(generator)?;
generator.register_type::<EffectFfi>()?;
generator.register_type::<::crux_core::bridge::Request<EffectFfi>>()?;
Ok(())
Expand All @@ -370,22 +249,13 @@ mod tests {
let actual = quote!(#input);

insta::assert_snapshot!(pretty_print(&actual), @r###"
use ::crux_core::capability::Capability;
impl ::crux_core::typegen::Export for Capabilities {
#[cfg(feature = "typegen")]
fn register_types(
generator: &mut ::crux_core::typegen::TypeGen,
) -> ::crux_core::typegen::Result {
generator
.register_type::<
<Render<Event> as ::crux_core::capability::Capability<Event>>::Operation,
>()?;
generator
.register_type::<
<<Render<
Event,
> as ::crux_core::capability::Capability<
Event,
>>::Operation as ::crux_core::capability::Operation>::Output,
>()?;
Render::<Event>::register_types(generator)?;
generator.register_type::<MyEffectFfi>()?;
generator.register_type::<::crux_core::bridge::Request<MyEffectFfi>>()?;
Ok(())
Expand Down
3 changes: 2 additions & 1 deletion examples/counter/web-nextjs/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,5 +24,6 @@
"@types/node": "20.14.9",
"@types/react": "18.3.3",
"@types/react-dom": "18.3.0"
}
},
"packageManager": "[email protected]+sha1.48be3292711ad554fe944f6caaf9b0f5477524fe"
}

0 comments on commit 375ea1a

Please sign in to comment.