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