Crates.io | casper-node-macros |
lib.rs | casper-node-macros |
version | 1.4.3 |
source | src |
created_at | 2020-11-11 15:44:22.491151 |
updated_at | 2022-04-05 11:15:55.591503 |
description | A macro to create reactor implementations for the casper-node. |
homepage | https://casperlabs.io |
repository | https://github.com/CasperLabs/casper-node/tree/master/node_macros |
max_upload_size | |
id | 311266 |
size | 57,117 |
casper-node-macros
Licensed under the Apache License Version 2.0.
The casper-node-macros
crate offers an easy-to-use macro to create reactor implementations for the component system. It enforces a set of convention and allows generating a large amount of otherwise boilerplate heavy setup code comfortably.
The macro is invoked by calling the cosy_macro::reactor
macro as follows:
reactor!(NameOfReactor {
type Config = ConfigurationType;
components: {
component_a = CompA<TypeArg>(constructor_arg_1, constructor_arg_2, ...);
component_b = has_effects CompB(constructor_arg1, ..);
// ...
}
events: {
component_a = Event<TypeArg>;
}
requests: {
StorageRequest -> component_a;
NetworkRequest -> component_b;
ThirdRequest -> component_a;
AnotherRequest -> !;
}
announcements: {
NetworkAnnouncement -> [component_a, component_b];
StorageAnnouncement -> [];
}
});
The sections in detail:
The definition of
reactor!(NameOfReactor {
type Config = ConfigurationType;
// ...
});
indicates that
NameOfReactor
andConfigurationType
.The types NameOfReactorEvent
and NameOfReactorError
will be automatically generated as well.
Components are defined in the first section:
components: {
component_a = CompA<TypeArg>(constructor_arg_1, constructor_arg_2, ...);
component_b = has_effects CompB(constructor_arg1, ..);
// ...
}
Here
component_a
and component_b
respectively,crate::components::comp_a::CompA
(automatically deduced from the name),constructor_arg_1
, constructor_arg_2
to the first and constructor_arg1
to the second component,CompA::new
will return just the component, while CompB::new
will return a tuple of (component, effects)
, indicated by the has_effects
keyword,NameOfReactorEvent::ComponentA
and NameOfReactorEvent::ComponentB
will be added to the reactors event type,crate::components::comp_a::Event
(see caveat below) and crate::components::comp_b::Event
respectively,From<crate::components::comp_a::Event>
impl will be generated for NameOfReactorEvent
(similarly for comp_b
),NameOfReactorError
enum,NameOfReactorEvent
that wrap a component event will be forwarded to that component's handle_event
function.Note that during construction, the parameters cfg
, registry
, event_queue
and rng
are available, as well as the local variable effect_builder
.
Ideally all NameOfReactorEvent
newtype variants would be written as NameOfReactorEvent::SomeComponent(<crate::components::some_component::SomeComponent as Component<Self>::Event>
in the generated code, which unfortunately is not possible due to a current shortcoming in the Rust trait system that will likely only be fixed with chalk.
As a workaround, NameOfReactorEvent::SomeComponent(crate::components::some_component::Event
will be used instead. This solution only works for event types that do not have their own type parameters. If they have, the Event
portion can be replaced using the event override section of the macro invocation:
events: {
component_a = Event<TypeArg>;
}
This will result in crate::components::comp_a::Event<TypeArg>
to be used to set the newtypes inner value instead.
The third section defines how requests are routed:
requests: {
StorageRequest -> component_a;
NetworkRequest -> component_b;
ThirdRequest -> component_a;
AnotherRequest -> #;
}
In the example,
StorageRequest
s are routed to component_a
,NetworkRequest
s are routed to component_b
,ThirdRequest
s are routed to component_a
(note that multiple requests can be routed to a single component instance), andAnotherRequest
is discarded quietly.Instead of #
, a request can be routed to !
, which will panic once it receives a request.
Routing a request ExampleRequest
to an example_target
means that
NameOfReactorEvent::ExampleRequest(ExampleRequest)
variant is generated,From<ExampleRequest>
is generated for NameOfReactorEvent
andNameOfReactorEvent::ExampleRequest
it will be turned into example_target
's event type using From
, then dispatched to example_target
's handle_event
.Not routing a request means that the reactor does not support components that require it.
Announcements are routed almost exactly like requests
announcements: {
NetworkAnnouncement -> [component_a, component_b];
StorageAnnouncement -> [];
}
with the key difference being that instead of a single target, an announcement is routed to zero or more instead. !
and #
can be used as targets the same way they are used with requests as well.