#[macro_export]
macro_rules! forward {
(@go $st:ty; [$field:tt]; map_err = $err:expr $(,)?) => {
#[inline]
fn bind(&self, ctx: $crate::BindCtx<'_>) {
ctx.bind::<_, $st, _>(&self.$field);
}
#[inline]
async fn ready(&self, ctx: $crate::Ctx<'_, Self, $st>) -> Result<(), Self::Error> {
ctx.ready(&self.$field).await.map_err($err)
}
#[inline]
async fn shutdown(&self, ctx: $crate::Ctx<'_, Self, $st>) {
ctx.shutdown(&self.$field).await
}
};
(@go $st:ty; [$($field:tt)+]; map_err = $err:expr $(,)?) => {
#[inline]
fn bind(&self, ctx: $crate::BindCtx<'_>) {
$(ctx.bind::<_, $st, _>(&self.$field);)+
}
async fn ready(&self, ctx: $crate::Ctx<'_, Self, $st>) -> Result<(), Self::Error> {
$crate::forward!(@ready ctx, self, $err; $($field)+)
.await
.map(|_| ())
}
async fn shutdown(&self, ctx: $crate::Ctx<'_, Self, $st>) {
$crate::forward!(@shutdown ctx, self; $($field)+).await
}
};
(@go $st:ty; []; map_err $($rest:tt)*) => {
::core::compile_error!(
"forward!: list at least one service field before `map_err`, e.g. `forward!(St, service, map_err = f)`"
);
};
(@go $st:ty; [$($field:tt)*]; self . $($rest:tt)*) => {
::core::compile_error!(
"forward!: write field names without `self.`, e.g. `forward!(St, service)`"
);
};
(@go $st:ty; [$($field:tt)*]; $next:tt . $($rest:tt)*) => {
::core::compile_error!(
"forward!: nested field paths are not supported, implement `bind`, `ready`, and `shutdown` manually"
);
};
(@go $st:ty; [$($field:tt)+]; ) => {
$crate::forward!(@go $st; [$($field)+]; map_err = ::core::convert::Into::into);
};
(@go $st:ty; [$($field:tt)*]; $next:tt $(, $($rest:tt)*)?) => {
$crate::forward!(@go $st; [$($field)* $next]; $($($rest)*)?);
};
(@ready $ctx:ident, $this:tt, $err:expr; $field:tt) => {
$crate::__private::ready_field($ctx, &$this.$field, $err)
};
(@ready $ctx:ident, $this:tt, $err:expr; $field:tt $($rest:tt)+) => {
$crate::__private::ready_join(
$ctx,
|| $crate::__private::ready_field($ctx, &$this.$field, $err),
|| $crate::forward!(@ready $ctx, $this, $err; $($rest)+),
)
};
(@shutdown $ctx:ident, $this:tt; $field:tt) => {
$ctx.shutdown(&$this.$field)
};
(@shutdown $ctx:ident, $this:tt; $field:tt $($rest:tt)+) => {
$crate::__private::join(
$ctx.shutdown(&$this.$field),
$crate::forward!(@shutdown $ctx, $this; $($rest)+),
)
};
($one:tt $(,)?) => {
::core::compile_error!(
"forward!: expected a state type and at least one service field, e.g. `forward!(St, service)`"
);
};
($st:ty, $($rest:tt)+) => {
$crate::forward!(@go $st; []; $($rest)+);
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! forward_bind {
($st:ty, $($field:tt),+ $(,)?) => {
#[inline]
fn bind(&self, ctx: $crate::BindCtx<'_>) {
$(ctx.bind::<_, $st, _>(&self.$field);)+
}
};
($st:ty, $this:ident.$field:tt) => {
#[inline]
fn bind(&$this, ctx: $crate::BindCtx<'_>) {
ctx.bind::<_, $st, _>(&$this.$field);
}
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! forward_ready {
($st:ty, $field:ident) => {
#[inline]
async fn ready(&self, ctx: $crate::Ctx<'_, Self, $st>) -> Result<(), Self::Error> {
ctx.ready(&self.$field)
.await
.map_err(::core::convert::Into::into)
}
};
($st:ty, $field:ident, $err:expr) => {
#[inline]
async fn ready(&self, ctx: $crate::Ctx<'_, Self, $st>) -> Result<(), Self::Error> {
ctx.ready(&self.$field).await.map_err($err)
}
};
($st:ty, $this:ident.$field:tt) => {
#[inline]
async fn ready(&$this, ctx: $crate::Ctx<'_, Self, $st>) -> Result<(), Self::Error> {
ctx.ready(&$this.$field)
.await
.map_err(::core::convert::Into::into)
}
};
($st:ty, $this:ident.$field:tt, $err:expr) => {
#[inline]
async fn ready(&$this, ctx: $crate::Ctx<'_, Self, $st>) -> Result<(), Self::Error> {
ctx.ready(&$this.$field).await.map_err($err)
}
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! forward_shutdown {
($st:ty, $field:ident) => {
#[inline]
async fn shutdown(&self, ctx: $crate::Ctx<'_, Self, $st>) {
ctx.shutdown(&self.$field).await
}
};
($st:ty, $this:ident.$field:tt) => {
#[inline]
async fn shutdown(&$this, ctx: $crate::Ctx<'_, Self, $st>) {
ctx.shutdown(&$this.$field).await
}
};
}