| Crates.io | casper-node-macros |
| lib.rs | casper-node-macros |
| version | 1.4.3 |
| created_at | 2020-11-11 15:44:22.491151+00 |
| updated_at | 2022-04-05 11:15:55.591503+00 |
| 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-macrosLicensed 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,
StorageRequests are routed to component_a,NetworkRequests are routed to component_b,ThirdRequests 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.