Skip to main content

persistent_queue/
typed.rs

1//! The typed queue layer: encode on push, decode on reserve, over any [`Codec`].
2
3use std::error::Error as StdError;
4use std::fmt;
5use std::marker::PhantomData;
6use std::ops::Deref;
7
8use crate::codec::{Codec, CodecError};
9use crate::error::{OpenError, PushError};
10use crate::queue::{Builder, Consumer, Producer, Reserved};
11use crate::store::Store;
12
13/// The producer/consumer pair returned by [`Builder::open_typed`].
14pub type TypedEnds<S, T, C> = (TypedProducer<S, T, C>, TypedConsumer<S, T, C>);
15
16impl<S: Store> Builder<S> {
17    /// Open a typed queue that encodes values with `codec`.
18    ///
19    /// Returns a typed producer/consumer pair over the same backend as
20    /// [`open`](Builder::open); the configured `capacity` and `durability` apply
21    /// unchanged.
22    pub fn open_typed<T, C>(self, codec: C) -> Result<TypedEnds<S, T, C>, OpenError<S::Error>>
23    where
24        C: Codec<T> + Clone,
25    {
26        let (producer, consumer) = self.open()?;
27        Ok((
28            TypedProducer {
29                inner: producer,
30                codec: codec.clone(),
31                _marker: PhantomData,
32            },
33            TypedConsumer {
34                inner: consumer,
35                codec,
36                _marker: PhantomData,
37            },
38        ))
39    }
40}
41
42/// The producer half of a typed queue. Clone it for multiple producers.
43pub struct TypedProducer<S, T, C> {
44    inner: Producer<S>,
45    codec: C,
46    _marker: PhantomData<fn(T)>,
47}
48
49impl<S, T, C: Clone> Clone for TypedProducer<S, T, C> {
50    fn clone(&self) -> Self {
51        Self {
52            inner: self.inner.clone(),
53            codec: self.codec.clone(),
54            _marker: PhantomData,
55        }
56    }
57}
58
59impl<S: Store, T, C: Codec<T>> TypedProducer<S, T, C> {
60    /// Encode and push `value`, waiting while the queue is at capacity.
61    pub fn push(&self, value: &T) -> Result<(), TypedPushError<S::Error>> {
62        let bytes = self.codec.encode(value).map_err(TypedPushError::Encode)?;
63        self.inner.push(&bytes).map_err(|e| match e {
64            PushError::Closed => TypedPushError::Closed,
65            PushError::Store(e) => TypedPushError::Store(e),
66        })
67    }
68
69    /// Close the queue; further pushes fail and the consumer drains what remains.
70    pub fn close(&self) {
71        self.inner.close();
72    }
73
74    /// Number of unacked items currently in the queue.
75    pub fn len(&self) -> usize {
76        self.inner.len()
77    }
78
79    /// Whether the queue holds no unacked items.
80    pub fn is_empty(&self) -> bool {
81        self.inner.is_empty()
82    }
83}
84
85/// The consumer half of a typed queue. Single consumer.
86pub struct TypedConsumer<S, T, C> {
87    inner: Consumer<S>,
88    codec: C,
89    _marker: PhantomData<fn() -> T>,
90}
91
92impl<S: Store, T, C: Codec<T>> TypedConsumer<S, T, C> {
93    /// Reserve and decode the oldest item, or `None` if there is nothing to deliver.
94    pub fn reserve(&self) -> Result<Option<TypedReserved<S, T>>, ReserveError<S::Error>> {
95        match self.inner.reserve().map_err(ReserveError::Store)? {
96            Some(reserved) => {
97                let value = self.codec.decode(&reserved).map_err(ReserveError::Decode)?;
98                Ok(Some(TypedReserved {
99                    inner: reserved,
100                    value,
101                }))
102            }
103            None => Ok(None),
104        }
105    }
106}
107
108/// A reserved, decoded item. Derefs to the value; [`ack`](TypedReserved::ack) removes
109/// it while [`nack`](TypedReserved::nack) or drop returns it for redelivery.
110pub struct TypedReserved<S: Store, T> {
111    inner: Reserved<S>,
112    value: T,
113}
114
115impl<S: Store, T> TypedReserved<S, T> {
116    /// The item's sequence number, stable across redeliveries.
117    pub fn seq(&self) -> u64 {
118        self.inner.seq()
119    }
120
121    /// Remove the item from the queue.
122    pub fn ack(self) -> Result<(), S::Error> {
123        self.inner.ack()
124    }
125
126    /// Return the item for redelivery without removing it.
127    pub fn nack(self) {
128        self.inner.nack();
129    }
130}
131
132impl<S: Store, T> Deref for TypedReserved<S, T> {
133    type Target = T;
134    fn deref(&self) -> &T {
135        &self.value
136    }
137}
138
139/// Error from [`TypedProducer::push`].
140#[derive(Debug)]
141pub enum TypedPushError<E> {
142    /// Encoding the value failed.
143    Encode(CodecError),
144    /// The queue was closed.
145    Closed,
146    /// The backend store failed.
147    Store(E),
148}
149
150impl<E: fmt::Display> fmt::Display for TypedPushError<E> {
151    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
152        match self {
153            TypedPushError::Encode(e) => write!(f, "{e}"),
154            TypedPushError::Closed => write!(f, "queue is closed"),
155            TypedPushError::Store(e) => write!(f, "store error: {e}"),
156        }
157    }
158}
159
160impl<E: StdError + 'static> StdError for TypedPushError<E> {
161    fn source(&self) -> Option<&(dyn StdError + 'static)> {
162        match self {
163            TypedPushError::Encode(e) => Some(e),
164            TypedPushError::Store(e) => Some(e),
165            TypedPushError::Closed => None,
166        }
167    }
168}
169
170/// Error from [`TypedConsumer::reserve`].
171#[derive(Debug)]
172pub enum ReserveError<E> {
173    /// The backend store failed.
174    Store(E),
175    /// Decoding the reserved item failed.
176    Decode(CodecError),
177}
178
179impl<E: fmt::Display> fmt::Display for ReserveError<E> {
180    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
181        match self {
182            ReserveError::Store(e) => write!(f, "store error: {e}"),
183            ReserveError::Decode(e) => write!(f, "{e}"),
184        }
185    }
186}
187
188impl<E: StdError + 'static> StdError for ReserveError<E> {
189    fn source(&self) -> Option<&(dyn StdError + 'static)> {
190        match self {
191            ReserveError::Store(e) => Some(e),
192            ReserveError::Decode(e) => Some(e),
193        }
194    }
195}