rustis/resp/json.rs
1use serde::{
2 Deserialize,
3 de::{self},
4 ser::Serialize,
5};
6
7/// Wrapper type that deserializes a Redis bulk string as JSON into a Rust value.
8///
9/// This is useful for retrieving structured data from Redis that was stored as JSON.
10/// Typically used with commands like `GET`, `HGET`, or any command returning a bulk string.
11///
12/// # Example
13/// ```rust
14/// use rustis::{
15/// client::Client,
16/// commands::{FlushingMode, ServerCommands, StringCommands},
17/// resp::{Json, JsonRef},
18/// Result
19/// };
20///
21/// #[derive(Debug, PartialEq, serde::Deserialize, serde::Serialize)]
22/// struct User {
23/// id: u32,
24/// name: String,
25/// }
26///
27/// #[cfg_attr(feature = "tokio-runtime", tokio::main)]
28/// #[cfg_attr(feature = "async-std-runtime", async_std::main)]
29/// async fn main() -> Result<()> {
30/// let client = Client::connect("127.0.0.1:6379").await?;
31/// client.flushall(FlushingMode::Sync).await?;
32/// let user1 = User { id: 12, name: "foo".to_string() };
33/// client.set("user:123", JsonRef(&user1)).await;
34/// let Json(user2): Json<User> = client.get("user:123").await?;
35///
36/// assert_eq!(user1, user2);
37/// Ok(())
38/// }
39/// ```
40#[derive(Debug, Clone)]
41#[must_use]
42pub struct Json<T>(pub T);
43
44impl<T> Json<T> {
45 pub fn into_inner(self) -> T {
46 self.0
47 }
48}
49
50impl<'de, T> Deserialize<'de> for Json<T>
51where
52 T: Deserialize<'de>,
53{
54 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
55 where
56 D: serde::Deserializer<'de>,
57 {
58 use std::{fmt, marker::PhantomData};
59
60 struct Visitor<T> {
61 phantom: PhantomData<T>,
62 }
63
64 impl<'de, T> de::Visitor<'de> for Visitor<T>
65 where
66 T: Deserialize<'de>,
67 {
68 type Value = Json<T>;
69
70 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
71 formatter.write_str("Json")
72 }
73
74 fn visit_borrowed_bytes<E>(self, v: &'de [u8]) -> Result<Self::Value, E>
75 where
76 E: de::Error,
77 {
78 let value: T = serde_json::from_slice(v).map_err(|e| {
79 de::Error::custom(format!(
80 "Cannot deserialize from json (borrowed bytes): {}",
81 e
82 ))
83 })?;
84 Ok(Json(value))
85 }
86
87 fn visit_borrowed_str<E>(self, v: &'de str) -> Result<Self::Value, E>
88 where
89 E: de::Error,
90 {
91 let value: T = serde_json::from_str(v).map_err(|e| {
92 de::Error::custom(format!(
93 "Cannot deserialize from json (borrowed str): {}",
94 e
95 ))
96 })?;
97 Ok(Json(value))
98 }
99 }
100
101 deserializer.deserialize_any(Visitor {
102 phantom: PhantomData,
103 })
104 }
105}
106
107/// Wrapper type that serializes a Rust value as JSON before sending it to Redis.
108///
109/// This is useful for storing structured data in Redis as a bulk string using JSON encoding.
110/// Typically used with commands like `SET`, `HSET`, or any command that takes a bulk string.
111///
112/// # Example
113/// ```rust
114/// use rustis::{
115/// client::Client,
116/// commands::{FlushingMode, ServerCommands, StringCommands},
117/// resp::{Json, JsonRef},
118/// Result
119/// };
120///
121/// #[derive(Debug, PartialEq, serde::Deserialize, serde::Serialize)]
122/// struct User {
123/// id: u32,
124/// name: String,
125/// }
126///
127/// #[cfg_attr(feature = "tokio-runtime", tokio::main)]
128/// #[cfg_attr(feature = "async-std-runtime", async_std::main)]
129/// async fn main() -> Result<()> {
130/// let client = Client::connect("127.0.0.1:6379").await?;
131/// client.flushall(FlushingMode::Sync).await?;
132/// let user1 = User { id: 12, name: "foo".to_string() };
133/// client.set("user:123", JsonRef(&user1)).await;
134/// let Json(user2): Json<User> = client.get("user:123").await?;
135///
136/// assert_eq!(user1, user2);
137/// Ok(())
138/// }
139/// ```
140#[derive(Debug, Clone)]
141#[must_use]
142pub struct JsonRef<'a, T>(pub &'a T);
143
144impl<'a, T> Serialize for JsonRef<'a, T>
145where
146 T: Serialize,
147{
148 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
149 where
150 S: serde::Serializer,
151 {
152 if let Ok(bytes) = serde_json::to_vec(&self.0) {
153 serializer.serialize_bytes(&bytes)
154 } else {
155 serializer.serialize_unit()
156 }
157 }
158}