-
-
Save rajivr/bd6397a186da0ba72c39214f7a6ebfb9 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//! 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