<commit_before>use core::cast::transmute;
use core::cmp::{Eq, Ord};
use core::ptr::to_unsafe_ptr;
use core::vec::raw::buf_as_slice;

use std::cmp::FuzzyEq;
use numeric::funs::*;
use numeric::types::angle::Radians;
use numeric::types::float::Float;
use numeric::types::number::Number;
use numeric::types::number::Number::{one, zero};

/**
 * A 4-dimensional vector
 *
 * # Type parameters
 *
 * * `T` - The type of the components. This is intended to support boolean,
 *         integer, unsigned integer, and floating point types.
 *
 * # Fields
 *
 * * `x` - the first component of the vector
 * * `y` - the second component of the vector
 * * `z` - the third component of the vector
 * * `w` - the fourth component of the vector
 */
#[deriving_eq]
pub struct Vec4<T> { x: T, y: T, z: T, w: T }

pub impl<T> Vec4<T>/*: Vector4<T>*/ {
    #[inline(always)]
    static pure fn new(x: T, y: T, z: T, w: T) -> Vec4<T> {
        Vec4 { x: x, y: y, z: z, w: w }
    }
}

pub impl<T:Copy> Vec4<T>: Vector<T> {
    #[inline(always)]
    static pure fn from_value(value: T) -> Vec4<T> {
        Vec4::new(value, value, value, value)
    }

    #[inline(always)]
    pure fn to_ptr(&self) -> *T {
        unsafe {
            transmute::<*Vec4<T>, *T>(
                to_unsafe_ptr(self)
            )
        }
    }
}

pub impl<T:Copy> Vec4<T>: Index<uint, T> {
    #[inline(always)]
    pure fn index(&self, i: uint) -> T {
        unsafe { do buf_as_slice(self.to_ptr(), 4) |slice| { slice[i] } }
    }
}

pub impl<T:Copy> Vec4<T>: MutableVector<T> {
    #[inline(always)]
    fn index_mut(&mut self, i: uint) -> &self/mut T {
        match i {
            0 => &mut self.x,
            1 => &mut self.y,
            2 => &mut self.z,
            3 => &mut self.w,
            _ => fail(fmt!("index out of bounds: expected an index from 0 to 3, but found %u", i))
        }
    }

    #[inline(always)]
    fn swap(&mut self, a: uint, b: uint) {
        util::swap(self.index_mut(a),
                   self.index_mut(b));
    }
}

pub impl<T:Copy Number> Vec4<T>: NumericVector<T> {
    #[inline(always)]
    static pure fn identity() -> Vec4<T> {
        Vec4::new(one(), one(), one(), one())
    }

    #[inline(always)]
    static pure fn zero() -> Vec4<T> {
        Vec4::new(zero(), zero(), zero(), zero())
    }

    #[inline(always)]
    pure fn is_zero(&self) -> bool {
        self[0] == Number::zero() &&
        self[1] == Number::zero() &&
        self[2] == Number::zero() &&
        self[3] == Number::zero()
    }

    #[inline(always)]
    pure fn mul_t(&self, value: T) -> Vec4<T> {
        Vec4::new(self[0] * value,
                  self[1] * value,
                  self[2] * value,
                  self[3] * value)
    }

    #[inline(always)]
    pure fn div_t(&self, value: T) -> Vec4<T> {
        Vec4::new(self[0] / value,
                  self[1] / value,
                  self[2] / value,
                  self[3] / value)
    }

    #[inline(always)]
    pure fn add_v(&self, other: &Vec4<T>) -> Vec4<T> {
        Vec4::new(self[0] + other[0],
                  self[1] + other[1],
                  self[2] + other[2],
                  self[3] + other[3])
    }

    #[inline(always)]
    pure fn sub_v(&self, other: &Vec4<T>) -> Vec4<T> {
        Vec4::new(self[0] - other[0],
                  self[1] - other[1],
                  self[2] - other[2],
                  self[3] - other[3])
    }

    #[inline(always)]
    pure fn mul_v(&self, other: &Vec4<T>) -> Vec4<T> {
        Vec4::new(self[0] * other[0],
                  self[1] * other[1],
                  self[2] * other[2],
                  self[3] * other[3])
    }

    #[inline(always)]
    pure fn div_v(&self, other: &Vec4<T>) -> Vec4<T> {
        Vec4::new(self[0] / other[0],
                  self[1] / other[1],
                  self[2] / other[2],
                  self[3] / other[3])
    }

    #[inline(always)]
    pure fn dot(&self, other: &Vec4<T>) -> T {
        self[0] * other[0] +
        self[1] * other[1] +
        self[2] * other[2] +
        self[3] * other[3]
    }
}

pub impl<T:Copy Number> Vec4<T>: Neg<Vec4<T>> {
    #[inline(always)]
    pure fn neg(&self) -> Vec4<T> {
        Vec4::new(-self[0], -self[1], -self[2], -self[3])
    }
}

pub impl<T:Copy Number> Vec4<T>: MutableNumericVector<&self/T> {
    #[inline(always)]
    fn neg_self(&mut self) {
        *self.index_mut(0) = -*self.index_mut(0);
        *self.index_mut(1) = -*self.index_mut(1);
        *self.index_mut(2) = -*self.index_mut(2);
        *self.index_mut(3) = -*self.index_mut(3);
    }

    #[inline(always)]
    fn mul_self_t(&mut self, value: &T) {
        *self.index_mut(0) *= (*value);
        *self.index_mut(1) *= (*value);
        *self.index_mut(2) *= (*value);
        *self.index_mut(3) *= (*value);
    }

    #[inline(always)]
    fn div_self_t(&mut self, value: &T) {
        *self.index_mut(0) /= (*value);
        *self.index_mut(1) /= (*value);
        *self.index_mut(2) /= (*value);
        *self.index_mut(3) /= (*value);
    }

    #[inline(always)]
    fn add_self_v(&mut self, other: &Vec4<T>) {
        *self.index_mut(0) += other[0];
        *self.index_mut(1) += other[1];
        *self.index_mut(2) += other[2];
        *self.index_mut(3) += other[3];
    }

    #[inline(always)]
    fn sub_self_v(&mut self, other: &Vec4<T>) {
        *self.index_mut(0) -= other[0];
        *self.index_mut(1) -= other[1];
        *self.index_mut(2) -= other[2];
        *self.index_mut(3) -= other[3];
    }

    #[inline(always)]
    fn mul_self_v(&mut self, other: &Vec4<T>) {
        *self.index_mut(0) *= other[0];
        *self.index_mut(1) *= other[1];
        *self.index_mut(2) *= other[2];
        *self.index_mut(3) *= other[3];
    }

    #[inline(always)]
    fn div_self_v(&mut self, other: &Vec4<T>) {
        *self.index_mut(0) /= other[0];
        *self.index_mut(1) /= other[1];
        *self.index_mut(2) /= other[2];
        *self.index_mut(3) /= other[3];
    }
}

pub impl<T:Copy Float> Vec4<T>: EuclideanVector<T> {
    #[inline(always)]
    pure fn length2(&self) -> T {
        self.dot(self)
    }

    #[inline(always)]
    pure fn length(&self) -> T {
        self.length2().sqrt()
    }

    #[inline(always)]
    pure fn distance2(&self, other: &Vec4<T>) -> T {
        other.sub_v(self).length2()
    }

    #[inline(always)]
    pure fn distance(&self, other: &Vec4<T>) -> T {
        other.distance2(self).sqrt()
    }

    #[inline(always)]
    pure fn angle(&self, other: &Vec4<T>) -> Radians<T> {
        acos(&(self.dot(other) / (self.length() * other.length())))
    }

    #[inline(always)]
    pure fn normalize(&self) -> Vec4<T> {
        self.mul_t(one::<T>()/self.length())
    }

    #[inline(always)]
    pure fn normalize_to(&self, length: T) -> Vec4<T> {
        self.mul_t(length / self.length())
    }

    #[inline(always)]
    pure fn lerp(&self, other: &Vec4<T>, amount: T) -> Vec4<T> {
        self.add_v(&other.sub_v(self).mul_t(amount))
    }
}

pub impl<T:Copy Float> Vec4<T>: MutableEuclideanVector<&self/T> {
    #[inline(always)]
    fn normalize_self(&mut self) {
        let n = one::<T>() / self.length();
        self.mul_self_t(&n);
    }

    #[inline(always)]
    fn normalize_self_to(&mut self, length: &T) {
        let n = length / self.length();
        self.mul_self_t(&n);
    }

    fn lerp_self(&mut self, other: &Vec4<T>, amount: &T) {
        self.add_self_v(&other.sub_v(&*self).mul_t(*amount));
    }
}

pub impl<T:Copy FuzzyEq> Vec4<T>: FuzzyEq {
    #[inline(always)]
    pure fn fuzzy_eq(other: &Vec4<T>) -> bool {
        self[0].fuzzy_eq(&other[0]) &&
        self[1].fuzzy_eq(&other[1]) &&
        self[2].fuzzy_eq(&other[2]) &&
        self[3].fuzzy_eq(&other[3])
    }
}

pub impl<T:Copy Ord> Vec4<T>: OrdinalVector<T, Vec4<bool>> {
    #[inline(always)]
    pure fn less_than(&self, other: &Vec4<T>) -> Vec4<bool> {
        Vec4::new(self[0] < other[0],
                  self[1] < other[1],
                  self[2] < other[2],
                  self[3] < other[3])
    }

    #[inline(always)]
    pure fn less_than_equal(&self, other: &Vec4<T>) -> Vec4<bool> {
        Vec4::new(self[0] <= other[0],
                  self[1] <= other[1],
                  self[2] <= other[2],
                  self[3] <= other[3])
    }

    #[inline(always)]
    pure fn greater_than(&self, other: &Vec4<T>) -> Vec4<bool> {
        Vec4::new(self[0] > other[0],
                  self[1] > other[1],
                  self[2] > other[2],
                  self[3] > other[3])
    }

    #[inline(always)]
    pure fn greater_than_equal(&self, other: &Vec4<T>) -> Vec4<bool> {
        Vec4::new(self[0] >= other[0],
                  self[1] >= other[1],
                  self[2] >= other[2],
                  self[3] >= other[3])
    }
}

pub impl<T:Copy Eq> Vec4<T>: EquableVector<T, Vec4<bool>> {
    #[inline(always)]
    pure fn equal(&self, other: &Vec4<T>) -> Vec4<bool> {
        Vec4::new(self[0] == other[0],
                  self[1] == other[1],
                  self[2] == other[2],
                  self[3] == other[3])
    }

    #[inline(always)]
    pure fn not_equal(&self, other: &Vec4<T>) -> Vec4<bool> {
        Vec4::new(self[0] != other[0],
                  self[1] != other[1],
                  self[2] != other[2],
                  self[3] != other[3])
    }
}

pub impl Vec4<bool>: BooleanVector {
    #[inline(always)]
    pure fn any(&self) -> bool {
        self[0] || self[1] || self[2] || self[3]
    }

    #[inline(always)]
    pure fn all(&self) -> bool {
        self[0] && self[1] && self[2] && self[3]
    }

    #[inline(always)]
    pure fn not(&self) -> Vec4<bool> {
        Vec4::new(!self[0], !self[1], !self[2], !self[3])
    }
}<commit_msg>Remove unnecessary module specification<commit_after>use core::cast::transmute;
use core::cmp::{Eq, Ord};
use core::ptr::to_unsafe_ptr;
use core::vec::raw::buf_as_slice;

use std::cmp::FuzzyEq;
use numeric::funs::*;
use numeric::types::angle::Radians;
use numeric::types::float::Float;
use numeric::types::number::Number;
use numeric::types::number::Number::{one, zero};

/**
 * A 4-dimensional vector
 *
 * # Type parameters
 *
 * * `T` - The type of the components. This is intended to support boolean,
 *         integer, unsigned integer, and floating point types.
 *
 * # Fields
 *
 * * `x` - the first component of the vector
 * * `y` - the second component of the vector
 * * `z` - the third component of the vector
 * * `w` - the fourth component of the vector
 */
#[deriving_eq]
pub struct Vec4<T> { x: T, y: T, z: T, w: T }

pub impl<T> Vec4<T>/*: Vector4<T>*/ {
    #[inline(always)]
    static pure fn new(x: T, y: T, z: T, w: T) -> Vec4<T> {
        Vec4 { x: x, y: y, z: z, w: w }
    }
}

pub impl<T:Copy> Vec4<T>: Vector<T> {
    #[inline(always)]
    static pure fn from_value(value: T) -> Vec4<T> {
        Vec4::new(value, value, value, value)
    }

    #[inline(always)]
    pure fn to_ptr(&self) -> *T {
        unsafe {
            transmute::<*Vec4<T>, *T>(
                to_unsafe_ptr(self)
            )
        }
    }
}

pub impl<T:Copy> Vec4<T>: Index<uint, T> {
    #[inline(always)]
    pure fn index(&self, i: uint) -> T {
        unsafe { do buf_as_slice(self.to_ptr(), 4) |slice| { slice[i] } }
    }
}

pub impl<T:Copy> Vec4<T>: MutableVector<T> {
    #[inline(always)]
    fn index_mut(&mut self, i: uint) -> &self/mut T {
        match i {
            0 => &mut self.x,
            1 => &mut self.y,
            2 => &mut self.z,
            3 => &mut self.w,
            _ => fail(fmt!("index out of bounds: expected an index from 0 to 3, but found %u", i))
        }
    }

    #[inline(always)]
    fn swap(&mut self, a: uint, b: uint) {
        util::swap(self.index_mut(a),
                   self.index_mut(b));
    }
}

pub impl<T:Copy Number> Vec4<T>: NumericVector<T> {
    #[inline(always)]
    static pure fn identity() -> Vec4<T> {
        Vec4::new(one(), one(), one(), one())
    }

    #[inline(always)]
    static pure fn zero() -> Vec4<T> {
        Vec4::new(zero(), zero(), zero(), zero())
    }

    #[inline(always)]
    pure fn is_zero(&self) -> bool {
        self[0] == zero() &&
        self[1] == zero() &&
        self[2] == zero() &&
        self[3] == zero()
    }

    #[inline(always)]
    pure fn mul_t(&self, value: T) -> Vec4<T> {
        Vec4::new(self[0] * value,
                  self[1] * value,
                  self[2] * value,
                  self[3] * value)
    }

    #[inline(always)]
    pure fn div_t(&self, value: T) -> Vec4<T> {
        Vec4::new(self[0] / value,
                  self[1] / value,
                  self[2] / value,
                  self[3] / value)
    }

    #[inline(always)]
    pure fn add_v(&self, other: &Vec4<T>) -> Vec4<T> {
        Vec4::new(self[0] + other[0],
                  self[1] + other[1],
                  self[2] + other[2],
                  self[3] + other[3])
    }

    #[inline(always)]
    pure fn sub_v(&self, other: &Vec4<T>) -> Vec4<T> {
        Vec4::new(self[0] - other[0],
                  self[1] - other[1],
                  self[2] - other[2],
                  self[3] - other[3])
    }

    #[inline(always)]
    pure fn mul_v(&self, other: &Vec4<T>) -> Vec4<T> {
        Vec4::new(self[0] * other[0],
                  self[1] * other[1],
                  self[2] * other[2],
                  self[3] * other[3])
    }

    #[inline(always)]
    pure fn div_v(&self, other: &Vec4<T>) -> Vec4<T> {
        Vec4::new(self[0] / other[0],
                  self[1] / other[1],
                  self[2] / other[2],
                  self[3] / other[3])
    }

    #[inline(always)]
    pure fn dot(&self, other: &Vec4<T>) -> T {
        self[0] * other[0] +
        self[1] * other[1] +
        self[2] * other[2] +
        self[3] * other[3]
    }
}

pub impl<T:Copy Number> Vec4<T>: Neg<Vec4<T>> {
    #[inline(always)]
    pure fn neg(&self) -> Vec4<T> {
        Vec4::new(-self[0], -self[1], -self[2], -self[3])
    }
}

pub impl<T:Copy Number> Vec4<T>: MutableNumericVector<&self/T> {
    #[inline(always)]
    fn neg_self(&mut self) {
        *self.index_mut(0) = -*self.index_mut(0);
        *self.index_mut(1) = -*self.index_mut(1);
        *self.index_mut(2) = -*self.index_mut(2);
        *self.index_mut(3) = -*self.index_mut(3);
    }

    #[inline(always)]
    fn mul_self_t(&mut self, value: &T) {
        *self.index_mut(0) *= (*value);
        *self.index_mut(1) *= (*value);
        *self.index_mut(2) *= (*value);
        *self.index_mut(3) *= (*value);
    }

    #[inline(always)]
    fn div_self_t(&mut self, value: &T) {
        *self.index_mut(0) /= (*value);
        *self.index_mut(1) /= (*value);
        *self.index_mut(2) /= (*value);
        *self.index_mut(3) /= (*value);
    }

    #[inline(always)]
    fn add_self_v(&mut self, other: &Vec4<T>) {
        *self.index_mut(0) += other[0];
        *self.index_mut(1) += other[1];
        *self.index_mut(2) += other[2];
        *self.index_mut(3) += other[3];
    }

    #[inline(always)]
    fn sub_self_v(&mut self, other: &Vec4<T>) {
        *self.index_mut(0) -= other[0];
        *self.index_mut(1) -= other[1];
        *self.index_mut(2) -= other[2];
        *self.index_mut(3) -= other[3];
    }

    #[inline(always)]
    fn mul_self_v(&mut self, other: &Vec4<T>) {
        *self.index_mut(0) *= other[0];
        *self.index_mut(1) *= other[1];
        *self.index_mut(2) *= other[2];
        *self.index_mut(3) *= other[3];
    }

    #[inline(always)]
    fn div_self_v(&mut self, other: &Vec4<T>) {
        *self.index_mut(0) /= other[0];
        *self.index_mut(1) /= other[1];
        *self.index_mut(2) /= other[2];
        *self.index_mut(3) /= other[3];
    }
}

pub impl<T:Copy Float> Vec4<T>: EuclideanVector<T> {
    #[inline(always)]
    pure fn length2(&self) -> T {
        self.dot(self)
    }

    #[inline(always)]
    pure fn length(&self) -> T {
        self.length2().sqrt()
    }

    #[inline(always)]
    pure fn distance2(&self, other: &Vec4<T>) -> T {
        other.sub_v(self).length2()
    }

    #[inline(always)]
    pure fn distance(&self, other: &Vec4<T>) -> T {
        other.distance2(self).sqrt()
    }

    #[inline(always)]
    pure fn angle(&self, other: &Vec4<T>) -> Radians<T> {
        acos(&(self.dot(other) / (self.length() * other.length())))
    }

    #[inline(always)]
    pure fn normalize(&self) -> Vec4<T> {
        self.mul_t(one::<T>()/self.length())
    }

    #[inline(always)]
    pure fn normalize_to(&self, length: T) -> Vec4<T> {
        self.mul_t(length / self.length())
    }

    #[inline(always)]
    pure fn lerp(&self, other: &Vec4<T>, amount: T) -> Vec4<T> {
        self.add_v(&other.sub_v(self).mul_t(amount))
    }
}

pub impl<T:Copy Float> Vec4<T>: MutableEuclideanVector<&self/T> {
    #[inline(always)]
    fn normalize_self(&mut self) {
        let n = one::<T>() / self.length();
        self.mul_self_t(&n);
    }

    #[inline(always)]
    fn normalize_self_to(&mut self, length: &T) {
        let n = length / self.length();
        self.mul_self_t(&n);
    }

    fn lerp_self(&mut self, other: &Vec4<T>, amount: &T) {
        self.add_self_v(&other.sub_v(&*self).mul_t(*amount));
    }
}

pub impl<T:Copy FuzzyEq> Vec4<T>: FuzzyEq {
    #[inline(always)]
    pure fn fuzzy_eq(other: &Vec4<T>) -> bool {
        self[0].fuzzy_eq(&other[0]) &&
        self[1].fuzzy_eq(&other[1]) &&
        self[2].fuzzy_eq(&other[2]) &&
        self[3].fuzzy_eq(&other[3])
    }
}

pub impl<T:Copy Ord> Vec4<T>: OrdinalVector<T, Vec4<bool>> {
    #[inline(always)]
    pure fn less_than(&self, other: &Vec4<T>) -> Vec4<bool> {
        Vec4::new(self[0] < other[0],
                  self[1] < other[1],
                  self[2] < other[2],
                  self[3] < other[3])
    }

    #[inline(always)]
    pure fn less_than_equal(&self, other: &Vec4<T>) -> Vec4<bool> {
        Vec4::new(self[0] <= other[0],
                  self[1] <= other[1],
                  self[2] <= other[2],
                  self[3] <= other[3])
    }

    #[inline(always)]
    pure fn greater_than(&self, other: &Vec4<T>) -> Vec4<bool> {
        Vec4::new(self[0] > other[0],
                  self[1] > other[1],
                  self[2] > other[2],
                  self[3] > other[3])
    }

    #[inline(always)]
    pure fn greater_than_equal(&self, other: &Vec4<T>) -> Vec4<bool> {
        Vec4::new(self[0] >= other[0],
                  self[1] >= other[1],
                  self[2] >= other[2],
                  self[3] >= other[3])
    }
}

pub impl<T:Copy Eq> Vec4<T>: EquableVector<T, Vec4<bool>> {
    #[inline(always)]
    pure fn equal(&self, other: &Vec4<T>) -> Vec4<bool> {
        Vec4::new(self[0] == other[0],
                  self[1] == other[1],
                  self[2] == other[2],
                  self[3] == other[3])
    }

    #[inline(always)]
    pure fn not_equal(&self, other: &Vec4<T>) -> Vec4<bool> {
        Vec4::new(self[0] != other[0],
                  self[1] != other[1],
                  self[2] != other[2],
                  self[3] != other[3])
    }
}

pub impl Vec4<bool>: BooleanVector {
    #[inline(always)]
    pure fn any(&self) -> bool {
        self[0] || self[1] || self[2] || self[3]
    }

    #[inline(always)]
    pure fn all(&self) -> bool {
        self[0] && self[1] && self[2] && self[3]
    }

    #[inline(always)]
    pure fn not(&self) -> Vec4<bool> {
        Vec4::new(!self[0], !self[1], !self[2], !self[3])
    }
}<|endoftext|>


<commit_before>// -*- coding: utf-8 -*-
// ------------------------------------------------------------------------------------------------
// Copyright © 2019, HST authors.
//
// 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.
// ------------------------------------------------------------------------------------------------

//! Defines several traits that CSP processes will probably implement.

use std::collections::HashMap;
use std::hash::Hash;
use std::iter::FromIterator;

/// Returns the events that the process is willing to perform.
pub trait Initials<E> {
    type Initials;
    fn initials(&self) -> Self::Initials;
}

/// Returns how the process behaves after one of its initial events is performed.  The result is
/// a _set_ of processes; if there are multiple processes in the set, then there is nondeterminism,
/// and the process will behave like one of the elements arbitrarily.
pub trait Afters<E, P> {
    type Afters;
    fn afters(&self, initial: &E) -> Option<Self::Afters>;
}

/// Returns all of the outgoing transitions for the process.  This is a map where the keys are the
/// initial events of the process, and the values are a collection of the after processes for each
/// of those events.
pub fn transitions<'a, E, P, C>(process: &P) -> HashMap<E, C>
where
    E: Eq + Hash,
    P: Initials<E>,
    P: Afters<E, P>,
    C: FromIterator<P>,
    P::Initials: IntoIterator<Item = E>,
    P::Afters: IntoIterator<Item = P>,
{
    let mut transitions = HashMap::new();
    for initial in process.initials() {
        let afters = process
            .afters(&initial)
            .expect("No afters for initial")
            .into_iter()
            .collect();
        transitions.insert(initial, afters);
    }
    transitions
}
<commit_msg>Add consistency check for initials and afters<commit_after>// -*- coding: utf-8 -*-
// ------------------------------------------------------------------------------------------------
// Copyright © 2019, HST authors.
//
// 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.
// ------------------------------------------------------------------------------------------------

//! Defines several traits that CSP processes will probably implement.

use std::collections::HashMap;
use std::hash::Hash;
use std::iter::FromIterator;

/// Returns the events that the process is willing to perform.
pub trait Initials<E> {
    type Initials;
    fn initials(&self) -> Self::Initials;
}

/// Returns how the process behaves after one of its initial events is performed.  The result is
/// a _set_ of processes; if there are multiple processes in the set, then there is nondeterminism,
/// and the process will behave like one of the elements arbitrarily.
pub trait Afters<E, P> {
    type Afters;
    fn afters(&self, initial: &E) -> Option<Self::Afters>;
}

/// Returns all of the outgoing transitions for the process.  This is a map where the keys are the
/// initial events of the process, and the values are a collection of the after processes for each
/// of those events.
pub fn transitions<'a, E, P, C>(process: &P) -> HashMap<E, C>
where
    E: Eq + Hash,
    P: Initials<E>,
    P: Afters<E, P>,
    C: FromIterator<P>,
    P::Initials: IntoIterator<Item = E>,
    P::Afters: IntoIterator<Item = P>,
{
    let mut transitions = HashMap::new();
    for initial in process.initials() {
        let afters = process
            .afters(&initial)
            .expect("No afters for initial")
            .into_iter()
            .collect();
        transitions.insert(initial, afters);
    }
    transitions
}

#[cfg(test)]
mod tests {
    use super::*;

    use proptest_attr_macro::proptest;

    use crate::csp::CSP;
    use crate::test_support::TestEvent;

    #[proptest]
    /// The `initials` and `afters` methods for a process must be consistent with each other.  If
    /// an event is in the `initials` set, `afters` must return a process iterator with at least
    /// one element.  If an event is not in the `initials` set, `afters` must return `None`.
    fn initials_consistent_with_afters(process: CSP<TestEvent>, initial: TestEvent) {
        let in_initials = process.initials().into_iter().any(|e| e == initial);
        let afters = process.afters(&initial);
        if in_initials {
            let afters = afters.expect(&format!(
                "Afters can't be None for initial event {}",
                initial
            ));
            assert!(
                afters.into_iter().next().is_some(),
                "Afters can't be empty for initial event {}",
                initial
            );
        } else {
            assert!(
                afters.is_none(),
                "Afters must be None for non-initial event {}",
                initial
            );
        }
    }
}
<|endoftext|>


<commit_before>use parser::{Cond, Expr, Node, Target, WS};
use std::str;
use std::collections::HashSet;
use syn;

fn annotations(generics: &syn::Generics) -> String {
    if generics.lifetimes.len() < 1 {
        return String::new();
    }
    let mut res = String::new();
    res.push('<');
    for lt in &generics.lifetimes {
        res.push_str(lt.lifetime.ident.as_ref());
    }
    res.push('>');
    res
}

fn path_as_identifier(s: &str) -> String {
    let mut res = String::new();
    for c in s.chars() {
        if c.is_alphanumeric() {
            res.push(c);
        } else {
            res.push_str(&format!("{:x}", c as u32));
        }
    }
    res
}

struct Generator<'a> {
    buf: String,
    indent: u8,
    start: bool,
    locals: HashSet<String>,
    next_ws: Option<&'a str>,
    skip_ws: bool,
}

impl<'a> Generator<'a> {

    fn new() -> Generator<'a> {
        Generator {
            buf: String::new(),
            indent: 0,
            start: true,
            locals: HashSet::new(),
            next_ws: None,
            skip_ws: false,
        }
    }

    fn indent(&mut self) {
        self.indent += 1;
    }

    fn dedent(&mut self) {
        self.indent -= 1;
    }

    fn write(&mut self, s: &str) {
        if self.start {
            for _ in 0..(self.indent * 4) {
                self.buf.push(' ');
            }
            self.start = false;
        }
        self.buf.push_str(s);
    }

    fn writeln(&mut self, s: &str) {
        if s.is_empty() {
            return;
        }
        self.write(s);
        self.buf.push('\n');
        self.start = true;
    }

    fn visit_str_lit(&mut self, s: &str) {
        self.write(&format!("\"{}\"", s));
    }

    fn visit_var(&mut self, s: &str) {
        if self.locals.contains(s) {
            self.write(s);
        } else {
            self.write(&format!("self.{}", s));
        }
    }

    fn visit_filter(&mut self, name: &str, val: &Expr) {
        self.write(&format!("askama::filters::{}(&", name));
        self.visit_expr(val);
        self.write(")");
    }

    fn visit_compare(&mut self, op: &str, left: &Expr, right: &Expr) {
        self.visit_expr(left);
        self.write(&format!(" {} ", op));
        self.visit_expr(right);
    }

    fn visit_expr(&mut self, expr: &Expr) {
        match *expr {
            Expr::StrLit(s) => self.visit_str_lit(s),
            Expr::Var(s) => self.visit_var(s),
            Expr::Filter(name, ref val) => self.visit_filter(name, val),
            Expr::Compare(op, ref left, ref right) =>
                self.visit_compare(op, left, right),
        }
    }

    fn visit_target_single(&mut self, name: &str) -> Vec<String> {
        vec![name.to_string()]
    }

    fn visit_target(&mut self, target: &Target) -> Vec<String> {
        match *target {
            Target::Name(s) => { self.visit_target_single(s) },
        }
    }

    fn flush_ws(&mut self, ws: &WS) {
        if self.next_ws.is_some() && !ws.0 {
            let val = self.next_ws.unwrap();
            if !val.is_empty() {
                self.write(&format!("writer.write_str({:#?}).unwrap();",
                                    val));
            }
        } else if self.next_ws.is_some() {
        }
        self.next_ws = None;
    }

    fn prepare_ws(&mut self, ws: &WS) {
        self.skip_ws = ws.1;
    }

    fn handle_ws(&mut self, ws: &WS) {
        self.flush_ws(ws);
        self.prepare_ws(ws);
    }

    fn write_lit(&mut self, lws: &'a str, val: &str, rws: &'a str) {
        assert!(self.next_ws.is_none());
        if !lws.is_empty() {
            if self.skip_ws {
                self.skip_ws = false;
            } else if val.is_empty() {
                assert!(rws.is_empty());
                self.next_ws = Some(lws);
            } else {
                self.write(&format!("writer.write_str({:#?}).unwrap();", lws));
            }
        }
        if !val.is_empty() {
            self.write(&format!("writer.write_str({:#?}).unwrap();", val));
        }
        if !rws.is_empty() {
            self.next_ws = Some(rws);
        }
    }

    fn write_expr(&mut self, ws: &WS, s: &Expr) {
        self.handle_ws(ws);
        self.write("writer.write_fmt(format_args!(\"{}\", ");
        self.visit_expr(s);
        self.writeln(")).unwrap();");
    }

    fn write_cond(&mut self, conds: &'a [Cond], ws: &WS) {
        for (i, &(ref cws, ref cond, ref nodes)) in conds.iter().enumerate() {
            self.handle_ws(cws);
            match *cond {
                Some(ref expr) => {
                    if i == 0 {
                        self.write("if ");
                    } else {
                        self.write("} else if ");
                    }
                    self.visit_expr(expr);
                },
                None => { self.writeln("} else"); },
            }
            self.writeln(" {");
            self.indent();
            self.handle(nodes);
            self.dedent();
        }
        self.handle_ws(ws);
        self.writeln("}");
    }

    fn write_loop(&mut self, ws1: &WS, var: &Target, iter: &Expr,
                  body: &'a [Node], ws2: &WS) {

        self.handle_ws(ws1);
        self.write("for ");
        let targets = self.visit_target(var);
        for name in &targets {
            self.locals.insert(name.clone());
            self.write(name);
        }
        self.write(" in &");
        self.visit_expr(iter);
        self.writeln(" {");

        self.indent();
        self.handle(body);
        self.handle_ws(ws2);
        self.dedent();
        self.writeln("}");
        for name in &targets {
            self.locals.remove(name);
        }
    }

    fn write_block(&mut self, ws1: &WS, name: &str, ws2: &WS) {
        self.flush_ws(ws1);
        self.writeln(&format!("self.render_block_{}_to(writer);", name));
        self.prepare_ws(ws2);
    }

    fn write_block_def(&mut self, ws1: &WS, name: &str, nodes: &'a [Node],
                       ws2: &WS) {
        self.writeln("#[allow(unused_variables)]");
        self.writeln(&format!(
            "fn render_block_{}_to(&self, writer: &mut std::fmt::Write) {{",
            name));
        self.indent();
        self.prepare_ws(ws1);
        self.handle(nodes);
        self.flush_ws(ws2);
        self.dedent();
        self.writeln("}");
    }

    fn handle(&mut self, nodes: &'a [Node]) {
        for n in nodes {
            match *n {
                Node::Lit(lws, val, rws) => { self.write_lit(lws, val, rws); }
                Node::Expr(ref ws, ref val) => { self.write_expr(ws, val); },
                Node::Cond(ref conds, ref ws) => {
                    self.write_cond(conds, ws);
                },
                Node::Loop(ref ws1, ref var, ref iter, ref body, ref ws2) => {
                    self.write_loop(ws1, var, iter, body, ws2);
                },
                Node::Block(ref ws1, name, ref ws2) => {
                    self.write_block(ws1, name, ws2);
                },
                Node::BlockDef(ref ws1, name, ref block_nodes, ref ws2) => {
                    self.write_block_def(ws1, name, block_nodes, ws2);
                }
                Node::Extends(_) => {
                    panic!("no extends or block definition allowed in content");
                },
            }
        }
    }

    fn path_based_name(&mut self, ast: &syn::DeriveInput, path: &str) {
        let encoded = path_as_identifier(path);
        let original = ast.ident.as_ref();
        let anno = annotations(&ast.generics);
        self.writeln("#[allow(dead_code, non_camel_case_types)]");
        let s = format!("type TemplateFrom{}{} = {}{};",
                        encoded, &anno, original, &anno);
        self.writeln(&s);
    }

    fn template_impl(&mut self, ast: &syn::DeriveInput, nodes: &'a [Node]) {
        let anno = annotations(&ast.generics);
        self.writeln(&format!("impl{} askama::Template for {}{} {{",
                              anno, ast.ident.as_ref(), anno));
        self.indent();

        self.writeln("fn render_to(&self, writer: &mut std::fmt::Write) {");
        self.indent();
        self.handle(nodes);
        self.flush_ws(&WS(false, false));
        self.dedent();
        self.writeln("}");

        self.dedent();
        self.writeln("}");
    }

    fn trait_impl(&mut self, ast: &syn::DeriveInput, base: &str, blocks: &'a [Node]) {
        let anno = annotations(&ast.generics);
        self.writeln(&format!("impl{} TraitFrom{} for {}{} {{",
                              anno, path_as_identifier(base),
                              ast.ident.as_ref(), anno));
        self.indent();
        self.handle(blocks);
        self.flush_ws(&WS(false, false));
        self.dedent();
        self.writeln("}");
    }

    fn trait_based_impl(&mut self, ast: &syn::DeriveInput) {
        let anno = annotations(&ast.generics);
        self.writeln(&format!("impl{} askama::Template for {}{} {{",
                              anno, ast.ident.as_ref(), anno));
        self.indent();

        self.writeln("fn render_to(&self, writer: &mut std::fmt::Write) {");
        self.indent();
        self.writeln("self.render_trait_to(writer);");
        self.dedent();
        self.writeln("}");

        self.dedent();
        self.writeln("}");
    }

    fn template_trait(&mut self, ast: &syn::DeriveInput, path: &str,
                      blocks: &'a [Node], nodes: &'a [Node]) {
        let anno = annotations(&ast.generics);
        self.writeln(&format!("trait{} TraitFrom{}{} {{", anno,
                              path_as_identifier(path), anno));
        self.indent();

        self.handle(blocks);

        self.writeln("fn render_trait_to(&self, writer: &mut std::fmt::Write) {");
        self.indent();
        self.handle(nodes);
        self.flush_ws(&WS(false, false));
        self.dedent();
        self.writeln("}");

        self.dedent();
        self.writeln("}");
    }

    fn result(self) -> String {
        self.buf
    }

}

pub fn generate(ast: &syn::DeriveInput, path: &str, mut nodes: Vec<Node>) -> String {
    let mut base: Option<Expr> = None;
    let mut blocks = Vec::new();
    let mut content = Vec::new();
    for n in nodes.drain(..) {
        match n {
            Node::Extends(path) => {
                match base {
                    Some(_) => panic!("multiple extend blocks found"),
                    None => { base = Some(path); },
                }
            },
            Node::BlockDef(ws1, name, _, ws2) => {
                blocks.push(n);
                content.push(Node::Block(ws1, name, ws2));
            },
            _ => { content.push(n); },
        }
    }

    let empty = Vec::new();
    let mut gen = Generator::new();
    gen.path_based_name(ast, path);
    if !blocks.is_empty() {
        if let Some(extends) = base {
            if let Expr::StrLit(base_path) = extends {
                gen.trait_impl(ast, base_path, &blocks);
            }
        } else {
            gen.template_trait(ast, path, &blocks, &content);
            gen.trait_impl(ast, path, &empty);
        }
        gen.trait_based_impl(ast);
    } else {
        gen.template_impl(ast, &content);
    }
    gen.result()
}
<commit_msg>Refactor implementation of template inheritance<commit_after>use parser::{Cond, Expr, Node, Target, WS};
use std::str;
use std::collections::HashSet;
use syn;

fn annotations(generics: &syn::Generics) -> String {
    if generics.lifetimes.len() < 1 {
        return String::new();
    }
    let mut res = String::new();
    res.push('<');
    for lt in &generics.lifetimes {
        res.push_str(lt.lifetime.ident.as_ref());
    }
    res.push('>');
    res
}

fn path_as_identifier(s: &str) -> String {
    let mut res = String::new();
    for c in s.chars() {
        if c.is_alphanumeric() {
            res.push(c);
        } else {
            res.push_str(&format!("{:x}", c as u32));
        }
    }
    res
}

struct Generator<'a> {
    buf: String,
    indent: u8,
    start: bool,
    locals: HashSet<String>,
    next_ws: Option<&'a str>,
    skip_ws: bool,
}

impl<'a> Generator<'a> {

    fn new() -> Generator<'a> {
        Generator {
            buf: String::new(),
            indent: 0,
            start: true,
            locals: HashSet::new(),
            next_ws: None,
            skip_ws: false,
        }
    }

    fn indent(&mut self) {
        self.indent += 1;
    }

    fn dedent(&mut self) {
        self.indent -= 1;
    }

    fn write(&mut self, s: &str) {
        if self.start {
            for _ in 0..(self.indent * 4) {
                self.buf.push(' ');
            }
            self.start = false;
        }
        self.buf.push_str(s);
    }

    fn writeln(&mut self, s: &str) {
        if s.is_empty() {
            return;
        }
        self.write(s);
        self.buf.push('\n');
        self.start = true;
    }

    fn visit_str_lit(&mut self, s: &str) {
        self.write(&format!("\"{}\"", s));
    }

    fn visit_var(&mut self, s: &str) {
        if self.locals.contains(s) {
            self.write(s);
        } else {
            self.write(&format!("self.{}", s));
        }
    }

    fn visit_filter(&mut self, name: &str, val: &Expr) {
        self.write(&format!("askama::filters::{}(&", name));
        self.visit_expr(val);
        self.write(")");
    }

    fn visit_compare(&mut self, op: &str, left: &Expr, right: &Expr) {
        self.visit_expr(left);
        self.write(&format!(" {} ", op));
        self.visit_expr(right);
    }

    fn visit_expr(&mut self, expr: &Expr) {
        match *expr {
            Expr::StrLit(s) => self.visit_str_lit(s),
            Expr::Var(s) => self.visit_var(s),
            Expr::Filter(name, ref val) => self.visit_filter(name, val),
            Expr::Compare(op, ref left, ref right) =>
                self.visit_compare(op, left, right),
        }
    }

    fn visit_target_single(&mut self, name: &str) -> Vec<String> {
        vec![name.to_string()]
    }

    fn visit_target(&mut self, target: &Target) -> Vec<String> {
        match *target {
            Target::Name(s) => { self.visit_target_single(s) },
        }
    }

    fn flush_ws(&mut self, ws: &WS) {
        if self.next_ws.is_some() && !ws.0 {
            let val = self.next_ws.unwrap();
            if !val.is_empty() {
                self.write(&format!("writer.write_str({:#?}).unwrap();",
                                    val));
            }
        } else if self.next_ws.is_some() {
        }
        self.next_ws = None;
    }

    fn prepare_ws(&mut self, ws: &WS) {
        self.skip_ws = ws.1;
    }

    fn handle_ws(&mut self, ws: &WS) {
        self.flush_ws(ws);
        self.prepare_ws(ws);
    }

    fn write_lit(&mut self, lws: &'a str, val: &str, rws: &'a str) {
        assert!(self.next_ws.is_none());
        if !lws.is_empty() {
            if self.skip_ws {
                self.skip_ws = false;
            } else if val.is_empty() {
                assert!(rws.is_empty());
                self.next_ws = Some(lws);
            } else {
                self.write(&format!("writer.write_str({:#?}).unwrap();", lws));
            }
        }
        if !val.is_empty() {
            self.write(&format!("writer.write_str({:#?}).unwrap();", val));
        }
        if !rws.is_empty() {
            self.next_ws = Some(rws);
        }
    }

    fn write_expr(&mut self, ws: &WS, s: &Expr) {
        self.handle_ws(ws);
        self.write("writer.write_fmt(format_args!(\"{}\", ");
        self.visit_expr(s);
        self.writeln(")).unwrap();");
    }

    fn write_cond(&mut self, conds: &'a [Cond], ws: &WS) {
        for (i, &(ref cws, ref cond, ref nodes)) in conds.iter().enumerate() {
            self.handle_ws(cws);
            match *cond {
                Some(ref expr) => {
                    if i == 0 {
                        self.write("if ");
                    } else {
                        self.write("} else if ");
                    }
                    self.visit_expr(expr);
                },
                None => { self.writeln("} else"); },
            }
            self.writeln(" {");
            self.indent();
            self.handle(nodes);
            self.dedent();
        }
        self.handle_ws(ws);
        self.writeln("}");
    }

    fn write_loop(&mut self, ws1: &WS, var: &Target, iter: &Expr,
                  body: &'a [Node], ws2: &WS) {

        self.handle_ws(ws1);
        self.write("for ");
        let targets = self.visit_target(var);
        for name in &targets {
            self.locals.insert(name.clone());
            self.write(name);
        }
        self.write(" in &");
        self.visit_expr(iter);
        self.writeln(" {");

        self.indent();
        self.handle(body);
        self.handle_ws(ws2);
        self.dedent();
        self.writeln("}");
        for name in &targets {
            self.locals.remove(name);
        }
    }

    fn write_block(&mut self, ws1: &WS, name: &str, ws2: &WS) {
        self.flush_ws(ws1);
        self.writeln(&format!("self.render_block_{}_to(writer);", name));
        self.prepare_ws(ws2);
    }

    fn write_block_def(&mut self, ws1: &WS, name: &str, nodes: &'a [Node],
                       ws2: &WS) {
        self.writeln("#[allow(unused_variables)]");
        self.writeln(&format!(
            "fn impl_block_{}_to(&self, writer: &mut std::fmt::Write) {{",
            name));
        self.indent();
        self.prepare_ws(ws1);
        self.handle(nodes);
        self.flush_ws(ws2);
        self.dedent();
        self.writeln("}");
    }

    fn handle(&mut self, nodes: &'a [Node]) {
        for n in nodes {
            match *n {
                Node::Lit(lws, val, rws) => { self.write_lit(lws, val, rws); }
                Node::Expr(ref ws, ref val) => { self.write_expr(ws, val); },
                Node::Cond(ref conds, ref ws) => {
                    self.write_cond(conds, ws);
                },
                Node::Loop(ref ws1, ref var, ref iter, ref body, ref ws2) => {
                    self.write_loop(ws1, var, iter, body, ws2);
                },
                Node::Block(ref ws1, name, ref ws2) => {
                    self.write_block(ws1, name, ws2);
                },
                Node::BlockDef(ref ws1, name, ref block_nodes, ref ws2) => {
                    self.write_block_def(ws1, name, block_nodes, ws2);
                }
                Node::Extends(_) => {
                    panic!("no extends or block definition allowed in content");
                },
            }
        }
    }

    fn path_based_name(&mut self, ast: &syn::DeriveInput, path: &str) {
        let encoded = path_as_identifier(path);
        let original = ast.ident.as_ref();
        let anno = annotations(&ast.generics);
        self.writeln("#[allow(dead_code, non_camel_case_types)]");
        let s = format!("type TemplateFrom{}{} = {}{};",
                        encoded, &anno, original, &anno);
        self.writeln(&s);
    }

    fn struct_impl(&mut self, ast: &syn::DeriveInput, blocks: &'a [Node]) {
        let anno = annotations(&ast.generics);
        self.writeln(&format!("impl{} {}{} {{", anno, ast.ident.as_ref(),
                              anno));
        self.indent();
        self.handle(blocks);
        self.dedent();
        self.writeln("}");
    }

    fn template_impl(&mut self, ast: &syn::DeriveInput, nodes: &'a [Node]) {
        let anno = annotations(&ast.generics);
        self.writeln(&format!("impl{} askama::Template for {}{} {{",
                              anno, ast.ident.as_ref(), anno));
        self.indent();

        self.writeln("fn render_to(&self, writer: &mut std::fmt::Write) {");
        self.indent();
        self.handle(nodes);
        self.flush_ws(&WS(false, false));
        self.dedent();
        self.writeln("}");

        self.dedent();
        self.writeln("}");
    }

    fn trait_impl(&mut self, ast: &syn::DeriveInput, base: &str,
                  block_names: &[&str]) {
        let anno = annotations(&ast.generics);
        self.writeln(&format!("impl{} TraitFrom{} for {}{} {{",
                              anno, path_as_identifier(base),
                              ast.ident.as_ref(), anno));
        self.indent();

        for bname in block_names {
            self.writeln(&format!(
                "fn render_block_{}_to(&self, writer: &mut std::fmt::Write) {{",
                bname));
            self.indent();
            self.writeln(&format!("self.impl_block_{}_to(writer);", bname));
            self.dedent();
            self.writeln("}");
        }

        self.flush_ws(&WS(false, false));
        self.dedent();
        self.writeln("}");
    }

    fn trait_based_impl(&mut self, ast: &syn::DeriveInput) {
        let anno = annotations(&ast.generics);
        self.writeln(&format!("impl{} askama::Template for {}{} {{",
                              anno, ast.ident.as_ref(), anno));
        self.indent();

        self.writeln("fn render_to(&self, writer: &mut std::fmt::Write) {");
        self.indent();
        self.writeln("self.render_trait_to(writer);");
        self.dedent();
        self.writeln("}");

        self.dedent();
        self.writeln("}");
    }

    fn template_trait(&mut self, ast: &syn::DeriveInput, path: &str,
                      block_names: &[&str], nodes: &'a [Node]) {
        let anno = annotations(&ast.generics);
        self.writeln(&format!("trait{} TraitFrom{}{} {{", anno,
                              path_as_identifier(path), anno));
        self.indent();

        for bname in block_names {
            self.writeln(&format!(
                "fn render_block_{}_to(&self, writer: &mut std::fmt::Write);",
                bname));
        }

        self.writeln("fn render_trait_to(&self, writer: &mut std::fmt::Write) {");
        self.indent();
        self.handle(nodes);
        self.flush_ws(&WS(false, false));
        self.dedent();
        self.writeln("}");

        self.dedent();
        self.writeln("}");
    }

    fn result(self) -> String {
        self.buf
    }

}

pub fn generate(ast: &syn::DeriveInput, path: &str, mut nodes: Vec<Node>) -> String {
    let mut base: Option<Expr> = None;
    let mut blocks = Vec::new();
    let mut block_names = Vec::new();
    let mut content = Vec::new();
    for n in nodes.drain(..) {
        match n {
            Node::Extends(path) => {
                match base {
                    Some(_) => panic!("multiple extend blocks found"),
                    None => { base = Some(path); },
                }
            },
            Node::BlockDef(ws1, name, _, ws2) => {
                blocks.push(n);
                block_names.push(name);
                content.push(Node::Block(ws1, name, ws2));
            },
            _ => { content.push(n); },
        }
    }

    let mut gen = Generator::new();
    gen.path_based_name(ast, path);
    if !blocks.is_empty() {
        gen.struct_impl(ast, &blocks);
        if base.is_none() {
            gen.template_trait(ast, path, &block_names, &content);
        }
        let tmpl_path = match base {
            Some(Expr::StrLit(base_path)) => { base_path },
            _ => { path },
        };
        gen.trait_impl(ast, tmpl_path, &block_names);
        gen.trait_based_impl(ast);
    } else {
        gen.template_impl(ast, &content);
    }
    gen.result()
}
<|endoftext|>


<commit_before>use std::io::timer::sleep;
use std::time::duration::Duration;
use std::comm::{Disconnected, TryRecvError};

use std::sync::{Arc, Mutex};

use super::intercommunication::{Intercommunication, Ack, LeaderQuery, LeaderQueryResponse, Pack, Endpoint};

#[deriving(Clone,Show,PartialEq)]
pub enum State {
    Follower,
    Candidate,
    Leader,
}

pub struct Node {
    contact: Option < NodeContact >,
}

#[deriving(Clone,Show,PartialEq)]
pub struct NodeHost {
    pub host: String,
}

struct NodeService {
    state: State,
    my_host: NodeHost,
    leader_host: Option < NodeHost >,

    contact: NodeServiceContact,
    nodes: Vec < NodeHost >,

    comm: Endpoint,
}

struct NodeContact {
    state_tx: Sender < Option < State > >,
    state_rx: Receiver < State >,

    leader_tx: Sender < Option < String > >,
    leader_rx: Receiver < Option < NodeHost > >,

    exit_tx: Sender < int >,

    nodes_tx: Sender < int >,
    nodes_rx: Receiver < Vec < NodeHost > >,

    introduce_tx: Sender < String >,
}

