use crate::Environment;
#[doc(hidden)]
pub trait TopicsBuilderBackend<E>
where
E: Environment,
{
type Output;
fn expect(&mut self, expected_topics: usize);
fn push_topic<T>(&mut self, topic_value: &T)
where
T: scale::Encode;
fn output(self) -> Self::Output;
}
#[doc(hidden)]
pub struct TopicsBuilder<S, E, B> {
backend: B,
state: core::marker::PhantomData<fn() -> (S, E)>,
}
impl<E, B> From<B> for TopicsBuilder<state::Uninit, E, B>
where
E: Environment,
B: TopicsBuilderBackend<E>,
{
fn from(backend: B) -> Self {
Self {
backend,
state: Default::default(),
}
}
}
#[doc(hidden)]
pub mod state {
pub enum Uninit {}
pub enum HasRemainingTopics {}
pub enum NoRemainingTopics {}
}
impl<E, B> TopicsBuilder<state::Uninit, E, B>
where
E: Environment,
B: TopicsBuilderBackend<E>,
{
pub fn build<Evt: Event>(
mut self,
) -> TopicsBuilder<<Evt as Event>::RemainingTopics, E, B> {
self.backend
.expect(<<Evt as Event>::RemainingTopics as EventTopicsAmount>::AMOUNT);
TopicsBuilder {
backend: self.backend,
state: Default::default(),
}
}
}
impl<E, S, B> TopicsBuilder<S, E, B>
where
E: Environment,
S: SomeRemainingTopics,
B: TopicsBuilderBackend<E>,
{
pub fn push_topic<T>(
mut self,
value: Option<&T>,
) -> TopicsBuilder<<S as SomeRemainingTopics>::Next, E, B>
where
T: scale::Encode,
{
if let Some(topic) = value {
self.backend.push_topic::<T>(topic);
} else {
self.backend.push_topic::<u8>(&0u8);
}
TopicsBuilder {
backend: self.backend,
state: Default::default(),
}
}
}
impl<E, B> TopicsBuilder<state::NoRemainingTopics, E, B>
where
E: Environment,
B: TopicsBuilderBackend<E>,
{
pub fn finish(self) -> <B as TopicsBuilderBackend<E>>::Output
where
B: TopicsBuilderBackend<E>,
{
self.backend.output()
}
}
#[doc(hidden)]
pub trait SomeRemainingTopics {
type Next;
}
#[doc(hidden)]
pub trait EventTopicsAmount {
const AMOUNT: usize;
}
macro_rules! impl_some_remaining_for {
( $( $n:literal ),* $(,)? ) => {
$(
impl SomeRemainingTopics for [state::HasRemainingTopics; $n] {
type Next = [state::HasRemainingTopics; $n - 1];
}
impl EventTopicsAmount for [state::HasRemainingTopics; $n] {
const AMOUNT: usize = $n;
}
)*
};
}
#[rustfmt::skip]
impl_some_remaining_for!(
2, 3, 4, 5, 6, 7, 8, 9,
10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
30, 31, 32,
);
impl SomeRemainingTopics for [state::HasRemainingTopics; 1] {
type Next = state::NoRemainingTopics;
}
impl EventTopicsAmount for [state::HasRemainingTopics; 1] {
const AMOUNT: usize = 1;
}
impl EventTopicsAmount for state::NoRemainingTopics {
const AMOUNT: usize = 0;
}
pub trait Event: scale::Encode {
type RemainingTopics: EventTopicsAmount;
const SIGNATURE_TOPIC: core::option::Option<[u8; 32]>;
fn topics<E, B>(
&self,
builder: TopicsBuilder<state::Uninit, E, B>,
) -> <B as TopicsBuilderBackend<E>>::Output
where
E: Environment,
B: TopicsBuilderBackend<E>;
}