nursery 0.0.1

An implemenation of Nathaniel J. Smiths Concurrency primitive for Rust.
Documentation
// Copyright 2019 Jeremy Wall
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use std::boxed::Box;
use std::thread;

use crate::{Schedulable, Waitable};

/// An unscheduled operation for a thread.
pub struct Pending<F>
where
    F: FnOnce() -> (),
    F: Send + 'static,
{
    op: Option<F>,
}

impl<F> Pending<F>
where
    F: FnOnce() -> (),
    F: Send + 'static,
{
    pub fn new(op: F) -> Self {
        Self { op: Some(op) }
    }
}

impl<F> Schedulable for Pending<F>
where
    F: FnOnce() -> (),
    F: Send + 'static,
{
    fn start(&mut self) -> Box<dyn Waitable> {
        let mut op = None;
        std::mem::swap(&mut self.op, &mut op);
        if let Some(op) = op {
            Box::new(Handle::new(op))
        } else {
            panic!("Attempt to schdule more than once!");
        }
    }
}

/// A `Waitable` handle for an asynchronous operation running on another
/// thread.
/// 
/// # Example
/// 
/// ```rust
/// # extern crate nursery;
/// # use nursery::thread::Handle;
/// # use nursery::Waitable;
/// use std::sync::Arc;
/// use std::sync::Mutex;
/// 
/// pub struct Counter {
///     count: i32,
/// }
/// 
/// impl Counter {
///     pub fn incr(&mut self) {
///         self.count += 1;
///     }
/// }
/// 
/// let counter = Arc::new(Mutex::new(Counter { count: 0 }));
/// let h_counter = counter.clone();
/// let mut h = Handle::new(move || {
///     let mut c = h_counter.lock().unwrap();
///     c.incr();
/// });
/// h.wait();
/// assert_eq!(counter.lock().unwrap().count, 1);
/// ```
pub struct Handle<'a> {
    handle: Option<thread::JoinHandle<()>>,
    err_handler: Option<Box<FnMut() -> () + 'a>>,
}

impl<'a> Handle<'a> {
    /// Construct a new Handle. Spawns a thread immediately.
    pub fn new<F>(f: F) -> Self
    where
        F: FnOnce() -> (),
        F: Send + 'static,
    {
        Self {
            handle: Some(thread::spawn(f)),
            err_handler: None,
        }
    }

    /// Adds a handler for join failures.
    pub fn with_handler<F>(mut self, f: Box<F>) -> Self
    where
        F: FnMut() -> (),
        F: 'a,
    {
        self.err_handler = Some(f);
        self
    }
}

impl<'a> Waitable for Handle<'a> {
    fn wait(&mut self) {
        let mut handle = None;
        std::mem::swap(&mut self.handle, &mut handle);
        if let Some(handle) = handle {
            if let Err(_) = handle.join() {
                if let Some(ref mut f) = self.err_handler {
                    f()
                }
            }
        }
    }
}