foundationdb_simulation/
bindings.rs1use std::{ffi, str::FromStr, time::Duration};
7
8use foundationdb as fdb;
9
10mod raw_bindings {
11 #![allow(non_camel_case_types)]
12 #![allow(non_upper_case_globals)]
13 #![allow(non_snake_case)]
14 #![allow(dead_code)]
15 #![allow(missing_docs)]
16 include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
17}
18pub use raw_bindings::{
19 FDBDatabase, FDBMetrics, FDBPromise, FDBWorkload, FDBWorkloadContext, OpaqueWorkload,
20};
21use raw_bindings::{
22 FDBMetric, FDBSeverity, FDBSeverity_FDBSeverity_Debug, FDBSeverity_FDBSeverity_Error,
23 FDBSeverity_FDBSeverity_Info, FDBSeverity_FDBSeverity_Warn, FDBSeverity_FDBSeverity_WarnAlways,
24 FDBStringPair,
25};
26
27pub use raw_bindings::FDBWorkload_FDBWorkload_VT as FDBWorkload_VT;
28pub const FDB_WORKLOAD_API_VERSION: i32 = raw_bindings::FDB_WORKLOAD_API_VERSION as i32;
29
30#[doc(hidden)]
34#[allow(clippy::not_unsafe_ptr_arg_deref)]
35pub fn str_from_c(c_buf: *const i8) -> String {
36 let c_str = unsafe { ffi::CStr::from_ptr(c_buf) };
37 c_str.to_str().unwrap().to_string()
38}
39#[doc(hidden)]
40pub fn str_for_c<T>(buf: T) -> ffi::CString
41where
42 T: Into<Vec<u8>>,
43{
44 ffi::CString::new(buf).unwrap()
45}
46
47fn capitalize_first(s: &str) -> Option<String> {
51 let mut chars = s.chars();
52 chars
53 .next()
54 .map(|first| first.to_uppercase().collect::<String>() + chars.as_str())
55}
56
57#[macro_export]
59macro_rules! details {
60 ($($k:expr_2021 => $v:expr_2021),* $(,)?) => {
61 &[
62 $((
63 &$k.to_string(), &$v.to_string()
64 )),*
65 ]
66 };
67}
68
69pub struct WorkloadContext(FDBWorkloadContext);
74pub struct Promise(FDBPromise);
76pub struct Metrics(FDBMetrics);
78
79#[derive(Clone)]
81pub struct Metric<'a> {
82 pub key: &'a str,
84 pub val: f64,
86 pub avg: bool,
88 pub fmt: Option<&'a str>,
90}
91
92#[derive(Clone, Copy)]
94#[repr(u32)]
95pub enum Severity {
96 Debug = FDBSeverity_FDBSeverity_Debug,
98 Info = FDBSeverity_FDBSeverity_Info,
100 Warn = FDBSeverity_FDBSeverity_Warn,
102 WarnAlways = FDBSeverity_FDBSeverity_WarnAlways,
104 Error = FDBSeverity_FDBSeverity_Error,
106}
107
108macro_rules! with {
112 ($this:expr_2021=>$method:ident($($args:expr_2021),* $(,)?)) => {
113 unsafe { (*$this.vt).$method.unwrap_unchecked()($this.inner $(, $args)*) }
114 };
115}
116
117impl WorkloadContext {
118 #[doc(hidden)]
119 pub fn new(raw: FDBWorkloadContext) -> Self {
120 Self(raw)
121 }
122
123 pub fn get_workload_api_version(&self) -> i32 {
125 self.0.api_version
126 }
127
128 pub fn trace<S, S2, S3>(&self, severity: Severity, name: S, details: &[(S2, S3)])
130 where
131 S: Into<Vec<u8>>,
132 S2: AsRef<str>,
133 S3: AsRef<str>,
134 {
135 let name = str_for_c(name);
136 let details_storage = details
137 .iter()
138 .filter_map(|(key, val)| {
139 let val = val.as_ref();
140 if val.is_empty() {
141 return None;
142 }
143 capitalize_first(key.as_ref()).map(|k| (str_for_c(k), str_for_c(val)))
144 })
145 .collect::<Vec<_>>();
146 let details = details_storage
147 .iter()
148 .map(|(key, val)| FDBStringPair {
149 key: key.as_ptr(),
150 val: val.as_ptr(),
151 })
152 .collect::<Vec<_>>();
153 with! {
154 self.0 => trace(
155 severity as FDBSeverity,
156 name.as_ptr(),
157 details.as_ptr(),
158 details.len() as i32,
159 )
160 }
161 }
162 pub fn get_process_id(&self) -> u64 {
164 with! { self.0 => getProcessID() }
165 }
166 pub fn set_process_id(&self, id: u64) {
168 with! { self.0 => setProcessID(id) }
169 }
170 pub fn now(&self) -> f64 {
172 with! { self.0 => now() }
173 }
174 pub fn rnd(&self) -> u32 {
176 with! { self.0 => rnd() }
177 }
178 pub fn get_option<T>(&self, name: &str) -> Option<T>
182 where
183 T: FromStr,
184 {
185 self.get_option_raw(name)
186 .and_then(|value| value.parse::<T>().ok())
187 }
188 fn get_option_raw(&self, name: &str) -> Option<String> {
189 let null = "";
190 let name = str_for_c(name);
191 let default_value = str_for_c(null);
192 let raw_value = with! {
193 self.0 => getOption(name.as_ptr(), default_value.as_ptr())
194 };
195 let value = str_from_c(raw_value.inner);
196 with! { raw_value => free() };
197 if value == null { None } else { Some(value) }
198 }
199 pub fn client_id(&self) -> i32 {
201 with! { self.0 => clientId() }
202 }
203 pub fn client_count(&self) -> i32 {
205 with! { self.0 => clientCount() }
206 }
207 pub fn shared_random_number(&self) -> i64 {
209 with! { self.0 => sharedRandomNumber() }
210 }
211 pub fn delay(
213 &self,
214 duration: Duration,
215 ) -> impl std::future::Future<Output = fdb::FdbResult<()>> + Send + Sync + 'static + use<> {
216 let f = with! { self.0 => delay(duration.as_secs_f64()) };
217 fdb::future::FdbFuture::new(f as *mut _)
218 }
219}
220
221impl Promise {
222 pub(crate) fn new(raw: FDBPromise) -> Self {
223 Self(raw)
224 }
225 pub fn send(self, value: bool) {
230 with! { self.0 => send(value) };
231 }
232}
233impl Drop for Promise {
234 fn drop(&mut self) {
235 with! { self.0 => free() };
236 }
237}
238
239impl Metrics {
240 pub(crate) fn new(raw: FDBMetrics) -> Self {
241 Self(raw)
242 }
243 pub fn reserve(&mut self, n: usize) {
245 with! { self.0 => reserve(n as i32) }
246 }
247 pub fn push(&mut self, metric: Metric) {
249 let key_storage = str_for_c(metric.key);
250 let fmt_storage = str_for_c(metric.fmt.unwrap_or("%.3g"));
251 with! {
252 self.0 => push(FDBMetric {
253 key: key_storage.as_ptr(),
254 fmt: fmt_storage.as_ptr(),
255 val: metric.val,
256 avg: metric.avg,
257 })
258 }
259 }
260 pub fn extend<'a, T>(&mut self, metrics: T)
262 where
263 T: IntoIterator<Item = Metric<'a>>,
264 {
265 let metrics = metrics.into_iter();
266 let (min, max) = metrics.size_hint();
267 self.reserve(max.unwrap_or(min));
268 for metric in metrics {
269 self.push(metric);
270 }
271 }
272}
273
274impl<'a> Metric<'a> {
275 pub fn val<V>(key: &'a str, val: V) -> Self
277 where
278 V: TryInto<f64>,
279 {
280 Self {
281 key,
282 val: val.try_into().ok().expect("convertion failed"),
283 avg: false,
284 fmt: None,
285 }
286 }
287 pub fn avg<V>(key: &'a str, val: V) -> Self
289 where
290 V: TryInto<f64>,
291 {
292 Self {
293 key,
294 val: val.try_into().ok().expect("convertion failed"),
295 avg: true,
296 fmt: None,
297 }
298 }
299}