struct NodeServiceContact {
    state_rx: Receiver < Option < State > >,
    state_tx: Sender < State >,

    leader_rx: Receiver < Option < String > >,
    leader_tx: Sender < Option < NodeHost > >,

    exit_rx: Receiver < int >,

    nodes_tx: Sender < Vec < NodeHost > >,
    nodes_rx: Receiver < int >,

    introduce_rx: Receiver < String >,
}

impl Node {
    pub fn new() -> Node {
        Node { contact: None }
    }

    pub fn state(&self) -> State {
        self.contact().state_tx.send(None);
        self.contact().state_rx.recv()
    }

    pub fn forced_state(&self, state: State) -> State {
        self.contact().state_tx.send(Some(state));
        self.contact().state_rx.recv()
    }

    pub fn fetch_leader(&self) -> Option < NodeHost > {
        self.contact().leader_tx.send(None);
        self.contact().leader_rx.recv()
    }

    pub fn force_follow(&self, host: &str) -> Option < NodeHost > {
        self.forced_state(Follower);

        self.contact().leader_tx.send(Some(host.to_string()));
        self.contact().leader_rx.recv()
    }

    pub fn introduce(&self, host: &str) {
        self.contact().introduce_tx.send(host.to_string());
    }

    pub fn fetch_nodes(&self) -> Vec < NodeHost > {
        self.contact().nodes_tx.send(0);
        self.contact().nodes_rx.recv()
    }

    pub fn stop(&self) {
        self.contact().exit_tx.send(0);
    }

    pub fn start(&mut self, host: &str, intercommunication: &mut Intercommunication) {
        match self.contact {
            Some(_) => {},
            None => self.contact = Some(NodeService::start_service(
                    host.to_string(),
                    intercommunication,
                    )),
        }
    }

    // private

    fn contact(&self) -> &NodeContact {
        match self.contact {
            Some(ref x) => x,
            None => fail!("You forgot to start the node")
        }
    }

}

impl NodeService {
    fn start_service(host: String, intercommunication: &mut Intercommunication) -> NodeContact {
        let (state_tx, service_state_rx) = channel();
        let (service_state_tx, state_rx) = channel();

        let (leader_tx, service_leader_rx) = channel();
        let (service_leader_tx, leader_rx) = channel();

        let (exit_tx, service_exit_rx) = channel();

        let (nodes_tx, service_nodes_rx) = channel();
        let (service_nodes_tx, nodes_rx) = channel();

        let (introduce_tx, service_introduce_rx) = channel();

        let contact = NodeContact {
            state_tx: state_tx,
            state_rx: state_rx,

            leader_tx: leader_tx,
            leader_rx: leader_rx,

            exit_tx: exit_tx,

            nodes_tx: nodes_tx,
            nodes_rx: nodes_rx,

            introduce_tx: introduce_tx,
        };

        let service_contact = NodeServiceContact {
            state_rx: service_state_rx,
            state_tx: service_state_tx,

            leader_rx: service_leader_rx,
            leader_tx: service_leader_tx,

            exit_rx: service_exit_rx,

            nodes_tx: service_nodes_tx,
            nodes_rx: service_nodes_rx,

            introduce_rx: service_introduce_rx,
        };

        let mut comm = intercommunication.register(host.clone());

        spawn(proc() {
            let (send_ack_tx, send_ack_rx) = channel();

            let mut me = NodeService {
                state: Follower,
                my_host: NodeHost { host: host.clone() },
                leader_host: None,

                contact: service_contact,
                nodes: vec![NodeHost { host: host.clone() }],

                comm: comm,
            };

            let mut dead = false;

            while !dead {
                dead = dead || me.try_serve_state(|new_state| {});

                dead = dead || me.try_serve_leader(|new_leader| {
                    send_ack_tx.send(new_leader.host);
                });

                dead = dead || me.try_serve_nodes();
                dead = dead || me.exit_if_asked();

                match me.contact.introduce_rx.try_recv() {
                    Ok(host) => {
                        me.comm.send(host.clone(), Ack);
                        me.comm.send(host, LeaderQuery);
                    },
                    _ => ()
                }

                match send_ack_rx.try_recv() {
                    Ok(host) => me.comm.send(host, Ack),
                    _ => ()
                }

                match me.comm.listen() {
                    Some(Pack(from, _, Ack)) => me.nodes.push(NodeHost { host: from }),
                    Some(Pack(from, _, LeaderQuery)) => {
                        let leader_host = match me.leader_host {
                            Some(NodeHost { ref host }) => Some(host.clone()),
                            None => None,
                        };

                        me.comm.send(from, LeaderQueryResponse(leader_host));
                    },
                    Some(Pack(_, _, LeaderQueryResponse(leader_host))) => {
                        match leader_host {
                            Some(host) => me.comm.send(host, Ack),
                            None => (),
                        }
                    },
                    None => ()
                }

                sleep(Duration::milliseconds(10));
            }
        });

        contact
    }

    fn try_serve_nodes(&mut self) -> bool {
        match self.contact.nodes_rx.try_recv() {
            Ok(_) => {
                self.contact.nodes_tx.send(self.nodes.clone());
                false
            },
            Err(err) if err == Disconnected => true,
            _ => false
        }
    }

    fn try_serve_state(&mut self, f: |State| -> ()) -> bool {
        let received = self.contact.state_rx.try_recv();

        self.try_serve(
            received,
            |ref mut me, value| { me.state = value; f(me.state.clone()); },
            |ref me| { me.contact.state_tx.send(me.state.clone()); }
            )
    }

    fn try_serve_leader(&mut self, f: |NodeHost| -> ()) -> bool {
        let received = self.contact.leader_rx.try_recv();

        self.try_serve(
            received,
            |ref mut me, value| {
                me.leader_host = Some(NodeHost { host: value.clone() });
                f(NodeHost { host: value });
            },
            |ref me| { me.contact.leader_tx.send(me.leader_host.clone()); }
            )
    }

    fn try_serve < T > (&mut self, received: Result < Option < T >, TryRecvError >, change: |&mut NodeService, T| -> (), respond: |&NodeService| -> ()) -> bool {
        match received {
            Ok(value) => {
                match value {
                    Some(value) => change(self, value),
                    _ => {},
                }

                respond(self);
                false
            },
            Err(err) if err == Disconnected => true,
            _ => false
        }
    }

    fn exit_if_asked(&self) -> bool {
        match self.contact.exit_rx.try_recv() {
            Ok(_) => true,
            _ => false
        }
    }
}
<commit_msg>simplified commands and NodeService class<commit_after>use std::io::timer::sleep;
use std::time::duration::Duration;
use std::comm::{Disconnected, TryRecvError};

use std::sync::{Arc, Mutex};

use super::intercommunication::{Intercommunication, Ack, LeaderQuery, LeaderQueryResponse, Pack, Endpoint};

#[deriving(Clone,Show,PartialEq)]
pub enum State {
    Follower,
    Candidate,
    Leader,
}

pub struct Node {
    contact: Option < NodeContact >,
}

#[deriving(Clone,Show,PartialEq)]
pub struct NodeHost {
    pub host: String,
}

struct NodeService {
    state: State,
    my_host: NodeHost,
    leader_host: Option < NodeHost >,

    contact: NodeServiceContact,
    nodes: Vec < NodeHost >,

    comm: Endpoint,
}

struct NodeContact {
    tx: Sender < Command >,
    rx: Receiver < CommandResponse >,
}

struct NodeServiceContact {
    tx: Sender < CommandResponse >,
    rx: Receiver < Command >,
}

enum Command {
    Introduce(String),

    FetchNodes,

    AssignLeader(Option < NodeHost >),
    FetchLeader,

    AssignState(State),
    FetchState,

    ExitCommand,
}

enum CommandResponse {
    FetchedLeader(Option < NodeHost >),

    FetchedState(State),

    FetchedNodes(Vec < NodeHost >),
}

impl Node {
    pub fn new() -> Node {
        Node { contact: None }
    }

    pub fn state(&self) -> State {
        self.contact().tx.send(FetchState);
        match self.contact().rx.recv() {
            FetchedState(state) => state,
            _ => unreachable!(),
        }
    }

    pub fn forced_state(&self, state: State) -> State {
        self.contact().tx.send(AssignState(state));
        match self.contact().rx.recv() {
            FetchedState(state) => state,
            _ => unreachable!(),
        }
    }

    pub fn fetch_leader(&self) -> Option < NodeHost > {
        self.contact().tx.send(FetchLeader);
        match self.contact().rx.recv() {
            FetchedLeader(leader) => leader,
            _ => unreachable!(),
        }
    }

    pub fn force_follow(&self, host: &str) -> Option < NodeHost > {
        self.forced_state(Follower);

        self.contact().tx.send(AssignLeader(Some(NodeHost { host: host.to_string() })));
        match self.contact().rx.recv() {
            FetchedLeader(leader) => leader,
            _ => unreachable!(),
        }
    }

    pub fn introduce(&self, host: &str) {
        self.contact().tx.send(Introduce(host.to_string()));
    }

    pub fn fetch_nodes(&self) -> Vec < NodeHost > {
        self.contact().tx.send(FetchNodes);
        match self.contact().rx.recv() {
            FetchedNodes(nodes) => nodes,
            _ => unreachable!(),
        }
    }

    pub fn stop(&self) {
        self.contact().tx.send(ExitCommand);
    }

    pub fn start(&mut self, host: &str, intercommunication: &mut Intercommunication) {
        match self.contact {
            Some(_) => {},
            None => self.contact = Some(NodeService::start_service(
                    host.to_string(),
                    intercommunication,
                    )),
        }
    }

    // private

    fn contact(&self) -> &NodeContact {
        match self.contact {
            Some(ref x) => x,
            None => fail!("You forgot to start the node")
        }
    }

}

impl NodeService {
    fn new(host: String, service_contact: NodeServiceContact, comm: Endpoint) -> NodeService {
        NodeService {
            state: Follower,
            my_host: NodeHost { host: host.clone() },
            leader_host: None,

            contact: service_contact,
            nodes: vec![NodeHost { host: host.clone() }],

            comm: comm,
        }
    }

    fn start_service(host: String, intercommunication: &mut Intercommunication) -> NodeContact {
        let (contact, service_contact) = NodeService::channels();

        let mut comm = intercommunication.register(host.clone());

        spawn(proc() {
            let mut me = NodeService::new(host, service_contact, comm);

            let mut dead = false;

            while !dead {
                dead = dead || me.react_to_commands();

                me.react_to_intercommunication();

                sleep(Duration::milliseconds(10));
            }
        });

        contact
    }

    fn channels() -> (NodeContact, NodeServiceContact) {
        let (tx, service_rx) = channel();
        let (service_tx, rx) = channel();

        let contact = NodeContact {
            tx: tx,
            rx: rx,
        };

        let service_contact = NodeServiceContact {
            tx: service_tx,
            rx: service_rx,
        };

        (contact, service_contact)
    }

    fn react_to_commands(&mut self) -> bool {
        let mut dead = false;

        match self.contact.rx.try_recv() {
            Ok(FetchState) => self.contact.tx.send(FetchedState(self.state)),
            Ok(AssignState(state)) => {
                self.state = state;
                self.contact.tx.send(FetchedState(self.state));
            },

            Ok(FetchLeader) => self.contact.tx.send(FetchedLeader(self.leader_host.clone())),
            Ok(AssignLeader(leader)) => {
                self.leader_host = leader.clone();
                match leader {
                    Some(leader) => self.comm.send(leader.host, Ack),
                    None => (),
                }
                self.contact.tx.send(FetchedLeader(self.leader_host.clone()));
            },

            Ok(FetchNodes) => self.contact.tx.send(FetchedNodes(self.nodes.clone())),

            Ok(ExitCommand) => dead = true,

            Ok(Introduce(host)) => self.comm.send(host, LeaderQuery),

            Err(Disconnected) => dead = true,

            Err(_) => (),
        }

        dead
    }

    fn react_to_intercommunication(&mut self) {
        match self.comm.listen() {
            Some(Pack(from, _, Ack)) => self.nodes.push(NodeHost { host: from }),
            Some(Pack(from, _, LeaderQuery)) => {
                let leader_host = match self.leader_host {
                    Some(NodeHost { ref host }) => Some(host.clone()),
                    None => None,
                };

                self.comm.send(from, LeaderQueryResponse(leader_host));
            },
            Some(Pack(_, _, LeaderQueryResponse(leader_host))) => {
                match leader_host {
                    Some(host) => self.comm.send(host, Ack),
                    None => (),
                }
            },
            None => ()
        }
    }
}
<|endoftext|>


<commit_before>use core::marker::PhantomData;

/// Enumeration possible write operations.
#[derive(Debug, PartialEq)]
pub enum WriteMode {
    Command(u8),
    Data(u8),
}

