1use crate::client::SynapClient;
4use crate::error::Result;
5use serde::{Deserialize, Serialize};
6use serde_json::json;
7
8#[derive(Debug, Clone, Copy, PartialEq, Eq)]
10pub enum BitmapOperation {
11 And,
12 Or,
13 Xor,
14 Not,
15}
16
17impl BitmapOperation {
18 fn as_str(&self) -> &'static str {
19 match self {
20 BitmapOperation::And => "AND",
21 BitmapOperation::Or => "OR",
22 BitmapOperation::Xor => "XOR",
23 BitmapOperation::Not => "NOT",
24 }
25 }
26}
27
28#[derive(Debug, Clone, Serialize, Deserialize, Default)]
30pub struct BitmapStats {
31 pub total_bitmaps: usize,
32 pub total_bits: usize,
33 pub setbit_count: usize,
34 pub getbit_count: usize,
35 pub bitcount_count: usize,
36 pub bitop_count: usize,
37 pub bitpos_count: usize,
38 pub bitfield_count: usize,
39}
40
41#[derive(Clone)]
42pub struct BitmapManager {
43 client: SynapClient,
44}
45
46impl BitmapManager {
47 pub(crate) fn new(client: SynapClient) -> Self {
48 Self { client }
49 }
50
51 pub async fn setbit(&self, key: &str, offset: usize, value: u8) -> Result<u8> {
63 if value > 1 {
64 return Err(crate::error::SynapError::ServerError(
65 "Bitmap value must be 0 or 1".to_string(),
66 ));
67 }
68
69 let payload = json!({
70 "key": key,
71 "offset": offset,
72 "value": value,
73 });
74
75 let response = self.client.send_command("bitmap.setbit", payload).await?;
76 Ok(response["old_value"].as_u64().unwrap_or(0) as u8)
77 }
78
79 pub async fn getbit(&self, key: &str, offset: usize) -> Result<u8> {
90 let payload = json!({
91 "key": key,
92 "offset": offset,
93 });
94
95 let response = self.client.send_command("bitmap.getbit", payload).await?;
96 Ok(response["value"].as_u64().unwrap_or(0) as u8)
97 }
98
99 pub async fn bitcount(
111 &self,
112 key: &str,
113 start: Option<usize>,
114 end: Option<usize>,
115 ) -> Result<usize> {
116 let mut payload = json!({"key": key});
117 if let Some(start_val) = start {
118 payload["start"] = json!(start_val);
119 }
120 if let Some(end_val) = end {
121 payload["end"] = json!(end_val);
122 }
123
124 let response = self.client.send_command("bitmap.bitcount", payload).await?;
125 Ok(response["count"].as_u64().unwrap_or(0) as usize)
126 }
127
128 pub async fn bitpos(
141 &self,
142 key: &str,
143 value: u8,
144 start: Option<usize>,
145 end: Option<usize>,
146 ) -> Result<Option<usize>> {
147 if value > 1 {
148 return Err(crate::error::SynapError::ServerError(
149 "Bitmap value must be 0 or 1".to_string(),
150 ));
151 }
152
153 let mut payload = json!({
154 "key": key,
155 "value": value,
156 });
157 if let Some(start_val) = start {
158 payload["start"] = json!(start_val);
159 }
160 if let Some(end_val) = end {
161 payload["end"] = json!(end_val);
162 }
163
164 let response = self.client.send_command("bitmap.bitpos", payload).await?;
165
166 if let Some(pos) = response["position"].as_u64() {
167 Ok(Some(pos as usize))
168 } else {
169 Ok(None)
170 }
171 }
172
173 pub async fn bitop<S>(
191 &self,
192 operation: BitmapOperation,
193 destination: &str,
194 source_keys: &[S],
195 ) -> Result<usize>
196 where
197 S: AsRef<str>,
198 {
199 if operation == BitmapOperation::Not && source_keys.len() != 1 {
200 return Err(crate::error::SynapError::ServerError(
201 "NOT operation requires exactly one source key".to_string(),
202 ));
203 }
204
205 if source_keys.is_empty() {
206 return Err(crate::error::SynapError::ServerError(
207 "BITOP requires at least one source key".to_string(),
208 ));
209 }
210
211 let payload = json!({
212 "destination": destination,
213 "operation": operation.as_str(),
214 "source_keys": source_keys.iter().map(|s| s.as_ref()).collect::<Vec<_>>(),
215 });
216
217 let response = self.client.send_command("bitmap.bitop", payload).await?;
218 Ok(response["length"].as_u64().unwrap_or(0) as usize)
219 }
220
221 pub async fn bitfield(&self, key: &str, operations: &[serde_json::Value]) -> Result<Vec<i64>> {
268 let payload = json!({
269 "key": key,
270 "operations": operations,
271 });
272
273 let response = self.client.send_command("bitmap.bitfield", payload).await?;
274 let results = response["results"]
275 .as_array()
276 .ok_or_else(|| {
277 crate::error::SynapError::ServerError(
278 "Invalid response format for bitfield".to_string(),
279 )
280 })?
281 .iter()
282 .map(|v| v.as_i64().unwrap_or(0))
283 .collect();
284
285 Ok(results)
286 }
287
288 pub async fn stats(&self) -> Result<BitmapStats> {
290 let response = self.client.send_command("bitmap.stats", json!({})).await?;
291 let stats: BitmapStats = serde_json::from_value(response)?;
292 Ok(stats)
293 }
294}