mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-04-27 15:07:59 +00:00
Create a more rigid overseer builder pattern that fails at compile time (#4753)
Introduces `Missing<Field>` and `Init<Field>` states, that are used in place of builder generics, and make this possible.
This commit is contained in:
@@ -33,7 +33,7 @@ use polkadot_node_core_dispute_coordinator::Config as DisputeCoordinatorConfig;
|
||||
use polkadot_node_core_provisioner::ProvisionerConfig;
|
||||
use polkadot_node_network_protocol::request_response::{v1 as request_v1, IncomingRequestReceiver};
|
||||
use polkadot_overseer::{
|
||||
metrics::Metrics as OverseerMetrics, BlockInfo, MetricsTrait, Overseer, OverseerBuilder,
|
||||
metrics::Metrics as OverseerMetrics, BlockInfo, MetricsTrait, Overseer, InitializedOverseerBuilder,
|
||||
OverseerConnector, OverseerHandle,
|
||||
};
|
||||
use polkadot_primitives::v1::ParachainHost;
|
||||
@@ -139,7 +139,7 @@ pub fn prepared_overseer_builder<Spawner, RuntimeClient>(
|
||||
disputes_enabled,
|
||||
}: OverseerGenArgs<'_, Spawner, RuntimeClient>,
|
||||
) -> Result<
|
||||
OverseerBuilder<
|
||||
InitializedOverseerBuilder<
|
||||
Spawner,
|
||||
Arc<RuntimeClient>,
|
||||
CandidateValidationSubsystem,
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
# overseer pattern
|
||||
|
||||
The overseer pattern is a partial actor pattern
|
||||
|
||||
## proc-macro
|
||||
|
||||
The proc macro provides a convenience generator with a builder pattern,
|
||||
where at it's core it creates and spawns a set of subsystems, which are purely
|
||||
declarative.
|
||||
|
||||
```rust
|
||||
#[overlord(signal=SigSigSig, event=Event, gen=AllMessages, error=OverseerError)]
|
||||
pub struct Overseer {
|
||||
#[subsystem(MsgA)]
|
||||
sub_a: AwesomeSubSysA,
|
||||
|
||||
#[subsystem(MsgB)]
|
||||
sub_b: AwesomeSubSysB,
|
||||
}
|
||||
```
|
||||
|
||||
* Each subsystem is annotated with `#[subsystem(_)]` where `MsgA` respectively `MsgB` are the messages
|
||||
being consumed by that particular subsystem. Each of those subsystems is required to implement the subsystem
|
||||
trait.
|
||||
* `error=` tells the overseer to use the user provided
|
||||
error type, if not provided a builtin one is used. Note that this is the one error type used throughout all calls, so make sure it does impl `From<E>` for all other error types `E` that are relevant to your application.
|
||||
* `event=` declares an external event type, that injects certain events
|
||||
into the overseer, without participating in the subsystem pattern.
|
||||
* `signal=` defines a signal type to be used for the overseer. This is a shared "clock" for all subsystems.
|
||||
* `gen=` defines a wrapping `enum` type that is used to wrap all messages that can be consumed by _any_ subsystem.
|
||||
|
||||
```rust
|
||||
/// Execution context, always requred.
|
||||
pub struct DummyCtx;
|
||||
|
||||
/// Task spawner, always required.
|
||||
pub struct DummySpawner;
|
||||
|
||||
fn main() {
|
||||
let _overseer = Overseer::builder()
|
||||
.sub_a(AwesomeSubSysA::default())
|
||||
.sub_b(AwesomeSubSysB::default())
|
||||
.spawner(DummySpawner)
|
||||
.build();
|
||||
}
|
||||
```
|
||||
|
||||
In the shown `main`, the overseer is created by means of a generated, compile time erroring
|
||||
builder pattern.
|
||||
|
||||
The builder requires all subsystems, baggage fields (additional struct data) and spawner to be
|
||||
set via the according setter method before `build` method could even be called. Failure to do
|
||||
such an initialization will lead to a compile error. This is implemented by encoding each
|
||||
builder field in a set of so called `state generics`, meaning that each field can be either
|
||||
`Init<T>` or `Missing<T>`, so each setter translates a state from `Missing` to `Init` state
|
||||
for the specific struct field. Therefore, if you see a compile time error that blames about
|
||||
`Missing` where `Init` is expected it usually means that some subsystems or baggage fields were
|
||||
not set prior to the `build` call.
|
||||
|
||||
To exclude subsystems from such a check, one can set `wip` attribute on some subsystem that
|
||||
is not ready to be included in the Overseer:
|
||||
|
||||
```rust
|
||||
#[overlord(signal=SigSigSig, event=Event, gen=AllMessages, error=OverseerError)]
|
||||
pub struct Overseer {
|
||||
#[subsystem(MsgA)]
|
||||
sub_a: AwesomeSubSysA,
|
||||
|
||||
#[subsystem(MsgB), wip]
|
||||
sub_b: AwesomeSubSysB, // This subsystem will not be required nor allowed to be set
|
||||
}
|
||||
```
|
||||
|
||||
Baggage fields can be initialized more than one time, however, it is not true for subsystems:
|
||||
subsystems must be initialized only once (another compile time check) or be _replaced_ by
|
||||
a special setter like method `replace_<subsystem>`.
|
||||
|
||||
A task spawner and subsystem context are required to be defined with `SpawnNamed` and respectively `SubsystemContext` implemented.
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
use polkadot_node_network_protocol::WrongVariant;
|
||||
use polkadot_overseer_gen::*;
|
||||
use std::collections::HashMap;
|
||||
|
||||
/// Concrete subsystem implementation for `MsgStrukt` msg type.
|
||||
#[derive(Default)]
|
||||
@@ -88,7 +89,7 @@ impl NetworkMsg {
|
||||
}
|
||||
|
||||
#[overlord(signal=SigSigSig, event=EvX, error=Yikes, network=NetworkMsg, gen=AllMessages)]
|
||||
struct Xxx {
|
||||
struct Xxx<T> {
|
||||
#[subsystem(MsgStrukt)]
|
||||
sub0: AwesomeSubSys,
|
||||
|
||||
@@ -96,6 +97,8 @@ struct Xxx {
|
||||
plinkos: GoblinTower,
|
||||
|
||||
i_like_pi: f64,
|
||||
i_like_generic: T,
|
||||
i_like_hash: HashMap<f64, f64>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
@@ -125,12 +128,16 @@ impl SpawnNamed for DummySpawner {
|
||||
struct DummyCtx;
|
||||
|
||||
fn main() {
|
||||
let (overseer, _handle): (Xxx<_>, _) = Xxx::builder()
|
||||
let (overseer, _handle): (Xxx<_, f64>, _) = Xxx::builder()
|
||||
.sub0(AwesomeSubSys::default())
|
||||
.plinkos(GoblinTower::default())
|
||||
.i_like_pi(::std::f64::consts::PI)
|
||||
.i_like_generic(42.0)
|
||||
.i_like_hash(HashMap::new())
|
||||
.spawner(DummySpawner)
|
||||
.build()
|
||||
.unwrap();
|
||||
assert_eq!(overseer.i_like_pi.floor() as i8, 3);
|
||||
assert_eq!(overseer.i_like_generic.floor() as i8, 42);
|
||||
assert_eq!(overseer.i_like_hash.len() as i8, 0);
|
||||
}
|
||||
|
||||
@@ -15,41 +15,15 @@
|
||||
// along with Polkadot. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use quote::{format_ident, quote};
|
||||
use syn::Ident;
|
||||
use syn::{parse_quote, Path, PathSegment};
|
||||
|
||||
use super::*;
|
||||
|
||||
/// Returns all combinations for a single replacement:
|
||||
/// 1. generic args with `NEW` in place
|
||||
/// 2. subsystem type to be replaced
|
||||
/// 3. the subsystem name to be replaced by a new type and value
|
||||
/// 4. all other subsystems that are supposed to be kept
|
||||
fn derive_replacable_generic_lists(
|
||||
info: &OverseerInfo,
|
||||
) -> Vec<(TokenStream, Ident, Ident, Vec<Ident>)> {
|
||||
// subsystem generic types
|
||||
let builder_generic_ty = info.builder_generic_types();
|
||||
|
||||
let to_be_replaced_name = info.subsystem_names_without_wip();
|
||||
let baggage_generic_ty = &info.baggage_generic_types();
|
||||
|
||||
builder_generic_ty
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(idx, to_be_replaced_ty)| {
|
||||
let mut to_keep_name = to_be_replaced_name.clone();
|
||||
let to_be_replaced_name: Ident = to_keep_name.remove(idx);
|
||||
|
||||
let mut builder_generic_ty = builder_generic_ty.clone();
|
||||
builder_generic_ty[idx] = format_ident!("NEW");
|
||||
|
||||
let generics_ts = quote! {
|
||||
<S, #( #baggage_generic_ty, )* #( #builder_generic_ty, )* >
|
||||
};
|
||||
|
||||
(generics_ts, to_be_replaced_ty.clone(), to_be_replaced_name, to_keep_name)
|
||||
})
|
||||
.collect::<Vec<(_, _, _, _)>>()
|
||||
fn recollect_without_idx<T: Clone>(x: &[T], idx: usize) -> Vec<T> {
|
||||
let mut v = Vec::<T>::with_capacity(x.len().saturating_sub(1));
|
||||
v.extend(x.iter().take(idx).cloned());
|
||||
v.extend(x.iter().skip(idx + 1).cloned());
|
||||
v
|
||||
}
|
||||
|
||||
/// Implement a builder pattern for the `Overseer`-type,
|
||||
@@ -58,24 +32,15 @@ fn derive_replacable_generic_lists(
|
||||
/// Elements tagged with `wip` are not covered here.
|
||||
pub(crate) fn impl_builder(info: &OverseerInfo) -> proc_macro2::TokenStream {
|
||||
let overseer_name = info.overseer_name.clone();
|
||||
let builder = Ident::new(&(overseer_name.to_string() + "Builder"), overseer_name.span());
|
||||
let handle = Ident::new(&(overseer_name.to_string() + "Handle"), overseer_name.span());
|
||||
let connector = Ident::new(&(overseer_name.to_string() + "Connector"), overseer_name.span());
|
||||
let builder = format_ident!("{}Builder", overseer_name);
|
||||
let handle = format_ident!("{}Handle", overseer_name);
|
||||
let connector = format_ident!("{}Connector", overseer_name);
|
||||
let subsystem_ctx_name = format_ident!("{}SubsystemContext", overseer_name);
|
||||
|
||||
let subsystem_name = &info.subsystem_names_without_wip();
|
||||
let subsystem_name_init_with = &info
|
||||
.subsystem_names_without_wip()
|
||||
.iter()
|
||||
.map(|subsystem_name| format_ident!("{}_with", subsystem_name))
|
||||
.collect::<Vec<_>>();
|
||||
let subsystem_name_replace_with = &info
|
||||
.subsystem_names_without_wip()
|
||||
.iter()
|
||||
.map(|subsystem_name| format_ident!("replace_{}", subsystem_name))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let builder_generic_ty = &info.builder_generic_types();
|
||||
let subsystem_generics = &info.subsystem_generic_types();
|
||||
|
||||
let consumes = &info.consumes_without_wip();
|
||||
let channel_name = &info.channel_names_without_wip("");
|
||||
let channel_name_unbounded = &info.channel_names_without_wip("_unbounded");
|
||||
|
||||
@@ -85,11 +50,20 @@ pub(crate) fn impl_builder(info: &OverseerInfo) -> proc_macro2::TokenStream {
|
||||
let channel_name_rx = &info.channel_names_without_wip("_rx");
|
||||
let channel_name_unbounded_rx = &info.channel_names_without_wip("_unbounded_rx");
|
||||
|
||||
let baggage_generic_ty = &info.baggage_generic_types();
|
||||
let baggage_name = &info.baggage_names();
|
||||
let baggage_ty = &info.baggage_types();
|
||||
let baggage_generic_ty = &info.baggage_generic_types();
|
||||
|
||||
let subsystem_ctx_name = format_ident!("{}SubsystemContext", overseer_name);
|
||||
// State generics that are used to encode each field's status (Init/Missing)
|
||||
let baggage_passthrough_state_generics = baggage_name
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(idx, _)| format_ident!("InitStateBaggage{}", idx))
|
||||
.collect::<Vec<_>>();
|
||||
let subsystem_passthrough_state_generics = subsystem_name
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(idx, _)| format_ident!("InitStateSubsystem{}", idx))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let error_ty = &info.extern_error_ty;
|
||||
|
||||
@@ -107,49 +81,256 @@ pub(crate) fn impl_builder(info: &OverseerInfo) -> proc_macro2::TokenStream {
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let generics = quote! {
|
||||
< S, #( #baggage_generic_ty, )* >
|
||||
};
|
||||
let where_clause = quote! {
|
||||
where
|
||||
S: #support_crate ::SpawnNamed,
|
||||
// Helpers to use within quote! macros
|
||||
let spawner_where_clause: syn::TypeParam = parse_quote! {
|
||||
S: #support_crate ::SpawnNamed + Send
|
||||
};
|
||||
|
||||
let builder_generics = quote! {
|
||||
<S, #( #baggage_generic_ty, )* #( #builder_generic_ty, )* >
|
||||
};
|
||||
// Field names and real types
|
||||
let field_name = subsystem_name.iter().chain(baggage_name.iter()).collect::<Vec<_>>();
|
||||
let field_type = subsystem_generics
|
||||
.iter()
|
||||
.map(|ident| Path::from(PathSegment::from(ident.clone())))
|
||||
.chain(info.baggage().iter().map(|bag| bag.field_ty.clone()))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
// all subsystems must have the same context
|
||||
// even if the overseer does not impose such a limit.
|
||||
let builder_additional_generics = quote! {
|
||||
<#( #builder_generic_ty, )* >
|
||||
};
|
||||
// Setters logic
|
||||
|
||||
let consumes = &info.consumes();
|
||||
// For each setter we need to leave the remaining fields untouched and
|
||||
// remove the field that we are fixing in this setter
|
||||
// For subsystems `*_with` and `replace_*` setters are needed.
|
||||
let subsystem_specific_setters =
|
||||
info.subsystems().iter().filter(|ssf| !ssf.wip).enumerate().map(|(idx, ssf)| {
|
||||
let field_name = &ssf.name;
|
||||
let field_type = &ssf.generic;
|
||||
let subsystem_consumes = &ssf.consumes;
|
||||
// Remove state generic for the item to be replaced. It sufficient to know `field_type` for
|
||||
// that since we always move from `Init<#field_type>` to `Init<NEW>`.
|
||||
let impl_subsystem_state_generics = recollect_without_idx(&subsystem_passthrough_state_generics[..], idx);
|
||||
|
||||
let subsyste_ctx_name =
|
||||
Ident::new(&(overseer_name.to_string() + "SubsystemContext"), overseer_name.span());
|
||||
let field_name_with = format_ident!("{}_with", field_name);
|
||||
let field_name_replace = format_ident!("replace_{}", field_name);
|
||||
|
||||
let builder_where_clause = quote! {
|
||||
where
|
||||
S: #support_crate ::SpawnNamed,
|
||||
#(
|
||||
#builder_generic_ty : Subsystem<#subsyste_ctx_name< #consumes >, #error_ty>,
|
||||
)*
|
||||
};
|
||||
// In a setter we replace `Uninit<T>` with `Init<T>` leaving all other
|
||||
// types as they are, as such they will be free generics.
|
||||
let mut current_state_generics = subsystem_passthrough_state_generics
|
||||
.iter()
|
||||
.map(|subsystem_state_generic_ty| parse_quote!(#subsystem_state_generic_ty))
|
||||
.collect::<Vec<syn::GenericArgument>>();
|
||||
current_state_generics[idx] = parse_quote! { Missing<#field_type> };
|
||||
|
||||
// Generics that will be present after initializing a specific `Missing<_>` field.
|
||||
let mut post_setter_state_generics = current_state_generics.clone();
|
||||
post_setter_state_generics[idx] = parse_quote! { Init<#field_type> };
|
||||
|
||||
let mut post_replace_state_generics = current_state_generics.clone();
|
||||
post_replace_state_generics[idx] = parse_quote! { Init<NEW> };
|
||||
|
||||
// All fields except the one we update with the new argument
|
||||
// see the loop below.
|
||||
let to_keep_subsystem_name = recollect_without_idx(&subsystem_name[..], idx);
|
||||
|
||||
// Create the field init `fn`
|
||||
quote! {
|
||||
impl <InitStateSpawner, #field_type, #( #impl_subsystem_state_generics, )* #( #baggage_passthrough_state_generics, )*>
|
||||
#builder <InitStateSpawner, #( #current_state_generics, )* #( #baggage_passthrough_state_generics, )*>
|
||||
where
|
||||
#field_type : Subsystem<#subsystem_ctx_name<#subsystem_consumes>, #error_ty>,
|
||||
{
|
||||
/// Specify the subsystem in the builder directly
|
||||
pub fn #field_name (self, var: #field_type ) ->
|
||||
#builder <InitStateSpawner, #( #post_setter_state_generics, )* #( #baggage_passthrough_state_generics, )*>
|
||||
{
|
||||
#builder {
|
||||
#field_name: Init::<#field_type>::Value(var),
|
||||
#(
|
||||
#to_keep_subsystem_name: self. #to_keep_subsystem_name,
|
||||
)*
|
||||
#(
|
||||
#baggage_name: self. #baggage_name,
|
||||
)*
|
||||
spawner: self.spawner,
|
||||
}
|
||||
}
|
||||
/// Specify the the initialization function for a subsystem
|
||||
pub fn #field_name_with<'a, F>(self, subsystem_init_fn: F ) ->
|
||||
#builder <InitStateSpawner, #( #post_setter_state_generics, )* #( #baggage_passthrough_state_generics, )*>
|
||||
where
|
||||
F: 'static + FnOnce(#handle) ->
|
||||
::std::result::Result<#field_type, #error_ty>,
|
||||
{
|
||||
let boxed_func = Init::<#field_type>::Fn(
|
||||
Box::new(subsystem_init_fn) as SubsystemInitFn<#field_type>
|
||||
);
|
||||
#builder {
|
||||
#field_name: boxed_func,
|
||||
#(
|
||||
#to_keep_subsystem_name: self. #to_keep_subsystem_name,
|
||||
)*
|
||||
#(
|
||||
#baggage_name: self. #baggage_name,
|
||||
)*
|
||||
spawner: self.spawner,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl <InitStateSpawner, #field_type, #( #impl_subsystem_state_generics, )* #( #baggage_passthrough_state_generics, )*>
|
||||
#builder <InitStateSpawner, #( #post_setter_state_generics, )* #( #baggage_passthrough_state_generics, )*>
|
||||
where
|
||||
#field_type : Subsystem<#subsystem_ctx_name<#subsystem_consumes>, #error_ty>,
|
||||
{
|
||||
/// Replace a subsystem by another implementation for the
|
||||
/// consumable message type.
|
||||
pub fn #field_name_replace<NEW, F>(self, gen_replacement_fn: F)
|
||||
-> #builder <InitStateSpawner, #( #post_replace_state_generics, )* #( #baggage_passthrough_state_generics, )*>
|
||||
where
|
||||
#field_type: 'static,
|
||||
F: 'static + FnOnce(#field_type) -> NEW,
|
||||
NEW: #support_crate ::Subsystem<#subsystem_ctx_name< #subsystem_consumes >, #error_ty>,
|
||||
{
|
||||
let replacement: Init<NEW> = match self.#field_name {
|
||||
Init::Fn(fx) =>
|
||||
Init::<NEW>::Fn(Box::new(move |handle: #handle| {
|
||||
let orig = fx(handle)?;
|
||||
Ok(gen_replacement_fn(orig))
|
||||
})),
|
||||
Init::Value(val) =>
|
||||
Init::Value(gen_replacement_fn(val)),
|
||||
};
|
||||
#builder {
|
||||
#field_name: replacement,
|
||||
#(
|
||||
#to_keep_subsystem_name: self. #to_keep_subsystem_name,
|
||||
)*
|
||||
#(
|
||||
#baggage_name: self. #baggage_name,
|
||||
)*
|
||||
spawner: self.spawner,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Produce setters for all baggage fields as well
|
||||
let baggage_specific_setters = info.baggage().iter().enumerate().map(|(idx, bag_field)| {
|
||||
// Baggage fields follow subsystems
|
||||
let fname = &bag_field.field_name;
|
||||
let field_type = &bag_field.field_ty;
|
||||
let impl_baggage_state_generics = recollect_without_idx(&baggage_passthrough_state_generics[..], idx);
|
||||
let to_keep_baggage_name = recollect_without_idx(&baggage_name[..], idx);
|
||||
|
||||
let mut pre_setter_generics = baggage_passthrough_state_generics
|
||||
.iter()
|
||||
.map(|gen_ty| parse_quote!(#gen_ty))
|
||||
.collect::<Vec<syn::GenericArgument>>();
|
||||
pre_setter_generics[idx] = parse_quote! { Missing<#field_type> };
|
||||
|
||||
let mut post_setter_generics = pre_setter_generics.clone();
|
||||
post_setter_generics[idx] = parse_quote! { Init<#field_type> };
|
||||
|
||||
// Baggage can also be generic, so we need to include that to a signature
|
||||
let preserved_baggage_generic = if bag_field.generic {
|
||||
quote! {#field_type,}
|
||||
} else {
|
||||
TokenStream::new()
|
||||
};
|
||||
|
||||
quote! {
|
||||
impl <InitStateSpawner, #preserved_baggage_generic #( #subsystem_passthrough_state_generics, )* #( #impl_baggage_state_generics, )* >
|
||||
#builder <InitStateSpawner, #( #subsystem_passthrough_state_generics, )* #( #pre_setter_generics, )* >
|
||||
{
|
||||
/// Specify the baggage in the builder when it was not initialized before
|
||||
pub fn #fname (self, var: #field_type ) ->
|
||||
#builder <InitStateSpawner, #( #subsystem_passthrough_state_generics, )* #( #post_setter_generics, )* >
|
||||
{
|
||||
#builder {
|
||||
#fname: Init::<#field_type>::Value(var),
|
||||
#(
|
||||
#subsystem_name: self. #subsystem_name,
|
||||
)*
|
||||
#(
|
||||
#to_keep_baggage_name: self. #to_keep_baggage_name,
|
||||
)*
|
||||
spawner: self.spawner,
|
||||
}
|
||||
}
|
||||
}
|
||||
impl <InitStateSpawner, #preserved_baggage_generic #( #subsystem_passthrough_state_generics, )* #( #impl_baggage_state_generics, )* >
|
||||
#builder <InitStateSpawner, #( #subsystem_passthrough_state_generics, )* #( #post_setter_generics, )* > {
|
||||
/// Specify the baggage in the builder when it has been previously initialized
|
||||
pub fn #fname (self, var: #field_type ) ->
|
||||
#builder <InitStateSpawner, #( #subsystem_passthrough_state_generics, )* #( #post_setter_generics, )* >
|
||||
{
|
||||
#builder {
|
||||
#fname: Init::<#field_type>::Value(var),
|
||||
#(
|
||||
#subsystem_name: self. #subsystem_name,
|
||||
)*
|
||||
#(
|
||||
#to_keep_baggage_name: self. #to_keep_baggage_name,
|
||||
)*
|
||||
spawner: self.spawner,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
let event = &info.extern_event_ty;
|
||||
let initialized_builder = format_ident!("Initialized{}", builder);
|
||||
// The direct generics as expected by the `Overseer<_,_,..>`, without states
|
||||
let initialized_builder_generics = quote! {
|
||||
S, #( #baggage_generic_ty, )* #( #subsystem_generics, )*
|
||||
};
|
||||
|
||||
let mut ts = quote! {
|
||||
impl #generics #overseer_name #generics #where_clause {
|
||||
/// Create a new overseer utilizing the builder.
|
||||
pub fn builder #builder_additional_generics () -> #builder #builder_generics
|
||||
#builder_where_clause
|
||||
{
|
||||
#builder :: default()
|
||||
/// Convenience alias.
|
||||
type SubsystemInitFn<T> = Box<dyn FnOnce(#handle) -> ::std::result::Result<T, #error_ty> >;
|
||||
|
||||
/// Type for the initialized field of the overseer builder
|
||||
pub enum Init<T> {
|
||||
/// Defer initialization to a point where the `handle` is available.
|
||||
Fn(SubsystemInitFn<T>),
|
||||
/// Directly initialize the subsystem with the given subsystem type `T`.
|
||||
/// Also used for baggage fields
|
||||
Value(T),
|
||||
}
|
||||
/// Type marker for the uninitialized field of the overseer builder.
|
||||
/// `PhantomData` is used for type hinting when creating uninitialized
|
||||
/// builder, e.g. to avoid specifying the generics when instantiating
|
||||
/// the `FooBuilder` when calling `Foo::builder()`
|
||||
#[derive(Debug)]
|
||||
pub struct Missing<T>(::core::marker::PhantomData<T>);
|
||||
|
||||
/// Trait used to mark fields status in a builder
|
||||
trait OverseerFieldState<T> {}
|
||||
|
||||
impl<T> OverseerFieldState<T> for Init<T> {}
|
||||
impl<T> OverseerFieldState<T> for Missing<T> {}
|
||||
|
||||
impl<T> ::std::default::Default for Missing<T> {
|
||||
fn default() -> Self {
|
||||
Missing::<T>(::core::marker::PhantomData::<T>::default())
|
||||
}
|
||||
}
|
||||
|
||||
impl<S, #( #baggage_generic_ty, )*> #overseer_name <S, #( #baggage_generic_ty, )*> where #spawner_where_clause {
|
||||
/// Create a new overseer utilizing the builder.
|
||||
pub fn builder< #( #subsystem_generics),* >() ->
|
||||
#builder<Missing<S> #(, Missing<#field_type> )* >
|
||||
where
|
||||
#(
|
||||
#subsystem_generics : Subsystem<#subsystem_ctx_name< #consumes >, #error_ty>,
|
||||
)*
|
||||
{
|
||||
#builder :: new()
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
ts.extend(quote! {
|
||||
/// Handle for an overseer.
|
||||
pub type #handle = #support_crate ::metered::MeteredSender< #event >;
|
||||
|
||||
@@ -192,39 +373,26 @@ pub(crate) fn impl_builder(info: &OverseerInfo) -> proc_macro2::TokenStream {
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
/// Convenience alias.
|
||||
type SubsystemInitFn<T> = Box<dyn FnOnce(#handle) -> ::std::result::Result<T, #error_ty> >;
|
||||
|
||||
/// Initialization type to be used for a field of the overseer.
|
||||
enum FieldInitMethod<T> {
|
||||
/// Defer initialization to a point where the `handle` is available.
|
||||
Fn(SubsystemInitFn<T>),
|
||||
/// Directly initialize the subsystem with the given subsystem type `T`.
|
||||
Value(T),
|
||||
/// Subsystem field does not have a value just yet.
|
||||
Uninitialized
|
||||
}
|
||||
|
||||
impl<T> ::std::default::Default for FieldInitMethod<T> {
|
||||
fn default() -> Self {
|
||||
Self::Uninitialized
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(missing_docs)]
|
||||
pub struct #builder #builder_generics {
|
||||
ts.extend(quote!{
|
||||
/// Builder pattern to create compile time safe construction path.
|
||||
pub struct #builder <InitStateSpawner, #( #subsystem_passthrough_state_generics, )* #( #baggage_passthrough_state_generics, )*> {
|
||||
#(
|
||||
#subsystem_name : FieldInitMethod< #builder_generic_ty >,
|
||||
#subsystem_name: #subsystem_passthrough_state_generics,
|
||||
)*
|
||||
#(
|
||||
#baggage_name : ::std::option::Option< #baggage_ty >,
|
||||
#baggage_name: #baggage_passthrough_state_generics,
|
||||
)*
|
||||
spawner: ::std::option::Option< S >,
|
||||
spawner: InitStateSpawner,
|
||||
}
|
||||
});
|
||||
|
||||
impl #builder_generics Default for #builder #builder_generics {
|
||||
fn default() -> Self {
|
||||
ts.extend(quote! {
|
||||
impl<#initialized_builder_generics> #builder<Missing<S>, #( Missing<#field_type>, )*>
|
||||
{
|
||||
/// Create a new builder pattern, with all fields being uninitialized.
|
||||
fn new() -> Self {
|
||||
// explicitly assure the required traits are implemented
|
||||
fn trait_from_must_be_implemented<E>()
|
||||
where
|
||||
@@ -234,62 +402,57 @@ pub(crate) fn impl_builder(info: &OverseerInfo) -> proc_macro2::TokenStream {
|
||||
trait_from_must_be_implemented::< #error_ty >();
|
||||
|
||||
Self {
|
||||
#(
|
||||
#subsystem_name: Default::default(),
|
||||
)*
|
||||
#(
|
||||
#baggage_name: None,
|
||||
)*
|
||||
spawner: None,
|
||||
#(
|
||||
#field_name: Missing::<#field_type>::default(),
|
||||
)*
|
||||
spawner: Missing::<S>::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
impl #builder_generics #builder #builder_generics #builder_where_clause {
|
||||
/// The spawner to use for spawning tasks.
|
||||
pub fn spawner(mut self, spawner: S) -> Self
|
||||
where
|
||||
S: #support_crate ::SpawnNamed + Send
|
||||
// Spawner setter
|
||||
ts.extend(quote!{
|
||||
impl<S, #( #subsystem_passthrough_state_generics, )* #( #baggage_passthrough_state_generics, )*>
|
||||
#builder<Missing<S>, #( #subsystem_passthrough_state_generics, )* #( #baggage_passthrough_state_generics, )*>
|
||||
where
|
||||
#spawner_where_clause
|
||||
{
|
||||
/// The `spawner` to use for spawning tasks.
|
||||
pub fn spawner(self, spawner: S) -> #builder<Init<S>, #( #subsystem_passthrough_state_generics, )* #( #baggage_passthrough_state_generics, )*>
|
||||
{
|
||||
self.spawner = Some(spawner);
|
||||
self
|
||||
#builder {
|
||||
#(
|
||||
#field_name: self. #field_name,
|
||||
)*
|
||||
spawner: Init::<S>::Value(spawner),
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
ts.extend(quote! {
|
||||
/// Type used to represent a builder where all fields are initialized and the overseer could be constructed.
|
||||
pub type #initialized_builder<#initialized_builder_generics> = #builder<Init<S>, #( Init<#field_type>, )*>;
|
||||
|
||||
// A builder specialization where all fields are set
|
||||
impl<#initialized_builder_generics> #initialized_builder<#initialized_builder_generics>
|
||||
where
|
||||
#spawner_where_clause,
|
||||
#(
|
||||
/// Specify the particular subsystem implementation.
|
||||
pub fn #subsystem_name (mut self, subsystem: #builder_generic_ty ) -> Self {
|
||||
self. #subsystem_name = FieldInitMethod::Value( subsystem );
|
||||
self
|
||||
}
|
||||
|
||||
/// Specify the particular subsystem by giving a init function.
|
||||
pub fn #subsystem_name_init_with <'a, F> (mut self, subsystem_init_fn: F ) -> Self
|
||||
where
|
||||
F: 'static + FnOnce(#handle) -> ::std::result::Result<#builder_generic_ty, #error_ty>,
|
||||
{
|
||||
self. #subsystem_name = FieldInitMethod::Fn(
|
||||
Box::new(subsystem_init_fn) as SubsystemInitFn<#builder_generic_ty>
|
||||
);
|
||||
self
|
||||
}
|
||||
#subsystem_generics : Subsystem<#subsystem_ctx_name< #consumes >, #error_ty>,
|
||||
)*
|
||||
|
||||
#(
|
||||
/// Attach the user defined addendum type.
|
||||
pub fn #baggage_name (mut self, baggage: #baggage_ty ) -> Self {
|
||||
self. #baggage_name = Some( baggage );
|
||||
self
|
||||
}
|
||||
)*
|
||||
|
||||
{
|
||||
/// Complete the construction and create the overseer type.
|
||||
pub fn build(self) -> ::std::result::Result<(#overseer_name #generics, #handle), #error_ty> {
|
||||
pub fn build(self)
|
||||
-> ::std::result::Result<(#overseer_name<S, #( #baggage_generic_ty, )*>, #handle), #error_ty> {
|
||||
let connector = #connector ::default();
|
||||
self.build_with_connector(connector)
|
||||
}
|
||||
|
||||
/// Complete the construction and create the overseer type based on an existing `connector`.
|
||||
pub fn build_with_connector(self, connector: #connector) -> ::std::result::Result<(#overseer_name #generics, #handle), #error_ty>
|
||||
pub fn build_with_connector(self, connector: #connector)
|
||||
-> ::std::result::Result<(#overseer_name<S, #( #baggage_generic_ty, )*>, #handle), #error_ty>
|
||||
{
|
||||
let #connector {
|
||||
handle: events_tx,
|
||||
@@ -327,20 +490,19 @@ pub(crate) fn impl_builder(info: &OverseerInfo) -> proc_macro2::TokenStream {
|
||||
)*
|
||||
};
|
||||
|
||||
let mut spawner = self.spawner.expect("Spawner is set. qed");
|
||||
let mut spawner = match self.spawner {
|
||||
Init::Value(value) => value,
|
||||
_ => unreachable!("Only ever init spawner as value. qed"),
|
||||
};
|
||||
|
||||
let mut running_subsystems = #support_crate ::FuturesUnordered::<
|
||||
BoxFuture<'static, ::std::result::Result<(), #error_ty > >
|
||||
>::new();
|
||||
|
||||
#(
|
||||
// TODO generate a builder pattern that ensures this
|
||||
// TODO https://github.com/paritytech/polkadot/issues/3427
|
||||
let #subsystem_name = match self. #subsystem_name {
|
||||
FieldInitMethod::Fn(func) => func(handle.clone())?,
|
||||
FieldInitMethod::Value(val) => val,
|
||||
FieldInitMethod::Uninitialized =>
|
||||
panic!("All subsystems must exist with the builder pattern."),
|
||||
Init::Fn(func) => func(handle.clone())?,
|
||||
Init::Value(val) => val,
|
||||
};
|
||||
|
||||
let unbounded_meter = #channel_name_unbounded_rx.meter().clone();
|
||||
@@ -351,11 +513,11 @@ pub(crate) fn impl_builder(info: &OverseerInfo) -> proc_macro2::TokenStream {
|
||||
let (signal_tx, signal_rx) = #support_crate ::metered::channel(SIGNAL_CHANNEL_CAPACITY);
|
||||
|
||||
// Generate subsystem name based on overseer field name.
|
||||
let mut subsystem_string = String::from(stringify!(#subsystem_name));
|
||||
let subsystem_string = String::from(stringify!(#subsystem_name));
|
||||
// Convert owned `snake case` string to a `kebab case` static str.
|
||||
let subsystem_static_str = Box::leak(subsystem_string.replace("_", "-").into_boxed_str());
|
||||
|
||||
let ctx = #subsyste_ctx_name::< #consumes >::new(
|
||||
let ctx = #subsystem_ctx_name::< #consumes >::new(
|
||||
signal_rx,
|
||||
message_rx,
|
||||
channels_out.clone(),
|
||||
@@ -376,15 +538,6 @@ pub(crate) fn impl_builder(info: &OverseerInfo) -> proc_macro2::TokenStream {
|
||||
)?;
|
||||
)*
|
||||
|
||||
#(
|
||||
let #baggage_name = self. #baggage_name .expect(
|
||||
&format!("Baggage variable `{0}` of `{1}` must be set by the user!",
|
||||
stringify!(#baggage_name),
|
||||
stringify!(#overseer_name)
|
||||
)
|
||||
);
|
||||
)*
|
||||
|
||||
use #support_crate ::StreamExt;
|
||||
|
||||
let to_overseer_rx = to_overseer_rx.fuse();
|
||||
@@ -394,7 +547,10 @@ pub(crate) fn impl_builder(info: &OverseerInfo) -> proc_macro2::TokenStream {
|
||||
)*
|
||||
|
||||
#(
|
||||
#baggage_name,
|
||||
#baggage_name: match self. #baggage_name {
|
||||
Init::Value(val) => val,
|
||||
_ => panic!("unexpected baggage initialization, must be value"),
|
||||
},
|
||||
)*
|
||||
|
||||
spawner,
|
||||
@@ -406,84 +562,10 @@ pub(crate) fn impl_builder(info: &OverseerInfo) -> proc_macro2::TokenStream {
|
||||
Ok((overseer, handle))
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let mut acc = TokenStream::new();
|
||||
|
||||
for (
|
||||
(
|
||||
(
|
||||
ref modified_generics,
|
||||
ref to_be_replaced_ty,
|
||||
ref to_be_replaced_name,
|
||||
ref to_keep_name,
|
||||
),
|
||||
subsystem_name_replace_with,
|
||||
),
|
||||
consumes,
|
||||
) in derive_replacable_generic_lists(info)
|
||||
.into_iter()
|
||||
.zip(subsystem_name_replace_with.iter())
|
||||
.zip(consumes.iter())
|
||||
{
|
||||
let replace1 = quote! {
|
||||
/// Replace a subsystem by another implementation for the
|
||||
/// consumable message type.
|
||||
pub fn #subsystem_name_replace_with < NEW, F >
|
||||
(self, gen_replacement_fn: F) -> #builder #modified_generics
|
||||
where
|
||||
#to_be_replaced_ty: 'static,
|
||||
F: 'static + FnOnce(#to_be_replaced_ty) -> NEW,
|
||||
NEW: #support_crate ::Subsystem<#subsystem_ctx_name< #consumes >, #error_ty>,
|
||||
{
|
||||
|
||||
let Self {
|
||||
#to_be_replaced_name,
|
||||
#(
|
||||
#to_keep_name,
|
||||
)*
|
||||
#(
|
||||
#baggage_name,
|
||||
)*
|
||||
spawner,
|
||||
} = self;
|
||||
|
||||
// Some cases require that parts of the original are copied
|
||||
// over, since they include a one time initialization.
|
||||
let replacement: FieldInitMethod<NEW> = match #to_be_replaced_name {
|
||||
FieldInitMethod::Fn(fx) => FieldInitMethod::Fn(
|
||||
Box::new(move |handle: #handle| {
|
||||
let orig = fx(handle)?;
|
||||
Ok(gen_replacement_fn(orig))
|
||||
})
|
||||
),
|
||||
FieldInitMethod::Value(val) => FieldInitMethod::Value(gen_replacement_fn(val)),
|
||||
FieldInitMethod::Uninitialized => panic!("Must have a value before it can be replaced. qed"),
|
||||
};
|
||||
|
||||
#builder :: #modified_generics {
|
||||
#to_be_replaced_name: replacement,
|
||||
#(
|
||||
#to_keep_name,
|
||||
)*
|
||||
#(
|
||||
#baggage_name,
|
||||
)*
|
||||
spawner,
|
||||
}
|
||||
}
|
||||
};
|
||||
acc.extend(replace1);
|
||||
}
|
||||
|
||||
ts.extend(quote! {
|
||||
impl #builder_generics #builder #builder_generics
|
||||
#builder_where_clause
|
||||
{
|
||||
#acc
|
||||
}
|
||||
});
|
||||
|
||||
ts.extend(baggage_specific_setters);
|
||||
ts.extend(subsystem_specific_setters);
|
||||
ts.extend(impl_task_kind(info));
|
||||
ts
|
||||
}
|
||||
|
||||
@@ -264,12 +264,21 @@ impl OverseerInfo {
|
||||
.collect::<Vec<_>>()
|
||||
}
|
||||
|
||||
pub(crate) fn subsystem_generic_types(&self) -> Vec<Ident> {
|
||||
self.subsystems
|
||||
.iter()
|
||||
.filter(|ssf| !ssf.wip)
|
||||
.map(|sff| sff.generic.clone())
|
||||
.collect::<Vec<_>>()
|
||||
}
|
||||
|
||||
pub(crate) fn baggage(&self) -> &[BaggageField] {
|
||||
self.baggage.as_slice()
|
||||
}
|
||||
|
||||
pub(crate) fn baggage_names(&self) -> Vec<Ident> {
|
||||
self.baggage.iter().map(|bag| bag.field_name.clone()).collect::<Vec<_>>()
|
||||
}
|
||||
pub(crate) fn baggage_types(&self) -> Vec<Path> {
|
||||
self.baggage.iter().map(|bag| bag.field_ty.clone()).collect::<Vec<_>>()
|
||||
}
|
||||
pub(crate) fn baggage_decl(&self) -> Vec<TokenStream> {
|
||||
self.baggage
|
||||
.iter()
|
||||
@@ -280,15 +289,6 @@ impl OverseerInfo {
|
||||
.collect::<Vec<TokenStream>>()
|
||||
}
|
||||
|
||||
/// Generic types per subsystem, as defined by the user.
|
||||
pub(crate) fn builder_generic_types(&self) -> Vec<Ident> {
|
||||
self.subsystems
|
||||
.iter()
|
||||
.filter(|ssf| !ssf.wip)
|
||||
.map(|sff| sff.generic.clone())
|
||||
.collect::<Vec<_>>()
|
||||
}
|
||||
|
||||
pub(crate) fn baggage_generic_types(&self) -> Vec<Ident> {
|
||||
self.baggage
|
||||
.iter()
|
||||
|
||||
@@ -7,3 +7,9 @@ fn ui_compile_fail() {
|
||||
let t = trybuild::TestCases::new();
|
||||
t.compile_fail("tests/ui/err-*.rs");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ui_pass() {
|
||||
let t = trybuild::TestCases::new();
|
||||
t.pass("tests/ui/ok-*.rs");
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
error[E0119]: conflicting implementations of trait `std::convert::From<MsgStrukt>` for type `AllMessages`
|
||||
--> $DIR/err-01-duplicate-consumer.rs:19:1
|
||||
--> tests/ui/err-01-duplicate-consumer.rs:19:1
|
||||
|
|
||||
19 | #[overlord(signal=SigSigSig, event=Event, gen=AllMessages, error=OverseerError)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
@@ -10,7 +10,7 @@ error[E0119]: conflicting implementations of trait `std::convert::From<MsgStrukt
|
||||
= note: this error originates in the attribute macro `overlord` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error[E0119]: conflicting implementations of trait `polkadot_overseer_gen::SubsystemSender<MsgStrukt>` for type `OverseerSubsystemSender`
|
||||
--> $DIR/err-01-duplicate-consumer.rs:19:1
|
||||
--> tests/ui/err-01-duplicate-consumer.rs:19:1
|
||||
|
|
||||
19 | #[overlord(signal=SigSigSig, event=Event, gen=AllMessages, error=OverseerError)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
#![allow(dead_code)]
|
||||
|
||||
use polkadot_overseer_gen::*;
|
||||
|
||||
#[derive(Default)]
|
||||
struct AwesomeSubSys;
|
||||
|
||||
impl ::polkadot_overseer_gen::Subsystem<OverseerSubsystemContext<MsgStrukt>, OverseerError> for AwesomeSubSys {
|
||||
fn start(self, _ctx: OverseerSubsystemContext<MsgStrukt>) -> SpawnedSubsystem<OverseerError> {
|
||||
unimplemented!("starting yay!")
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct SigSigSig;
|
||||
|
||||
pub struct Event;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct MsgStrukt(u8);
|
||||
|
||||
#[overlord(signal=SigSigSig, error=OverseerError, event=Event, gen=AllMessages)]
|
||||
struct Overseer {
|
||||
#[subsystem(no_dispatch, MsgStrukt)]
|
||||
sub0: AwesomeSubSys,
|
||||
i_like_pie: f64,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct DummySpawner;
|
||||
|
||||
impl SpawnNamed for DummySpawner {
|
||||
fn spawn_blocking(
|
||||
&self,
|
||||
task_name: &'static str,
|
||||
subsystem_name: Option<&'static str>,
|
||||
_future: futures::future::BoxFuture<'static, ()>,
|
||||
) {
|
||||
unimplemented!("spawn blocking {} {}", task_name, subsystem_name.unwrap_or("default"))
|
||||
}
|
||||
|
||||
fn spawn(
|
||||
&self,
|
||||
task_name: &'static str,
|
||||
subsystem_name: Option<&'static str>,
|
||||
_future: futures::future::BoxFuture<'static, ()>,
|
||||
) {
|
||||
unimplemented!("spawn {} {}", task_name, subsystem_name.unwrap_or("default"))
|
||||
}
|
||||
}
|
||||
|
||||
struct DummyCtx;
|
||||
|
||||
fn main() {
|
||||
let _ = Overseer::builder()
|
||||
.sub0(AwesomeSubSys::default())
|
||||
//.i_like_pie(std::f64::consts::PI) // The filed is not initialised
|
||||
.spawner(DummySpawner)
|
||||
.build()
|
||||
.unwrap();
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
error[E0599]: no method named `build` found for struct `OverseerBuilder<Init<DummySpawner>, Init<AwesomeSubSys>, Missing<f64>>` in the current scope
|
||||
--> tests/ui/err-05-missing-field.rs:59:4
|
||||
|
|
||||
22 | #[overlord(signal=SigSigSig, error=OverseerError, event=Event, gen=AllMessages)]
|
||||
| -------------------------------------------------------------------------------- method `build` not found for this
|
||||
...
|
||||
59 | .build()
|
||||
| ^^^^^ method not found in `OverseerBuilder<Init<DummySpawner>, Init<AwesomeSubSys>, Missing<f64>>`
|
||||
|
|
||||
= note: the method was found for
|
||||
- `OverseerBuilder<Init<S>, Init<AwesomeSubSys>, Init<f64>>`
|
||||
= help: items from traits can only be used if the trait is implemented and in scope
|
||||
= note: the following traits define an item `build`, perhaps you need to implement one of them:
|
||||
candidate #1: `frame_support::traits::hooks::GenesisBuild`
|
||||
candidate #2: `prometheus::vec::MetricVecBuilder`
|
||||
@@ -0,0 +1,61 @@
|
||||
#![allow(dead_code)]
|
||||
|
||||
use polkadot_overseer_gen::*;
|
||||
|
||||
#[derive(Default)]
|
||||
struct AwesomeSubSys;
|
||||
|
||||
impl ::polkadot_overseer_gen::Subsystem<OverseerSubsystemContext<MsgStrukt>, OverseerError> for AwesomeSubSys {
|
||||
fn start(self, _ctx: OverseerSubsystemContext<MsgStrukt>) -> SpawnedSubsystem<OverseerError> {
|
||||
unimplemented!("starting yay!")
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct SigSigSig;
|
||||
|
||||
pub struct Event;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct MsgStrukt(u8);
|
||||
|
||||
#[overlord(signal=SigSigSig, error=OverseerError, event=Event, gen=AllMessages)]
|
||||
struct Overseer {
|
||||
#[subsystem(no_dispatch, MsgStrukt)]
|
||||
sub0: AwesomeSubSys,
|
||||
i_like_pie: f64,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct DummySpawner;
|
||||
|
||||
impl SpawnNamed for DummySpawner {
|
||||
fn spawn_blocking(
|
||||
&self,
|
||||
task_name: &'static str,
|
||||
subsystem_name: Option<&'static str>,
|
||||
_future: futures::future::BoxFuture<'static, ()>,
|
||||
) {
|
||||
unimplemented!("spawn blocking {} {}", task_name, subsystem_name.unwrap_or("default"))
|
||||
}
|
||||
|
||||
fn spawn(
|
||||
&self,
|
||||
task_name: &'static str,
|
||||
subsystem_name: Option<&'static str>,
|
||||
_future: futures::future::BoxFuture<'static, ()>,
|
||||
) {
|
||||
unimplemented!("spawn {} {}", task_name, subsystem_name.unwrap_or("default"))
|
||||
}
|
||||
}
|
||||
|
||||
struct DummyCtx;
|
||||
|
||||
fn main() {
|
||||
let _ = Overseer::builder()
|
||||
//.sub0(AwesomeSubSys::default()) // Subsystem is uninitialized
|
||||
.i_like_pie(std::f64::consts::PI)
|
||||
.spawner(DummySpawner)
|
||||
.build()
|
||||
.unwrap();
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
error[E0599]: no method named `build` found for struct `OverseerBuilder<Init<DummySpawner>, Missing<_>, Init<f64>>` in the current scope
|
||||
--> tests/ui/err-06-missing-subsystem.rs:59:4
|
||||
|
|
||||
22 | #[overlord(signal=SigSigSig, error=OverseerError, event=Event, gen=AllMessages)]
|
||||
| -------------------------------------------------------------------------------- method `build` not found for this
|
||||
...
|
||||
59 | .build()
|
||||
| ^^^^^ method not found in `OverseerBuilder<Init<DummySpawner>, Missing<_>, Init<f64>>`
|
||||
|
|
||||
= note: the method was found for
|
||||
- `OverseerBuilder<Init<S>, Init<AwesomeSubSys>, Init<f64>>`
|
||||
= help: items from traits can only be used if the trait is implemented and in scope
|
||||
= note: the following traits define an item `build`, perhaps you need to implement one of them:
|
||||
candidate #1: `frame_support::traits::hooks::GenesisBuild`
|
||||
candidate #2: `prometheus::vec::MetricVecBuilder`
|
||||
@@ -0,0 +1,61 @@
|
||||
#![allow(dead_code)]
|
||||
|
||||
use polkadot_overseer_gen::*;
|
||||
|
||||
#[derive(Default)]
|
||||
struct AwesomeSubSys;
|
||||
|
||||
impl ::polkadot_overseer_gen::Subsystem<OverseerSubsystemContext<MsgStrukt>, OverseerError> for AwesomeSubSys {
|
||||
fn start(self, _ctx: OverseerSubsystemContext<MsgStrukt>) -> SpawnedSubsystem<OverseerError> {
|
||||
unimplemented!("starting yay!")
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct SigSigSig;
|
||||
|
||||
pub struct Event;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct MsgStrukt(u8);
|
||||
|
||||
#[overlord(signal=SigSigSig, error=OverseerError, event=Event, gen=AllMessages)]
|
||||
struct Overseer {
|
||||
#[subsystem(no_dispatch, MsgStrukt)]
|
||||
sub0: AwesomeSubSys,
|
||||
i_like_pie: f64,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct DummySpawner;
|
||||
|
||||
impl SpawnNamed for DummySpawner {
|
||||
fn spawn_blocking(
|
||||
&self,
|
||||
task_name: &'static str,
|
||||
subsystem_name: Option<&'static str>,
|
||||
_future: futures::future::BoxFuture<'static, ()>,
|
||||
) {
|
||||
unimplemented!("spawn blocking {} {}", task_name, subsystem_name.unwrap_or("default"))
|
||||
}
|
||||
|
||||
fn spawn(
|
||||
&self,
|
||||
task_name: &'static str,
|
||||
subsystem_name: Option<&'static str>,
|
||||
_future: futures::future::BoxFuture<'static, ()>,
|
||||
) {
|
||||
unimplemented!("spawn {} {}", task_name, subsystem_name.unwrap_or("default"))
|
||||
}
|
||||
}
|
||||
|
||||
struct DummyCtx;
|
||||
|
||||
fn main() {
|
||||
let _ = Overseer::builder()
|
||||
.sub0(AwesomeSubSys::default())
|
||||
.i_like_pie(std::f64::consts::PI)
|
||||
//.spawner(DummySpawner) // Spawner is missing
|
||||
.build()
|
||||
.unwrap();
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
error[E0599]: no method named `build` found for struct `OverseerBuilder<Missing<_>, Init<AwesomeSubSys>, Init<f64>>` in the current scope
|
||||
--> tests/ui/err-07-missing-spawner.rs:59:4
|
||||
|
|
||||
22 | #[overlord(signal=SigSigSig, error=OverseerError, event=Event, gen=AllMessages)]
|
||||
| -------------------------------------------------------------------------------- method `build` not found for this
|
||||
...
|
||||
59 | .build()
|
||||
| ^^^^^ method not found in `OverseerBuilder<Missing<_>, Init<AwesomeSubSys>, Init<f64>>`
|
||||
|
|
||||
= note: the method was found for
|
||||
- `OverseerBuilder<Init<S>, Init<AwesomeSubSys>, Init<f64>>`
|
||||
= help: items from traits can only be used if the trait is implemented and in scope
|
||||
= note: the following traits define an item `build`, perhaps you need to implement one of them:
|
||||
candidate #1: `frame_support::traits::hooks::GenesisBuild`
|
||||
candidate #2: `prometheus::vec::MetricVecBuilder`
|
||||
@@ -0,0 +1,62 @@
|
||||
#![allow(dead_code)]
|
||||
|
||||
use polkadot_overseer_gen::*;
|
||||
|
||||
#[derive(Default)]
|
||||
struct AwesomeSubSys;
|
||||
|
||||
impl ::polkadot_overseer_gen::Subsystem<OverseerSubsystemContext<MsgStrukt>, OverseerError> for AwesomeSubSys {
|
||||
fn start(self, _ctx: OverseerSubsystemContext<MsgStrukt>) -> SpawnedSubsystem<OverseerError> {
|
||||
unimplemented!("starting yay!")
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct SigSigSig;
|
||||
|
||||
pub struct Event;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct MsgStrukt(u8);
|
||||
|
||||
#[overlord(signal=SigSigSig, error=OverseerError, event=Event, gen=AllMessages)]
|
||||
struct Overseer {
|
||||
#[subsystem(no_dispatch, MsgStrukt)]
|
||||
sub0: AwesomeSubSys,
|
||||
i_like_pie: f64,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct DummySpawner;
|
||||
|
||||
impl SpawnNamed for DummySpawner {
|
||||
fn spawn_blocking(
|
||||
&self,
|
||||
task_name: &'static str,
|
||||
subsystem_name: Option<&'static str>,
|
||||
_future: futures::future::BoxFuture<'static, ()>,
|
||||
) {
|
||||
unimplemented!("spawn blocking {} {}", task_name, subsystem_name.unwrap_or("default"))
|
||||
}
|
||||
|
||||
fn spawn(
|
||||
&self,
|
||||
task_name: &'static str,
|
||||
subsystem_name: Option<&'static str>,
|
||||
_future: futures::future::BoxFuture<'static, ()>,
|
||||
) {
|
||||
unimplemented!("spawn {} {}", task_name, subsystem_name.unwrap_or("default"))
|
||||
}
|
||||
}
|
||||
|
||||
struct DummyCtx;
|
||||
|
||||
fn main() {
|
||||
let _ = Overseer::builder()
|
||||
.sub0(AwesomeSubSys::default())
|
||||
.sub0(AwesomeSubSys::default()) // Duplicate subsystem
|
||||
.i_like_pie(std::f64::consts::PI)
|
||||
.spawner(DummySpawner)
|
||||
.build()
|
||||
.unwrap();
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
error[E0599]: no method named `sub0` found for struct `OverseerBuilder<Missing<_>, Init<AwesomeSubSys>, Missing<f64>>` in the current scope
|
||||
--> tests/ui/err-08-duplicate-subsystem.rs:57:4
|
||||
|
|
||||
22 | #[overlord(signal=SigSigSig, error=OverseerError, event=Event, gen=AllMessages)]
|
||||
| -------------------------------------------------------------------------------- method `sub0` not found for this
|
||||
...
|
||||
57 | .sub0(AwesomeSubSys::default()) // Duplicate subsystem
|
||||
| ^^^^-------------------------- help: remove the arguments
|
||||
| |
|
||||
| field, not a method
|
||||
@@ -0,0 +1,61 @@
|
||||
#![allow(dead_code)]
|
||||
|
||||
use polkadot_overseer_gen::*;
|
||||
|
||||
#[derive(Default)]
|
||||
struct AwesomeSubSys;
|
||||
|
||||
impl ::polkadot_overseer_gen::Subsystem<OverseerSubsystemContext<MsgStrukt>, OverseerError> for AwesomeSubSys {
|
||||
fn start(self, _ctx: OverseerSubsystemContext<MsgStrukt>) -> SpawnedSubsystem<OverseerError> {
|
||||
unimplemented!("starting yay!")
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct SigSigSig;
|
||||
|
||||
pub struct Event;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct MsgStrukt(u8);
|
||||
|
||||
#[overlord(signal=SigSigSig, error=OverseerError, event=Event, gen=AllMessages)]
|
||||
struct Overseer<T> {
|
||||
#[subsystem(no_dispatch, MsgStrukt)]
|
||||
sub0: AwesomeSubSys,
|
||||
i_like_pie: T,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct DummySpawner;
|
||||
|
||||
impl SpawnNamed for DummySpawner {
|
||||
fn spawn_blocking(
|
||||
&self,
|
||||
task_name: &'static str,
|
||||
subsystem_name: Option<&'static str>,
|
||||
_future: futures::future::BoxFuture<'static, ()>,
|
||||
) {
|
||||
unimplemented!("spawn blocking {} {}", task_name, subsystem_name.unwrap_or("default"))
|
||||
}
|
||||
|
||||
fn spawn(
|
||||
&self,
|
||||
task_name: &'static str,
|
||||
subsystem_name: Option<&'static str>,
|
||||
_future: futures::future::BoxFuture<'static, ()>,
|
||||
) {
|
||||
unimplemented!("spawn {} {}", task_name, subsystem_name.unwrap_or("default"))
|
||||
}
|
||||
}
|
||||
|
||||
struct DummyCtx;
|
||||
|
||||
fn main() {
|
||||
let (_, _): (Overseer<_, f64>, _) = Overseer::builder()
|
||||
.sub0(AwesomeSubSys::default())
|
||||
//.i_like_pie(std::f64::consts::PI) // The filed is not initialised
|
||||
.spawner(DummySpawner)
|
||||
.build()
|
||||
.unwrap();
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
error[E0599]: no method named `build` found for struct `OverseerBuilder<Init<DummySpawner>, Init<AwesomeSubSys>, Missing<_>>` in the current scope
|
||||
--> tests/ui/err-09-uninit_generic_baggage.rs:59:4
|
||||
|
|
||||
22 | #[overlord(signal=SigSigSig, error=OverseerError, event=Event, gen=AllMessages)]
|
||||
| -------------------------------------------------------------------------------- method `build` not found for this
|
||||
...
|
||||
59 | .build()
|
||||
| ^^^^^ method not found in `OverseerBuilder<Init<DummySpawner>, Init<AwesomeSubSys>, Missing<_>>`
|
||||
|
|
||||
= note: the method was found for
|
||||
- `OverseerBuilder<Init<S>, Init<AwesomeSubSys>, Init<T>>`
|
||||
= help: items from traits can only be used if the trait is implemented and in scope
|
||||
= note: the following traits define an item `build`, perhaps you need to implement one of them:
|
||||
candidate #1: `frame_support::traits::hooks::GenesisBuild`
|
||||
candidate #2: `prometheus::vec::MetricVecBuilder`
|
||||
@@ -0,0 +1,75 @@
|
||||
#![allow(dead_code)]
|
||||
|
||||
use polkadot_overseer_gen::*;
|
||||
|
||||
#[derive(Default)]
|
||||
struct AwesomeSubSysA;
|
||||
|
||||
|
||||
impl ::polkadot_overseer_gen::Subsystem<OverseerSubsystemContext<MsgA>, OverseerError> for AwesomeSubSysA {
|
||||
fn start(self, _ctx: OverseerSubsystemContext<MsgA>) -> SpawnedSubsystem<OverseerError> {
|
||||
SpawnedSubsystem { name: "sub A", future: Box::pin(async move { Ok(()) }) }
|
||||
}
|
||||
}
|
||||
impl ::polkadot_overseer_gen::Subsystem<OverseerSubsystemContext<MsgB>, OverseerError> for AwesomeSubSysB {
|
||||
fn start(self, _ctx: OverseerSubsystemContext<MsgB>) -> SpawnedSubsystem<OverseerError> {
|
||||
SpawnedSubsystem { name: "sub B", future: Box::pin(async move { Ok(()) }) }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct DummySpawner;
|
||||
|
||||
impl SpawnNamed for DummySpawner {
|
||||
fn spawn_blocking(
|
||||
&self,
|
||||
task_name: &'static str,
|
||||
subsystem_name: Option<&'static str>,
|
||||
_future: futures::future::BoxFuture<'static, ()>,
|
||||
) {
|
||||
println!("spawn blocking {} {}", task_name, subsystem_name.unwrap_or("default"))
|
||||
}
|
||||
|
||||
fn spawn(
|
||||
&self,
|
||||
task_name: &'static str,
|
||||
subsystem_name: Option<&'static str>,
|
||||
_future: futures::future::BoxFuture<'static, ()>,
|
||||
) {
|
||||
println!("spawn {} {}", task_name, subsystem_name.unwrap_or("default"))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
struct AwesomeSubSysB;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct SigSigSig;
|
||||
|
||||
pub struct Event;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct MsgA(u8);
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct MsgB(u8);
|
||||
|
||||
#[overlord(signal=SigSigSig, event=Event, gen=AllMessages, error=OverseerError)]
|
||||
pub struct Overseer {
|
||||
#[subsystem(MsgA)]
|
||||
sub_a: AwesomeSubSysA,
|
||||
|
||||
#[subsystem(wip, MsgB)]
|
||||
sub_b: AwesomeSubSysB,
|
||||
}
|
||||
|
||||
pub struct DummyCtx;
|
||||
|
||||
fn main() {
|
||||
let _overseer_builder = Overseer::builder()
|
||||
.sub_a(AwesomeSubSysA::default())
|
||||
// b is tagged as `wip`
|
||||
// .sub_b(AwesomeSubSysB::default())
|
||||
.spawner(DummySpawner)
|
||||
.build();
|
||||
}
|
||||
@@ -15,8 +15,8 @@
|
||||
// along with Polkadot. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use crate::{
|
||||
prometheus::Registry, AllMessages, HeadSupportsParachains, MetricsTrait, Overseer,
|
||||
OverseerBuilder, OverseerMetrics, OverseerSignal, OverseerSubsystemContext, SpawnNamed,
|
||||
prometheus::Registry, AllMessages, HeadSupportsParachains, InitializedOverseerBuilder,
|
||||
MetricsTrait, Overseer, OverseerMetrics, OverseerSignal, OverseerSubsystemContext, SpawnNamed,
|
||||
KNOWN_LEAVES_CACHE_SIZE,
|
||||
};
|
||||
use lru::LruCache;
|
||||
@@ -66,7 +66,7 @@ pub fn dummy_overseer_builder<'a, Spawner, SupportsParachains>(
|
||||
supports_parachains: SupportsParachains,
|
||||
registry: Option<&'a Registry>,
|
||||
) -> Result<
|
||||
OverseerBuilder<
|
||||
InitializedOverseerBuilder<
|
||||
Spawner,
|
||||
SupportsParachains,
|
||||
DummySubsystem,
|
||||
@@ -107,7 +107,7 @@ pub fn one_for_all_overseer_builder<'a, Spawner, SupportsParachains, Sub>(
|
||||
subsystem: Sub,
|
||||
registry: Option<&'a Registry>,
|
||||
) -> Result<
|
||||
OverseerBuilder<
|
||||
InitializedOverseerBuilder<
|
||||
Spawner,
|
||||
SupportsParachains,
|
||||
Sub,
|
||||
|
||||
@@ -30,8 +30,8 @@ pub use polkadot_overseer::{
|
||||
HeadSupportsParachains,
|
||||
};
|
||||
use polkadot_overseer::{
|
||||
metrics::Metrics as OverseerMetrics, BlockInfo, MetricsTrait, Overseer, OverseerBuilder,
|
||||
OverseerConnector, OverseerHandle,
|
||||
metrics::Metrics as OverseerMetrics, BlockInfo, InitializedOverseerBuilder, MetricsTrait,
|
||||
Overseer, OverseerConnector, OverseerHandle,
|
||||
};
|
||||
|
||||
use polkadot_primitives::v2::ParachainHost;
|
||||
@@ -142,7 +142,7 @@ pub fn prepared_overseer_builder<'a, Spawner, RuntimeClient>(
|
||||
pvf_checker_enabled,
|
||||
}: OverseerGenArgs<'a, Spawner, RuntimeClient>,
|
||||
) -> Result<
|
||||
OverseerBuilder<
|
||||
InitializedOverseerBuilder<
|
||||
Spawner,
|
||||
Arc<RuntimeClient>,
|
||||
CandidateValidationSubsystem,
|
||||
|
||||
Reference in New Issue
Block a user