<commit_before>//! Data types and utility function for units:
//! Implement a poor man's unit type system for now...
//!
//! Maybe we can have s.th. like this (F#) for Rust: https://en.wikibooks.org/wiki/F_Sharp_Programming/Units_of_Measure
//! Alternatively, see here:
//! https://www.reddit.com/r/rust/comments/37qut9/typesafe_userdefined_units_of_measure_for_rust/
//! https://blog.mozilla.org/research/2014/06/23/static-checking-of-units-in-servo/

use std::ops::Add;
use std::ops::Sub;
use std::ops::Mul;
use std::ops::Div;
use std::cmp::PartialEq;

macro_rules! init_unit {
    ($unit:ident) => {
        #[derive(Debug,Clone,Copy)]
        pub struct $unit(pub f64);

        impl PartialEq for $unit {
            fn eq(self: &$unit, &$unit(rhs): &$unit) -> bool {
                let $unit(lhs) = *self;
                lhs == rhs
            }
        }

        impl Add for $unit {
            type Output = $unit;

            fn add(self: $unit, $unit(rhs): $unit) -> $unit {
                let $unit(lhs) = self;
                $unit(lhs + rhs)
            }
        }

        impl Sub for $unit {
            type Output = $unit;

            fn sub(self: $unit, $unit(rhs): $unit) -> $unit {
                let $unit(lhs) = self;
                $unit(lhs - rhs)
            }
        }

        impl Mul<f64> for $unit {
            type Output = $unit;

            fn mul(self: $unit, rhs: f64) -> $unit {
                let $unit(lhs) = self;
                $unit(lhs * rhs)
            }
        }

        impl Mul<$unit> for f64 {
            type Output = $unit;

            fn mul(self: f64, $unit(rhs): $unit) -> $unit {
                $unit(self * rhs)
            }
        }

        impl Div<f64> for $unit {
            type Output = $unit;

            fn div(self: $unit, rhs: f64) -> $unit {
                let $unit(lhs) = self;
                $unit(lhs / rhs)
            }
        }

        impl Div<$unit> for $unit {
            type Output = f64;

            fn div(self: $unit, $unit(rhs): $unit) -> f64 {
                let $unit(lhs) = self;
                lhs / rhs
            }
        }
    }
}

macro_rules! mul_div_unit {
    // $unit1 * $unit2 = $unit3
    // $unit2 * $unit1 = $unit3
    // $unit1 = $unit3 / $unit2
    // $unit2 = $unit3 / $unit1
    ($unit1:ident, $unit2:ident, $unit3:ident) => {
        impl Mul<$unit2> for $unit1 {
            type Output = $unit3;

            fn mul(self: $unit1, $unit2(rhs): $unit2) -> $unit3 {
                let $unit1(lhs) = self;
                $unit3(lhs * rhs)
            }
        }

        impl Mul<$unit1> for $unit2 {
            type Output = $unit3;

            fn mul(self: $unit2, $unit1(rhs): $unit1) -> $unit3 {
                let $unit2(lhs) = self;
                $unit3(lhs * rhs)
            }
        }

        impl Div<$unit2> for $unit3 {
            type Output = $unit1;

            fn div(self: $unit3, $unit2(rhs): $unit2) -> $unit1 {
                let $unit3(lhs) = self;
                $unit1(lhs / rhs)
            }
        }

        impl Div<$unit1> for $unit3 {
            type Output = $unit2;

            fn div(self: $unit3, $unit1(rhs): $unit1) -> $unit2 {
                let $unit3(lhs) = self;
                $unit2(lhs / rhs)
            }
        }
    };

    // $unit1 * $unit1 = $unit2
    // $unit1 = $unit2 / $unit1
    ($unit1:ident, $unit2:ident) => {
        impl Mul<$unit1> for $unit1 {
            type Output = $unit2;

            fn mul(self: $unit1, $unit1(rhs): $unit1) -> $unit2 {
                let $unit1(lhs) = self;
                $unit2(lhs * rhs)
            }
        }

        impl Div<$unit1> for $unit2 {
            type Output = $unit1;

            fn div(self: $unit2, $unit1(rhs): $unit1) -> $unit1 {
                let $unit2(lhs) = self;
                $unit1(lhs / rhs)
            }
        }
    }
}

macro_rules! inverse_unit {
    ($unit1:ident, $unit2:ident) => {
        // A * B = 1
        impl Mul<$unit2> for $unit1 {
            type Output = f64;

            fn mul(self: $unit1, $unit2(rhs): $unit2) -> f64 {
                let $unit1(lhs) = self;
                lhs * rhs
            }
        }

        // B * A = 1
        impl Mul<$unit1> for $unit2 {
            type Output = f64;

            fn mul(self: $unit2, $unit1(rhs): $unit1) -> f64 {
                let $unit2(lhs) = self;
                lhs * rhs
            }
        }

        // 1 / A = B
        impl Div<$unit1> for f64 {
            type Output = $unit2;

            fn div(self: f64, $unit1(rhs): $unit1) -> $unit2 {
                $unit2(self / rhs)
            }
        }

        // 1 / B = A
        impl Div<$unit2> for f64 {
            type Output = $unit1;

            fn div(self: f64, $unit2(rhs): $unit2) -> $unit1 {
                $unit1(self / rhs)
            }
        }
    }
}

macro_rules! init_unit_and_inverse {
    ($unit1:ident, $per_unit1:ident) => {
        init_unit!($unit1);
        init_unit!($per_unit1);
        inverse_unit!($unit1, $per_unit1);
    }
}

macro_rules! power3_unit {
    ($unit1:ident, $unit2:ident, $unit3:ident, $per_unit1:ident, $per_unit2:ident, $per_unit3:ident) => {
        mul_div_unit!($unit1, $unit2);
        mul_div_unit!($unit1, $unit2, $unit3);

        mul_div_unit!($per_unit1, $per_unit2);
        mul_div_unit!($per_unit1, $per_unit2, $per_unit3);

        mul_div_unit!($unit1, $per_unit2, $per_unit1);
        mul_div_unit!($unit1, $per_unit3, $per_unit2);

        mul_div_unit!($unit2, $per_unit1, $unit1);
        mul_div_unit!($unit2, $per_unit3, $per_unit1);

        mul_div_unit!($unit3, $per_unit1, $unit2);
        mul_div_unit!($unit3, $per_unit2, $unit1);
    }
}

macro_rules! combine_unit {
    ($unit1:ident, $per_unit1:ident, $unit2:ident, $per_unit2:ident, $unit1_unit2:ident, $unit1_per_unit2:ident, $unit2_per_unit1:ident, $per_unit1_unit2:ident) => {
        mul_div_unit!($unit1, $unit2, $unit1_unit2);
        mul_div_unit!($unit1, $per_unit2, $unit1_per_unit2);

        mul_div_unit!($unit1_per_unit2, $unit2, $unit1);
        mul_div_unit!($unit1_per_unit2, $per_unit1, $per_unit2);

        mul_div_unit!($unit2_per_unit1, $unit1, $unit2);
        mul_div_unit!($unit2_per_unit1, $per_unit2, $per_unit1);

        mul_div_unit!($unit2, $per_unit1, $unit2_per_unit1);
        mul_div_unit!($per_unit1, $per_unit2, $per_unit1_unit2);

        mul_div_unit!($unit1_unit2, $per_unit1, $unit2);
        mul_div_unit!($unit1_unit2, $per_unit2, $unit1);

        mul_div_unit!($per_unit1_unit2, $unit1, $per_unit2);
        mul_div_unit!($per_unit1_unit2, $unit2, $per_unit1);
    }
}

init_unit_and_inverse!(Meter, PerMeter);
init_unit_and_inverse!(Meter2, PerMeter2);
init_unit_and_inverse!(Meter3, PerMeter3);
power3_unit!(Meter, Meter2, Meter3, PerMeter, PerMeter2, PerMeter3);

init_unit_and_inverse!(Second, PerSecond);
init_unit_and_inverse!(Second2, PerSecond2);
init_unit_and_inverse!(Second3, PerSecond3);
power3_unit!(Second, Second2, Second3, PerSecond, PerSecond2, PerSecond3);

init_unit_and_inverse!(MeterPerSecond, SecondPerMeter);
init_unit_and_inverse!(MeterPerSecond2, Second2PerMeter);
init_unit_and_inverse!(Meter2PerSecond, SecondPerMeter2);
init_unit_and_inverse!(Meter2PerSecond2, Second2PerMeter2);
init_unit_and_inverse!(MeterSecond, PerMeterSecond);
init_unit_and_inverse!(Meter2Second, PerMeter2Second);
init_unit_and_inverse!(MeterSecond2, PerMeterSecond2);
init_unit_and_inverse!(Meter2Second2, PerMeter2Second2);

combine_unit!(Meter, PerMeter, Second, PerSecond, MeterSecond, MeterPerSecond, SecondPerMeter, PerMeterSecond);
combine_unit!(Meter2, PerMeter2, Second, PerSecond, Meter2Second, Meter2PerSecond, SecondPerMeter2, PerMeter2Second);
combine_unit!(Meter, PerMeter, Second2, PerSecond2, MeterSecond2, MeterPerSecond2, Second2PerMeter, PerMeterSecond2);
combine_unit!(Meter2, PerMeter2, Second2, PerSecond2, Meter2Second2, Meter2PerSecond2, Second2PerMeter2, PerMeter2Second2);

mul_div_unit!(PerSecond2, Meter2Second, Meter2PerSecond);

init_unit_and_inverse!(Kilogram, PerKilogram);

 // momentum, impulse
init_unit_and_inverse!(KilogramMeterPerSecond, SecondPerKilogramMeter);

mul_div_unit!(Kilogram, MeterPerSecond, KilogramMeterPerSecond);

init_unit_and_inverse!(Newton, PerNewton);

mul_div_unit!(Kilogram, MeterPerSecond2, Newton);
mul_div_unit!(Newton, Second, KilogramMeterPerSecond);

init_unit_and_inverse!(Pascal, PerPascal);

mul_div_unit!(Pascal, Meter2, Newton);

init_unit_and_inverse!(Joule, PerJoule);

mul_div_unit!(Joule, Meter, Newton);

init_unit_and_inverse!(Watt, PerWatt);

mul_div_unit!(Watt, Second, Joule);

init_unit_and_inverse!(DegC, PerDegC);

init_unit_and_inverse!(Kelvin, PerKelvin);

init_unit_and_inverse!(Kelvin2, PerKelvin2);

mul_div_unit!(Kelvin, Kelvin2);

init_unit_and_inverse!(KelvinPerSecond, SecondPerKelvin);

mul_div_unit!(KelvinPerSecond, Second, Kelvin);

init_unit_and_inverse!(DegCPerSecond, SecondPerDegC);

mul_div_unit!(DegCPerSecond, Second, DegC);

init_unit!(JouleDegCPerSecond);

mul_div_unit!(DegCPerSecond, Joule, JouleDegCPerSecond);

init_unit!(JouleKelvinPerSecond);

mul_div_unit!(KelvinPerSecond, Joule, JouleKelvinPerSecond);

init_unit_and_inverse!(Mol, PerMol);

init_unit_and_inverse!(JoulePerKelvin, KelvinPerJoule);

init_unit_and_inverse!(JoulePerMol, MolPerJoule);

init_unit_and_inverse!(JoulePerKelvinMol, KelvinMolPerJoule);

init_unit_and_inverse!(JouleKelvinPerMol, MolPerJouleKelvin);

mul_div_unit!(JoulePerKelvinMol, Kelvin2, JouleKelvinPerMol);

init_unit_and_inverse!(SecondPerMol, MolPerSecond);

init_unit_and_inverse!(JouleKelvinPerMolSecond, MolSecondPerJouleKelvin);

mul_div_unit!(SecondPerMol, JouleKelvinPerSecond, JouleKelvinPerMol);

mul_div_unit!(Mol, SecondPerMol, Second);

mul_div_unit!(Mol, JoulePerKelvinMol, JoulePerKelvin);

mul_div_unit!(Kelvin, JoulePerKelvin, Joule);

mul_div_unit!(JoulePerMol, KelvinPerSecond, JouleKelvinPerMolSecond);

mul_div_unit!(Kelvin,  JoulePerKelvinMol, JoulePerMol);

mul_div_unit!(Second, JouleKelvinPerMolSecond, JouleKelvinPerMol);

<commit_msg>add comments to macros<commit_after>//! Data types and utility function for units:
//! Implement a poor man's unit type system for now...
//!
//! Maybe we can have s.th. like this (F#) for Rust:
//!
//! https://en.wikibooks.org/wiki/F_Sharp_Programming/Units_of_Measure
//!
//! Alternatively, see here:
//!
//! https://www.reddit.com/r/rust/comments/37qut9/typesafe_userdefined_units_of_measure_for_rust/
//!
//! https://blog.mozilla.org/research/2014/06/23/static-checking-of-units-in-servo/

use std::ops::Add;
use std::ops::Sub;
use std::ops::Mul;
use std::ops::Div;
use std::cmp::PartialEq;

/// This macro initializes a new unit
macro_rules! init_unit {
    ($unit:ident) => {
        #[derive(Debug,Clone,Copy)]
        pub struct $unit(pub f64);

        impl PartialEq for $unit {
            fn eq(self: &$unit, &$unit(rhs): &$unit) -> bool {
                let $unit(lhs) = *self;
                lhs == rhs
            }
        }

        impl Add for $unit {
            type Output = $unit;

            fn add(self: $unit, $unit(rhs): $unit) -> $unit {
                let $unit(lhs) = self;
                $unit(lhs + rhs)
            }
        }

        impl Sub for $unit {
            type Output = $unit;

            fn sub(self: $unit, $unit(rhs): $unit) -> $unit {
                let $unit(lhs) = self;
                $unit(lhs - rhs)
            }
        }

        impl Mul<f64> for $unit {
            type Output = $unit;

            fn mul(self: $unit, rhs: f64) -> $unit {
                let $unit(lhs) = self;
                $unit(lhs * rhs)
            }
        }

        impl Mul<$unit> for f64 {
            type Output = $unit;

            fn mul(self: f64, $unit(rhs): $unit) -> $unit {
                $unit(self * rhs)
            }
        }

        impl Div<f64> for $unit {
            type Output = $unit;

            fn div(self: $unit, rhs: f64) -> $unit {
                let $unit(lhs) = self;
                $unit(lhs / rhs)
            }
        }

        impl Div<$unit> for $unit {
            type Output = f64;

            fn div(self: $unit, $unit(rhs): $unit) -> f64 {
                let $unit(lhs) = self;
                lhs / rhs
            }
        }
    }
}

/// This macro implements multiplication and division for a given unit
macro_rules! mul_div_unit {
    // $unit1 * $unit2 = $unit3
    // $unit2 * $unit1 = $unit3
    // $unit1 = $unit3 / $unit2
    // $unit2 = $unit3 / $unit1
    ($unit1:ident, $unit2:ident, $unit3:ident) => {
        impl Mul<$unit2> for $unit1 {
            type Output = $unit3;

            fn mul(self: $unit1, $unit2(rhs): $unit2) -> $unit3 {
                let $unit1(lhs) = self;
                $unit3(lhs * rhs)
            }
        }

        impl Mul<$unit1> for $unit2 {
            type Output = $unit3;

            fn mul(self: $unit2, $unit1(rhs): $unit1) -> $unit3 {
                let $unit2(lhs) = self;
                $unit3(lhs * rhs)
            }
        }

        impl Div<$unit2> for $unit3 {
            type Output = $unit1;

            fn div(self: $unit3, $unit2(rhs): $unit2) -> $unit1 {
                let $unit3(lhs) = self;
                $unit1(lhs / rhs)
            }
        }

        impl Div<$unit1> for $unit3 {
            type Output = $unit2;

            fn div(self: $unit3, $unit1(rhs): $unit1) -> $unit2 {
                let $unit3(lhs) = self;
                $unit2(lhs / rhs)
            }
        }
    };

    // $unit1 * $unit1 = $unit2
    // $unit1 = $unit2 / $unit1
    ($unit1:ident, $unit2:ident) => {
        impl Mul<$unit1> for $unit1 {
            type Output = $unit2;

            fn mul(self: $unit1, $unit1(rhs): $unit1) -> $unit2 {
                let $unit1(lhs) = self;
                $unit2(lhs * rhs)
            }
        }

        impl Div<$unit1> for $unit2 {
            type Output = $unit1;

            fn div(self: $unit2, $unit1(rhs): $unit1) -> $unit1 {
                let $unit2(lhs) = self;
                $unit1(lhs / rhs)
            }
        }
    }
}

/// This macro implements the inverse of the given unit
macro_rules! inverse_unit {
    ($unit1:ident, $unit2:ident) => {
        // A * B = 1
        impl Mul<$unit2> for $unit1 {
            type Output = f64;

            fn mul(self: $unit1, $unit2(rhs): $unit2) -> f64 {
                let $unit1(lhs) = self;
                lhs * rhs
            }
        }

        // B * A = 1
        impl Mul<$unit1> for $unit2 {
            type Output = f64;

            fn mul(self: $unit2, $unit1(rhs): $unit1) -> f64 {
                let $unit2(lhs) = self;
                lhs * rhs
            }
        }

        // 1 / A = B
        impl Div<$unit1> for f64 {
            type Output = $unit2;

            fn div(self: f64, $unit1(rhs): $unit1) -> $unit2 {
                $unit2(self / rhs)
            }
        }

        // 1 / B = A
        impl Div<$unit2> for f64 {
            type Output = $unit1;

            fn div(self: f64, $unit2(rhs): $unit2) -> $unit1 {
                $unit1(self / rhs)
            }
        }
    }
}

/// This macro implements a new unit and the inverse unit
macro_rules! init_unit_and_inverse {
    ($unit1:ident, $per_unit1:ident) => {
        init_unit!($unit1);
        init_unit!($per_unit1);
        inverse_unit!($unit1, $per_unit1);
    }
}

/// This macro implements unit^2, unit^3, 1/unit^2 and 1/unit^3
macro_rules! power3_unit {
    ($unit1:ident, $unit2:ident, $unit3:ident, $per_unit1:ident, $per_unit2:ident, $per_unit3:ident) => {
        mul_div_unit!($unit1, $unit2);
        mul_div_unit!($unit1, $unit2, $unit3);

        mul_div_unit!($per_unit1, $per_unit2);
        mul_div_unit!($per_unit1, $per_unit2, $per_unit3);

        mul_div_unit!($unit1, $per_unit2, $per_unit1);
        mul_div_unit!($unit1, $per_unit3, $per_unit2);

        mul_div_unit!($unit2, $per_unit1, $unit1);
        mul_div_unit!($unit2, $per_unit3, $per_unit1);

        mul_div_unit!($unit3, $per_unit1, $unit2);
        mul_div_unit!($unit3, $per_unit2, $unit1);
    }
}

/// This macro combines two units and some permutation / inverse
macro_rules! combine_unit {
    ($unit1:ident, $per_unit1:ident, $unit2:ident, $per_unit2:ident, $unit1_unit2:ident, $unit1_per_unit2:ident, $unit2_per_unit1:ident, $per_unit1_unit2:ident) => {
        mul_div_unit!($unit1, $unit2, $unit1_unit2);
        mul_div_unit!($unit1, $per_unit2, $unit1_per_unit2);

        mul_div_unit!($unit1_per_unit2, $unit2, $unit1);
        mul_div_unit!($unit1_per_unit2, $per_unit1, $per_unit2);

        mul_div_unit!($unit2_per_unit1, $unit1, $unit2);
        mul_div_unit!($unit2_per_unit1, $per_unit2, $per_unit1);

        mul_div_unit!($unit2, $per_unit1, $unit2_per_unit1);
        mul_div_unit!($per_unit1, $per_unit2, $per_unit1_unit2);

        mul_div_unit!($unit1_unit2, $per_unit1, $unit2);
        mul_div_unit!($unit1_unit2, $per_unit2, $unit1);

        mul_div_unit!($per_unit1_unit2, $unit1, $per_unit2);
        mul_div_unit!($per_unit1_unit2, $unit2, $per_unit1);
    }
}

init_unit_and_inverse!(Meter, PerMeter);
init_unit_and_inverse!(Meter2, PerMeter2);
init_unit_and_inverse!(Meter3, PerMeter3);
power3_unit!(Meter, Meter2, Meter3, PerMeter, PerMeter2, PerMeter3);

init_unit_and_inverse!(Second, PerSecond);
init_unit_and_inverse!(Second2, PerSecond2);
init_unit_and_inverse!(Second3, PerSecond3);
power3_unit!(Second, Second2, Second3, PerSecond, PerSecond2, PerSecond3);

init_unit_and_inverse!(MeterPerSecond, SecondPerMeter);
init_unit_and_inverse!(MeterPerSecond2, Second2PerMeter);
init_unit_and_inverse!(Meter2PerSecond, SecondPerMeter2);
init_unit_and_inverse!(Meter2PerSecond2, Second2PerMeter2);
init_unit_and_inverse!(MeterSecond, PerMeterSecond);
init_unit_and_inverse!(Meter2Second, PerMeter2Second);
init_unit_and_inverse!(MeterSecond2, PerMeterSecond2);
init_unit_and_inverse!(Meter2Second2, PerMeter2Second2);

combine_unit!(Meter, PerMeter, Second, PerSecond, MeterSecond, MeterPerSecond, SecondPerMeter, PerMeterSecond);
combine_unit!(Meter2, PerMeter2, Second, PerSecond, Meter2Second, Meter2PerSecond, SecondPerMeter2, PerMeter2Second);
combine_unit!(Meter, PerMeter, Second2, PerSecond2, MeterSecond2, MeterPerSecond2, Second2PerMeter, PerMeterSecond2);
combine_unit!(Meter2, PerMeter2, Second2, PerSecond2, Meter2Second2, Meter2PerSecond2, Second2PerMeter2, PerMeter2Second2);

mul_div_unit!(PerSecond2, Meter2Second, Meter2PerSecond);

init_unit_and_inverse!(Kilogram, PerKilogram);

 // momentum, impulse
init_unit_and_inverse!(KilogramMeterPerSecond, SecondPerKilogramMeter);

mul_div_unit!(Kilogram, MeterPerSecond, KilogramMeterPerSecond);

init_unit_and_inverse!(Newton, PerNewton);

mul_div_unit!(Kilogram, MeterPerSecond2, Newton);
mul_div_unit!(Newton, Second, KilogramMeterPerSecond);

init_unit_and_inverse!(Pascal, PerPascal);

mul_div_unit!(Pascal, Meter2, Newton);

init_unit_and_inverse!(Joule, PerJoule);

mul_div_unit!(Joule, Meter, Newton);

init_unit_and_inverse!(Watt, PerWatt);

mul_div_unit!(Watt, Second, Joule);

init_unit_and_inverse!(DegC, PerDegC);

init_unit_and_inverse!(Kelvin, PerKelvin);

init_unit_and_inverse!(Kelvin2, PerKelvin2);

mul_div_unit!(Kelvin, Kelvin2);

init_unit_and_inverse!(KelvinPerSecond, SecondPerKelvin);

mul_div_unit!(KelvinPerSecond, Second, Kelvin);

init_unit_and_inverse!(DegCPerSecond, SecondPerDegC);

mul_div_unit!(DegCPerSecond, Second, DegC);

init_unit!(JouleDegCPerSecond);

mul_div_unit!(DegCPerSecond, Joule, JouleDegCPerSecond);

init_unit!(JouleKelvinPerSecond);

mul_div_unit!(KelvinPerSecond, Joule, JouleKelvinPerSecond);

init_unit_and_inverse!(Mol, PerMol);

init_unit_and_inverse!(JoulePerKelvin, KelvinPerJoule);

init_unit_and_inverse!(JoulePerMol, MolPerJoule);

init_unit_and_inverse!(JoulePerKelvinMol, KelvinMolPerJoule);

init_unit_and_inverse!(JouleKelvinPerMol, MolPerJouleKelvin);

mul_div_unit!(JoulePerKelvinMol, Kelvin2, JouleKelvinPerMol);

init_unit_and_inverse!(SecondPerMol, MolPerSecond);

init_unit_and_inverse!(JouleKelvinPerMolSecond, MolSecondPerJouleKelvin);

mul_div_unit!(SecondPerMol, JouleKelvinPerSecond, JouleKelvinPerMol);

mul_div_unit!(Mol, SecondPerMol, Second);

mul_div_unit!(Mol, JoulePerKelvinMol, JoulePerKelvin);

mul_div_unit!(Kelvin, JoulePerKelvin, Joule);

mul_div_unit!(JoulePerMol, KelvinPerSecond, JouleKelvinPerMolSecond);

mul_div_unit!(Kelvin,  JoulePerKelvinMol, JoulePerMol);

mul_div_unit!(Second, JouleKelvinPerMolSecond, JouleKelvinPerMol);
<|endoftext|>


<commit_before>use {Errno, Error, Result, NixPath};
use fcntl::OFlag;
use libc::{self, c_void, size_t, off_t, mode_t};
use sys::stat::Mode;
use std::os::unix::io::RawFd;

pub use self::consts::*;

bitflags!{
    flags ProtFlags : libc::c_int {
        const PROT_NONE      = libc::PROT_NONE,
        const PROT_READ      = libc::PROT_READ,
        const PROT_WRITE     = libc::PROT_WRITE,
        const PROT_EXEC      = libc::PROT_EXEC,
        #[cfg(any(target_os = "linux", target_os = "android"))]
        const PROT_GROWSDOWN = libc::PROT_GROWSDOWN,
        #[cfg(any(target_os = "linux", target_os = "android"))]
        const PROT_GROWSUP   = libc::PROT_GROWSUP,
    }
}

#[cfg(any(target_os = "linux", target_os = "android"))]
mod consts {
    use libc::{self, c_int};

    bitflags!{
        flags MapFlags: c_int {
            const MAP_FILE       = libc::MAP_FILE,
            const MAP_SHARED     = libc::MAP_SHARED,
            const MAP_PRIVATE    = libc::MAP_PRIVATE,
            const MAP_FIXED      = libc::MAP_FIXED,
            const MAP_ANON       = libc::MAP_ANON,
            const MAP_ANONYMOUS  = libc::MAP_ANON,
            #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
            const MAP_32BIT      = libc::MAP_32BIT,
            const MAP_GROWSDOWN  = libc::MAP_GROWSDOWN,
            const MAP_DENYWRITE  = libc::MAP_DENYWRITE,
            const MAP_EXECUTABLE = libc::MAP_EXECUTABLE,
            const MAP_LOCKED     = libc::MAP_LOCKED,
            const MAP_NORESERVE  = libc::MAP_NORESERVE,
            const MAP_POPULATE   = libc::MAP_POPULATE,
            const MAP_NONBLOCK   = libc::MAP_NONBLOCK,
            const MAP_STACK      = libc::MAP_STACK,
            const MAP_HUGETLB    = libc::MAP_HUGETLB,
        }
    }

