kevy_embedded/
ops_bitmap.rs1use crate::{KevyError, KevyResult};
8
9use crate::store::ensure_writable;
10use crate::store::{Store, commit_write, store_err};
11
12impl Store {
13 pub fn getbit(&self, key: &[u8], offset: u64) -> KevyResult<u8> {
16 self.wshard(key).store.getbit(key, offset).map_err(store_err)
17 }
18
19 pub fn setbit(&self, key: &[u8], offset: u64, value: u8) -> KevyResult<u8> {
23 ensure_writable(self)?;
24 let mut g = self.wshard(key);
25 let prev = g.store.setbit(key, offset, value).map_err(store_err)?;
26 let off_str = format!("{offset}");
27 let val_str = format!("{value}");
28 commit_write(&mut g, &[b"SETBIT", key, off_str.as_bytes(), val_str.as_bytes()])?;
29 Ok(prev)
30 }
31
32 pub fn bitcount(&self, key: &[u8], range: Option<(i64, i64)>) -> KevyResult<u64> {
36 self.wshard(key).store.bitcount(key, range).map_err(store_err)
37 }
38
39 pub fn bitpos(
43 &self,
44 key: &[u8],
45 bit: u8,
46 range: Option<(i64, i64)>,
47 ) -> KevyResult<Option<u64>> {
48 self.wshard(key)
49 .store
50 .bitpos(key, bit, range)
51 .map_err(store_err)
52 }
53
54 pub fn getrange(&self, key: &[u8], start: i64, end: i64) -> KevyResult<Vec<u8>> {
57 self.wshard(key)
58 .store
59 .getrange(key, start, end)
60 .map_err(store_err)
61 }
62
63 pub fn setrange(
67 &self,
68 key: &[u8],
69 offset: u64,
70 value: &[u8],
71 ) -> KevyResult<usize> {
72 ensure_writable(self)?;
73 let mut g = self.wshard(key);
74 let new_len = g
75 .store
76 .setrange(key, offset, value)
77 .map_err(store_err)?;
78 let off_str = format!("{offset}");
79 commit_write(&mut g, &[b"SETRANGE", key, off_str.as_bytes(), value])?;
80 Ok(new_len)
81 }
82
83 pub fn bitop(
89 &self,
90 op: BitOp,
91 dst: &[u8],
92 srcs: &[&[u8]],
93 ) -> KevyResult<usize> {
94 ensure_writable(self)?;
95 if srcs.is_empty() {
96 return Ok(0);
97 }
98 if matches!(op, BitOp::Not) && srcs.len() != 1 {
99 return Err(KevyError::InvalidInput("BITOP NOT takes exactly one source key".into()));
100 }
101 let mut srcs_bytes: Vec<Vec<u8>> = Vec::with_capacity(srcs.len());
103 for k in srcs {
104 let v = self.get(k)?.unwrap_or_default();
105 srcs_bytes.push(v);
106 }
107 let max_len = srcs_bytes.iter().map(Vec::len).max().unwrap_or(0);
108 if max_len == 0 {
109 self.del(&[dst])?;
111 return Ok(0);
112 }
113 let out = bitop_combine(op, &srcs_bytes, max_len);
114 self.set(dst, &out)?;
116 Ok(max_len)
117 }
118
119 pub fn time(&self) -> (u64, u32) {
122 let now = std::time::SystemTime::now()
123 .duration_since(std::time::UNIX_EPOCH)
124 .unwrap_or_default();
125 (now.as_secs(), now.subsec_micros())
126 }
127}
128
129fn bitop_combine(op: BitOp, srcs_bytes: &[Vec<u8>], max_len: usize) -> Vec<u8> {
132 let mut out = vec![0u8; max_len];
133 match op {
134 BitOp::Not => {
135 let s = &srcs_bytes[0];
136 for (i, b) in s.iter().enumerate() {
137 out[i] = !b;
138 }
139 for byte in out.iter_mut().skip(s.len()) {
142 *byte = 0xff;
143 }
144 }
145 _ => {
146 let init = match op {
147 BitOp::And => 0xff,
148 BitOp::Or | BitOp::Xor => 0x00,
149 BitOp::Not => unreachable!(),
150 };
151 for byte in out.iter_mut() {
152 *byte = init;
153 }
154 for s in srcs_bytes {
155 for (i, b) in out.iter_mut().enumerate() {
156 let sb = s.get(i).copied().unwrap_or(0);
157 *b = match op {
158 BitOp::And => *b & sb,
159 BitOp::Or => *b | sb,
160 BitOp::Xor => *b ^ sb,
161 BitOp::Not => unreachable!(),
162 };
163 }
164 }
165 }
166 }
167 out
168}
169
170#[derive(Clone, Copy, Debug, PartialEq, Eq)]
172pub enum BitOp {
173 And,
175 Or,
177 Xor,
179 Not,
181}