mod autoreply;
mod ping;
use std::ops::ControlFlow;
pub use autoreply::*;
pub use ping::*;
use super::{cf_discard, channel::SenderRef, queue::QueueEditGuard, Handler, SelfMadeHandler};
use crate::{
client::ClientState,
ircmsg::{ServerMsg, ServerMsgKindRaw},
names::{NameValued, ServerMsgKind},
util::FlatMap,
};
#[derive(Clone, Copy, Debug, Default)]
pub struct YieldAll;
impl Handler for YieldAll {
type Value = ServerMsg<'static>;
fn handle(
&mut self,
msg: &crate::ircmsg::ServerMsg<'_>,
_: &mut ClientState,
_: QueueEditGuard<'_>,
mut channel: super::channel::SenderRef<'_, Self::Value>,
) -> ControlFlow<()> {
crate::client::cf_discard(channel.send(msg.clone().owning()))
}
fn wants_owning(&self) -> bool {
true
}
}
impl SelfMadeHandler for YieldAll {
type Receiver<Spec: super::channel::ChannelSpec> = Spec::Queue<Self::Value>;
fn queue_msgs(&self, _: &ClientState, _: QueueEditGuard<'_>) {}
fn make_channel<Spec: super::channel::ChannelSpec>(
spec: &Spec,
) -> (Box<dyn super::channel::Sender<Value = Self::Value> + Send>, Self::Receiver<Spec>) {
spec.new_queue()
}
}
type Parser<T> = dyn FnMut(ServerMsg<'static>, SenderRef<T>) -> ControlFlow<()> + Send;
#[derive(Default)]
pub struct YieldParsed<T>(FlatMap<(ServerMsgKindRaw<'static>, Box<Parser<T>>)>);
impl<T: 'static + Send> YieldParsed<T> {
pub const fn new() -> Self {
YieldParsed(FlatMap::new())
}
pub fn just<N>(kind: N) -> Self
where
N: NameValued<ServerMsgKind, Value<'static> = T>,
{
YieldParsed(FlatMap::singleton((
kind.as_raw().clone(),
Box::new(|raw, mut sender| {
if let Ok(parsed) = N::from_union(&raw) {
cf_discard(sender.send(parsed))
} else {
ControlFlow::Continue(())
}
}),
)))
}
#[deprecated = "Function parameter changing in 0.4. Use `YieldAll::just_flat_map` instead."]
pub fn just_map<U, N, F>(kind: N, f: F) -> Self
where
N: NameValued<ServerMsgKind, Value<'static> = U>,
F: FnMut(U) -> Option<T> + 'static + Send,
{
Self::just_flat_map(kind, f)
}
pub fn just_flat_map<U, N, I, F>(kind: N, mut f: F) -> Self
where
N: NameValued<ServerMsgKind, Value<'static> = U>,
I: IntoIterator<Item = T>,
F: FnMut(U) -> I + 'static + Send,
{
YieldParsed(FlatMap::singleton((
kind.as_raw().clone(),
Box::new(move |raw, mut sender| {
if let Ok(parsed) = N::from_union(&raw) {
for value in f(parsed) {
cf_discard(sender.send(value))?;
}
}
ControlFlow::Continue(())
}),
)))
}
pub fn with<N>(mut self, kind: N) -> Self
where
N: NameValued<ServerMsgKind, Value<'static> = T>,
{
self.0.edit().insert((
kind.as_raw().clone(),
Box::new(|raw, mut sender| {
if let Ok(parsed) = N::from_union(&raw) {
cf_discard(sender.send(parsed))
} else {
ControlFlow::Continue(())
}
}),
));
self
}
#[deprecated = "Function parameter changing in 0.4. Use `YieldAll::with_flat_map` instead."]
pub fn with_map<U, N, F>(self, kind: N, f: F) -> Self
where
N: NameValued<ServerMsgKind, Value<'static> = U>,
F: FnMut(U) -> Option<T> + 'static + Send,
{
self.with_flat_map(kind, f)
}
pub fn with_flat_map<U, N, I, F>(mut self, kind: N, mut f: F) -> Self
where
N: NameValued<ServerMsgKind, Value<'static> = U>,
I: IntoIterator<Item = T>,
F: FnMut(U) -> I + 'static + Send,
{
self.0.edit().insert((
kind.as_raw().clone(),
Box::new(move |raw, mut sender| {
if let Ok(parsed) = N::from_union(&raw) {
for value in f(parsed) {
cf_discard(sender.send(value))?;
}
}
ControlFlow::Continue(())
}),
));
self
}
}
impl<T: 'static + Send> Handler for YieldParsed<T> {
type Value = T;
fn handle(
&mut self,
msg: &ServerMsg<'_>,
_: &mut ClientState,
_: QueueEditGuard<'_>,
channel: super::channel::SenderRef<'_, Self::Value>,
) -> ControlFlow<()> {
let msg = msg.clone().owning();
if let Some((_, parser)) = self.0.get_mut(&msg.kind) {
parser(msg, channel)?;
};
ControlFlow::Continue(())
}
fn wants_owning(&self) -> bool {
true
}
}
impl<T: 'static + Send> SelfMadeHandler for YieldParsed<T> {
type Receiver<Spec: super::channel::ChannelSpec> = Spec::Queue<T>;
fn queue_msgs(&self, _: &ClientState, _: QueueEditGuard<'_>) {}
fn make_channel<Spec: super::channel::ChannelSpec>(
spec: &Spec,
) -> (Box<dyn super::channel::Sender<Value = Self::Value> + Send>, Self::Receiver<Spec>) {
spec.new_queue()
}
}