    pub type MmapAdvise = c_int;

    pub const MADV_NORMAL     : MmapAdvise  = 0; /* No further special treatment.  */
    pub const MADV_RANDOM     : MmapAdvise  = 1; /* Expect random page references.  */
    pub const MADV_SEQUENTIAL : MmapAdvise  = 2; /* Expect sequential page references.  */
    pub const MADV_WILLNEED   : MmapAdvise  = 3; /* Will need these pages.  */
    pub const MADV_DONTNEED   : MmapAdvise  = 4; /* Don't need these pages.  */
    pub const MADV_REMOVE     : MmapAdvise  = 9; /* Remove these pages and resources.  */
    pub const MADV_DONTFORK   : MmapAdvise  = 10; /* Do not inherit across fork.  */
    pub const MADV_DOFORK     : MmapAdvise  = 11; /* Do inherit across fork.  */
    pub const MADV_MERGEABLE  : MmapAdvise  = 12; /* KSM may merge identical pages.  */
    pub const MADV_UNMERGEABLE: MmapAdvise  = 13; /* KSM may not merge identical pages.  */
    pub const MADV_HUGEPAGE   : MmapAdvise  = 14; /* Worth backing with hugepages.  */
    pub const MADV_NOHUGEPAGE : MmapAdvise  = 15; /* Not worth backing with hugepages.  */
    pub const MADV_DONTDUMP   : MmapAdvise  = 16; /* Explicity exclude from the core dump, overrides the coredump filter bits.  */
    pub const MADV_DODUMP     : MmapAdvise  = 17; /* Clear the MADV_DONTDUMP flag.  */
    pub const MADV_HWPOISON   : MmapAdvise  = 100; /* Poison a page for testing.  */

    bitflags!{
        flags MsFlags: c_int {
            const MS_ASYNC      = libc::MS_ASYNC,
            const MS_INVALIDATE = libc::MS_INVALIDATE,
            const MS_SYNC       = libc::MS_SYNC,
        }
    }

    pub const MAP_FAILED: isize               = -1;
}

#[cfg(any(target_os = "macos",
          target_os = "ios"))]
mod consts {
    use libc::{self, c_int};

    bitflags!{
        flags MapFlags: c_int {
            const MAP_FILE    = libc::MAP_FILE,
            const MAP_SHARED  = libc::MAP_SHARED,
            const MAP_PRIVATE = libc::MAP_PRIVATE,
            const MAP_FIXED   = libc::MAP_FIXED,
            const MAP_ANON    = libc::MAP_ANON,
            const MAP_NOCACHE = libc::MAP_NOCACHE,
            const MAP_JIT     = libc::MAP_JIT,
        }
    }

    pub type MmapAdvise = c_int;

    pub const MADV_NORMAL     : MmapAdvise      = 0; /* No further special treatment.  */
    pub const MADV_RANDOM     : MmapAdvise      = 1; /* Expect random page references.  */
    pub const MADV_SEQUENTIAL : MmapAdvise      = 2; /* Expect sequential page references.  */
    pub const MADV_WILLNEED   : MmapAdvise      = 3; /* Will need these pages.  */
    pub const MADV_DONTNEED   : MmapAdvise      = 4; /* Don't need these pages.  */
    pub const MADV_FREE       : MmapAdvise      = 5; /* pages unneeded, discard contents */
    pub const MADV_ZERO_WIRED_PAGES: MmapAdvise = 6; /* zero the wired pages that have not been unwired before the entry is deleted */
    pub const MADV_FREE_REUSABLE : MmapAdvise   = 7; /* pages can be reused (by anyone) */
    pub const MADV_FREE_REUSE : MmapAdvise      = 8; /* caller wants to reuse those pages */
    pub const MADV_CAN_REUSE : MmapAdvise       = 9;

    bitflags!{
        flags MsFlags: c_int {
            const MS_ASYNC      = libc::MS_ASYNC, /* [MF|SIO] return immediately */
            const MS_INVALIDATE = libc::MS_INVALIDATE, /* [MF|SIO] invalidate all cached data */
            const MS_KILLPAGES  = libc::MS_KILLPAGES, /* invalidate pages, leave mapped */
            const MS_DEACTIVATE = libc::MS_DEACTIVATE, /* deactivate pages, leave mapped */
            const MS_SYNC       = libc::MS_SYNC, /* [MF|SIO] msync synchronously */
        }
    }

    pub const MAP_FAILED: isize               = -1;
}

#[cfg(any(target_os = "freebsd", target_os = "dragonfly", target_os = "openbsd", target_os = "netbsd"))]
mod consts {
    use libc::{self, c_int};

    bitflags!{
        flags MapFlags: c_int {
            const MAP_FILE         = libc::MAP_FILE,
            const MAP_SHARED       = libc::MAP_SHARED,
            const MAP_PRIVATE      = libc::MAP_PRIVATE,
            const MAP_FIXED        = libc::MAP_FIXED,
            const MAP_RENAME       = libc::MAP_RENAME,
            const MAP_NORESERVE    = libc::MAP_NORESERVE,
            const MAP_HASSEMAPHORE = libc::MAP_HASSEMAPHORE,
            const MAP_STACK        = libc::MAP_STACK,
            #[cfg(target_os = "netbsd")]
            const MAP_WIRED        = libc::MAP_WIRED,
            const MAP_NOSYNC       = libc::MAP_NOSYNC,
            const MAP_ANON         = libc::MAP_ANON,
        }
    }

    pub type MmapAdvise = c_int;

    pub const MADV_NORMAL     : MmapAdvise      = 0; /* No further special treatment.  */
    pub const MADV_RANDOM     : MmapAdvise      = 1; /* Expect random page references.  */
    pub const MADV_SEQUENTIAL : MmapAdvise      = 2; /* Expect sequential page references.  */
    pub const MADV_WILLNEED   : MmapAdvise      = 3; /* Will need these pages.  */
    pub const MADV_DONTNEED   : MmapAdvise      = 4; /* Don't need these pages.  */
    pub const MADV_FREE       : MmapAdvise      = 5; /* pages unneeded, discard contents */
    pub const MADV_NOSYNC     : MmapAdvise      = 6; /* try to avoid flushes to physical media*/
    pub const MADV_AUTOSYNC   : MmapAdvise      = 7; /* refert to default flushing strategy */
    pub const MADV_NOCORE     : MmapAdvise      = 8; /* do not include these pages in a core file */
    pub const MADV_CORE       : MmapAdvise      = 9; /* revert to including pages in a core file */
    #[cfg(not(target_os = "dragonfly"))]
    pub const MADV_PROTECT    : MmapAdvise      = 10; /* protect process from pageout kill */
    #[cfg(target_os = "dragonfly")]
    pub const MADV_INVAL      : MmapAdvise      = 10; /* virt page tables have changed, inval pmap */
    #[cfg(target_os = "dragonfly")]
    pub const MADV_SETMAP     : MmapAdvise      = 11; /* set page table directory page for map */

    bitflags!{
        flags MsFlags: c_int {
            const MS_ASYNC      = libc::MS_ASYNC, /* [MF|SIO] return immediately */
            const MS_INVALIDATE = libc::MS_INVALIDATE, /* [MF|SIO] invalidate all cached data */
            #[cfg(not(target_os = "dragonfly"))]
            const MS_KILLPAGES  = 0x0004, /* invalidate pages, leave mapped */
            #[cfg(not(target_os = "dragonfly"))]
            const MS_DEACTIVATE = 0x0004, /* deactivate pages, leave mapped */
            const MS_SYNC       = libc::MS_SYNC, /* [MF|SIO] msync synchronously */
        }
    }

    pub const MAP_FAILED: isize                 = -1;
}

mod ffi {
    use libc::{c_void, size_t, c_int, c_char, mode_t};

    pub use libc::{mmap, munmap};

    #[allow(improper_ctypes)]
    extern {
        pub fn shm_open(name: *const c_char, oflag: c_int, mode: mode_t) -> c_int;
        pub fn shm_unlink(name: *const c_char) -> c_int;
        pub fn mlock(addr: *const c_void, len: size_t) -> c_int;
        pub fn munlock(addr: *const c_void, len: size_t) -> c_int;
        pub fn madvise (addr: *const c_void, len: size_t, advice: c_int) -> c_int;
        pub fn msync (addr: *const c_void, len: size_t, flags: c_int) -> c_int;
    }
}

pub unsafe fn mlock(addr: *const c_void, length: size_t) -> Result<()> {
    Errno::result(ffi::mlock(addr, length)).map(drop)
}

pub fn munlock(addr: *const c_void, length: size_t) -> Result<()> {
    Errno::result(unsafe { ffi::munlock(addr, length) }).map(drop)
}

/// Calls to mmap are inherently unsafe, so they must be made in an unsafe block. Typically
/// a higher-level abstraction will hide the unsafe interactions with the mmap'd region.
pub fn mmap(addr: *mut c_void, length: size_t, prot: ProtFlags, flags: MapFlags, fd: RawFd, offset: off_t) -> Result<*mut c_void> {
    let ret = unsafe { ffi::mmap(addr, length, prot.bits(), flags.bits(), fd, offset) };

    if ret as isize == MAP_FAILED  {
        Err(Error::Sys(Errno::last()))
    } else {
        Ok(ret)
    }
}

pub fn munmap(addr: *mut c_void, len: size_t) -> Result<()> {
    Errno::result(unsafe { ffi::munmap(addr, len) }).map(drop)
}

pub fn madvise(addr: *const c_void, length: size_t, advise: MmapAdvise) -> Result<()> {
    Errno::result(unsafe { ffi::madvise(addr, length, advise) }).map(drop)
}

pub fn msync(addr: *const c_void, length: size_t, flags: MsFlags) -> Result<()> {
    Errno::result(unsafe { ffi::msync(addr, length, flags.bits()) }).map(drop)
}

pub fn shm_open<P: ?Sized + NixPath>(name: &P, flag: OFlag, mode: Mode) -> Result<RawFd> {
    let ret = try!(name.with_nix_path(|cstr| {
        unsafe {
            ffi::shm_open(cstr.as_ptr(), flag.bits(), mode.bits() as mode_t)
        }
    }));

    Errno::result(ret)
}

pub fn shm_unlink<P: ?Sized + NixPath>(name: &P) -> Result<()> {
    let ret = try!(name.with_nix_path(|cstr| {
        unsafe { ffi::shm_unlink(cstr.as_ptr()) }
    }));

    Errno::result(ret).map(drop)
}
<commit_msg>Withdraw MAP_STACK flag from OpenBSD<commit_after>use {Errno, Error, Result, NixPath};
use fcntl::OFlag;
use libc::{self, c_void, size_t, off_t, mode_t};
use sys::stat::Mode;
use std::os::unix::io::RawFd;

pub use self::consts::*;

bitflags!{
    flags ProtFlags : libc::c_int {
        const PROT_NONE      = libc::PROT_NONE,
        const PROT_READ      = libc::PROT_READ,
        const PROT_WRITE     = libc::PROT_WRITE,
        const PROT_EXEC      = libc::PROT_EXEC,
        #[cfg(any(target_os = "linux", target_os = "android"))]
        const PROT_GROWSDOWN = libc::PROT_GROWSDOWN,
        #[cfg(any(target_os = "linux", target_os = "android"))]
        const PROT_GROWSUP   = libc::PROT_GROWSUP,
    }
}

#[cfg(any(target_os = "linux", target_os = "android"))]
mod consts {
    use libc::{self, c_int};

    bitflags!{
        flags MapFlags: c_int {
            const MAP_FILE       = libc::MAP_FILE,
            const MAP_SHARED     = libc::MAP_SHARED,
            const MAP_PRIVATE    = libc::MAP_PRIVATE,
            const MAP_FIXED      = libc::MAP_FIXED,
            const MAP_ANON       = libc::MAP_ANON,
            const MAP_ANONYMOUS  = libc::MAP_ANON,
            #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
            const MAP_32BIT      = libc::MAP_32BIT,
            const MAP_GROWSDOWN  = libc::MAP_GROWSDOWN,
            const MAP_DENYWRITE  = libc::MAP_DENYWRITE,
            const MAP_EXECUTABLE = libc::MAP_EXECUTABLE,
            const MAP_LOCKED     = libc::MAP_LOCKED,
            const MAP_NORESERVE  = libc::MAP_NORESERVE,
            const MAP_POPULATE   = libc::MAP_POPULATE,
            const MAP_NONBLOCK   = libc::MAP_NONBLOCK,
            const MAP_STACK      = libc::MAP_STACK,
            const MAP_HUGETLB    = libc::MAP_HUGETLB,
        }
    }

    pub type MmapAdvise = c_int;

