Skip to content

Instantly share code, notes, and snippets.

@rajivr

rajivr/mod.rs Secret

Created August 6, 2021 05:58
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rajivr/bd6397a186da0ba72c39214f7a6ebfb9 to your computer and use it in GitHub Desktop.
Save rajivr/bd6397a186da0ba72c39214f7a6ebfb9 to your computer and use it in GitHub Desktop.
//! Provides types and traits for working with FoundationDB Futures
// TODO: document the behavior of FdbFuture.
//
// 1. FdbFuture represents a computation that is happening in the
// background. In this regard it is similar to
// std::thread::JoinHandle. Unlike Rust Future, FdbFuture need not be
// polled in order to make progress. It makes progress the network
// thread.
//
// 2. Like Rust Futures, when FdbFuture is dropped, the computation is
// cancelled. In this regard, it is similar to Rust Future, and is not
// like JoinHandle. In case of JoinHandle, we only lose the ability to
// "join"
use crate::error::check;
use crate::FdbResult;
use std::marker::PhantomData;
use std::ptr::NonNull;
#[derive(Debug)]
pub struct FdbFuture<T> {
c_ptr: Option<Box<NonNull<fdb_sys::FDBFuture>>>,
_marker: PhantomData<T>,
}
impl<T> FdbFuture<T>
where
T: FdbFutureGet,
{
fn new(fdb_future: *mut fdb_sys::FDBFuture) -> FdbFuture<T> {
FdbFuture {
c_ptr: Some(Box::new(NonNull::new(fdb_future).expect(
"Tried to create FdbNativeFuture with a null fdb_sys::FDBFuture",
))),
_marker: PhantomData,
}
}
fn join(self) -> FdbResult<T> {
let fut_c_ptr = (&self.c_ptr.as_ref().unwrap()).as_ptr();
unsafe {
fdb_sys::fdb_future_block_until_ready(fut_c_ptr);
FdbFutureGet::get(fut_c_ptr)
}
}
}
/// # Safety
///
/// `FdbNativeFuture` does not implement `Copy` and `Clone`
/// traits. Therefore there does not exist a way to make a copy of
/// `FdbNativeFuture` after it has been created. Also the `c_ptr` is
/// *only* accessed read-only when passed to a different thread.
unsafe impl<T> Send for FdbFuture<T> {}
unsafe impl<T> Sync for FdbFuture<T> {}
impl<T> Drop for FdbFuture<T> {
fn drop(&mut self) {
self.c_ptr.take().map(|boxed_c_ptr| {
unsafe {
fdb_sys::fdb_future_destroy((*boxed_c_ptr).as_ptr());
}
drop(boxed_c_ptr);
});
}
}
pub trait FdbFutureGet {
unsafe fn get(fdb_future_ptr: *mut fdb_sys::FDBFuture) -> FdbResult<Self>
where
Self: Sized;
}
impl FdbFutureGet for () {
unsafe fn get(fdb_future_ptr: *mut fdb_sys::FDBFuture) -> FdbResult<()> {
check(fdb_sys::fdb_future_get_error(fdb_future_ptr))
}
}
pub type FdbFutureUnit = FdbFuture<()>;
impl FdbFutureGet for i64 {
unsafe fn get(fdb_future_ptr: *mut fdb_sys::FDBFuture) -> FdbResult<i64> {
let mut version = 0;
check(fdb_sys::fdb_future_get_int64(fdb_future_ptr, &mut version)).map(|_| version)
}
}
pub type FdbFutureI64 = FdbFuture<i64>;
#[cfg(test)]
mod tests {
use super::FdbFutureUnit;
use static_assertions::{assert_impl_all, assert_not_impl_any};
use std::marker::PhantomData;
use std::ptr::NonNull;
#[derive(Debug)]
struct DummyFdbFuture<T> {
c_ptr: Option<Box<NonNull<fdb_sys::FDBFuture>>>,
_marker: PhantomData<T>,
}
unsafe impl<T> Send for DummyFdbFuture<T> {}
unsafe impl<T> Sync for DummyFdbFuture<T> {}
#[test]
fn trait_bounds() {
/// TODO: Document *why* we need FdbFuture to be 'static.
fn trait_bounds_for_fdb_future<T>(_t: T)
where
T: Send + Sync + 'static,
{
}
let f: DummyFdbFuture<()> = DummyFdbFuture {
c_ptr: Some(Box::new(NonNull::dangling())),
_marker: PhantomData,
};
trait_bounds_for_fdb_future(f);
}
assert_impl_all!(FdbFutureUnit: Send, Sync);
assert_not_impl_any!(FdbFutureUnit: Copy, Clone);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment