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::clone::Clone;
use std::convert::Into;
use std::sync::Arc;
use std::sync::Mutex;

use crate::thread::{Handle, Pending};
use crate::{Nursery, Waitable};

pub struct Counter {
    count: i32,
}

impl Counter {
    pub fn incr(&mut self) {
        self.count += 1;
    }
}

#[test]
fn thread_handle_runs_failure_handler() {
    let mut err_counter = 0;
    {
        let mut h = Handle::new(move || {
            panic!("Aaahhh!");
        })
        .with_handler(Box::new(|| err_counter += 1));
        h.wait();
    }
    assert_eq!(err_counter, 1);
}

#[test]
fn thread_handle_runs() {
    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);
}

#[test]
fn thread_handle_wait_is_idempotent() {
    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();
    h.wait();
    assert_eq!(counter.lock().unwrap().count, 1);
}

#[test]
fn nursery_runs_handles() {
    let counter = Arc::new(Mutex::new(Counter { count: 0 }));
    let h_counter = counter.clone();
    let h1 = Pending::new(move || {
        let mut c = h_counter.lock().unwrap();
        c.incr();
    });
    let h_counter = counter.clone();
    let h2 = Pending::new(move || {
        let mut c = h_counter.lock().unwrap();
        c.incr();
    });
    let mut nursery = Nursery::new();
    nursery.schedule(Box::new(h1));
    nursery.schedule(Box::new(h2));
    nursery.wait();
    assert_eq!(counter.lock().unwrap().count, 2);
}

#[test]
fn child_nursery_runs_handles() {
    let counter = Arc::new(Mutex::new(Counter { count: 0 }));
    let h_counter = counter.clone();
    let h1 = Pending::new(move || {
        let mut c = h_counter.lock().unwrap();
        c.incr();
    });
    let h_counter = counter.clone();
    let h2 = Pending::new(move || {
        let mut c = h_counter.lock().unwrap();
        c.incr();
    });
    let mut child = Nursery::new();
    child.schedule(Box::new(h1));
    child.schedule(Box::new(h2));
    let mut parent = Nursery::new();
    parent.adopt(child.into());
    parent.wait();
    assert_eq!(counter.lock().unwrap().count, 2);
}

#[test]
fn nursery_wait_is_idempotent() {
    let counter = Arc::new(Mutex::new(Counter { count: 0 }));
    let h_counter = counter.clone();
    let h1 = Pending::new(move || {
        let mut c = h_counter.lock().unwrap();
        c.incr();
    });
    let h_counter = counter.clone();
    let h2 = Pending::new(move || {
        let mut c = h_counter.lock().unwrap();
        c.incr();
    });
    let mut nursery = Nursery::new();
    nursery.schedule(Box::new(h1));
    nursery.wait();
    nursery.schedule(Box::new(h2));
    nursery.wait();
    nursery.wait();
    assert_eq!(counter.lock().unwrap().count, 2);
}

#[test]
fn child_nursery_wait_is_idempotent() {
    let counter = Arc::new(Mutex::new(Counter { count: 0 }));
    let h_counter = counter.clone();
    let h1 = Pending::new(move || {
        let mut c = h_counter.lock().unwrap();
        c.incr();
    });
    let h_counter = counter.clone();
    let h2 = Pending::new(move || {
        let mut c = h_counter.lock().unwrap();
        c.incr();
    });
    let mut child = Nursery::new();
    child.schedule(Box::new(h1));
    child.schedule(Box::new(h2));
    child.wait();
    let mut parent = Nursery::new();
    parent.adopt(child.into());
    parent.wait();
    assert_eq!(counter.lock().unwrap().count, 2);
}

#[test]
fn dropped_nurseries_wait_on_all_children() {
    let counter = Arc::new(Mutex::new(Counter { count: 0 }));
    {
        let h_counter = counter.clone();
        let h1 = Pending::new(move || {
            let mut c = h_counter.lock().unwrap();
            c.incr();
        });
        let h_counter = counter.clone();
        let h2 = Pending::new(move || {
            let mut c = h_counter.lock().unwrap();
            c.incr();
        });
        let mut child = Nursery::new();
        child.schedule(Box::new(h1));
        child.schedule(Box::new(h2));
        let mut parent = Nursery::new();
        parent.adopt(child.into());
    }
    assert_eq!(counter.lock().unwrap().count, 2);
}