    pub const MADV_NORMAL     : MmapAdvise  = 0; /* No further special treatment.  */
    pub const MADV_RANDOM     : MmapAdvise  = 1; /* Expect random page references.  */
    pub const MADV_SEQUENTIAL : MmapAdvise  = 2; /* Expect sequential page references.  */
    pub const MADV_WILLNEED   : MmapAdvise  = 3; /* Will need these pages.  */
    pub const MADV_DONTNEED   : MmapAdvise  = 4; /* Don't need these pages.  */
    pub const MADV_REMOVE     : MmapAdvise  = 9; /* Remove these pages and resources.  */
    pub const MADV_DONTFORK   : MmapAdvise  = 10; /* Do not inherit across fork.  */
    pub const MADV_DOFORK     : MmapAdvise  = 11; /* Do inherit across fork.  */
    pub const MADV_MERGEABLE  : MmapAdvise  = 12; /* KSM may merge identical pages.  */
    pub const MADV_UNMERGEABLE: MmapAdvise  = 13; /* KSM may not merge identical pages.  */
    pub const MADV_HUGEPAGE   : MmapAdvise  = 14; /* Worth backing with hugepages.  */
    pub const MADV_NOHUGEPAGE : MmapAdvise  = 15; /* Not worth backing with hugepages.  */
    pub const MADV_DONTDUMP   : MmapAdvise  = 16; /* Explicity exclude from the core dump, overrides the coredump filter bits.  */
    pub const MADV_DODUMP     : MmapAdvise  = 17; /* Clear the MADV_DONTDUMP flag.  */
    pub const MADV_HWPOISON   : MmapAdvise  = 100; /* Poison a page for testing.  */

    bitflags!{
        flags MsFlags: c_int {
            const MS_ASYNC      = libc::MS_ASYNC,
            const MS_INVALIDATE = libc::MS_INVALIDATE,
            const MS_SYNC       = libc::MS_SYNC,
        }
    }

    pub const MAP_FAILED: isize               = -1;
}

#[cfg(any(target_os = "macos",
          target_os = "ios"))]
mod consts {
    use libc::{self, c_int};

    bitflags!{
        flags MapFlags: c_int {
            const MAP_FILE    = libc::MAP_FILE,
            const MAP_SHARED  = libc::MAP_SHARED,
            const MAP_PRIVATE = libc::MAP_PRIVATE,
            const MAP_FIXED   = libc::MAP_FIXED,
            const MAP_ANON    = libc::MAP_ANON,
            const MAP_NOCACHE = libc::MAP_NOCACHE,
            const MAP_JIT     = libc::MAP_JIT,
        }
    }

    pub type MmapAdvise = c_int;

    pub const MADV_NORMAL     : MmapAdvise      = 0; /* No further special treatment.  */
    pub const MADV_RANDOM     : MmapAdvise      = 1; /* Expect random page references.  */
    pub const MADV_SEQUENTIAL : MmapAdvise      = 2; /* Expect sequential page references.  */
    pub const MADV_WILLNEED   : MmapAdvise      = 3; /* Will need these pages.  */
    pub const MADV_DONTNEED   : MmapAdvise      = 4; /* Don't need these pages.  */
    pub const MADV_FREE       : MmapAdvise      = 5; /* pages unneeded, discard contents */
    pub const MADV_ZERO_WIRED_PAGES: MmapAdvise = 6; /* zero the wired pages that have not been unwired before the entry is deleted */
    pub const MADV_FREE_REUSABLE : MmapAdvise   = 7; /* pages can be reused (by anyone) */
    pub const MADV_FREE_REUSE : MmapAdvise      = 8; /* caller wants to reuse those pages */
    pub const MADV_CAN_REUSE : MmapAdvise       = 9;

    bitflags!{
        flags MsFlags: c_int {
            const MS_ASYNC      = libc::MS_ASYNC, /* [MF|SIO] return immediately */
            const MS_INVALIDATE = libc::MS_INVALIDATE, /* [MF|SIO] invalidate all cached data */
            const MS_KILLPAGES  = libc::MS_KILLPAGES, /* invalidate pages, leave mapped */
            const MS_DEACTIVATE = libc::MS_DEACTIVATE, /* deactivate pages, leave mapped */
            const MS_SYNC       = libc::MS_SYNC, /* [MF|SIO] msync synchronously */
        }
    }

    pub const MAP_FAILED: isize               = -1;
}

#[cfg(any(target_os = "freebsd", target_os = "dragonfly", target_os = "openbsd", target_os = "netbsd"))]
mod consts {
    use libc::{self, c_int};

    bitflags!{
        flags MapFlags: c_int {
            const MAP_FILE         = libc::MAP_FILE,
            const MAP_SHARED       = libc::MAP_SHARED,
            const MAP_PRIVATE      = libc::MAP_PRIVATE,
            const MAP_FIXED        = libc::MAP_FIXED,
            const MAP_RENAME       = libc::MAP_RENAME,
            const MAP_NORESERVE    = libc::MAP_NORESERVE,
            const MAP_HASSEMAPHORE = libc::MAP_HASSEMAPHORE,
            #[cfg(not(target_os = "openbsd"))]
            const MAP_STACK        = libc::MAP_STACK,
            #[cfg(target_os = "netbsd")]
            const MAP_WIRED        = libc::MAP_WIRED,
            const MAP_NOSYNC       = libc::MAP_NOSYNC,
            const MAP_ANON         = libc::MAP_ANON,
        }
    }

    pub type MmapAdvise = c_int;

    pub const MADV_NORMAL     : MmapAdvise      = 0; /* No further special treatment.  */
    pub const MADV_RANDOM     : MmapAdvise      = 1; /* Expect random page references.  */
    pub const MADV_SEQUENTIAL : MmapAdvise      = 2; /* Expect sequential page references.  */
    pub const MADV_WILLNEED   : MmapAdvise      = 3; /* Will need these pages.  */
    pub const MADV_DONTNEED   : MmapAdvise      = 4; /* Don't need these pages.  */
    pub const MADV_FREE       : MmapAdvise      = 5; /* pages unneeded, discard contents */
    pub const MADV_NOSYNC     : MmapAdvise      = 6; /* try to avoid flushes to physical media*/
    pub const MADV_AUTOSYNC   : MmapAdvise      = 7; /* refert to default flushing strategy */
    pub const MADV_NOCORE     : MmapAdvise      = 8; /* do not include these pages in a core file */
    pub const MADV_CORE       : MmapAdvise      = 9; /* revert to including pages in a core file */
    #[cfg(not(target_os = "dragonfly"))]
    pub const MADV_PROTECT    : MmapAdvise      = 10; /* protect process from pageout kill */
    #[cfg(target_os = "dragonfly")]
    pub const MADV_INVAL      : MmapAdvise      = 10; /* virt page tables have changed, inval pmap */
    #[cfg(target_os = "dragonfly")]
    pub const MADV_SETMAP     : MmapAdvise      = 11; /* set page table directory page for map */

    bitflags!{
        flags MsFlags: c_int {
            const MS_ASYNC      = libc::MS_ASYNC, /* [MF|SIO] return immediately */
            const MS_INVALIDATE = libc::MS_INVALIDATE, /* [MF|SIO] invalidate all cached data */
            #[cfg(not(target_os = "dragonfly"))]
            const MS_KILLPAGES  = 0x0004, /* invalidate pages, leave mapped */
            #[cfg(not(target_os = "dragonfly"))]
            const MS_DEACTIVATE = 0x0004, /* deactivate pages, leave mapped */
            const MS_SYNC       = libc::MS_SYNC, /* [MF|SIO] msync synchronously */
        }
    }

    pub const MAP_FAILED: isize                 = -1;
}

mod ffi {
    use libc::{c_void, size_t, c_int, c_char, mode_t};

    pub use libc::{mmap, munmap};

    #[allow(improper_ctypes)]
    extern {
        pub fn shm_open(name: *const c_char, oflag: c_int, mode: mode_t) -> c_int;
        pub fn shm_unlink(name: *const c_char) -> c_int;
        pub fn mlock(addr: *const c_void, len: size_t) -> c_int;
        pub fn munlock(addr: *const c_void, len: size_t) -> c_int;
        pub fn madvise (addr: *const c_void, len: size_t, advice: c_int) -> c_int;
        pub fn msync (addr: *const c_void, len: size_t, flags: c_int) -> c_int;
    }
}

pub unsafe fn mlock(addr: *const c_void, length: size_t) -> Result<()> {
    Errno::result(ffi::mlock(addr, length)).map(drop)
}

pub fn munlock(addr: *const c_void, length: size_t) -> Result<()> {
    Errno::result(unsafe { ffi::munlock(addr, length) }).map(drop)
}

/// Calls to mmap are inherently unsafe, so they must be made in an unsafe block. Typically
/// a higher-level abstraction will hide the unsafe interactions with the mmap'd region.
pub fn mmap(addr: *mut c_void, length: size_t, prot: ProtFlags, flags: MapFlags, fd: RawFd, offset: off_t) -> Result<*mut c_void> {
    let ret = unsafe { ffi::mmap(addr, length, prot.bits(), flags.bits(), fd, offset) };

    if ret as isize == MAP_FAILED  {
        Err(Error::Sys(Errno::last()))
    } else {
        Ok(ret)
    }
}

pub fn munmap(addr: *mut c_void, len: size_t) -> Result<()> {
    Errno::result(unsafe { ffi::munmap(addr, len) }).map(drop)
}

pub fn madvise(addr: *const c_void, length: size_t, advise: MmapAdvise) -> Result<()> {
    Errno::result(unsafe { ffi::madvise(addr, length, advise) }).map(drop)
}

pub fn msync(addr: *const c_void, length: size_t, flags: MsFlags) -> Result<()> {
    Errno::result(unsafe { ffi::msync(addr, length, flags.bits()) }).map(drop)
}

pub fn shm_open<P: ?Sized + NixPath>(name: &P, flag: OFlag, mode: Mode) -> Result<RawFd> {
    let ret = try!(name.with_nix_path(|cstr| {
        unsafe {
            ffi::shm_open(cstr.as_ptr(), flag.bits(), mode.bits() as mode_t)
        }
    }));

    Errno::result(ret)
}

pub fn shm_unlink<P: ?Sized + NixPath>(name: &P) -> Result<()> {
    let ret = try!(name.with_nix_path(|cstr| {
        unsafe { ffi::shm_unlink(cstr.as_ptr()) }
    }));

    Errno::result(ret).map(drop)
}
<|endoftext|>


<commit_before>use std::{fmt, ops};
use libc::{time_t, suseconds_t};

#[repr(C)]
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)]
pub struct TimeVal {
    pub tv_sec: time_t,
    pub tv_usec: suseconds_t,
}

const MICROS_PER_SEC: i64 = 1_000_000;
const SECS_PER_MINUTE: i64 = 60;
const SECS_PER_HOUR: i64 = 3600;

#[cfg(target_pointer_width = "64")]
const MAX_SECONDS: i64 = (::std::i64::MAX / MICROS_PER_SEC) - 1;

#[cfg(target_pointer_width = "32")]
const MAX_SECONDS: i64 = ::std::isize::MAX as i64;

const MIN_SECONDS: i64 = -MAX_SECONDS;

impl TimeVal {
    #[inline]
    pub fn zero() -> TimeVal {
        TimeVal::microseconds(0)
    }

    #[inline]
    pub fn hours(hours: i64) -> TimeVal {
        let secs = hours.checked_mul(SECS_PER_HOUR)
            .expect("TimeVal::hours ouf of bounds");

        TimeVal::seconds(secs)
    }

    #[inline]
    pub fn minutes(minutes: i64) -> TimeVal {
        let secs = minutes.checked_mul(SECS_PER_MINUTE)
            .expect("TimeVal::minutes out of bounds");

        TimeVal::seconds(secs)
    }

    #[inline]
    pub fn seconds(seconds: i64) -> TimeVal {
        assert!(seconds >= MIN_SECONDS && seconds <= MAX_SECONDS, "TimeVal out of bounds; seconds={}", seconds);
        TimeVal { tv_sec: seconds as time_t, tv_usec: 0 }
    }

    #[inline]
    pub fn milliseconds(milliseconds: i64) -> TimeVal {
        let microseconds = milliseconds.checked_mul(1_000)
            .expect("TimeVal::milliseconds out of bounds");

        TimeVal::microseconds(microseconds)
    }

    /// Makes a new `TimeVal` with given number of microseconds.
    #[inline]
    pub fn microseconds(microseconds: i64) -> TimeVal {
        let (secs, micros) = div_mod_floor_64(microseconds, MICROS_PER_SEC);
        assert!(secs >= MIN_SECONDS && secs <= MAX_SECONDS, "TimeVal out of bounds");
        TimeVal { tv_sec: secs as time_t, tv_usec: micros as suseconds_t }
    }

    pub fn num_hours(&self) -> i64 {
        self.num_seconds() / 3600
    }

    pub fn num_minutes(&self) -> i64 {
        self.num_seconds() / 60
    }

    pub fn num_seconds(&self) -> i64 {
        if self.tv_sec < 0 && self.tv_usec > 0 {
            (self.tv_sec + 1) as i64
        } else {
            self.tv_sec as i64
        }
    }

    pub fn num_milliseconds(&self) -> i64 {
        self.num_microseconds() / 1_000
    }

    pub fn num_microseconds(&self) -> i64 {
        let secs = self.num_seconds() * 1_000_000;
        let usec = self.micros_mod_sec();
        secs + usec as i64
    }

    fn micros_mod_sec(&self) -> suseconds_t {
        if self.tv_sec < 0 && self.tv_usec > 0 {
            self.tv_usec - MICROS_PER_SEC as suseconds_t
        } else {
            self.tv_usec
        }
    }
}

impl ops::Neg for TimeVal {
    type Output = TimeVal;