/// Enumeration possible read operations.
pub enum ReadMode {
    Data,
    BusyFlag,
}

/// Enumeration of possible data directions of a pin.
#[derive(Debug, PartialEq)]
pub enum Direction {
    In,
    Out,
}

/// Enumeration of possible levels of a pin.
#[derive(Debug, PartialEq)]
pub enum Level {
    Low,
    High,
}

impl From<WriteMode> for (Level, u8) {
    fn from(mode: WriteMode) -> Self {
        match mode {
            WriteMode::Command(value) => (Level::Low, value),
            WriteMode::Data(value) => (Level::High, value),
        }
    }
}

enum Nibble {
    Upper(u8),
    Lower(u8),
}

impl From<Nibble> for u8 {
    fn from(n: Nibble) -> Self {
        match n {
            Nibble::Upper(base) => base >> 4,
            Nibble::Lower(base) => base & 0x0f,
        }
    }
}

/// This trait is used to provide an initialization implementation for a [`Display`] connection.
/// [`Display`]: struct.Display.html
pub trait Init {
    /// Initializes the connection.
    fn init(&self);
}

/// This trait is used to provide an implementation for sending data via a [`Display`] connection.
/// [`Display`]: struct.Display.html
pub trait Send {
    /// Sends data via the connection.
    fn send(&self, mode: WriteMode);
}

/// This trait is used to provide an implementation for receiving data via a [`Display`] connection.
/// [`Display`]: struct.Display.html
pub trait Receive {
    fn receive(&self, mode: ReadMode) -> u8;
}

pub trait SendRaw {
    fn send_byte(&self, byte: u8);
}

pub trait ReceiveRaw {
    fn receive_byte(&self) -> u8;
}

/// The `DisplayHardwareLayer` trait is intended to be implemented by the library user as a thin
/// wrapper around the hardware specific system calls.
pub trait DisplayHardwareLayer {
    /// Initializes an I/O pin.
    fn init(&self) {}
    /// Cleanup an I/O pin.
    fn cleanup(&self) {}

    fn set_direction(&self, Direction);
    /// Sets a value on an I/O pin.
    fn set_level(&self, Level);

    fn get_value(&self) -> u8;
}

/// The `Delay` trait is used to adapt the timing to the specific hardware and must be implemented
/// by the libary user.
pub trait Delay {
    /// The time (ns) between register select (RS) and read/write (R/W) to enable signal (E).
    const ADDRESS_SETUP_TIME: u16 = 60;
    /// The duration (ns) the enable signal is set to `High`.
    const ENABLE_PULSE_WIDTH: u16 = 450;
    /// The duration (ns) the data pins will be set after the enable signal was dropped.
    const DATA_HOLD_TIME: u16 = 20;

    /// The maximum execution time of instruction commands.
    const COMMAND_EXECUTION_TIME: u16 = 37;

    /// Wait for the given amount of nanoseconds.
    fn delay_ns(ns: u16);

    /// Wait for the given amount of microseconds.
    fn delay_us(us: u16) {
        for _ in 0..us {
            Self::delay_ns(1000);
        }
    }
}

/// This struct is used for easily setting up [`ParallelConnection`]s.
///
/// [`ParallelConnection`]: struct.ParallelConnection.html
pub struct Pins<RS, R, E, D> {
    pub register_select: RS,
    pub read: R,
    pub enable: E,
    pub data: D,
}

impl<RS, R, E, D> Pins<RS, R, E, D> {
    /// Converts the pin setup into a [`ParallelConnection`] that is by `Display` to communicate
    /// with the LCD device.
    ///
    /// [`ParallelConnection`]: struct.ParallelConnection.html
    pub fn into_connection<T>(self) -> ParallelConnection<RS, R, E, D, T> {
        ParallelConnection {
            register_select: self.register_select,
            read: self.read,
            enable: self.enable,
            data: self.data,
            _delay_marker: PhantomData,
        }
    }
}

/// The parallel connection mode is the most common wiring mode for HD44780 compliant displays.
/// It can be used with either four ([`DataPins4Lines`]) or eight ([`DataPins8Lines`]) data lines.
///
/// [`DataPins4Lines`]: struct.DataPins4Lines.html
/// [`DataPins8Lines`]: struct.DataPins8Lines.html
pub struct ParallelConnection<RS, R, E, D, T> {
    register_select: RS,
    read: R,
    enable: E,
    data: D,
    _delay_marker: PhantomData<T>,
}

impl<RS, R, E, D, T> Init for ParallelConnection<RS, R, E, D, T>
where
    RS: DisplayHardwareLayer,
    R: DisplayHardwareLayer,
    E: DisplayHardwareLayer,
    D: Init,
    T: Delay,
{
    fn init(&self) {
        self.register_select.init();
        self.register_select.set_direction(Direction::Out);

        self.read.init();
        self.read.set_direction(Direction::Out);

        self.enable.init();
        self.enable.set_direction(Direction::Out);

        self.data.init();
    }
}

impl<RS, R, E, D, T> Send for ParallelConnection<RS, R, E, D, T>
where
    Self: SendRaw,
    RS: DisplayHardwareLayer,
    R: DisplayHardwareLayer,
{
    fn send(&self, mode: WriteMode) {
        self.read.set_level(Level::Low);

        let (level, value) = mode.into();
        self.register_select.set_level(level);

        self.send_byte(value);
    }
}

impl<RS, R, E, D, T> Receive for ParallelConnection<RS, R, E, D, T>
where
    Self: ReceiveRaw,
    RS: DisplayHardwareLayer,
    R: DisplayHardwareLayer,
{
    fn receive(&self, mode: ReadMode) -> u8 {
        self.read.set_level(Level::High);

        match mode {
            ReadMode::Data => self.register_select.set_level(Level::High),
            ReadMode::BusyFlag => self.register_select.set_level(Level::Low),
        };

        self.receive_byte()
    }
}

// FIXME: WARNING - dummy implementation, not tested
impl<RS, R, E, T, P0, P1, P2, P3, P4, P5, P6, P7> SendRaw
    for ParallelConnection<RS, R, E, DataPins8Lines<P0, P1, P2, P3, P4, P5, P6, P7>, T>
where
    E: DisplayHardwareLayer,
    T: Delay,
    P0: DisplayHardwareLayer,
    P0: DisplayHardwareLayer,
    P1: DisplayHardwareLayer,
    P2: DisplayHardwareLayer,
    P3: DisplayHardwareLayer,
    P4: DisplayHardwareLayer,
    P5: DisplayHardwareLayer,
    P6: DisplayHardwareLayer,
    P7: DisplayHardwareLayer,
{
    fn send_byte(&self, byte: u8) {
        T::delay_ns(T::ADDRESS_SETUP_TIME);
        self.enable.set_level(Level::High);

        self.data.data0.set_level(get_bit(byte, 0b0000_0001));
        self.data.data1.set_level(get_bit(byte, 0b0000_0010));
        self.data.data2.set_level(get_bit(byte, 0b0000_0100));
        self.data.data3.set_level(get_bit(byte, 0b0000_1000));
        self.data.data4.set_level(get_bit(byte, 0b0001_0000));
        self.data.data5.set_level(get_bit(byte, 0b0010_0000));
        self.data.data6.set_level(get_bit(byte, 0b0100_0000));
        self.data.data7.set_level(get_bit(byte, 0b1000_0000));

        T::delay_ns(T::ENABLE_PULSE_WIDTH);
        self.enable.set_level(Level::Low);
        T::delay_ns(T::DATA_HOLD_TIME);
    }
}

fn get_bit(val: u8, bit: u8) -> Level {
    if val & bit == bit {
        Level::High
    } else {
        Level::Low
    }
}

/// Eight data lines pin wiring setup.
pub struct DataPins8Lines<P0, P1, P2, P3, P4, P5, P6, P7>
where
    P0: DisplayHardwareLayer,
    P1: DisplayHardwareLayer,
    P2: DisplayHardwareLayer,
    P3: DisplayHardwareLayer,
    P4: DisplayHardwareLayer,
    P5: DisplayHardwareLayer,
    P6: DisplayHardwareLayer,
    P7: DisplayHardwareLayer,
{
    pub data0: P0,
    pub data1: P1,
    pub data2: P2,
    pub data3: P3,
    pub data4: P4,
    pub data5: P5,
    pub data6: P6,
    pub data7: P7,
}

impl<P0, P1, P2, P3, P4, P5, P6, P7> Init for DataPins8Lines<P0, P1, P2, P3, P4, P5, P6, P7>
where
    P0: DisplayHardwareLayer,
    P0: DisplayHardwareLayer,
    P1: DisplayHardwareLayer,
    P2: DisplayHardwareLayer,
    P3: DisplayHardwareLayer,
    P4: DisplayHardwareLayer,
    P5: DisplayHardwareLayer,
    P6: DisplayHardwareLayer,
    P7: DisplayHardwareLayer,
{
    fn init(&self) {
// TODO maybe not needed because of pin state config
        self.data0.init();
        self.data1.init();
        self.data2.init();
        self.data3.init();
        self.data4.init();
        self.data5.init();
        self.data6.init();
        self.data7.init();
    }
}

/// Four data lines pin wiring setup.
pub struct DataPins4Lines<P4, P5, P6, P7>
where
    P4: DisplayHardwareLayer,
    P5: DisplayHardwareLayer,
    P6: DisplayHardwareLayer,
    P7: DisplayHardwareLayer,
{
    pub data4: P4,
    pub data5: P5,
    pub data6: P6,
    pub data7: P7,
}

impl<P4, P5, P6, P7> Init for DataPins4Lines<P4, P5, P6, P7>
where
    P4: DisplayHardwareLayer,
    P5: DisplayHardwareLayer,
    P6: DisplayHardwareLayer,
    P7: DisplayHardwareLayer,
{
    fn init(&self) {
        self.data4.init();
        self.data5.init();
        self.data6.init();
        self.data7.init();
    }
}

impl<RS, R, E, T, P4, P5, P6, P7> SendRaw
    for ParallelConnection<RS, R, E, DataPins4Lines<P4, P5, P6, P7>, T>
where
    E: DisplayHardwareLayer,
    T: Delay,
    P4: DisplayHardwareLayer,
    P5: DisplayHardwareLayer,
    P6: DisplayHardwareLayer,
    P7: DisplayHardwareLayer,
{
    fn send_byte(&self, byte: u8) {
        self.data.data4.set_direction(Direction::Out);
        self.data.data5.set_direction(Direction::Out);
        self.data.data6.set_direction(Direction::Out);
        self.data.data7.set_direction(Direction::Out);

        write_4bit(self, Nibble::Upper(byte));
        write_4bit(self, Nibble::Lower(byte));
    }
}

fn write_4bit<RS, R, E, T, P4, P5, P6, P7>(
    pins: &ParallelConnection<RS, R, E, DataPins4Lines<P4, P5, P6, P7>, T>,
    nibble: Nibble,
) where
    E: DisplayHardwareLayer,
    T: Delay,
    P4: DisplayHardwareLayer,
    P5: DisplayHardwareLayer,
    P6: DisplayHardwareLayer,
    P7: DisplayHardwareLayer,
{
    let value: u8 = nibble.into();

    T::delay_ns(T::ADDRESS_SETUP_TIME);
    pins.enable.set_level(Level::High);

    if value & 0x01 == 0x01 {
        pins.data.data4.set_level(Level::High);
    } else {
        pins.data.data4.set_level(Level::Low);
    }

    if value & 0x02 == 0x02 {
        pins.data.data5.set_level(Level::High);
    } else {
        pins.data.data5.set_level(Level::Low);
    }

    if value & 0x04 == 0x04 {
        pins.data.data6.set_level(Level::High);
    } else {
        pins.data.data6.set_level(Level::Low);
    }

    if value & 0x08 == 0x08 {
        pins.data.data7.set_level(Level::High);
    } else {
        pins.data.data7.set_level(Level::Low);
    }

    T::delay_ns(T::ENABLE_PULSE_WIDTH);
    pins.enable.set_level(Level::Low);
    T::delay_ns(T::DATA_HOLD_TIME);
}

impl<RS, R, E, T, P4, P5, P6, P7> ReceiveRaw
    for ParallelConnection<RS, R, E, DataPins4Lines<P4, P5, P6, P7>, T>
where
    E: DisplayHardwareLayer,
    T: Delay,
    P4: DisplayHardwareLayer,
    P5: DisplayHardwareLayer,
    P6: DisplayHardwareLayer,
    P7: DisplayHardwareLayer,
{
    fn receive_byte(&self) -> u8 {
        self.data.data4.set_direction(Direction::In);
        self.data.data5.set_direction(Direction::In);
        self.data.data6.set_direction(Direction::In);
        self.data.data7.set_direction(Direction::In);

        let upper = read_single_nibble(self);
        let lower = read_single_nibble(self);

        let mut result = upper << 4;
        result |= lower & 0x0f;

        result
    }
}

