foundationdb_simulation/
bindings.rs1use std::{ffi, str::FromStr};
7
8mod raw_bindings {
9 #![allow(non_camel_case_types)]
10 #![allow(non_upper_case_globals)]
11 #![allow(non_snake_case)]
12 #![allow(dead_code)]
13 #![allow(missing_docs)]
14 include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
15}
16pub use raw_bindings::{
17 FDBDatabase, FDBMetrics, FDBPromise, FDBWorkload, FDBWorkloadContext, OpaqueWorkload,
18};
19use raw_bindings::{
20 FDBMetric, FDBSeverity, FDBSeverity_FDBSeverity_Debug, FDBSeverity_FDBSeverity_Error,
21 FDBSeverity_FDBSeverity_Info, FDBSeverity_FDBSeverity_Warn, FDBSeverity_FDBSeverity_WarnAlways,
22 FDBStringPair,
23};
24
25#[doc(hidden)]
29#[allow(clippy::not_unsafe_ptr_arg_deref)]
30pub fn str_from_c(c_buf: *const i8) -> String {
31 let c_str = unsafe { ffi::CStr::from_ptr(c_buf) };
32 c_str.to_str().unwrap().to_string()
33}
34#[doc(hidden)]
35pub fn str_for_c<T>(buf: T) -> ffi::CString
36where
37 T: Into<Vec<u8>>,
38{
39 ffi::CString::new(buf).unwrap()
40}
41
42#[macro_export]
44macro_rules! details {
45 ($($k:expr => $v:expr),* $(,)?) => {
46 &[
47 $((
48 &$k.to_string(), &$v.to_string()
49 )),*
50 ]
51 };
52}
53
54pub struct WorkloadContext(FDBWorkloadContext);
59pub struct Promise(FDBPromise);
61pub struct Metrics(FDBMetrics);
63
64#[derive(Clone)]
66pub struct Metric<'a> {
67 pub key: &'a str,
69 pub val: f64,
71 pub avg: bool,
73 pub fmt: Option<&'a str>,
75}
76
77#[derive(Clone, Copy)]
79#[repr(u32)]
80pub enum Severity {
81 Debug = FDBSeverity_FDBSeverity_Debug,
83 Info = FDBSeverity_FDBSeverity_Info,
85 Warn = FDBSeverity_FDBSeverity_Warn,
87 WarnAlways = FDBSeverity_FDBSeverity_WarnAlways,
89 Error = FDBSeverity_FDBSeverity_Error,
91}
92
93impl WorkloadContext {
97 #[doc(hidden)]
98 pub fn new(raw: FDBWorkloadContext) -> Self {
99 Self(raw)
100 }
101
102 pub fn trace<S, S2, S3>(&self, severity: Severity, name: S, details: &[(S2, S3)])
104 where
105 S: Into<Vec<u8>>,
106 S2: AsRef<str>,
107 S3: AsRef<str>,
108 {
109 let name = str_for_c(name);
110 let details_storage = details
111 .iter()
112 .map(|(key, val)| {
113 let key = str_for_c(key.as_ref());
114 let val = str_for_c(val.as_ref());
115 (key, val)
116 })
117 .collect::<Vec<_>>();
118 let details = details_storage
119 .iter()
120 .map(|(key, val)| FDBStringPair {
121 key: key.as_ptr(),
122 val: val.as_ptr(),
123 })
124 .collect::<Vec<_>>();
125 unsafe {
126 self.0.trace.unwrap_unchecked()(
127 self.0.inner,
128 severity as FDBSeverity,
129 name.as_ptr(),
130 details.as_ptr(),
131 details.len() as i32,
132 )
133 }
134 }
135 pub fn get_process_id(&self) -> u64 {
137 unsafe { self.0.getProcessID.unwrap_unchecked()(self.0.inner) }
138 }
139 pub fn set_process_id(&self, id: u64) {
141 unsafe { self.0.setProcessID.unwrap_unchecked()(self.0.inner, id) }
142 }
143 pub fn now(&self) -> f64 {
145 unsafe { self.0.now.unwrap_unchecked()(self.0.inner) }
146 }
147 pub fn rnd(&self) -> u32 {
149 unsafe { self.0.rnd.unwrap_unchecked()(self.0.inner) }
150 }
151 pub fn get_option<T>(&self, name: &str) -> Option<T>
155 where
156 T: FromStr,
157 {
158 self.get_option_raw(name)
159 .and_then(|value| value.parse::<T>().ok())
160 }
161 fn get_option_raw(&self, name: &str) -> Option<String> {
162 let null = "";
163 let name = str_for_c(name);
164 let default_value = str_for_c(null);
165 let raw_value = unsafe {
166 self.0.getOption.unwrap_unchecked()(self.0.inner, name.as_ptr(), default_value.as_ptr())
167 };
168 let value = str_from_c(raw_value.inner);
169 unsafe { raw_value.free.unwrap_unchecked()(raw_value.inner) };
170 if value == null {
171 None
172 } else {
173 Some(value)
174 }
175 }
176 pub fn client_id(&self) -> i32 {
178 unsafe { self.0.clientId.unwrap_unchecked()(self.0.inner) }
179 }
180 pub fn client_count(&self) -> i32 {
182 unsafe { self.0.clientCount.unwrap_unchecked()(self.0.inner) }
183 }
184 pub fn shared_random_number(&self) -> i64 {
186 unsafe { self.0.sharedRandomNumber.unwrap_unchecked()(self.0.inner) }
187 }
188}
189
190impl Promise {
191 pub(crate) fn new(raw: FDBPromise) -> Self {
192 Self(raw)
193 }
194 pub fn send(self, value: bool) {
199 unsafe { self.0.send.unwrap_unchecked()(self.0.inner, value) };
200 }
201}
202impl Drop for Promise {
203 fn drop(&mut self) {
204 unsafe { self.0.free.unwrap_unchecked()(self.0.inner) };
205 }
206}
207
208impl Metrics {
209 pub(crate) fn new(raw: FDBMetrics) -> Self {
210 Self(raw)
211 }
212 pub fn reserve(&mut self, n: usize) {
214 unsafe { self.0.reserve.unwrap_unchecked()(self.0.inner, n as i32) }
215 }
216 pub fn push(&mut self, metric: Metric) {
218 let key_storage = str_for_c(metric.key);
219 let fmt_storage = str_for_c(metric.fmt.unwrap_or("%.3g"));
220 unsafe {
221 self.0.push.unwrap_unchecked()(
222 self.0.inner,
223 FDBMetric {
224 key: key_storage.as_ptr(),
225 fmt: fmt_storage.as_ptr(),
226 val: metric.val,
227 avg: metric.avg,
228 },
229 )
230 }
231 }
232 pub fn extend<'a, T>(&mut self, metrics: T)
234 where
235 T: IntoIterator<Item = Metric<'a>>,
236 {
237 let metrics = metrics.into_iter();
238 let (min, max) = metrics.size_hint();
239 self.reserve(max.unwrap_or(min));
240 for metric in metrics {
241 self.push(metric);
242 }
243 }
244}
245
246impl<'a> Metric<'a> {
247 pub fn val<V>(key: &'a str, val: V) -> Self
249 where
250 V: TryInto<f64>,
251 {
252 Self {
253 key,
254 val: val.try_into().ok().expect("convertion failed"),
255 avg: false,
256 fmt: None,
257 }
258 }
259 pub fn avg<V>(key: &'a str, val: V) -> Self
261 where
262 V: TryInto<f64>,
263 {
264 Self {
265 key,
266 val: val.try_into().ok().expect("convertion failed"),
267 avg: true,
268 fmt: None,
269 }
270 }
271}