    fn neg(self) -> TimeVal {
        TimeVal::microseconds(-self.num_microseconds())
    }
}

impl ops::Add for TimeVal {
    type Output = TimeVal;

    fn add(self, rhs: TimeVal) -> TimeVal {
        TimeVal::microseconds(
            self.num_microseconds() + rhs.num_microseconds())
    }
}

impl ops::Sub for TimeVal {
    type Output = TimeVal;

    fn sub(self, rhs: TimeVal) -> TimeVal {
        TimeVal::microseconds(
            self.num_microseconds() - rhs.num_microseconds())
    }
}

impl ops::Mul<i32> for TimeVal {
    type Output = TimeVal;

    fn mul(self, rhs: i32) -> TimeVal {
        let usec = self.num_microseconds().checked_mul(rhs as i64)
            .expect("TimeVal multiply out of bounds");

        TimeVal::microseconds(usec)
    }
}

impl ops::Div<i32> for TimeVal {
    type Output = TimeVal;

    fn div(self, rhs: i32) -> TimeVal {
        let usec = self.num_microseconds() / rhs as i64;
        TimeVal::microseconds(usec)
    }
}

impl fmt::Display for TimeVal {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let (abs, sign) = if self.tv_sec < 0 {
            (-*self, "-")
        } else {
            (*self, "")
        };

        let sec = abs.tv_sec;

        try!(write!(f, "{}", sign));

        if abs.tv_usec == 0 {
            if abs.tv_sec == 1 {
                try!(write!(f, "{} second", sec));
            } else {
                try!(write!(f, "{} seconds", sec));
            }
        } else if abs.tv_usec % 1000 == 0 {
            try!(write!(f, "{}.{:03} seconds", sec, abs.tv_usec / 1000));
        } else {
            try!(write!(f, "{}.{:06} seconds", sec, abs.tv_usec));
        }

        Ok(())
    }
}

#[inline]
fn div_mod_floor_64(this: i64, other: i64) -> (i64, i64) {
    (div_floor_64(this, other), mod_floor_64(this, other))
}

#[inline]
fn div_floor_64(this: i64, other: i64) -> i64 {
    match div_rem_64(this, other) {
        (d, r) if (r > 0 && other < 0)
               || (r < 0 && other > 0) => d - 1,
        (d, _)                         => d,
    }
}

#[inline]
fn mod_floor_64(this: i64, other: i64) -> i64 {
    match this % other {
        r if (r > 0 && other < 0)
          || (r < 0 && other > 0) => r + other,
        r                         => r,
    }
}

#[inline]
fn div_rem_64(this: i64, other: i64) -> (i64, i64) {
    (this / other, this % other)
}

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

    #[test]
    pub fn test_time_val() {
        assert!(TimeVal::seconds(1) != TimeVal::zero());
        assert_eq!(TimeVal::seconds(1) + TimeVal::seconds(2), TimeVal::seconds(3));
        assert_eq!(TimeVal::minutes(3) + TimeVal::seconds(2),
                   TimeVal::seconds(182));
    }

    #[test]
    pub fn test_time_val_neg() {
        let a = TimeVal::seconds(1) + TimeVal::microseconds(123);
        let b = TimeVal::seconds(-1) + TimeVal::microseconds(-123);

        assert_eq!(a, -b);
    }

    #[test]
    pub fn test_time_val_fmt() {
        assert_eq!(TimeVal::zero().to_string(), "0 seconds");
        assert_eq!(TimeVal::seconds(42).to_string(), "42 seconds");
        assert_eq!(TimeVal::milliseconds(42).to_string(), "0.042 seconds");
        assert_eq!(TimeVal::microseconds(42).to_string(), "0.000042 seconds");
        assert_eq!(TimeVal::seconds(-86401).to_string(), "-86401 seconds");
    }
}
<commit_msg>Opaqueify TimeVal<commit_after>use std::{fmt, ops};
use libc::{time_t, suseconds_t};

#[repr(C)]
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)]
pub struct TimeVal {
    tv_sec: time_t,
    tv_usec: suseconds_t,
}

const MICROS_PER_SEC: i64 = 1_000_000;
const SECS_PER_MINUTE: i64 = 60;
const SECS_PER_HOUR: i64 = 3600;

#[cfg(target_pointer_width = "64")]
const MAX_SECONDS: i64 = (::std::i64::MAX / MICROS_PER_SEC) - 1;

#[cfg(target_pointer_width = "32")]
const MAX_SECONDS: i64 = ::std::isize::MAX as i64;

const MIN_SECONDS: i64 = -MAX_SECONDS;

impl TimeVal {
    #[inline]
    pub fn zero() -> TimeVal {
        TimeVal::microseconds(0)
    }

    #[inline]
    pub fn hours(hours: i64) -> TimeVal {
        let secs = hours.checked_mul(SECS_PER_HOUR)
            .expect("TimeVal::hours ouf of bounds");

        TimeVal::seconds(secs)
    }

    #[inline]
    pub fn minutes(minutes: i64) -> TimeVal {
        let secs = minutes.checked_mul(SECS_PER_MINUTE)
            .expect("TimeVal::minutes out of bounds");

        TimeVal::seconds(secs)
    }

    #[inline]
    pub fn seconds(seconds: i64) -> TimeVal {
        assert!(seconds >= MIN_SECONDS && seconds <= MAX_SECONDS, "TimeVal out of bounds; seconds={}", seconds);
        TimeVal { tv_sec: seconds as time_t, tv_usec: 0 }
    }

    #[inline]
    pub fn milliseconds(milliseconds: i64) -> TimeVal {
        let microseconds = milliseconds.checked_mul(1_000)
            .expect("TimeVal::milliseconds out of bounds");

        TimeVal::microseconds(microseconds)
    }

    /// Makes a new `TimeVal` with given number of microseconds.
    #[inline]
    pub fn microseconds(microseconds: i64) -> TimeVal {
        let (secs, micros) = div_mod_floor_64(microseconds, MICROS_PER_SEC);
        assert!(secs >= MIN_SECONDS && secs <= MAX_SECONDS, "TimeVal out of bounds");
        TimeVal { tv_sec: secs as time_t, tv_usec: micros as suseconds_t }
    }

    pub fn num_hours(&self) -> i64 {
        self.num_seconds() / 3600
    }

    pub fn num_minutes(&self) -> i64 {
        self.num_seconds() / 60
    }

    pub fn num_seconds(&self) -> i64 {
        if self.tv_sec < 0 && self.tv_usec > 0 {
            (self.tv_sec + 1) as i64
        } else {
            self.tv_sec as i64
        }
    }

    pub fn num_milliseconds(&self) -> i64 {
        self.num_microseconds() / 1_000
    }

    pub fn num_microseconds(&self) -> i64 {
        let secs = self.num_seconds() * 1_000_000;
        let usec = self.micros_mod_sec();
        secs + usec as i64
    }

    fn micros_mod_sec(&self) -> suseconds_t {
        if self.tv_sec < 0 && self.tv_usec > 0 {
            self.tv_usec - MICROS_PER_SEC as suseconds_t
        } else {
            self.tv_usec
        }
    }
}

impl ops::Neg for TimeVal {
    type Output = TimeVal;

    fn neg(self) -> TimeVal {
        TimeVal::microseconds(-self.num_microseconds())
    }
}

impl ops::Add for TimeVal {
    type Output = TimeVal;

    fn add(self, rhs: TimeVal) -> TimeVal {
        TimeVal::microseconds(
            self.num_microseconds() + rhs.num_microseconds())
    }
}

impl ops::Sub for TimeVal {
    type Output = TimeVal;

    fn sub(self, rhs: TimeVal) -> TimeVal {
        TimeVal::microseconds(
            self.num_microseconds() - rhs.num_microseconds())
    }
}

impl ops::Mul<i32> for TimeVal {
    type Output = TimeVal;

    fn mul(self, rhs: i32) -> TimeVal {
        let usec = self.num_microseconds().checked_mul(rhs as i64)
            .expect("TimeVal multiply out of bounds");

        TimeVal::microseconds(usec)
    }
}

impl ops::Div<i32> for TimeVal {
    type Output = TimeVal;

    fn div(self, rhs: i32) -> TimeVal {
        let usec = self.num_microseconds() / rhs as i64;
        TimeVal::microseconds(usec)
    }
}

impl fmt::Display for TimeVal {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let (abs, sign) = if self.tv_sec < 0 {
            (-*self, "-")
        } else {
            (*self, "")
        };

        let sec = abs.tv_sec;

        try!(write!(f, "{}", sign));

        if abs.tv_usec == 0 {
            if abs.tv_sec == 1 {
                try!(write!(f, "{} second", sec));
            } else {
                try!(write!(f, "{} seconds", sec));
            }
        } else if abs.tv_usec % 1000 == 0 {
            try!(write!(f, "{}.{:03} seconds", sec, abs.tv_usec / 1000));
        } else {
            try!(write!(f, "{}.{:06} seconds", sec, abs.tv_usec));
        }

        Ok(())
    }
}

#[inline]
fn div_mod_floor_64(this: i64, other: i64) -> (i64, i64) {
    (div_floor_64(this, other), mod_floor_64(this, other))
}

#[inline]
fn div_floor_64(this: i64, other: i64) -> i64 {
    match div_rem_64(this, other) {
        (d, r) if (r > 0 && other < 0)
               || (r < 0 && other > 0) => d - 1,
        (d, _)                         => d,
    }
}

#[inline]
fn mod_floor_64(this: i64, other: i64) -> i64 {
    match this % other {
        r if (r > 0 && other < 0)
          || (r < 0 && other > 0) => r + other,
        r                         => r,
    }
}

#[inline]
fn div_rem_64(this: i64, other: i64) -> (i64, i64) {
    (this / other, this % other)
}

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

    #[test]
    pub fn test_time_val() {
        assert!(TimeVal::seconds(1) != TimeVal::zero());
        assert_eq!(TimeVal::seconds(1) + TimeVal::seconds(2), TimeVal::seconds(3));
        assert_eq!(TimeVal::minutes(3) + TimeVal::seconds(2),
                   TimeVal::seconds(182));
    }

    #[test]
    pub fn test_time_val_neg() {
        let a = TimeVal::seconds(1) + TimeVal::microseconds(123);
        let b = TimeVal::seconds(-1) + TimeVal::microseconds(-123);

        assert_eq!(a, -b);
    }

    #[test]
    pub fn test_time_val_fmt() {
        assert_eq!(TimeVal::zero().to_string(), "0 seconds");
        assert_eq!(TimeVal::seconds(42).to_string(), "42 seconds");
        assert_eq!(TimeVal::milliseconds(42).to_string(), "0.042 seconds");
        assert_eq!(TimeVal::microseconds(42).to_string(), "0.000042 seconds");
        assert_eq!(TimeVal::seconds(-86401).to_string(), "-86401 seconds");
    }
}
<|endoftext|>


<commit_before>use std::collections::BTreeMap;
use std::rc::Rc;
use std::cell::RefCell;

type WordCell = Rc<RefCell<Word>>;
type AuthorCell = Rc<RefCell<Author>>;
type SourceCell = Rc<RefCell<Source>>;
type MessageCell = Rc<RefCell<Message>>;
type CategoryCell = Rc<RefCell<Category>>;
type ConversationCell = Rc<RefCell<Conversation>>;

const RATIO_CONTAINED_BEFORE_COMBINATION: f64 = 0.8;

struct Lexicon {
    words: BTreeMap<String, WordCell>,
    authors: BTreeMap<String, AuthorCell>,
    sources: BTreeMap<String, SourceCell>,
    conversations: Vec<ConversationCell>,
}

struct Conversation {
    source: SourceCell,
    messages: Vec<Message>,
}

struct Author {
    name: String,
}

struct Source {
    name: String,
    messages: u64,
}

struct MessageWord {
    word: WordCell,
    category: CategoryCell,
}

struct Message {
    author: AuthorCell,
    conversation: ConversationCell,
    index: usize,
    words: Vec<MessageWord>,
}

struct WordInstance {
    word: WordCell,
    message: MessageCell,
    index: usize,
}

struct Category {
    instances: Vec<WordInstance>,
    subcategories: Vec<CategoryCell>,
}

struct Word {
    name: String,
    instances: Vec<WordInstance>,
}
<commit_msg>correct conversation to contain a cell<commit_after>use std::collections::BTreeMap;
use std::rc::Rc;
use std::cell::RefCell;

type WordCell = Rc<RefCell<Word>>;
type AuthorCell = Rc<RefCell<Author>>;
type SourceCell = Rc<RefCell<Source>>;
type MessageCell = Rc<RefCell<Message>>;
type CategoryCell = Rc<RefCell<Category>>;
type ConversationCell = Rc<RefCell<Conversation>>;

const RATIO_CONTAINED_BEFORE_COMBINATION: f64 = 0.8;

struct Lexicon {
    words: BTreeMap<String, WordCell>,
    authors: BTreeMap<String, AuthorCell>,
    sources: BTreeMap<String, SourceCell>,
    conversations: Vec<ConversationCell>,
}

struct Conversation {
    source: SourceCell,
    messages: Vec<MessageCell>,
}

struct Author {
    name: String,
}

struct Source {
    name: String,
    messages: u64,
}

struct MessageWord {
    word: WordCell,
    category: CategoryCell,
}

struct Message {
    author: AuthorCell,
    conversation: ConversationCell,
    index: usize,
    words: Vec<MessageWord>,
}