fn read_single_nibble<RS, R, E, T, P4, P5, P6, P7>(
    pins: &ParallelConnection<RS, R, E, DataPins4Lines<P4, P5, P6, P7>, T>,
) -> u8
where
    E: DisplayHardwareLayer,
    T: Delay,
    P4: DisplayHardwareLayer,
    P5: DisplayHardwareLayer,
    P6: DisplayHardwareLayer,
    P7: DisplayHardwareLayer,
{
    let mut result = 0u8;

    T::delay_ns(T::ADDRESS_SETUP_TIME);
    pins.enable.set_level(Level::High);

    result |= pins.data.data7.get_value() << 3;
    result |= pins.data.data6.get_value() << 2;
    result |= pins.data.data5.get_value() << 1;
    result |= pins.data.data4.get_value();

    T::delay_ns(T::ENABLE_PULSE_WIDTH);
    pins.enable.set_level(Level::Low);
    T::delay_ns(T::DATA_HOLD_TIME);

    result
}
<commit_msg>Fix doc rendering warnings<commit_after>use core::marker::PhantomData;

/// Enumeration possible write operations.
#[derive(Debug, PartialEq)]
pub enum WriteMode {
    Command(u8),
    Data(u8),
}

/// Enumeration possible read operations.
pub enum ReadMode {
    Data,
    BusyFlag,
}

/// Enumeration of possible data directions of a pin.
#[derive(Debug, PartialEq)]
pub enum Direction {
    In,
    Out,
}

/// Enumeration of possible levels of a pin.
#[derive(Debug, PartialEq)]
pub enum Level {
    Low,
    High,
}

impl From<WriteMode> for (Level, u8) {
    fn from(mode: WriteMode) -> Self {
        match mode {
            WriteMode::Command(value) => (Level::Low, value),
            WriteMode::Data(value) => (Level::High, value),
        }
    }
}

enum Nibble {
    Upper(u8),
    Lower(u8),
}

impl From<Nibble> for u8 {
    fn from(n: Nibble) -> Self {
        match n {
            Nibble::Upper(base) => base >> 4,
            Nibble::Lower(base) => base & 0x0f,
        }
    }
}

/// This trait is used to provide an initialization implementation for a [`Display`] connection.
///
/// [`Display`]: struct.Display.html
pub trait Init {
    /// Initializes the connection.
    fn init(&self);
}

/// This trait is used to provide an implementation for sending data via a [`Display`] connection.
///
/// [`Display`]: struct.Display.html
pub trait Send {
    /// Sends data via the connection.
    fn send(&self, mode: WriteMode);
}

/// This trait is used to provide an implementation for receiving data via a [`Display`] connection.
///
/// [`Display`]: struct.Display.html
pub trait Receive {
    fn receive(&self, mode: ReadMode) -> u8;
}

pub trait SendRaw {
    fn send_byte(&self, byte: u8);
}

pub trait ReceiveRaw {
    fn receive_byte(&self) -> u8;
}

/// The `DisplayHardwareLayer` trait is intended to be implemented by the library user as a thin
/// wrapper around the hardware specific system calls.
pub trait DisplayHardwareLayer {
    /// Initializes an I/O pin.
    fn init(&self) {}
    /// Cleanup an I/O pin.
    fn cleanup(&self) {}

    fn set_direction(&self, Direction);
    /// Sets a value on an I/O pin.
    fn set_level(&self, Level);

    fn get_value(&self) -> u8;
}

/// The `Delay` trait is used to adapt the timing to the specific hardware and must be implemented
/// by the libary user.
pub trait Delay {
    /// The time (ns) between register select (RS) and read/write (R/W) to enable signal (E).
    const ADDRESS_SETUP_TIME: u16 = 60;
    /// The duration (ns) the enable signal is set to `High`.
    const ENABLE_PULSE_WIDTH: u16 = 450;
    /// The duration (ns) the data pins will be set after the enable signal was dropped.
    const DATA_HOLD_TIME: u16 = 20;

    /// The maximum execution time of instruction commands.
    const COMMAND_EXECUTION_TIME: u16 = 37;

    /// Wait for the given amount of nanoseconds.
    fn delay_ns(ns: u16);

    /// Wait for the given amount of microseconds.
    fn delay_us(us: u16) {
        for _ in 0..us {
            Self::delay_ns(1000);
        }
    }
}

/// This struct is used for easily setting up [`ParallelConnection`]s.
///
/// [`ParallelConnection`]: struct.ParallelConnection.html
pub struct Pins<RS, R, E, D> {
    pub register_select: RS,
    pub read: R,
    pub enable: E,
    pub data: D,
}

impl<RS, R, E, D> Pins<RS, R, E, D> {
    /// Converts the pin setup into a [`ParallelConnection`] that is by `Display` to communicate
    /// with the LCD device.
    ///
    /// [`ParallelConnection`]: struct.ParallelConnection.html
    pub fn into_connection<T>(self) -> ParallelConnection<RS, R, E, D, T> {
        ParallelConnection {
            register_select: self.register_select,
            read: self.read,
            enable: self.enable,
            data: self.data,
            _delay_marker: PhantomData,
        }
    }
}

/// The parallel connection mode is the most common wiring mode for HD44780 compliant displays.
/// It can be used with either four ([`DataPins4Lines`]) or eight ([`DataPins8Lines`]) data lines.
///
/// [`DataPins4Lines`]: struct.DataPins4Lines.html
/// [`DataPins8Lines`]: struct.DataPins8Lines.html
pub struct ParallelConnection<RS, R, E, D, T> {
    register_select: RS,
    read: R,
    enable: E,
    data: D,
    _delay_marker: PhantomData<T>,
}

impl<RS, R, E, D, T> Init for ParallelConnection<RS, R, E, D, T>
where
    RS: DisplayHardwareLayer,
    R: DisplayHardwareLayer,
    E: DisplayHardwareLayer,
    D: Init,
    T: Delay,
{
    fn init(&self) {
        self.register_select.init();
        self.register_select.set_direction(Direction::Out);

        self.read.init();
        self.read.set_direction(Direction::Out);

        self.enable.init();
        self.enable.set_direction(Direction::Out);

        self.data.init();
    }
}

impl<RS, R, E, D, T> Send for ParallelConnection<RS, R, E, D, T>
where
    Self: SendRaw,
    RS: DisplayHardwareLayer,
    R: DisplayHardwareLayer,
{
    fn send(&self, mode: WriteMode) {
        self.read.set_level(Level::Low);

        let (level, value) = mode.into();
        self.register_select.set_level(level);

        self.send_byte(value);
    }
}

impl<RS, R, E, D, T> Receive for ParallelConnection<RS, R, E, D, T>
where
    Self: ReceiveRaw,
    RS: DisplayHardwareLayer,
    R: DisplayHardwareLayer,
{
    fn receive(&self, mode: ReadMode) -> u8 {
        self.read.set_level(Level::High);

        match mode {
            ReadMode::Data => self.register_select.set_level(Level::High),
            ReadMode::BusyFlag => self.register_select.set_level(Level::Low),
        };

        self.receive_byte()
    }
}

// FIXME: WARNING - dummy implementation, not tested
impl<RS, R, E, T, P0, P1, P2, P3, P4, P5, P6, P7> SendRaw
    for ParallelConnection<RS, R, E, DataPins8Lines<P0, P1, P2, P3, P4, P5, P6, P7>, T>
where
    E: DisplayHardwareLayer,
    T: Delay,
    P0: DisplayHardwareLayer,
    P0: DisplayHardwareLayer,
    P1: DisplayHardwareLayer,
    P2: DisplayHardwareLayer,
    P3: DisplayHardwareLayer,
    P4: DisplayHardwareLayer,
    P5: DisplayHardwareLayer,
    P6: DisplayHardwareLayer,
    P7: DisplayHardwareLayer,
{
    fn send_byte(&self, byte: u8) {
        T::delay_ns(T::ADDRESS_SETUP_TIME);
        self.enable.set_level(Level::High);

        self.data.data0.set_level(get_bit(byte, 0b0000_0001));
        self.data.data1.set_level(get_bit(byte, 0b0000_0010));
        self.data.data2.set_level(get_bit(byte, 0b0000_0100));
        self.data.data3.set_level(get_bit(byte, 0b0000_1000));
        self.data.data4.set_level(get_bit(byte, 0b0001_0000));
        self.data.data5.set_level(get_bit(byte, 0b0010_0000));
        self.data.data6.set_level(get_bit(byte, 0b0100_0000));
        self.data.data7.set_level(get_bit(byte, 0b1000_0000));

        T::delay_ns(T::ENABLE_PULSE_WIDTH);
        self.enable.set_level(Level::Low);
        T::delay_ns(T::DATA_HOLD_TIME);
    }
}

fn get_bit(val: u8, bit: u8) -> Level {
    if val & bit == bit {
        Level::High
    } else {
        Level::Low
    }
}

/// Eight data lines pin wiring setup.
pub struct DataPins8Lines<P0, P1, P2, P3, P4, P5, P6, P7>
where
    P0: DisplayHardwareLayer,
    P1: DisplayHardwareLayer,
    P2: DisplayHardwareLayer,
    P3: DisplayHardwareLayer,
    P4: DisplayHardwareLayer,
    P5: DisplayHardwareLayer,
    P6: DisplayHardwareLayer,
    P7: DisplayHardwareLayer,
{
    pub data0: P0,
    pub data1: P1,
    pub data2: P2,
    pub data3: P3,
    pub data4: P4,
    pub data5: P5,
    pub data6: P6,
    pub data7: P7,
}

impl<P0, P1, P2, P3, P4, P5, P6, P7> Init for DataPins8Lines<P0, P1, P2, P3, P4, P5, P6, P7>
where
    P0: DisplayHardwareLayer,
    P0: DisplayHardwareLayer,
    P1: DisplayHardwareLayer,
    P2: DisplayHardwareLayer,
    P3: DisplayHardwareLayer,
    P4: DisplayHardwareLayer,
    P5: DisplayHardwareLayer,
    P6: DisplayHardwareLayer,
    P7: DisplayHardwareLayer,
{
    fn init(&self) {
        // TODO maybe not needed because of pin state config
        self.data0.init();
        self.data1.init();
        self.data2.init();
        self.data3.init();
        self.data4.init();
        self.data5.init();
        self.data6.init();
        self.data7.init();
    }
}

/// Four data lines pin wiring setup.
pub struct DataPins4Lines<P4, P5, P6, P7>
where
    P4: DisplayHardwareLayer,
    P5: DisplayHardwareLayer,
    P6: DisplayHardwareLayer,
    P7: DisplayHardwareLayer,
{
    pub data4: P4,
    pub data5: P5,
    pub data6: P6,
    pub data7: P7,
}

impl<P4, P5, P6, P7> Init for DataPins4Lines<P4, P5, P6, P7>
where
    P4: DisplayHardwareLayer,
    P5: DisplayHardwareLayer,
    P6: DisplayHardwareLayer,
    P7: DisplayHardwareLayer,
{
    fn init(&self) {
        self.data4.init();
        self.data5.init();
        self.data6.init();
        self.data7.init();
    }
}

impl<RS, R, E, T, P4, P5, P6, P7> SendRaw
    for ParallelConnection<RS, R, E, DataPins4Lines<P4, P5, P6, P7>, T>
where
    E: DisplayHardwareLayer,
    T: Delay,
    P4: DisplayHardwareLayer,
    P5: DisplayHardwareLayer,
    P6: DisplayHardwareLayer,
    P7: DisplayHardwareLayer,
{
    fn send_byte(&self, byte: u8) {
        self.data.data4.set_direction(Direction::Out);
        self.data.data5.set_direction(Direction::Out);
        self.data.data6.set_direction(Direction::Out);
        self.data.data7.set_direction(Direction::Out);

        write_4bit(self, Nibble::Upper(byte));
        write_4bit(self, Nibble::Lower(byte));
    }
}

