apalis_core/backend/
codec.rs

1//! Utilities for encoding and decoding task arguments and results
2//!
3//! # Overview
4//!
5//! The `Codec` trait allows for converting values
6//! between a type `T` and a more compact or transport-friendly representation.
7//! This is particularly useful for serializing/deserializing, compressing/expanding,
8//! or otherwise encoding/decoding values in a custom format.
9//!
10//! The module includes several implementations of the `Codec` trait, such as `IdentityCodec`
11//! and `NoopCodec`, as well as a JSON codec when the `json` feature is enabled.
12
13use crate::{
14    backend::{Backend, BackendExt},
15    worker::context::WorkerContext,
16};
17/// A trait for converting values between a type `T` and a more compact or
18/// transport-friendly representation for a `Backend`. Examples include json
19/// and bytes.
20///
21/// This is useful when you need to serialize/deserialize, compress/expand,
22/// or otherwise encode/decode values in a custom format.
23///
24/// By default, a backend doesn't care about the specific type implementing [`Codec`]
25/// but rather the [`Codec::Compact`] type. This means if it can accept bytes, you
26/// can use familiar crates such as bincode and rkyv
27///
28/// # Type Parameters
29/// - `T`: The type of value being encoded/decoded.
30pub trait Codec<T> {
31    /// The error type returned if encoding or decoding fails.
32    type Error;
33
34    /// The compact or encoded representation of `T`.
35    ///
36    /// This could be a primitive type, a byte buffer, or any other
37    /// representation that is more efficient to store or transmit.
38    type Compact;
39
40    /// Encode a value of type `T` into its compact representation.
41    ///
42    /// # Errors
43    /// Returns [`Self::Error`] if the value cannot be encoded.
44    fn encode(val: &T) -> Result<Self::Compact, Self::Error>;
45
46    /// Decode a compact representation back into a value of type `T`.
47    ///
48    /// # Errors
49    /// Returns [`Self::Error`] if the compact representation cannot
50    /// be decoded into a valid `T`.
51    fn decode(val: &Self::Compact) -> Result<T, Self::Error>;
52}
53
54/// A codec that performs no transformation, returning the input value as-is.
55#[derive(Debug, Clone, Default)]
56pub struct IdentityCodec;
57
58impl<T> Codec<T> for IdentityCodec
59where
60    T: Clone,
61{
62    type Compact = T;
63    type Error = std::convert::Infallible;
64
65    fn encode(val: &T) -> Result<Self::Compact, Self::Error> {
66        Ok(val.clone())
67    }
68
69    fn decode(val: &Self::Compact) -> Result<T, Self::Error> {
70        Ok(val.clone())
71    }
72}
73
74/// Wrapper that skips decoding and works directly with compact representation.
75///
76/// This is useful for backends that natively handle compact types and do not know the types at compile time.
77/// Examples include backends that work with raw bytes or JSON values like workflows that manipulate dynamic data.
78#[derive(Debug, Clone)]
79pub struct RawDataBackend<B> {
80    inner: B,
81}
82
83impl<B> RawDataBackend<B> {
84    /// Create a new `RawDataBackend` wrapping the given backend.
85    pub fn new(backend: B) -> Self {
86        Self { inner: backend }
87    }
88}
89
90impl<B> Backend for RawDataBackend<B>
91where
92    B: BackendExt,
93{
94    type Args = B::Compact;
95    type IdType = B::IdType;
96    type Context = B::Context;
97    type Error = B::Error;
98    type Stream = B::CompactStream;
99    type Beat = B::Beat;
100    type Layer = B::Layer;
101
102    fn heartbeat(&self, worker: &WorkerContext) -> Self::Beat {
103        self.inner.heartbeat(worker)
104    }
105
106    fn middleware(&self) -> Self::Layer {
107        self.inner.middleware()
108    }
109
110    fn poll(self, worker: &WorkerContext) -> Self::Stream {
111        self.inner.poll_compact(worker)
112    }
113}