struct WordInstance {
    word: WordCell,
    message: MessageCell,
    index: usize,
}

struct Category {
    instances: Vec<WordInstance>,
    subcategories: Vec<CategoryCell>,
}

struct Word {
    name: String,
    instances: Vec<WordInstance>,
}
<|endoftext|>


<commit_before>extern crate rand;
extern crate itertools;
use self::itertools::Itertools;

use std::collections::BTreeMap;
use std::collections::btree_map::Entry;
use std::rc::Rc;
use std::cell::RefCell;
use std::cell::Ref;
use std::sync::mpsc::Receiver;

type WordCell = Rc<RefCell<Word>>;
pub type AuthorCell = Rc<RefCell<Author>>;
pub type SourceCell = Rc<RefCell<Source>>;
type MessageCell = Rc<RefCell<Message>>;
type CategoryCell = Rc<RefCell<Category>>;
type ConversationCell = Rc<RefCell<Conversation>>;
type InstanceCell = Rc<RefCell<WordInstance>>;

enum Mismatch<T> {
    // Incompatible for matching or no mismatch (exactly the same)
    None,
    // Exactly one mismatch
    One(T),
    // Multiple mismatches
    Multiple,
}

fn wrap<T>(t: T) -> Rc<RefCell<T>> {
    Rc::new(RefCell::new(t))
}

// const RATIO_CONTAINED_BEFORE_COMBINATION: f64 = 0.8;

#[derive(Default)]
pub struct Lexicon<R: rand::Rng> {
    rng: R,
    words: BTreeMap<String, WordCell>,
    sources: BTreeMap<String, SourceCell>,
    conversations: Vec<ConversationCell>,
    messages: Vec<MessageCell>,

    active_conversations: BTreeMap<*const Source, ConversationCell>,
}

impl<R: rand::Rng> Lexicon<R> {
    pub fn new(rng: R) -> Lexicon<R> {
        Lexicon{
            rng: rng,
            words: Default::default(),
            sources: Default::default(),
            conversations: Default::default(),
            messages: Default::default(),
            active_conversations: Default::default(),
        }
    }

    pub fn source(&mut self, name: String) -> SourceCell {
        match self.sources.entry(name.clone()) {
            Entry::Vacant(v) => v.insert(wrap(Source{
                name: name,
                messages: 0,
                authors: BTreeMap::default(),
            })).clone(),
            Entry::Occupied(o) => o.get().clone(),
        }
    }

    pub fn author(&mut self, source: SourceCell, name: String) -> AuthorCell {
        match source.borrow_mut().authors.entry(name.clone()) {
            Entry::Vacant(v) => {
                let a = wrap(Author{
                    source: source.clone(),
                    name: name.clone(),
                });
                v.insert(a.clone());
                a
            },
            Entry::Occupied(o) => o.get().clone(),
        }
    }
    pub fn tell(&mut self, source: SourceCell, author: AuthorCell, content: String) -> Option<String> {
        let conversation = match self.active_conversations.entry(&*source.borrow() as *const Source) {
            Entry::Vacant(v) => {
                let c = wrap(Conversation{
                    source: source.clone(),
                    messages: Vec::new(),
                });
                v.insert(c.clone());
                self.conversations.push(c.clone());
                c
            },
            Entry::Occupied(o) => {
                o.get().clone()
            },
        };

        let message = wrap(Message{
            author: author.clone(),
            conversation: conversation.clone(),
            index: conversation.borrow().messages.len(),
            instances: Vec::new(),
        });

        self.messages.push(message.clone());

        for word in content.split(' ').map(|s| {
            let string = s.to_string();
            match self.words.entry(string.clone()) {
                Entry::Vacant(v) => {
                    let w = wrap(Word{
                        name: string,
                        instances: Vec::new(),
                    });
                    v.insert(w.clone());
                    w
                },
                Entry::Occupied(o) => {
                    o.get().clone()
                },
            }
        }) {
            // Create empty category for the word
            let category = wrap(Category::default());
            // Create instance of the word
            let instance = wrap(WordInstance{
                word: word.clone(),
                category: category.clone(),
                message: message.clone(),
                index: message.borrow().instances.len(),
            });
            // Insert word instance into the word, category, and message for future reference
            message.borrow_mut().instances.push(instance.clone());
            category.borrow_mut().instances.push(instance.clone());
            word.borrow_mut().instances.push(instance);
        }

        // Increment the messages by 1 for the source
        source.borrow_mut().messages += 1;

        // TODO: Determine what to say back
        None
    }

    pub fn initiate(&mut self, source: SourceCell) -> Option<String> {
        let conversation = wrap(Conversation{
            source: source.clone(),
            messages: Vec::new(),
        });

        match self.active_conversations.entry(&*source.borrow() as *const Source) {
            Entry::Vacant(v) => {
                v.insert(conversation.clone());
            },
            Entry::Occupied(mut o) => {
                o.insert(conversation.clone());
            },
        };

        self.conversations.push(conversation.clone());

        let base = match self.rng.choose(&self.messages[..]) {
            Some(m) => m.clone(),
            None => return None,
        };

        let bborrow = base.borrow();

        Some(bborrow.instances.iter()
            .map(|instance| instance.borrow().category.clone())
            // TODO: Allow random choosing from co-category instances as well
            .map(|category| self.rng.choose(&category.borrow().instances[..]).unwrap().clone())
            .map(|instance| {
                let ins = instance.borrow();
                let word = ins.word.borrow();
                word.name.clone()
            })
            .join(" "))
    }

    pub fn think(&mut self, end: Receiver<()>) {
        use std::sync::mpsc::TryRecvError::Empty;
        while end.try_recv() == Err(Empty) {
            // Choose a random message or break if there are none
            let message = match self.rng.choose(&self.messages[..]) {
                Some(m) => m.clone(),
                None => break,
            };

            // Vector of absolute perfect matches
            let mut vones = Vec::new();

            // Look through each word in the message
            for word in &message.borrow().instances {
                let borrow = word.borrow();
                // Check each instance in that words instances
                for instance in &borrow.word.borrow().instances {
                    // Get the message for each instance
                    let omessage = instance.borrow().message.clone();
                    // Find what kind of matches exist between the messages
                    if let Mismatch::One(best) =
                        Message::category_and_word_mismatch((message.clone(), omessage.clone())) {
                        vones.push(best);
                    }
                }
            }

            // Now that we have perfect matches, merge them into the same Category
            for ms in vones {
                // We only want to combine if they aren't already in the same category
                if ms.0.borrow().category != ms.1.borrow().category {
                    let cats = (ms.0.borrow().category.clone(), ms.1.borrow().category.clone());
                    Category::merge(cats);
                }
            }
        }
    }

    pub fn show_categories(&self) {
        use std::collections::BTreeSet;
        let mut set = BTreeSet::new();
        for message in &self.messages {
            for instance in &message.borrow().instances {
                let ib = instance.borrow();
                set.insert(&*ib.category.borrow() as *const Category);
            }
        }

        for cat in set {
            println!("Category:");
            let catr = unsafe{&*cat};
            for instance in &catr.instances {
                let ib = instance.borrow();
                println!("\t{}", ib.word.borrow().name);
            }
        }
    }
}

macro_rules! pointer_eq {
    ($s:ident) => {
        impl PartialEq for $s {
            fn eq(&self, other: &Self) -> bool {
                self as *const Self == other as *const Self
            }

            fn ne(&self, other: &Self) -> bool {
                self as *const Self != other as *const Self
            }
        }
    };
}

struct Conversation {
    source: SourceCell,
    messages: Vec<MessageCell>,
}

pointer_eq!(Conversation);

pub struct Author {
    source: SourceCell,
    name: String,
}

pointer_eq!(Author);

pub struct Source {
    name: String,
    messages: u64,
    authors: BTreeMap<String, AuthorCell>,
}

pointer_eq!(Source);

struct WordInstance {
    word: WordCell,
    category: CategoryCell,
    message: MessageCell,
    index: usize,
}

pointer_eq!(WordInstance);

struct Message {
    author: AuthorCell,
    conversation: ConversationCell,
    index: usize,
    instances: Vec<InstanceCell>,
}

impl Message {
    fn mismatch<F>(messages: (MessageCell, MessageCell), diff: F) -> Mismatch<(InstanceCell, InstanceCell)>
        where F: Fn((&WordInstance, &WordInstance)) -> bool
    {
        if messages.0 == messages.1 ||
            messages.0.borrow().instances.len() != messages.1.borrow().instances.len() {
            return Mismatch::None;
        }
        messages.0.borrow().instances.iter()
            .zip(messages.1.borrow().instances.iter())
            .fold(Mismatch::None, |acc, ws| {
                let bs = (ws.0.borrow(), ws.1.borrow());
                match acc {
                    Mismatch::None => {
                        if diff((&*bs.0, &*bs.1)) {
                            Mismatch::One((ws.0.clone(), ws.1.clone()))
                        } else {
                            Mismatch::None
                        }
                    },
                    Mismatch::One(best) => {
                        if diff((&*bs.0, &*bs.1)) {
                            Mismatch::Multiple
                        } else {
                            Mismatch::One(best)
                        }
                    },
                    Mismatch::Multiple => Mismatch::Multiple,
                }
            })
    }
    /*fn category_mismatch(messages: (MessageCell, MessageCell)) ->
        Mismatch<(InstanceCell, InstanceCell)> {
        Self::mismatch(messages, |ins| ins.0.category != ins.1.category)
    }

    fn word_mismatch(messages: (MessageCell, MessageCell)) ->
        Mismatch<(InstanceCell, InstanceCell)> {
        Self::mismatch(messages, |ins| ins.0.word != ins.1.word)
    }*/

    fn category_and_word_mismatch(messages: (MessageCell, MessageCell)) ->
        Mismatch<(InstanceCell, InstanceCell)> {
        Self::mismatch(messages, |ins| ins.0.word != ins.1.word && ins.0.category != ins.1.category)
    }
}

pointer_eq!(Message);

#[derive(Default)]
struct Category {
    instances: Vec<InstanceCell>,
    cocategories: Vec<CategoryCell>,
}

impl Category {
    fn merge(cs: (CategoryCell, CategoryCell)) -> CategoryCell {
        let cc = wrap(Self::default());
        {
            let clos = |cat: &CategoryCell| {
                for instance in cat.borrow().instances.iter().cloned() {
                    instance.borrow_mut().category = cc.clone();
                }
            };
            clos(&cs.0);
            clos(&cs.1);
            let mut ccm = cc.borrow_mut();
            ccm.instances.append(&mut cs.0.borrow_mut().instances);
            ccm.instances.append(&mut cs.1.borrow_mut().instances);
        }
        cc
    }
}

pointer_eq!(Category);

struct Word {
    name: String,
    instances: Vec<InstanceCell>,
}

pointer_eq!(Word);
<commit_msg>print original message too temporarily<commit_after>extern crate rand;
extern crate itertools;
use self::itertools::Itertools;

use std::collections::BTreeMap;
use std::collections::btree_map::Entry;
use std::rc::Rc;
use std::cell::RefCell;
use std::cell::Ref;
use std::sync::mpsc::Receiver;

type WordCell = Rc<RefCell<Word>>;
pub type AuthorCell = Rc<RefCell<Author>>;
pub type SourceCell = Rc<RefCell<Source>>;
type MessageCell = Rc<RefCell<Message>>;
type CategoryCell = Rc<RefCell<Category>>;
type ConversationCell = Rc<RefCell<Conversation>>;
type InstanceCell = Rc<RefCell<WordInstance>>;

enum Mismatch<T> {
    // Incompatible for matching or no mismatch (exactly the same)
    None,
    // Exactly one mismatch
    One(T),
    // Multiple mismatches
    Multiple,
}

fn wrap<T>(t: T) -> Rc<RefCell<T>> {
    Rc::new(RefCell::new(t))
}

// const RATIO_CONTAINED_BEFORE_COMBINATION: f64 = 0.8;

#[derive(Default)]
pub struct Lexicon<R: rand::Rng> {
    rng: R,
    words: BTreeMap<String, WordCell>,
    sources: BTreeMap<String, SourceCell>,
    conversations: Vec<ConversationCell>,
    messages: Vec<MessageCell>,

    active_conversations: BTreeMap<*const Source, ConversationCell>,
}

impl<R: rand::Rng> Lexicon<R> {
    pub fn new(rng: R) -> Lexicon<R> {
        Lexicon{
            rng: rng,
            words: Default::default(),
            sources: Default::default(),
            conversations: Default::default(),
            messages: Default::default(),
            active_conversations: Default::default(),
        }
    }

    pub fn source(&mut self, name: String) -> SourceCell {
        match self.sources.entry(name.clone()) {
            Entry::Vacant(v) => v.insert(wrap(Source{
                name: name,
                messages: 0,
                authors: BTreeMap::default(),
            })).clone(),
            Entry::Occupied(o) => o.get().clone(),
        }
    }