fn write_4bit<RS, R, E, T, P4, P5, P6, P7>(
    pins: &ParallelConnection<RS, R, E, DataPins4Lines<P4, P5, P6, P7>, T>,
    nibble: Nibble,
) where
    E: DisplayHardwareLayer,
    T: Delay,
    P4: DisplayHardwareLayer,
    P5: DisplayHardwareLayer,
    P6: DisplayHardwareLayer,
    P7: DisplayHardwareLayer,
{
    let value: u8 = nibble.into();

    T::delay_ns(T::ADDRESS_SETUP_TIME);
    pins.enable.set_level(Level::High);

    if value & 0x01 == 0x01 {
        pins.data.data4.set_level(Level::High);
    } else {
        pins.data.data4.set_level(Level::Low);
    }

    if value & 0x02 == 0x02 {
        pins.data.data5.set_level(Level::High);
    } else {
        pins.data.data5.set_level(Level::Low);
    }

    if value & 0x04 == 0x04 {
        pins.data.data6.set_level(Level::High);
    } else {
        pins.data.data6.set_level(Level::Low);
    }

    if value & 0x08 == 0x08 {
        pins.data.data7.set_level(Level::High);
    } else {
        pins.data.data7.set_level(Level::Low);
    }

    T::delay_ns(T::ENABLE_PULSE_WIDTH);
    pins.enable.set_level(Level::Low);
    T::delay_ns(T::DATA_HOLD_TIME);
}

impl<RS, R, E, T, P4, P5, P6, P7> ReceiveRaw
    for ParallelConnection<RS, R, E, DataPins4Lines<P4, P5, P6, P7>, T>
where
    E: DisplayHardwareLayer,
    T: Delay,
    P4: DisplayHardwareLayer,
    P5: DisplayHardwareLayer,
    P6: DisplayHardwareLayer,
    P7: DisplayHardwareLayer,
{
    fn receive_byte(&self) -> u8 {
        self.data.data4.set_direction(Direction::In);
        self.data.data5.set_direction(Direction::In);
        self.data.data6.set_direction(Direction::In);
        self.data.data7.set_direction(Direction::In);

        let upper = read_single_nibble(self);
        let lower = read_single_nibble(self);

        let mut result = upper << 4;
        result |= lower & 0x0f;

        result
    }
}

fn read_single_nibble<RS, R, E, T, P4, P5, P6, P7>(
    pins: &ParallelConnection<RS, R, E, DataPins4Lines<P4, P5, P6, P7>, T>,
) -> u8
where
    E: DisplayHardwareLayer,
    T: Delay,
    P4: DisplayHardwareLayer,
    P5: DisplayHardwareLayer,
    P6: DisplayHardwareLayer,
    P7: DisplayHardwareLayer,
{
    let mut result = 0u8;

    T::delay_ns(T::ADDRESS_SETUP_TIME);
    pins.enable.set_level(Level::High);

    result |= pins.data.data7.get_value() << 3;
    result |= pins.data.data6.get_value() << 2;
    result |= pins.data.data5.get_value() << 1;
    result |= pins.data.data4.get_value();

    T::delay_ns(T::ENABLE_PULSE_WIDTH);
    pins.enable.set_level(Level::Low);
    T::delay_ns(T::DATA_HOLD_TIME);

    result
}
<|endoftext|>


<commit_before>//!
//! This module defines a manager for holding multiple instances of mock servers.
//!

use crate::mock_server::MockServer;

use pact_matching::models::Pact;
use std::collections::BTreeMap;

struct ServerEntry {
    mock_server: Box<MockServer>,
    join_handle: tokio::task::JoinHandle<()>,
}

/// Struct to represent many mock servers running in a background thread
pub struct ServerManager {
    runtime: tokio::runtime::Runtime,
    mock_servers: BTreeMap<String, ServerEntry>,
}

impl ServerManager {
    /// Construct a new ServerManager for scheduling several instances of mock servers
    /// on one tokio runtime.
    pub fn new() -> ServerManager {
        ServerManager {
            runtime: tokio::runtime::Builder::new()
                .threaded_scheduler()
                .core_threads(1)
                .enable_all()
                .build()
                .unwrap(),
            mock_servers: BTreeMap::new(),
        }
    }

    /// Start a new server on the runtime
    pub fn start_mock_server_with_addr(
        &mut self,
        id: String,
        pact: Pact,
        addr: std::net::SocketAddr,
    ) -> Result<std::net::SocketAddr, String> {
        let (mock_server, future) =
            self.runtime
                .block_on(MockServer::new(id.clone(), pact, addr))?;

        let addr = mock_server.addr;

        self.mock_servers.insert(
            id,
            ServerEntry {
                mock_server: Box::new(mock_server),
                join_handle: self.runtime.spawn(future),
            },
        );
        Ok(addr)
    }

    /// Start a new server on the runtime
    pub fn start_mock_server(&mut self, id: String, pact: Pact, port: u16) -> Result<u16, String> {
        self.start_mock_server_with_addr(id, pact, ([0, 0, 0, 0], port as u16).into())
            .map(|addr| addr.port())
    }

    /// Shut down a server by its id
    pub fn shutdown_mock_server_by_id(&mut self, id: String) -> bool {
        match self.mock_servers.remove(&id) {
            Some(mut entry) => match entry.mock_server.shutdown() {
                Ok(()) => {
                    self.runtime.block_on(entry.join_handle).unwrap();
                    true
                }
                Err(_) => false,
            },
            None => false,
        }
    }

    /// Shut down a server by its local port number
    pub fn shutdown_mock_server_by_port(&mut self, port: u16) -> bool {
        log::debug!("Shutting down mock server with port {}", port);
        let result = self
            .mock_servers
            .iter()
            .find(|(_id, entry)| entry.mock_server.addr.port() == port)
            .map(|(_id, entry)| entry.mock_server.id.clone());

        if let Some(id) = result {
            if let Some(mut entry) = self.mock_servers.remove(&id) {
                return match entry.mock_server.shutdown() {
                    Ok(()) => {
                        self.runtime.block_on(entry.join_handle).unwrap();
                        true
                    }
                    Err(_) => false,
                };
            }
        }

        false
    }

    /// Find mock server by id, and map it using supplied function if found
    pub fn find_mock_server_by_id<R>(
        &self,
        id: &String,
        f: &dyn Fn(&MockServer) -> R,
    ) -> Option<R> {
        match self.mock_servers.get(id) {
            Some(entry) => Some(f(&entry.mock_server)),
            None => None,
        }
    }

    /// Find a mock server by port number and apply a mutating operation on it if successful
    pub fn find_mock_server_by_port_mut<R>(
        &mut self,
        mock_server_port: u16,
        f: &dyn Fn(&mut MockServer) -> R,
    ) -> Option<R> {
        match self
            .mock_servers
            .iter_mut()
            .find(|(_id, entry)| entry.mock_server.addr.port() == mock_server_port)
        {
            Some((_id, entry)) => Some(f(&mut entry.mock_server)),
            None => None,
        }
    }

    /// Map all the running mock servers
    pub fn map_mock_servers<R>(&self, f: &dyn Fn(&MockServer) -> R) -> Vec<R> {
        let mut results = vec![];
        for (_id_, entry) in self.mock_servers.iter() {
            results.push(f(&entry.mock_server));
        }
        return results;
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::net::TcpStream;

    #[test]
    fn manager_should_start_and_shutdown_mock_server() {
        let mut manager = ServerManager::new();
        let start_result = manager.start_mock_server("foobar".into(), Pact::default(), 0);

        assert!(start_result.is_ok());
        let server_port = start_result.unwrap();

        // Server should be up
        assert!(TcpStream::connect(("127.0.0.1", server_port)).is_ok());

        // Should be able to read matches without blocking
        let matches =
            manager.find_mock_server_by_port_mut(server_port, &|mock_server| mock_server.matches());
        assert_eq!(matches, Some(vec![]));

        let stopped = manager.shutdown_mock_server_by_port(server_port);
        assert!(stopped);

        // The tokio runtime is now out of tasks
        drop(manager);

        // Server should be down
        assert!(TcpStream::connect(("127.0.0.1", server_port)).is_err());
    }
}
<commit_msg>chore: add a wait for test on Appveyor<commit_after>//!
//! This module defines a manager for holding multiple instances of mock servers.
//!

use crate::mock_server::MockServer;

use pact_matching::models::Pact;
use std::collections::BTreeMap;

struct ServerEntry {
    mock_server: Box<MockServer>,
    join_handle: tokio::task::JoinHandle<()>,
}

/// Struct to represent many mock servers running in a background thread
pub struct ServerManager {
    runtime: tokio::runtime::Runtime,
    mock_servers: BTreeMap<String, ServerEntry>,
}

impl ServerManager {
    /// Construct a new ServerManager for scheduling several instances of mock servers
    /// on one tokio runtime.
    pub fn new() -> ServerManager {
        ServerManager {
            runtime: tokio::runtime::Builder::new()
                .threaded_scheduler()
                .core_threads(1)
                .enable_all()
                .build()
                .unwrap(),
            mock_servers: BTreeMap::new(),
        }
    }

    /// Start a new server on the runtime
    pub fn start_mock_server_with_addr(
        &mut self,
        id: String,
        pact: Pact,
        addr: std::net::SocketAddr,
    ) -> Result<std::net::SocketAddr, String> {
        let (mock_server, future) =
            self.runtime
                .block_on(MockServer::new(id.clone(), pact, addr))?;

        let addr = mock_server.addr;

        self.mock_servers.insert(
            id,
            ServerEntry {
                mock_server: Box::new(mock_server),
                join_handle: self.runtime.spawn(future),
            },
        );
        Ok(addr)
    }

    /// Start a new server on the runtime
    pub fn start_mock_server(&mut self, id: String, pact: Pact, port: u16) -> Result<u16, String> {
        self.start_mock_server_with_addr(id, pact, ([0, 0, 0, 0], port as u16).into())
            .map(|addr| addr.port())
    }

    /// Shut down a server by its id
    pub fn shutdown_mock_server_by_id(&mut self, id: String) -> bool {
        match self.mock_servers.remove(&id) {
            Some(mut entry) => match entry.mock_server.shutdown() {
                Ok(()) => {
                    self.runtime.block_on(entry.join_handle).unwrap();
                    true
                }
                Err(_) => false,
            },
            None => false,
        }
    }

    /// Shut down a server by its local port number
    pub fn shutdown_mock_server_by_port(&mut self, port: u16) -> bool {
        log::debug!("Shutting down mock server with port {}", port);
        let result = self
            .mock_servers
            .iter()
            .find(|(_id, entry)| entry.mock_server.addr.port() == port)
            .map(|(_id, entry)| entry.mock_server.id.clone());

        if let Some(id) = result {
            if let Some(mut entry) = self.mock_servers.remove(&id) {
                return match entry.mock_server.shutdown() {
                    Ok(()) => {
                        self.runtime.block_on(entry.join_handle).unwrap();
                        true
                    }
                    Err(_) => false,
                };
            }
        }

        false
    }

    /// Find mock server by id, and map it using supplied function if found
    pub fn find_mock_server_by_id<R>(
        &self,
        id: &String,
        f: &dyn Fn(&MockServer) -> R,
    ) -> Option<R> {
        match self.mock_servers.get(id) {
            Some(entry) => Some(f(&entry.mock_server)),
            None => None,
        }
    }

    /// Find a mock server by port number and apply a mutating operation on it if successful
    pub fn find_mock_server_by_port_mut<R>(
        &mut self,
        mock_server_port: u16,
        f: &dyn Fn(&mut MockServer) -> R,
    ) -> Option<R> {
        match self
            .mock_servers
            .iter_mut()
            .find(|(_id, entry)| entry.mock_server.addr.port() == mock_server_port)
        {
            Some((_id, entry)) => Some(f(&mut entry.mock_server)),
            None => None,
        }
    }

    /// Map all the running mock servers
    pub fn map_mock_servers<R>(&self, f: &dyn Fn(&MockServer) -> R) -> Vec<R> {
        let mut results = vec![];
        for (_id_, entry) in self.mock_servers.iter() {
            results.push(f(&entry.mock_server));
        }
        return results;
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::net::TcpStream;
    use std::{thread, time};

    #[test]
    fn manager_should_start_and_shutdown_mock_server() {
        let mut manager = ServerManager::new();
        let start_result = manager.start_mock_server("foobar".into(), Pact::default(), 0);

        assert!(start_result.is_ok());
        let server_port = start_result.unwrap();

        // Server should be up
        assert!(TcpStream::connect(("127.0.0.1", server_port)).is_ok());

        // Should be able to read matches without blocking
        let matches =
            manager.find_mock_server_by_port_mut(server_port, &|mock_server| mock_server.matches());
        assert_eq!(matches, Some(vec![]));

        let stopped = manager.shutdown_mock_server_by_port(server_port);
        assert!(stopped);

        // The tokio runtime is now out of tasks
        drop(manager);

        let ten_millis = time::Duration::from_millis(10);
        thread::sleep(ten_millis);

        // Server should be down
        assert!(TcpStream::connect(("127.0.0.1", server_port)).is_err());
    }
}
<|endoftext|>