use std::{
marker::PhantomData,
pin::Pin,
task::{Context, Poll},
};
use futures::Stream;
use pin_project_lite::pin_project;
use serde::de::DeserializeOwned;
use crate::{codec::CodecType, error::Result};
#[derive(Debug)]
pub struct Message<T> {
pub payload: T,
pub subject: String,
pub reply: Option<String>,
raw: async_nats::Message,
}
impl<T> Message<T> {
pub fn raw(&self) -> &async_nats::Message {
&self.raw
}
}
pin_project! {
pub struct Subscriber<T, C: CodecType> {
#[pin]
inner: async_nats::Subscriber,
_marker: PhantomData<(T, C)>,
}
}
impl<T, C: CodecType> Subscriber<T, C> {
pub(crate) fn new(inner: async_nats::Subscriber) -> Self {
Self {
inner,
_marker: PhantomData,
}
}
pub fn inner(&self) -> &async_nats::Subscriber {
&self.inner
}
pub async fn unsubscribe(mut self) -> Result<()> {
self.inner
.unsubscribe()
.await
.map_err(|e| crate::error::Error::Nats(e.into()))
}
}
impl<T: DeserializeOwned, C: CodecType> Stream for Subscriber<T, C> {
type Item = Result<Message<T>>;
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
let this = self.project();
match this.inner.poll_next(cx) {
Poll::Ready(Some(msg)) => {
let reply = msg.reply.as_ref().map(|r| r.to_string());
let result = C::decode(&msg.payload).map(|payload| Message {
payload,
subject: msg.subject.to_string(),
reply,
raw: msg,
});
Poll::Ready(Some(result))
}
Poll::Ready(None) => Poll::Ready(None),
Poll::Pending => Poll::Pending,
}
}
}