    pub fn author(&mut self, source: SourceCell, name: String) -> AuthorCell {
        match source.borrow_mut().authors.entry(name.clone()) {
            Entry::Vacant(v) => {
                let a = wrap(Author{
                    source: source.clone(),
                    name: name.clone(),
                });
                v.insert(a.clone());
                a
            },
            Entry::Occupied(o) => o.get().clone(),
        }
    }
    pub fn tell(&mut self, source: SourceCell, author: AuthorCell, content: String) -> Option<String> {
        let conversation = match self.active_conversations.entry(&*source.borrow() as *const Source) {
            Entry::Vacant(v) => {
                let c = wrap(Conversation{
                    source: source.clone(),
                    messages: Vec::new(),
                });
                v.insert(c.clone());
                self.conversations.push(c.clone());
                c
            },
            Entry::Occupied(o) => {
                o.get().clone()
            },
        };

        let message = wrap(Message{
            author: author.clone(),
            conversation: conversation.clone(),
            index: conversation.borrow().messages.len(),
            instances: Vec::new(),
        });

        self.messages.push(message.clone());

        for word in content.split(' ').map(|s| {
            let string = s.to_string();
            match self.words.entry(string.clone()) {
                Entry::Vacant(v) => {
                    let w = wrap(Word{
                        name: string,
                        instances: Vec::new(),
                    });
                    v.insert(w.clone());
                    w
                },
                Entry::Occupied(o) => {
                    o.get().clone()
                },
            }
        }) {
            // Create empty category for the word
            let category = wrap(Category::default());
            // Create instance of the word
            let instance = wrap(WordInstance{
                word: word.clone(),
                category: category.clone(),
                message: message.clone(),
                index: message.borrow().instances.len(),
            });
            // Insert word instance into the word, category, and message for future reference
            message.borrow_mut().instances.push(instance.clone());
            category.borrow_mut().instances.push(instance.clone());
            word.borrow_mut().instances.push(instance);
        }

        // Increment the messages by 1 for the source
        source.borrow_mut().messages += 1;

        // TODO: Determine what to say back
        None
    }

    pub fn initiate(&mut self, source: SourceCell) -> Option<String> {
        let conversation = wrap(Conversation{
            source: source.clone(),
            messages: Vec::new(),
        });

        match self.active_conversations.entry(&*source.borrow() as *const Source) {
            Entry::Vacant(v) => {
                v.insert(conversation.clone());
            },
            Entry::Occupied(mut o) => {
                o.insert(conversation.clone());
            },
        };

        self.conversations.push(conversation.clone());

        let base = match self.rng.choose(&self.messages[..]) {
            Some(m) => m.clone(),
            None => return None,
        };

        let bborrow = base.borrow();

        Some(format!("{} ~ {}",
            bborrow.instances.iter()
                .map(|instance| instance.borrow().category.clone())
                // TODO: Allow random choosing from co-category instances as well
                .map(|category| self.rng.choose(&category.borrow().instances[..]).unwrap().clone())
                .map(|instance| {
                    let ins = instance.borrow();
                    let word = ins.word.borrow();
                    word.name.clone()
                })
                .join(" "),
            bborrow.instances.iter()
                .map(|i| {
                    let b = i.borrow();
                    let b = b.word.borrow();
                    b.name.clone()
                })
                .join(" "))
        )
    }

    pub fn think(&mut self, end: Receiver<()>) {
        use std::sync::mpsc::TryRecvError::Empty;
        while end.try_recv() == Err(Empty) {
            // Choose a random message or break if there are none
            let message = match self.rng.choose(&self.messages[..]) {
                Some(m) => m.clone(),
                None => break,
            };

            // Vector of absolute perfect matches
            let mut vones = Vec::new();

            // Look through each word in the message
            for word in &message.borrow().instances {
                let borrow = word.borrow();
                // Check each instance in that words instances
                for instance in &borrow.word.borrow().instances {
                    // Get the message for each instance
                    let omessage = instance.borrow().message.clone();
                    // Find what kind of matches exist between the messages
                    if let Mismatch::One(best) =
                        Message::category_and_word_mismatch((message.clone(), omessage.clone())) {
                        vones.push(best);
                    }
                }
            }

            // Now that we have perfect matches, merge them into the same Category
            for ms in vones {
                // We only want to combine if they aren't already in the same category
                if ms.0.borrow().category != ms.1.borrow().category {
                    let cats = (ms.0.borrow().category.clone(), ms.1.borrow().category.clone());
                    Category::merge(cats);
                }
            }
        }
    }

    pub fn show_categories(&self) {
        use std::collections::BTreeSet;
        let mut set = BTreeSet::new();
        for message in &self.messages {
            for instance in &message.borrow().instances {
                let ib = instance.borrow();
                set.insert(&*ib.category.borrow() as *const Category);
            }
        }

        for cat in set {
            println!("Category:");
            let catr = unsafe{&*cat};
            for instance in &catr.instances {
                let ib = instance.borrow();
                println!("\t{}", ib.word.borrow().name);
            }
        }
    }
}

macro_rules! pointer_eq {
    ($s:ident) => {
        impl PartialEq for $s {
            fn eq(&self, other: &Self) -> bool {
                self as *const Self == other as *const Self
            }

            fn ne(&self, other: &Self) -> bool {
                self as *const Self != other as *const Self
            }
        }
    };
}

struct Conversation {
    source: SourceCell,
    messages: Vec<MessageCell>,
}

pointer_eq!(Conversation);

pub struct Author {
    source: SourceCell,
    name: String,
}

pointer_eq!(Author);

pub struct Source {
    name: String,
    messages: u64,
    authors: BTreeMap<String, AuthorCell>,
}

pointer_eq!(Source);

struct WordInstance {
    word: WordCell,
    category: CategoryCell,
    message: MessageCell,
    index: usize,
}

pointer_eq!(WordInstance);

struct Message {
    author: AuthorCell,
    conversation: ConversationCell,
    index: usize,
    instances: Vec<InstanceCell>,
}

impl Message {
    fn mismatch<F>(messages: (MessageCell, MessageCell), diff: F) -> Mismatch<(InstanceCell, InstanceCell)>
        where F: Fn((&WordInstance, &WordInstance)) -> bool
    {
        if messages.0 == messages.1 ||
            messages.0.borrow().instances.len() != messages.1.borrow().instances.len() {
            return Mismatch::None;
        }
        messages.0.borrow().instances.iter()
            .zip(messages.1.borrow().instances.iter())
            .fold(Mismatch::None, |acc, ws| {
                let bs = (ws.0.borrow(), ws.1.borrow());
                match acc {
                    Mismatch::None => {
                        if diff((&*bs.0, &*bs.1)) {
                            Mismatch::One((ws.0.clone(), ws.1.clone()))
                        } else {
                            Mismatch::None
                        }
                    },
                    Mismatch::One(best) => {
                        if diff((&*bs.0, &*bs.1)) {
                            Mismatch::Multiple
                        } else {
                            Mismatch::One(best)
                        }
                    },
                    Mismatch::Multiple => Mismatch::Multiple,
                }
            })
    }
    /*fn category_mismatch(messages: (MessageCell, MessageCell)) ->
        Mismatch<(InstanceCell, InstanceCell)> {
        Self::mismatch(messages, |ins| ins.0.category != ins.1.category)
    }

    fn word_mismatch(messages: (MessageCell, MessageCell)) ->
        Mismatch<(InstanceCell, InstanceCell)> {
        Self::mismatch(messages, |ins| ins.0.word != ins.1.word)
    }*/

    fn category_and_word_mismatch(messages: (MessageCell, MessageCell)) ->
        Mismatch<(InstanceCell, InstanceCell)> {
        Self::mismatch(messages, |ins| ins.0.word != ins.1.word && ins.0.category != ins.1.category)
    }
}

pointer_eq!(Message);

#[derive(Default)]
struct Category {
    instances: Vec<InstanceCell>,
    cocategories: Vec<CategoryCell>,
}

impl Category {
    fn merge(cs: (CategoryCell, CategoryCell)) -> CategoryCell {
        let cc = wrap(Self::default());
        {
            let clos = |cat: &CategoryCell| {
                for instance in cat.borrow().instances.iter().cloned() {
                    instance.borrow_mut().category = cc.clone();
                }
            };
            clos(&cs.0);
            clos(&cs.1);
            let mut ccm = cc.borrow_mut();
            ccm.instances.append(&mut cs.0.borrow_mut().instances);
            ccm.instances.append(&mut cs.1.borrow_mut().instances);
        }
        cc
    }
}

pointer_eq!(Category);

struct Word {
    name: String,
    instances: Vec<InstanceCell>,
}

pointer_eq!(Word);
<|endoftext|>


<commit_before>//! Tests specific definitions
use std::io::Write;
use std::iter::IntoIterator;
use std::slice::Iter;
use std::vec::IntoIter;

#[cfg(windows)]
use winapi;

use consts::KeyPress;
use ::error::ReadlineError;
use ::Result;
use super::{RawReader, Term};

pub type Mode = ();

pub fn enable_raw_mode() -> Result<Mode> {
    Ok(())
}
pub fn disable_raw_mode(_: Mode) -> Result<()> {
    Ok(())
}

impl<'a> RawReader for Iter<'a, KeyPress> {
    fn next_key(&mut self, _: bool) -> Result<KeyPress> {
        match self.next() {
            Some(key) => Ok(*key),
            None => Err(ReadlineError::Eof),
        }
    }
    #[cfg(unix)]
    fn next_char(&mut self) -> Result<char> {
        unimplemented!();
    }
}

impl RawReader for IntoIter<KeyPress> {
    fn next_key(&mut self, _: bool) -> Result<KeyPress> {
        match self.next() {
            Some(key) => Ok(key),
            None => Err(ReadlineError::Eof),
        }
    }
    #[cfg(unix)]
    fn next_char(&mut self) -> Result<char> {
        unimplemented!();
    }
}

pub type Terminal = DummyTerminal;

#[derive(Clone,Debug)]
pub struct DummyTerminal {
    pub keys: Vec<KeyPress>,
}

impl DummyTerminal {
    /// Create a RAW reader
    pub fn create_reader(&self) -> Result<IntoIter<KeyPress>> {
        Ok(self.keys.clone().into_iter())
    }

    #[cfg(windows)]
    pub fn get_console_screen_buffer_info(&self) -> Result<winapi::CONSOLE_SCREEN_BUFFER_INFO> {
        Ok(info)
    }

    #[cfg(windows)]
    pub fn set_console_cursor_position(&mut self, pos: winapi::COORD) -> Result<()> {
        Ok(())
    }

    #[cfg(windows)]
    pub fn fill_console_output_character(&mut self,
                                         length: winapi::DWORD,
                                         pos: winapi::COORD)
                                         -> Result<()> {
        Ok(())
    }
}

impl Term for DummyTerminal {
    fn new() -> DummyTerminal {
        DummyTerminal { keys: Vec::new() }
    }

    // Init checks:

    /// Check if current terminal can provide a rich line-editing user interface.
    fn is_unsupported(&self) -> bool {
        false
    }

    /// check if stdin is connected to a terminal.
    fn is_stdin_tty(&self) -> bool {
        true
    }

    // Interactive loop:

    /// Get the number of columns in the current terminal.
    fn get_columns(&self) -> usize {
        80
    }

    /// Get the number of rows in the current terminal.
    fn get_rows(&self) -> usize {
        24
    }

    /// Check if a SIGWINCH signal has been received
    fn sigwinch(&self) -> bool {
        false
    }

    /// Clear the screen. Used to handle ctrl+l
    fn clear_screen(&mut self, _: &mut Write) -> Result<()> {
        Ok(())
    }
}
<commit_msg>Fix Windows build<commit_after>//! Tests specific definitions
use std::io::Write;
use std::iter::IntoIterator;
use std::slice::Iter;
use std::vec::IntoIter;

#[cfg(windows)]
use winapi;

use consts::KeyPress;
use ::error::ReadlineError;
use ::Result;
use super::{RawReader, Term};

pub type Mode = ();

pub fn enable_raw_mode() -> Result<Mode> {
    Ok(())
}
pub fn disable_raw_mode(_: Mode) -> Result<()> {
    Ok(())
}

impl<'a> RawReader for Iter<'a, KeyPress> {
    fn next_key(&mut self, _: bool) -> Result<KeyPress> {
        match self.next() {
            Some(key) => Ok(*key),
            None => Err(ReadlineError::Eof),
        }
    }
    #[cfg(unix)]
    fn next_char(&mut self) -> Result<char> {
        unimplemented!();
    }
}

impl RawReader for IntoIter<KeyPress> {
    fn next_key(&mut self, _: bool) -> Result<KeyPress> {
        match self.next() {
            Some(key) => Ok(key),
            None => Err(ReadlineError::Eof),
        }
    }
    #[cfg(unix)]
    fn next_char(&mut self) -> Result<char> {
        unimplemented!();
    }
}

pub type Terminal = DummyTerminal;

#[derive(Clone,Debug)]
pub struct DummyTerminal {
    pub keys: Vec<KeyPress>,
}

impl DummyTerminal {
    /// Create a RAW reader
    pub fn create_reader(&self) -> Result<IntoIter<KeyPress>> {
        Ok(self.keys.clone().into_iter())
    }

    #[cfg(windows)]
    pub fn get_console_screen_buffer_info(&self) -> Result<winapi::CONSOLE_SCREEN_BUFFER_INFO> {
        let dw_size = winapi::COORD { X: 80, Y: 24 };
        let dw_cursor_osition = winapi::COORD { X: 0, Y: 0 };
        let sr_window = winapi::SMALL_RECT {
            Left: 0,
            Top: 0,
            Right: 0,
            Bottom: 0,
        };
        let info = winapi::CONSOLE_SCREEN_BUFFER_INFO {
            dwSize: dw_size,
            dwCursorPosition: dw_cursor_osition,
            wAttributes: 0,
            srWindow: sr_window,
            dwMaximumWindowSize: dw_size,
        };
        Ok(info)
    }

