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/// A trait for converting values between a type `T` and a more compact or
13/// transport-friendly representation for a `Backend`. Examples include json
14/// and bytes.
15///
16/// This is useful when you need to serialize/deserialize, compress/expand,
17/// or otherwise encode/decode values in a custom format.
18///
19/// By default, a backend doesn't care about the specific type implementing [`Codec`]
20/// but rather the [`Codec::Compact`] type. This means if it can accept bytes, you
21/// can use familiar crates such as bincode and rkyv
22///
23/// # Type Parameters
24/// - `T`: The type of value being encoded/decoded.
25pub trait Codec<T> {
26    /// The error type returned if encoding or decoding fails.
27    type Error;
28
29    /// The compact or encoded representation of `T`.
30    ///
31    /// This could be a primitive type, a byte buffer, or any other
32    /// representation that is more efficient to store or transmit.
33    type Compact;
34
35    /// Encode a value of type `T` into its compact representation.
36    ///
37    /// # Errors
38    /// Returns [`Self::Error`] if the value cannot be encoded.
39    fn encode(val: &T) -> Result<Self::Compact, Self::Error>;
40
41    /// Decode a compact representation back into a value of type `T`.
42    ///
43    /// # Errors
44    /// Returns [`Self::Error`] if the compact representation cannot
45    /// be decoded into a valid `T`.
46    fn decode(val: &Self::Compact) -> Result<T, Self::Error>;
47}
48
49/// A codec that performs no transformation, returning the input value as-is.
50#[derive(Debug, Clone, Default)]
51pub struct IdentityCodec;
52
53impl<T> Codec<T> for IdentityCodec
54where
55    T: Clone,
56{
57    type Compact = T;
58    type Error = std::convert::Infallible;
59
60    fn encode(val: &T) -> Result<Self::Compact, Self::Error> {
61        Ok(val.clone())
62    }
63
64    fn decode(val: &Self::Compact) -> Result<T, Self::Error> {
65        Ok(val.clone())
66    }
67}
68
69/// A codec that should never be used. This is primarily a placeholder
70#[derive(Debug, Clone, Default)]
71pub struct NoopCodec;
72
73impl<T> Codec<T> for NoopCodec {
74    type Compact = T;
75    type Error = std::convert::Infallible;
76
77    fn encode(_val: &T) -> Result<Self::Compact, Self::Error> {
78        unreachable!("NoopCodec should never be used for encoding, please use a real codec")
79    }
80
81    fn decode(_val: &Self::Compact) -> Result<T, Self::Error> {
82        unreachable!("NoopCodec should never be used for decoding, please use a real codec")
83    }
84}
85
86/// Encoding for tasks using json
87#[cfg(feature = "json")]
88pub mod json {
89    use std::marker::PhantomData;
90
91    use serde::{de::DeserializeOwned, Serialize};
92    use serde_json::Value;
93
94    use super::Codec;
95
96    /// Json encoding and decoding
97    #[derive(Debug, Clone, Default)]
98    pub struct JsonCodec<Output> {
99        _o: PhantomData<Output>,
100    }
101
102    impl<T: Serialize + DeserializeOwned> Codec<T> for JsonCodec<Vec<u8>> {
103        type Compact = Vec<u8>;
104        type Error = serde_json::Error;
105        fn encode(input: &T) -> Result<Vec<u8>, Self::Error> {
106            serde_json::to_vec(input)
107        }
108
109        fn decode(compact: &Vec<u8>) -> Result<T, Self::Error> {
110            serde_json::from_slice(compact)
111        }
112    }
113
114    impl<T: Serialize + DeserializeOwned> Codec<T> for JsonCodec<String> {
115        type Compact = String;
116        type Error = serde_json::Error;
117        fn encode(input: &T) -> Result<String, Self::Error> {
118            serde_json::to_string(input)
119        }
120        fn decode(compact: &String) -> Result<T, Self::Error> {
121            serde_json::from_str(&compact)
122        }
123    }
124
125    impl<T: Serialize + DeserializeOwned> Codec<T> for JsonCodec<Value> {
126        type Compact = Value;
127        type Error = serde_json::Error;
128        fn encode(input: &T) -> Result<Value, Self::Error> {
129            serde_json::to_value(input)
130        }
131
132        fn decode(compact: &Value) -> Result<T, Self::Error> {
133            T::deserialize(compact)
134        }
135    }
136}