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}