    #[cfg(windows)]
    pub fn set_console_cursor_position(&mut self, _: winapi::COORD) -> Result<()> {
        Ok(())
    }

    #[cfg(windows)]
    pub fn fill_console_output_character(&mut self,
                                         _: winapi::DWORD,
                                         _: winapi::COORD)
                                         -> Result<()> {
        Ok(())
    }
}

impl Term for DummyTerminal {
    fn new() -> DummyTerminal {
        DummyTerminal { keys: Vec::new() }
    }

    // Init checks:

    /// Check if current terminal can provide a rich line-editing user interface.
    fn is_unsupported(&self) -> bool {
        false
    }

    /// check if stdin is connected to a terminal.
    fn is_stdin_tty(&self) -> bool {
        true
    }

    // Interactive loop:

    /// Get the number of columns in the current terminal.
    fn get_columns(&self) -> usize {
        80
    }

    /// Get the number of rows in the current terminal.
    fn get_rows(&self) -> usize {
        24
    }

    /// Check if a SIGWINCH signal has been received
    fn sigwinch(&self) -> bool {
        false
    }

    /// Clear the screen. Used to handle ctrl+l
    fn clear_screen(&mut self, _: &mut Write) -> Result<()> {
        Ok(())
    }
}
<|endoftext|>


<commit_before>#[cfg(test)]
mod tests {
    extern crate env_logger;

    #[test]
    fn initialization_test() {
        env_logger::init().unwrap();
        ::Client::new(String::from("INSERT DISCORD BOT TOKEN HERE"), |message| {
            match message {
                "oh" => Some(String::from("ok")),
                _ => None
            }
        });
    }
}
<commit_msg>test that makes a bit more sense<commit_after>#[cfg(test)]
mod tests {
    extern crate env_logger;

    #[test]
    fn bot_test() {
        env_logger::init().unwrap();
        ::Client::new(String::from("INSERT DISCORD BOT TOKEN HERE"), |message| {
            match message {
                "ping" => Some(String::from("pong")),
                _ => None
            }
        });
    }
}
<|endoftext|>


<commit_before>use ui;
use ui::ncurses::*;
use ui::{CMD_ENTRY_HEIGHT, Window, Size, Position};
use std::cmp;

pub struct CommandEntry {
    parent: Window,
    child:  Window,
}

// char::is_control() checks for escape sequences,
// so we need to use our own version that works with ncurse's keypad() function
fn is_control_char(ch: char) -> bool {
    let ch = ch as i32;
    ch >= KEY_MIN && ch <= KEY_MAX
}

impl CommandEntry {
    pub fn new(size: Size) -> CommandEntry {
        let parent = newwin(CMD_ENTRY_HEIGHT,
                            size.width,
                            size.height - CMD_ENTRY_HEIGHT,
                            0);
        box_(parent, 0, 0);
        wrefresh(parent);

        let child = derwin(parent,
                           CMD_ENTRY_HEIGHT - 2,
                           size.width - 2,
                           1,
                           1);
        scrollok(child, true);
        keypad(child, true);

        CommandEntry {
            parent: Window::new(parent),
            child:  Window::new(child),
        }
    }

    pub fn read_input_char(&self) -> Option<char> {
        match wgetch(self.child.id) {
            -1 => None,
            i  => ::std::char::from_u32(i as u32),
        }
    }

    fn move_cursor(&self, x_pos: i32) {
        wmove(self.child.id, 0, cmp::max(x_pos, 0));
        wrefresh(self.child.id);
    }

    pub fn process_char(&self, ch: char) {
        if is_control_char(ch) {
            match ch as i32 {
                KEY_BACKSPACE => self.backspace_key(),
                KEY_HOME      => self.move_cursor(0),
                KEY_DC        => self.delete_key(),
                _             => (),
            }
        } else {
            wechochar(self.child.id, ch as u32);
        }
    }

    fn delete_char_at(&self, index: i32) {
        self.move_cursor(index);

        wdelch(self.child.id);
        wrefresh(self.child.id);
    }

    fn backspace_key(&self) {
        let Position { x, .. } = ui::get_cursor_pos(self.child.id);

        if x > 0 {
            self.delete_char_at(x - 1);
        }
    }

    fn delete_key(&self) {
        let Position { x, .. } = ui::get_cursor_pos(self.child.id);
        self.delete_char_at(x);
    }
}<commit_msg>Fix bad grammar<commit_after>use ui;
use ui::ncurses::*;
use ui::{CMD_ENTRY_HEIGHT, Window, Size, Position};
use std::cmp;

pub struct CommandEntry {
    parent: Window,
    child:  Window,
}

// char::is_control() checks for escape sequences,
// so we need to use our own version that works with ncurses' keypad() function
fn is_control_char(ch: char) -> bool {
    let ch = ch as i32;
    ch >= KEY_MIN && ch <= KEY_MAX
}

impl CommandEntry {
    pub fn new(size: Size) -> CommandEntry {
        let parent = newwin(CMD_ENTRY_HEIGHT,
                            size.width,
                            size.height - CMD_ENTRY_HEIGHT,
                            0);
        box_(parent, 0, 0);
        wrefresh(parent);

        let child = derwin(parent,
                           CMD_ENTRY_HEIGHT - 2,
                           size.width - 2,
                           1,
                           1);
        scrollok(child, true);
        keypad(child, true);

        CommandEntry {
            parent: Window::new(parent),
            child:  Window::new(child),
        }
    }

    pub fn read_input_char(&self) -> Option<char> {
        match wgetch(self.child.id) {
            -1 => None,
            i  => ::std::char::from_u32(i as u32),
        }
    }

    fn move_cursor(&self, x_pos: i32) {
        wmove(self.child.id, 0, cmp::max(x_pos, 0));
        wrefresh(self.child.id);
    }

    pub fn process_char(&self, ch: char) {
        if is_control_char(ch) {
            match ch as i32 {
                KEY_BACKSPACE => self.backspace_key(),
                KEY_HOME      => self.move_cursor(0),
                KEY_DC        => self.delete_key(),
                _             => (),
            }
        } else {
            wechochar(self.child.id, ch as u32);
        }
    }

    fn delete_char_at(&self, index: i32) {
        self.move_cursor(index);

        wdelch(self.child.id);
        wrefresh(self.child.id);
    }

    fn backspace_key(&self) {
        let Position { x, .. } = ui::get_cursor_pos(self.child.id);

        if x > 0 {
            self.delete_char_at(x - 1);
        }
    }

    fn delete_key(&self) {
        let Position { x, .. } = ui::get_cursor_pos(self.child.id);
        self.delete_char_at(x);
    }
}<|endoftext|>


<commit_before>#![allow(dead_code)]

use crate::{Command, Entry, Result, Signal, Slot};
use arrayvec::ArrayVec;
#[cfg(feature = "chrono")]
use chrono::{DateTime, TimeZone};
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};

#[cfg_attr(
    feature = "serde",
    derive(Serialize, Deserialize),
    serde(bound(serialize = "C: Serialize", deserialize = "C: Deserialize<'de>"))
)]
#[derive(Clone)]
pub struct Timeline<C, F = fn(Signal)> {
    entries: ArrayVec<[Entry<C>; 32]>,
    current: usize,
    saved: Option<usize>,
    slot: Slot<F>,
}

impl<C> Timeline<C> {
    pub fn new() -> Timeline<C> {
        Builder::new().build()
    }
}

impl<C, F> Timeline<C, F> {
    pub fn len(&self) -> usize {
        self.entries.len()
    }

    pub fn is_empty(&self) -> bool {
        self.entries.is_empty()
    }

    pub fn limit(&self) -> usize {
        self.entries.capacity()
    }

    pub fn connect(&mut self, slot: F) -> Option<F> {
        self.slot.f.replace(slot)
    }

    pub fn disconnect(&mut self) -> Option<F> {
        self.slot.f.take()
    }

    pub fn can_undo(&self) -> bool {
        self.current() > 0
    }

    pub fn can_redo(&self) -> bool {
        self.current() < self.len()
    }

    pub fn is_saved(&self) -> bool {
        self.saved.map_or(false, |saved| saved == self.current())
    }

    pub fn current(&self) -> usize {
        self.current
    }
}

impl<C: Command, F: FnMut(Signal)> Timeline<C, F> {
    pub fn apply(&mut self, _: &mut C::Target, _: C) -> Result<C> {
        unimplemented!()
    }

    pub fn undo(&mut self, _: &mut C::Target) -> Result<C> {
        unimplemented!()
    }

    pub fn redo(&mut self, _: &mut C::Target) -> Result<C> {
        unimplemented!()
    }

    pub fn go_to(&mut self, _: &mut C::Target, _: usize) -> Option<Result<C>> {
        unimplemented!()
    }

    #[cfg(feature = "chrono")]
    pub fn time_travel(
        &mut self,
        _: &mut C::Target,
        _: &DateTime<impl TimeZone>,
    ) -> Option<Result<C>> {
        unimplemented!()
    }
}

pub struct Builder<F = fn(Signal)> {
    saved: bool,
    slot: Slot<F>,
}

impl<F> Builder<F> {
    pub fn new() -> Builder<F> {
        Builder {
            saved: true,
            slot: Slot::default(),
        }
    }

    pub fn saved(mut self, saved: bool) -> Builder<F> {
        self.saved = saved;
        self
    }

    pub fn build<C>(self) -> Timeline<C, F> {
        Timeline {
            entries: ArrayVec::new(),
            current: 0,
            saved: if self.saved { Some(0) } else { None },
            slot: self.slot,
        }
    }
}

impl<F: FnMut(Signal)> Builder<F> {
    pub fn connect(mut self, f: F) -> Builder<F> {
        self.slot = Slot::from(f);
        self
    }
}

impl Default for Builder {
    fn default() -> Self {
        Builder::new()
    }
}
<commit_msg>Implement Debug for Timeline<commit_after>#![allow(dead_code)]

use crate::{Command, Entry, Result, Signal, Slot};
use arrayvec::ArrayVec;
#[cfg(feature = "chrono")]
use chrono::{DateTime, TimeZone};
use core::fmt;
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};

#[cfg_attr(
    feature = "serde",
    derive(Serialize, Deserialize),
    serde(bound(serialize = "C: Serialize", deserialize = "C: Deserialize<'de>"))
)]
#[derive(Clone)]
pub struct Timeline<C, F = fn(Signal)> {
    entries: ArrayVec<[Entry<C>; 32]>,
    current: usize,
    saved: Option<usize>,
    slot: Slot<F>,
}

impl<C> Timeline<C> {
    pub fn new() -> Timeline<C> {
        Builder::new().build()
    }
}

impl<C, F> Timeline<C, F> {
    pub fn len(&self) -> usize {
        self.entries.len()
    }

    pub fn is_empty(&self) -> bool {
        self.entries.is_empty()
    }

    pub fn limit(&self) -> usize {
        self.entries.capacity()
    }

    pub fn connect(&mut self, slot: F) -> Option<F> {
        self.slot.f.replace(slot)
    }

    pub fn disconnect(&mut self) -> Option<F> {
        self.slot.f.take()
    }

    pub fn can_undo(&self) -> bool {
        self.current() > 0
    }

    pub fn can_redo(&self) -> bool {
        self.current() < self.len()
    }

    pub fn is_saved(&self) -> bool {
        self.saved.map_or(false, |saved| saved == self.current())
    }

    pub fn current(&self) -> usize {
        self.current
    }
}

impl<C: Command, F: FnMut(Signal)> Timeline<C, F> {
    pub fn apply(&mut self, _: &mut C::Target, _: C) -> Result<C> {
        unimplemented!()
    }

    pub fn undo(&mut self, _: &mut C::Target) -> Result<C> {
        unimplemented!()
    }

    pub fn redo(&mut self, _: &mut C::Target) -> Result<C> {
        unimplemented!()
    }

    pub fn go_to(&mut self, _: &mut C::Target, _: usize) -> Option<Result<C>> {
        unimplemented!()
    }

    #[cfg(feature = "chrono")]
    pub fn time_travel(
        &mut self,
        _: &mut C::Target,
        _: &DateTime<impl TimeZone>,
    ) -> Option<Result<C>> {
        unimplemented!()
    }
}

impl<C: fmt::Debug, F> fmt::Debug for Timeline<C, F> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("Timeline")
            .field("entries", &self.entries)
            .field("current", &self.current)
            .field("saved", &self.saved)
            .field("slot", &self.slot)
            .finish()
    }
}

pub struct Builder<F = fn(Signal)> {
    saved: bool,
    slot: Slot<F>,
}

impl<F> Builder<F> {
    pub fn new() -> Builder<F> {
        Builder {
            saved: true,
            slot: Slot::default(),
        }
    }

    pub fn saved(mut self, saved: bool) -> Builder<F> {
        self.saved = saved;
        self
    }

    pub fn build<C>(self) -> Timeline<C, F> {
        Timeline {
            entries: ArrayVec::new(),
            current: 0,
            saved: if self.saved { Some(0) } else { None },
            slot: self.slot,
        }
    }
}

impl<F: FnMut(Signal)> Builder<F> {
    pub fn connect(mut self, f: F) -> Builder<F> {
        self.slot = Slot::from(f);
        self
    }
}

impl Default for Builder {
    fn default() -> Self {
        Builder::new()
    }
}
<|endoftext|>