rust_rocksdb/
merge_operator.rs1use libc::{self, c_char, c_int, c_void, size_t};
63use std::ffi::CString;
64use std::mem;
65use std::ptr;
66use std::slice;
67
68pub trait MergeFn:
69 Fn(&[u8], Option<&[u8]>, &MergeOperands) -> Option<Vec<u8>> + Send + Sync + 'static
70{
71}
72impl<F> MergeFn for F where
73 F: Fn(&[u8], Option<&[u8]>, &MergeOperands) -> Option<Vec<u8>> + Send + Sync + 'static
74{
75}
76
77pub struct MergeOperatorCallback<F: MergeFn, PF: MergeFn> {
78 pub name: CString,
79 pub full_merge_fn: F,
80 pub partial_merge_fn: PF,
81}
82
83pub unsafe extern "C" fn destructor_callback<F: MergeFn, PF: MergeFn>(raw_cb: *mut c_void) {
84 drop(Box::from_raw(raw_cb as *mut MergeOperatorCallback<F, PF>));
85}
86
87pub unsafe extern "C" fn delete_callback(
88 _raw_cb: *mut c_void,
89 value: *const c_char,
90 value_length: size_t,
91) {
92 if !value.is_null() {
93 drop(Box::from_raw(slice::from_raw_parts_mut(
94 value as *mut u8,
95 value_length,
96 )));
97 }
98}
99
100pub unsafe extern "C" fn name_callback<F: MergeFn, PF: MergeFn>(
101 raw_cb: *mut c_void,
102) -> *const c_char {
103 let cb = &mut *(raw_cb as *mut MergeOperatorCallback<F, PF>);
104 cb.name.as_ptr()
105}
106
107pub unsafe extern "C" fn full_merge_callback<F: MergeFn, PF: MergeFn>(
108 raw_cb: *mut c_void,
109 raw_key: *const c_char,
110 key_len: size_t,
111 existing_value: *const c_char,
112 existing_value_len: size_t,
113 operands_list: *const *const c_char,
114 operands_list_len: *const size_t,
115 num_operands: c_int,
116 success: *mut u8,
117 new_value_length: *mut size_t,
118) -> *mut c_char {
119 let cb = &mut *(raw_cb as *mut MergeOperatorCallback<F, PF>);
120 let operands = &MergeOperands::new(operands_list, operands_list_len, num_operands);
121 let key = slice::from_raw_parts(raw_key as *const u8, key_len);
122 let oldval = if existing_value.is_null() {
123 None
124 } else {
125 Some(slice::from_raw_parts(
126 existing_value as *const u8,
127 existing_value_len,
128 ))
129 };
130 (cb.full_merge_fn)(key, oldval, operands).map_or_else(
131 || {
132 *new_value_length = 0;
133 *success = 0_u8;
134 ptr::null_mut() as *mut c_char
135 },
136 |result| {
137 *new_value_length = result.len() as size_t;
138 *success = 1_u8;
139 Box::into_raw(result.into_boxed_slice()) as *mut c_char
140 },
141 )
142}
143
144pub unsafe extern "C" fn partial_merge_callback<F: MergeFn, PF: MergeFn>(
145 raw_cb: *mut c_void,
146 raw_key: *const c_char,
147 key_len: size_t,
148 operands_list: *const *const c_char,
149 operands_list_len: *const size_t,
150 num_operands: c_int,
151 success: *mut u8,
152 new_value_length: *mut size_t,
153) -> *mut c_char {
154 let cb = &mut *(raw_cb as *mut MergeOperatorCallback<F, PF>);
155 let operands = &MergeOperands::new(operands_list, operands_list_len, num_operands);
156 let key = slice::from_raw_parts(raw_key as *const u8, key_len);
157 (cb.partial_merge_fn)(key, None, operands).map_or_else(
158 || {
159 *new_value_length = 0;
160 *success = 0_u8;
161 ptr::null_mut::<c_char>()
162 },
163 |result| {
164 *new_value_length = result.len() as size_t;
165 *success = 1_u8;
166 Box::into_raw(result.into_boxed_slice()) as *mut c_char
167 },
168 )
169}
170
171pub struct MergeOperands {
172 operands_list: *const *const c_char,
173 operands_list_len: *const size_t,
174 num_operands: usize,
175}
176
177impl MergeOperands {
178 fn new(
179 operands_list: *const *const c_char,
180 operands_list_len: *const size_t,
181 num_operands: c_int,
182 ) -> MergeOperands {
183 assert!(num_operands >= 0);
184 MergeOperands {
185 operands_list,
186 operands_list_len,
187 num_operands: num_operands as usize,
188 }
189 }
190
191 pub fn len(&self) -> usize {
192 self.num_operands
193 }
194
195 pub fn is_empty(&self) -> bool {
196 self.num_operands == 0
197 }
198
199 pub fn iter(&self) -> MergeOperandsIter {
200 MergeOperandsIter {
201 operands: self,
202 cursor: 0,
203 }
204 }
205
206 fn get_operand(&self, index: usize) -> Option<&[u8]> {
207 if index >= self.num_operands {
208 None
209 } else {
210 unsafe {
211 let base = self.operands_list as usize;
212 let base_len = self.operands_list_len as usize;
213 let spacing = mem::size_of::<*const *const u8>();
214 let spacing_len = mem::size_of::<*const size_t>();
215 let len_ptr = (base_len + (spacing_len * index)) as *const size_t;
216 let len = *len_ptr;
217 let ptr = base + (spacing * index);
218 Some(slice::from_raw_parts(*(ptr as *const *const u8), len))
219 }
220 }
221 }
222}
223
224pub struct MergeOperandsIter<'a> {
225 operands: &'a MergeOperands,
226 cursor: usize,
227}
228
229impl<'a> Iterator for MergeOperandsIter<'a> {
230 type Item = &'a [u8];
231
232 fn next(&mut self) -> Option<Self::Item> {
233 let operand = self.operands.get_operand(self.cursor)?;
234 self.cursor += 1;
235 Some(operand)
236 }
237
238 fn size_hint(&self) -> (usize, Option<usize>) {
239 let remaining = self.operands.num_operands - self.cursor;
240 (remaining, Some(remaining))
241 }
242}
243
244impl<'a> IntoIterator for &'a MergeOperands {
245 type Item = &'a [u8];
246 type IntoIter = MergeOperandsIter<'a>;
247
248 fn into_iter(self) -> Self::IntoIter {
249 Self::IntoIter {
250 operands: self,
251 cursor: 0,
252 }
253 }
254}