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

refactor: reduce event bus provider boilerplate code #391

Open
wants to merge 3 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
13 changes: 13 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 @@ -202,6 +202,7 @@ pallet-storage-providers-runtime-api = { path = "pallets/providers/runtime-api",

# Local - StorageHub Client (used by the node, can be std or no_std)
shc-actors-framework = { path = "client/actors-framework", default-features = false }
shc-actors-derive = { path = "client/actors-derive", default-features = false }
shc-blockchain-service = { path = "client/blockchain-service", default-features = false }
shc-file-transfer-service = { path = "client/file-transfer-service", default-features = false }
shc-indexer-service = { path = "client/indexer-service", default-features = false }
Expand Down
24 changes: 24 additions & 0 deletions client/actors-derive/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
[package]
name = "shc-actors-derive"
description = "Procedural macros for the StorageHub actors framework"
version = "0.1.0"
homepage = { workspace = true }
license = { workspace = true }
authors = { workspace = true }
repository = { workspace = true }
edition = { workspace = true }

[lints]
workspace = true

[lib]
proc-macro = true

[dependencies]
proc-macro2 = "1.0.79"
quote = "1.0.35"
syn = { version = "2.0.52", features = ["full", "extra-traits"] }
once_cell = "1.18.0"

# Local dependencies
shc-actors-framework = { workspace = true }
119 changes: 119 additions & 0 deletions client/actors-derive/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
# StorageHub Actors Derive

This crate provides procedural macros to reduce boilerplate code in the StorageHub actors framework.

## Features

- `ActorEvent` derive macro: Implements `EventBusMessage` for event structs and registers them with a specific actor.
- `ActorEventBus` attribute macro: Generates the event bus provider struct and implements all the required methods and traits.

## Usage

First, add the dependency to your crate by including it in your Cargo.toml:

```toml
[dependencies]
shc-actors-derive = { workspace = true }
```

### 1. Defining Event Messages

Import the macros directly and use the `ActorEvent` derive macro:

```rust
use shc_actors_derive::ActorEvent;

#[derive(Debug, Clone, ActorEvent)]
#[actor(actor = "blockchain_service")]
pub struct NewChallengeSeed {
pub provider_id: String,
pub tick: u32,
pub seed: Vec<u8>,
}
```

This will:
- Implement `EventBusMessage` for the struct
- Register the event with the specified actor ID (`blockchain_service` in this example)

### 2. Creating Event Bus Providers

Use the `ActorEventBus` attribute macro:

```rust
use shc_actors_derive::ActorEventBus;

#[ActorEventBus("blockchain_service")]
pub struct BlockchainServiceEventBusProvider;
```

This will automatically:
- Add fields for each event bus registered with the specified actor ID
- Implement the `new()` method to initialize all event buses
- Implement `ProvidesEventBus<T>` for each event type

## Refactoring Example

### Before

```rust
#[derive(Clone)]
pub struct NewChallengeSeed {
pub provider_id: String,
pub tick: u32,
pub seed: Vec<u8>,
}

impl EventBusMessage for NewChallengeSeed {}

#[derive(Clone, Default)]
pub struct BlockchainServiceEventBusProvider {
new_challenge_seed_event_bus: EventBus<NewChallengeSeed>,
// Many more fields...
}

impl BlockchainServiceEventBusProvider {
pub fn new() -> Self {
Self {
new_challenge_seed_event_bus: EventBus::new(),
// Many more initializations...
}
}
}

impl ProvidesEventBus<NewChallengeSeed> for BlockchainServiceEventBusProvider {
fn event_bus(&self) -> &EventBus<NewChallengeSeed> {
&self.new_challenge_seed_event_bus
}
}
// Many more implementations...
```

### After

```rust
use shc_actors_derive::{ActorEvent, ActorEventBus};

#[derive(Debug, Clone, ActorEvent)]
#[actor(actor = "blockchain_service")]
pub struct NewChallengeSeed {
pub provider_id: String,
pub tick: u32,
pub seed: Vec<u8>,
}

#[ActorEventBus("blockchain_service")]
pub struct BlockchainServiceEventBusProvider;
```

## How It Works

1. The `ActorEvent` derive macro registers each event type with an actor ID in a global registry.
2. The `ActorEventBus` attribute macro looks up all the event types registered for the specified actor ID and generates the required code.

This approach greatly reduces boilerplate code while maintaining type safety and performance.

## Limitations

- All event types must be defined and processed before the `ActorEventBus` macro is used.
- The macro relies on a global state to keep track of registered events, which may cause issues in certain build scenarios.
Loading
Loading