use std::sync::atomic::AtomicBool;
use std::sync::Arc;
use std::thread::Builder as StdBuilder;
use failure::ResultExt;
use super::handles::ThreadGuard;
use super::registry::current_thread_id;
use super::status::RegisteredStatus;
use super::ErrorKind;
use super::Result;
use super::Thread;
use super::ThreadScope;
pub struct Builder {
full_name: String,
name: String,
std: StdBuilder,
}
impl Builder {
pub fn new<S: Into<String>>(name: S) -> Builder {
let name = name.into();
let std = StdBuilder::new().name(name.clone());
Builder {
name: name.clone(),
full_name: name,
std,
}
}
pub fn full_name<S: Into<String>>(mut self, name: S) -> Builder {
self.full_name = name.into();
self
}
pub fn spawn<F, T>(self, f: F) -> Result<Thread<T>>
where
F: FnOnce(ThreadScope) -> T,
F: Send + 'static,
T: Send + 'static,
{
let (join_check_send, join_check_receive) = ::crossbeam_channel::bounded(1);
let full_name = self.full_name;
let name = self.name;
let shutdown = Arc::new(AtomicBool::new(false));
let scope_shutdown = Arc::clone(&shutdown);
let join = self
.std
.spawn(|| {
let id = current_thread_id();
let status = RegisteredStatus::new(full_name, name);
let activity = status.activity();
let _guard = ThreadGuard::new(id, join_check_send, status);
let scope = ThreadScope::new(activity, scope_shutdown);
f(scope)
})
.with_context(|_| ErrorKind::Spawn)?;
Ok(Thread::new(join, join_check_receive, shutdown))
}
}
#[cfg(test)]
mod tests {
use super::Builder;
#[test]
fn spawn_and_join() {
Builder::new("spawn_and_join")
.spawn(|_| {})
.expect("failed to spawn thread")
.join()
.expect("failed to join thread");
}
}