<commit_before>use super::mpz::{mpz_struct, Mpz, mpz_ptr, mpz_srcptr};
use super::mpf::{Mpf, mpf_srcptr};
use ffi::*;
use libc::{c_double, c_int, c_ulong};
use std::convert::{From, Into};
use std::mem::uninitialized;
use std::fmt;
use std::cmp::Ordering::{self, Greater, Less, Equal};
use std::ops::{Div, DivAssign, Mul, MulAssign, Add, AddAssign, Sub, SubAssign, Neg};

#[repr(C)]
pub struct mpq_struct {
    _mp_num: mpz_struct,
    _mp_den: mpz_struct
}

pub type mpq_srcptr = *const mpq_struct;
pub type mpq_ptr = *mut mpq_struct;

#[link(name = "gmp")]
extern "C" {
    fn __gmpq_init(x: mpq_ptr);
    fn __gmpq_clear(x: mpq_ptr);
    fn __gmpq_set(rop: mpq_ptr, op: mpq_srcptr);
    fn __gmpq_set_z(rop: mpq_ptr, op: mpz_srcptr);
    fn __gmpq_set_ui(rop: mpq_ptr, op1: c_ulong, op2: c_ulong);
    fn __gmpq_set_d(rop: mpq_ptr, op: c_double);
    fn __gmpq_set_f(rop: mpq_ptr, op: mpf_srcptr);
    fn __gmpq_cmp(op1: mpq_srcptr, op2: mpq_srcptr) -> c_int;
    fn __gmpq_cmp_ui(op1: mpq_srcptr, num2: c_ulong, den2: c_ulong) -> c_int;
    fn __gmpq_equal(op1: mpq_srcptr, op2: mpq_srcptr) -> c_int;
    fn __gmpq_add(sum: mpq_ptr, addend1: mpq_srcptr, addend2: mpq_srcptr);
    fn __gmpq_sub(difference: mpq_ptr, minuend: mpq_srcptr, subtrahend: mpq_srcptr);
    fn __gmpq_mul(product: mpq_ptr, multiplier: mpq_srcptr, multiplicand: mpq_srcptr);
    fn __gmpq_div(product: mpq_ptr, multiplier: mpq_srcptr, multiplicand: mpq_srcptr);
    fn __gmpq_neg(negated_operand: mpq_ptr, operand: mpq_srcptr);
    fn __gmpq_abs(rop: mpq_ptr, op: mpq_srcptr);
    fn __gmpq_inv(inverted_number: mpq_ptr, number: mpq_srcptr);
    fn __gmpq_get_num(numerator: mpz_ptr, rational: mpq_srcptr);
    fn __gmpq_get_den(denominator: mpz_ptr, rational: mpq_srcptr);
    fn __gmpq_set_num(rational: mpq_ptr, numerator: mpz_srcptr);
    fn __gmpq_set_den(rational: mpq_ptr, denominator: mpz_srcptr);
    fn __gmpq_canonicalize(rational: mpq_ptr);
    fn __gmpq_get_d(rational: mpq_srcptr) -> c_double;
}

pub struct Mpq {
    mpq: mpq_struct,
}

unsafe impl Send for Mpq { }

impl Drop for Mpq {
    fn drop(&mut self) { unsafe { __gmpq_clear(&mut self.mpq) } }
}

impl Mpq {
    pub unsafe fn inner(&self) -> mpq_srcptr {
        &self.mpq
    }

    pub unsafe fn inner_mut(&mut self) -> mpq_ptr {
        &mut self.mpq
    }

    pub fn new() -> Mpq {
        unsafe {
            let mut mpq = uninitialized();
            __gmpq_init(&mut mpq);
            Mpq { mpq: mpq }
        }
    }

    pub fn ratio(num: &Mpz, den: &Mpz) -> Mpq {
        unsafe {
            let mut res = Mpq::new();
            __gmpq_set_num(&mut res.mpq, num.inner());
            __gmpq_set_den(&mut res.mpq, den.inner());
            res
        }
    }

    pub fn canonicalize(&mut self) {
        unsafe {
            __gmpq_canonicalize(&mut self.mpq);
        }
    }

    pub fn set(&mut self, other: &Mpq) {
        unsafe { __gmpq_set(&mut self.mpq, &other.mpq) }
    }

    pub fn set_z(&mut self, other: &Mpz) {
        unsafe { __gmpq_set_z(&mut self.mpq, other.inner()) }
    }

    pub fn set_d(&mut self, other: f64) {
        unsafe { __gmpq_set_d(&mut self.mpq, other) }
    }

    pub fn set_f(&mut self, other: &Mpf) {
        unsafe { __gmpq_set_f(&mut self.mpq, other.inner()) }
    }

    pub fn get_num(&self) -> Mpz {
        unsafe {
            let mut res = Mpz::new();
            __gmpq_get_num(res.inner_mut(), &self.mpq);
            res
        }
    }

    pub fn get_den(&self) -> Mpz {
        unsafe {
            let mut res = Mpz::new();
            __gmpq_get_den(res.inner_mut(), &self.mpq);
            res
        }
    }

    pub fn abs(&self) -> Mpq {
        unsafe {
            let mut res = Mpq::new();
            __gmpq_abs(&mut res.mpq, &self.mpq);
            res
        }
    }

    pub fn invert(&self) -> Mpq {
        unsafe {
            if self.is_zero() {
                panic!("divide by zero")
            }

            let mut res = Mpq::new();
            __gmpq_inv(&mut res.mpq, &self.mpq);
            res
        }
    }

    pub fn floor(&self) -> Mpz {
        let mut res = Mpz::new();
        unsafe {
            __gmpz_fdiv_q(res.inner_mut(), &self.mpq._mp_num, &self.mpq._mp_den);
        }
        res
    }

    pub fn ceil(&self) -> Mpz {
        let mut res = Mpz::new();
        unsafe {
            __gmpz_cdiv_q(res.inner_mut(), &self.mpq._mp_num, &self.mpq._mp_den);
        }
        res
    }

    pub fn one() -> Mpq {
        let mut res = Mpq::new();
        unsafe { __gmpq_set_ui(&mut res.mpq, 1, 1) }
        res
    }

    pub fn zero() -> Mpq { Mpq::new() }
    pub fn is_zero(&self) -> bool {
        unsafe { __gmpq_cmp_ui(&self.mpq, 0, 1) == 0 }
    }
}

impl Clone for Mpq {
    fn clone(&self) -> Mpq {
        let mut res = Mpq::new();
        res.set(self);
        res
    }
}

impl Eq for Mpq { }
impl PartialEq for Mpq {
    fn eq(&self, other: &Mpq) -> bool {
        unsafe { __gmpq_equal(&self.mpq, &other.mpq) != 0 }
    }
}

impl Ord for Mpq {
    fn cmp(&self, other: &Mpq) -> Ordering {
        let cmp = unsafe { __gmpq_cmp(&self.mpq, &other.mpq) };
        if cmp == 0 {
            Equal
        } else if cmp < 0 {
            Less
        } else {
            Greater
        }
    }
}
impl PartialOrd for Mpq {
    fn partial_cmp(&self, other: &Mpq) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

macro_rules! div_guard {
    (Div, $what: expr) => {
        if $what.is_zero() {
            panic!("divide by zero")
        }
    };
    ($tr: ident, $what: expr) => {}
}

macro_rules! impl_oper {
    ($tr: ident, $meth: ident, $tr_assign: ident, $meth_assign: ident, $fun: ident) => {
        impl $tr<Mpq> for Mpq {
            type Output = Mpq;
            #[inline]
            fn $meth(self, other: Mpq) -> Mpq {
                self.$meth(&other)
            }
        }

        impl<'a> $tr<&'a Mpq> for Mpq {
            type Output = Mpq;
            #[inline]
            fn $meth(mut self, other: &Mpq) -> Mpq {
                self.$meth_assign(other);
                self
            }
        }

        impl<'a> $tr<Mpq> for &'a Mpq {
            type Output = Mpq;
            #[inline]
            fn $meth(self, mut other: Mpq) -> Mpq {
                unsafe {
                    div_guard!($tr, other);
                    $fun(&mut other.mpq, &self.mpq, &other.mpq);
                    other
                }
            }
        }

        impl<'a, 'b> $tr<&'a Mpq> for &'b Mpq {
            type Output = Mpq;
            fn $meth(self, other: &Mpq) -> Mpq {
                unsafe {
                    div_guard!($tr, *other);
                    let mut res = Mpq::new();
                    $fun(&mut res.mpq, &self.mpq, &other.mpq);
                    res
                }
            }
        }

        impl<'a> $tr_assign<Mpq> for Mpq {
            #[inline]
            fn $meth_assign(&mut self, other: Mpq) {
                self.$meth_assign(&other)
            }
        }

        impl<'a> $tr_assign<&'a Mpq> for Mpq {
            #[inline]
            fn $meth_assign(&mut self, other: &Mpq) {
                unsafe {
                    div_guard!($tr, *other);
                    $fun(&mut self.mpq, &self.mpq, &other.mpq)
                }
            }
        }
    }
}

impl_oper!(Add, add, AddAssign, add_assign, __gmpq_add);
impl_oper!(Sub, sub, SubAssign, sub_assign, __gmpq_sub);
impl_oper!(Mul, mul, MulAssign, mul_assign, __gmpq_mul);
impl_oper!(Div, div, DivAssign, div_assign, __gmpq_div);

impl<'b> Neg for &'b Mpq {
    type Output = Mpq;
    fn neg(self) -> Mpq {
        unsafe {
            let mut res = Mpq::new();
            __gmpq_neg(&mut res.mpq, &self.mpq);
            res
        }
    }
}

impl Neg for Mpq {
    type Output = Mpq;
    #[inline]
    fn neg(mut self) -> Mpq {
        unsafe {
            __gmpq_neg(&mut self.mpq, &self.mpq);
            self
        }
    }
}

impl Into<Option<i64>> for Mpq {
    fn into(self) -> Option<i64> {
        panic!("not implemented")
    }
}

impl Into<Option<u64>> for Mpq {
    fn into(self) -> Option<u64> {
        panic!("not implemented")
    }
}

impl Into<f64> for Mpq {
    fn into(self) -> f64 {
        unsafe {
            __gmpq_get_d(&self.mpq) as f64
        }
    }
}

impl From<Mpz> for Mpq {
    fn from(other: Mpz) -> Mpq {
        let mut res = Mpq::new();
        res.set_z(&other);
        res
    }
}

impl From<i64> for Mpq {
    fn from(other: i64) -> Mpq {
        From::<Mpz>::from(From::<i64>::from(other))
    }
}

impl From<i32> for Mpq {
    fn from(other: i32) -> Mpq {
        From::<Mpz>::from(From::<i32>::from(other))
    }
}

impl From<u64> for Mpq {
    fn from(other: u64) -> Mpq {
        From::<Mpz>::from(From::<u64>::from(other))
    }
}

impl From<u32> for Mpq {
    fn from(other: u32) -> Mpq {
        From::<Mpz>::from(From::<u32>::from(other))
    }
}

impl fmt::Debug for Mpq {
    /// Renders as `numer/denom`. If denom=1, renders as numer.
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let numer = self.get_num();
        let denom = self.get_den();

        if denom == From::<i64>::from(1) {
            write!(f, "{}", numer)
        } else {
            write!(f, "{}/{}", numer, denom)
        }
    }
}
<commit_msg>Mpq: Remove implementations whose only purpose is to panic<commit_after>use super::mpz::{mpz_struct, Mpz, mpz_ptr, mpz_srcptr};
use super::mpf::{Mpf, mpf_srcptr};
use ffi::*;
use libc::{c_double, c_int, c_ulong};
use std::convert::{From, Into};
use std::mem::uninitialized;
use std::fmt;
use std::cmp::Ordering::{self, Greater, Less, Equal};
use std::ops::{Div, DivAssign, Mul, MulAssign, Add, AddAssign, Sub, SubAssign, Neg};

#[repr(C)]
pub struct mpq_struct {
    _mp_num: mpz_struct,
    _mp_den: mpz_struct
}

pub type mpq_srcptr = *const mpq_struct;
pub type mpq_ptr = *mut mpq_struct;

#[link(name = "gmp")]
extern "C" {
    fn __gmpq_init(x: mpq_ptr);
    fn __gmpq_clear(x: mpq_ptr);
    fn __gmpq_set(rop: mpq_ptr, op: mpq_srcptr);
    fn __gmpq_set_z(rop: mpq_ptr, op: mpz_srcptr);
    fn __gmpq_set_ui(rop: mpq_ptr, op1: c_ulong, op2: c_ulong);
    fn __gmpq_set_d(rop: mpq_ptr, op: c_double);
    fn __gmpq_set_f(rop: mpq_ptr, op: mpf_srcptr);
    fn __gmpq_cmp(op1: mpq_srcptr, op2: mpq_srcptr) -> c_int;
    fn __gmpq_cmp_ui(op1: mpq_srcptr, num2: c_ulong, den2: c_ulong) -> c_int;
    fn __gmpq_equal(op1: mpq_srcptr, op2: mpq_srcptr) -> c_int;
    fn __gmpq_add(sum: mpq_ptr, addend1: mpq_srcptr, addend2: mpq_srcptr);
    fn __gmpq_sub(difference: mpq_ptr, minuend: mpq_srcptr, subtrahend: mpq_srcptr);
    fn __gmpq_mul(product: mpq_ptr, multiplier: mpq_srcptr, multiplicand: mpq_srcptr);
    fn __gmpq_div(product: mpq_ptr, multiplier: mpq_srcptr, multiplicand: mpq_srcptr);
    fn __gmpq_neg(negated_operand: mpq_ptr, operand: mpq_srcptr);
    fn __gmpq_abs(rop: mpq_ptr, op: mpq_srcptr);
    fn __gmpq_inv(inverted_number: mpq_ptr, number: mpq_srcptr);
    fn __gmpq_get_num(numerator: mpz_ptr, rational: mpq_srcptr);
    fn __gmpq_get_den(denominator: mpz_ptr, rational: mpq_srcptr);
    fn __gmpq_set_num(rational: mpq_ptr, numerator: mpz_srcptr);
    fn __gmpq_set_den(rational: mpq_ptr, denominator: mpz_srcptr);
    fn __gmpq_canonicalize(rational: mpq_ptr);
    fn __gmpq_get_d(rational: mpq_srcptr) -> c_double;
}

pub struct Mpq {
    mpq: mpq_struct,
}

unsafe impl Send for Mpq { }

impl Drop for Mpq {
    fn drop(&mut self) { unsafe { __gmpq_clear(&mut self.mpq) } }
}

impl Mpq {
    pub unsafe fn inner(&self) -> mpq_srcptr {
        &self.mpq
    }

    pub unsafe fn inner_mut(&mut self) -> mpq_ptr {
        &mut self.mpq
    }

    pub fn new() -> Mpq {
        unsafe {
            let mut mpq = uninitialized();
            __gmpq_init(&mut mpq);
            Mpq { mpq: mpq }
        }
    }

    pub fn ratio(num: &Mpz, den: &Mpz) -> Mpq {
        unsafe {
            let mut res = Mpq::new();
            __gmpq_set_num(&mut res.mpq, num.inner());
            __gmpq_set_den(&mut res.mpq, den.inner());
            res
        }
    }

    pub fn canonicalize(&mut self) {
        unsafe {
            __gmpq_canonicalize(&mut self.mpq);
        }
    }

    pub fn set(&mut self, other: &Mpq) {
        unsafe { __gmpq_set(&mut self.mpq, &other.mpq) }
    }

    pub fn set_z(&mut self, other: &Mpz) {
        unsafe { __gmpq_set_z(&mut self.mpq, other.inner()) }
    }

    pub fn set_d(&mut self, other: f64) {
        unsafe { __gmpq_set_d(&mut self.mpq, other) }
    }

    pub fn set_f(&mut self, other: &Mpf) {
        unsafe { __gmpq_set_f(&mut self.mpq, other.inner()) }
    }

    pub fn get_num(&self) -> Mpz {
        unsafe {
            let mut res = Mpz::new();
            __gmpq_get_num(res.inner_mut(), &self.mpq);
            res
        }
    }

    pub fn get_den(&self) -> Mpz {
        unsafe {
            let mut res = Mpz::new();
            __gmpq_get_den(res.inner_mut(), &self.mpq);
            res
        }
    }

    pub fn abs(&self) -> Mpq {
        unsafe {
            let mut res = Mpq::new();
            __gmpq_abs(&mut res.mpq, &self.mpq);
            res
        }
    }

    pub fn invert(&self) -> Mpq {
        unsafe {
            if self.is_zero() {
                panic!("divide by zero")
            }

            let mut res = Mpq::new();
            __gmpq_inv(&mut res.mpq, &self.mpq);
            res
        }
    }

    pub fn floor(&self) -> Mpz {
        let mut res = Mpz::new();
        unsafe {
            __gmpz_fdiv_q(res.inner_mut(), &self.mpq._mp_num, &self.mpq._mp_den);
        }
        res
    }

    pub fn ceil(&self) -> Mpz {
        let mut res = Mpz::new();
        unsafe {
            __gmpz_cdiv_q(res.inner_mut(), &self.mpq._mp_num, &self.mpq._mp_den);
        }
        res
    }

    pub fn one() -> Mpq {
        let mut res = Mpq::new();
        unsafe { __gmpq_set_ui(&mut res.mpq, 1, 1) }
        res
    }

    pub fn zero() -> Mpq { Mpq::new() }
    pub fn is_zero(&self) -> bool {
        unsafe { __gmpq_cmp_ui(&self.mpq, 0, 1) == 0 }
    }
}

impl Clone for Mpq {
    fn clone(&self) -> Mpq {
        let mut res = Mpq::new();
        res.set(self);
        res
    }
}

impl Eq for Mpq { }
impl PartialEq for Mpq {
    fn eq(&self, other: &Mpq) -> bool {
        unsafe { __gmpq_equal(&self.mpq, &other.mpq) != 0 }
    }
}

impl Ord for Mpq {
    fn cmp(&self, other: &Mpq) -> Ordering {
        let cmp = unsafe { __gmpq_cmp(&self.mpq, &other.mpq) };
        if cmp == 0 {
            Equal
        } else if cmp < 0 {
            Less
        } else {
            Greater
        }
    }
}
impl PartialOrd for Mpq {
    fn partial_cmp(&self, other: &Mpq) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

macro_rules! div_guard {
    (Div, $what: expr) => {
        if $what.is_zero() {
            panic!("divide by zero")
        }
    };
    ($tr: ident, $what: expr) => {}
}

macro_rules! impl_oper {
    ($tr: ident, $meth: ident, $tr_assign: ident, $meth_assign: ident, $fun: ident) => {
        impl $tr<Mpq> for Mpq {
            type Output = Mpq;
            #[inline]
            fn $meth(self, other: Mpq) -> Mpq {
                self.$meth(&other)
            }
        }

        impl<'a> $tr<&'a Mpq> for Mpq {
            type Output = Mpq;
            #[inline]
            fn $meth(mut self, other: &Mpq) -> Mpq {
                self.$meth_assign(other);
                self
            }
        }

        impl<'a> $tr<Mpq> for &'a Mpq {
            type Output = Mpq;
            #[inline]
            fn $meth(self, mut other: Mpq) -> Mpq {
                unsafe {
                    div_guard!($tr, other);
                    $fun(&mut other.mpq, &self.mpq, &other.mpq);
                    other
                }
            }
        }

        impl<'a, 'b> $tr<&'a Mpq> for &'b Mpq {
            type Output = Mpq;
            fn $meth(self, other: &Mpq) -> Mpq {
                unsafe {
                    div_guard!($tr, *other);
                    let mut res = Mpq::new();
                    $fun(&mut res.mpq, &self.mpq, &other.mpq);
                    res
                }
            }
        }

        impl<'a> $tr_assign<Mpq> for Mpq {
            #[inline]
            fn $meth_assign(&mut self, other: Mpq) {
                self.$meth_assign(&other)
            }
        }

        impl<'a> $tr_assign<&'a Mpq> for Mpq {
            #[inline]
            fn $meth_assign(&mut self, other: &Mpq) {
                unsafe {
                    div_guard!($tr, *other);
                    $fun(&mut self.mpq, &self.mpq, &other.mpq)
                }
            }
        }
    }
}

impl_oper!(Add, add, AddAssign, add_assign, __gmpq_add);
impl_oper!(Sub, sub, SubAssign, sub_assign, __gmpq_sub);
impl_oper!(Mul, mul, MulAssign, mul_assign, __gmpq_mul);
impl_oper!(Div, div, DivAssign, div_assign, __gmpq_div);

impl<'b> Neg for &'b Mpq {
    type Output = Mpq;
    fn neg(self) -> Mpq {
        unsafe {
            let mut res = Mpq::new();
            __gmpq_neg(&mut res.mpq, &self.mpq);
            res
        }
    }
}

impl Neg for Mpq {
    type Output = Mpq;
    #[inline]
    fn neg(mut self) -> Mpq {
        unsafe {
            __gmpq_neg(&mut self.mpq, &self.mpq);
            self
        }
    }
}

impl Into<f64> for Mpq {
    fn into(self) -> f64 {
        unsafe {
            __gmpq_get_d(&self.mpq) as f64
        }
    }
}

impl From<Mpz> for Mpq {
    fn from(other: Mpz) -> Mpq {
        let mut res = Mpq::new();
        res.set_z(&other);
        res
    }
}

impl From<i64> for Mpq {
    fn from(other: i64) -> Mpq {
        From::<Mpz>::from(From::<i64>::from(other))
    }
}

impl From<i32> for Mpq {
    fn from(other: i32) -> Mpq {
        From::<Mpz>::from(From::<i32>::from(other))
    }
}

impl From<u64> for Mpq {
    fn from(other: u64) -> Mpq {
        From::<Mpz>::from(From::<u64>::from(other))
    }
}

impl From<u32> for Mpq {
    fn from(other: u32) -> Mpq {
        From::<Mpz>::from(From::<u32>::from(other))
    }
}

impl fmt::Debug for Mpq {
    /// Renders as `numer/denom`. If denom=1, renders as numer.
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let numer = self.get_num();
        let denom = self.get_den();

        if denom == From::<i64>::from(1) {
            write!(f, "{}", numer)
        } else {
            write!(f, "{}/{}", numer, denom)
        }
    }
}
<|endoftext|>


<commit_before>extern crate orbclient;

use super::start;

#[derive(Debug, Clone, Copy)]
pub struct Color {
    pub r: u8,
    pub g: u8,
    pub b: u8,
}

impl Color {
    pub fn new(r: u8, g: u8, b: u8) -> Color {
        Color {
            r: r,
            g: g,
            b: b,
        }
    }

    pub fn orb_color(&self) -> orbclient::color::Color {
        orbclient::color::Color::rgb(self.r, self.g, self.b)
    }
}

#[derive(Clone, Copy, Debug)]
pub struct FlatPoint {
    pub x: i32,
    pub y: i32,
}

/*impl FlatPoint {
    pub fn make_sdl(&self) -> sdl2::rect::Point {
        sdl2::rect::Point::new(self.x, self.y)
    }
}*/

#[derive(Clone, Copy, Debug)]
pub struct DepthPoint {
    pub x: f32,
    pub y: f32,
    pub z: f32,

    pub x_y: f32,
    pub x_z: f32,
    pub y_z: f32,

    last_x_y: f32,
    last_x_z: f32,
    last_y_z: f32,
}

impl DepthPoint {
    pub fn new(x: f32, y: f32, z: f32) -> DepthPoint {
        DepthPoint {
            x: x,
            y: y,
            z: z,

            x_y: 0.0,
            x_z: 0.0,
            y_z: 0.0,

            last_x_y: 0.0,
            last_x_z: 0.0,
            last_y_z: 0.0,
        }
    }

    pub fn flat_point(&mut self, engine_scr_x: u32, engine_scr_y: u32, offset_x: f32, offset_y: f32, offset_z: f32) -> FlatPoint {
        if self.z > -0.01 && self.z < 0.0 {
            self.z = 0.001
        }

        else if self.z < 0.1 { // Prevents division by nearly 0, that cause integer overflow/underflow
            self.z = 0.11;
        }

        FlatPoint {
            x: ((engine_scr_x as f32 * (self.x + offset_x) as f32/(self.z + offset_z)) + engine_scr_x as f32 / 2.0) as i32,
            y: ((engine_scr_x as f32 * (self.y + offset_y) as f32/(self.z + offset_z)) + engine_scr_y as f32 / 2.0) as i32,
        }
    }

    pub fn apply_camera_rotations(&mut self, engine: &start::Window) {
        use std::f32::consts::PI;

        let x_y = self.x_y;
        let x_z = self.x_z;
        let y_z = self.y_z;

        let last_x_y = self.last_x_y;
        let last_x_z = self.last_x_z;
        let last_y_z = self.last_y_z;

        self.camera_rotate_x_y(&engine, x_y - last_x_y);
        self.camera_rotate_x_z(&engine, x_z - last_x_z);
        self.camera_rotate_y_z(&engine, y_z - last_y_z);

        self.last_x_y = x_y;
        self.last_x_z = x_z;
        self.last_y_z = y_z;

        //normalize rotations
        if self.x_z > (PI * 2.0) {
            self.x_z -= (PI * 2.0);
        }

        if self.x_y > (PI * 2.0) {
            self.x_y -= (PI * 2.0);
        }

        if self.y_z > (PI * 2.0) {
            self.y_z -= (PI * 2.0);
        }
    }

    pub fn camera_rotate_x_y(&mut self, engine: &start::Window, angle: f32) {
        use std::f32;
        let s = f32::sin(angle);
        let c = f32::cos(angle);

        self.x -= engine.camera_x;
        self.y -= engine.camera_y;

        let new_x = self.x * c - self.y * s;
        let new_y = self.x * s + self.y * c;

        self.x = new_x + engine.camera_x;
        self.y = new_y + engine.camera_y;
    }

    pub fn camera_rotate_x_z(&mut self, engine: &start::Window, angle: f32) {
        use std::f32;
        let s = f32::sin(angle);
        let c = f32::cos(angle);

        self.x -= engine.camera_x;
        self.z -= engine.camera_z;

        let new_x = self.x * c - self.z * s;
        let new_z = self.x * s + self.z * c;

        self.x = new_x + engine.camera_x;
        self.z = new_z + engine.camera_z;
    }

    pub fn camera_rotate_y_z(&mut self, engine: &start::Window, angle: f32) {
        use std::f32;
        let s = f32::sin(angle);
        let c = f32::cos(angle);

        self.y -= engine.camera_y;
        self.z -= engine.camera_z;

        let new_y = self.y * c - self.z * s;
        let new_z = self.y * s + self.z * c;

        self.y = new_y + engine.camera_y;
        self.z = new_z + engine.camera_z;
    }

    pub fn coord_rotate_x_y(&mut self, x: f32, y: f32, angle: f32) {
        use std::f32;
        let s = f32::sin(angle);
        let c = f32::cos(angle);

        self.x -= x;
        self.y -= y;

        let new_x = self.x * c - self.y * s;
        let new_y = self.x * s + self.y * c;

        self.x = new_x + x;
        self.y = new_y + y;
    }

    pub fn coord_rotate_x_z(&mut self, x: f32, z: f32, angle: f32) {
        use std::f32;
        let s = f32::sin(angle);
        let c = f32::cos(angle);

        self.x -= x;
        self.z -= z;

        let new_x = self.x * c - self.z * s;
        let new_z = self.x * s + self.z * c;

        self.x = new_x + x;
        self.z = new_z + z;
    }

    pub fn coord_rotate_y_z(&mut self, y: f32, z: f32, angle: f32) {
        use std::f32;
        let s = f32::sin(angle);
        let c = f32::cos(angle);

        self.y -= y;
        self.z -= z;

        let new_y = self.y * c - self.z * s;
        let new_z = self.y * s + self.z * c;

        self.y = new_y + y;
        self.z = new_z + z;
    }
}

#[derive(Clone, Copy, Debug)]
pub struct Triangle {
    pub p1: DepthPoint,
    pub p2: DepthPoint,
    pub p3: DepthPoint,

    pub x: f32,
    pub y: f32,
    pub z: f32,

    pub x_y: f32,
    pub x_z: f32,
    pub y_z: f32,

    pub color: Color,
}

impl Triangle {
    pub fn new(p1: DepthPoint, p2: DepthPoint, p3: DepthPoint, x: f32, y: f32, z: f32, color: Color) -> Triangle {
        Triangle {
            p1: p1,
            p2: p2,
            p3: p3,

            x: x,
            y: y,
            z: z,

            x_y: 0.0,
            x_z: 0.0,
            y_z: 0.0,

            color: color,
        }
    }

    pub fn apply_camera_rotations(&mut self, engine: &start::Window) {
        self.p1.x_y += self.x_y;
        self.p1.x_z += self.x_z;
        self.p1.y_z += self.y_z;

        self.p2.x_y += self.x_y;
        self.p2.x_z += self.x_z;
        self.p2.y_z += self.y_z;

        self.p3.x_y += self.x_y;
        self.p3.x_z += self.x_z;
        self.p3.y_z += self.y_z;

        self.p1.apply_camera_rotations(&engine);
        self.p2.apply_camera_rotations(&engine);
        self.p3.apply_camera_rotations(&engine);

        self.p1.x_y -= self.x_y;
        self.p1.x_z -= self.x_z;
        self.p1.y_z -= self.y_z;

        self.p2.x_y -= self.x_y;
        self.p2.x_z -= self.x_z;
        self.p2.y_z -= self.y_z;

        self.p3.x_y -= self.x_y;
        self.p3.x_z -= self.x_z;
        self.p3.y_z -= self.y_z;
    }
}

#[derive(Clone, Debug)]
pub struct TriangleGroup {
    pub triangles: Vec<Triangle>,
}

impl TriangleGroup {
    pub fn new(triangles: Vec<Triangle>) -> TriangleGroup {
        TriangleGroup {
            triangles: triangles
        }
    }
}
<commit_msg>Added rotation methods to triangle.<commit_after>extern crate orbclient;

use super::start;

#[derive(Debug, Clone, Copy)]
pub struct Color {
    pub r: u8,
    pub g: u8,
    pub b: u8,
}

impl Color {
    pub fn new(r: u8, g: u8, b: u8) -> Color {
        Color {
            r: r,
            g: g,
            b: b,
        }
    }

    pub fn orb_color(&self) -> orbclient::color::Color {
        orbclient::color::Color::rgb(self.r, self.g, self.b)
    }
}

#[derive(Clone, Copy, Debug)]
pub struct FlatPoint {
    pub x: i32,
    pub y: i32,
}

/*impl FlatPoint {
    pub fn make_sdl(&self) -> sdl2::rect::Point {
        sdl2::rect::Point::new(self.x, self.y)
    }
}*/

#[derive(Clone, Copy, Debug)]
pub struct DepthPoint {
    pub x: f32,
    pub y: f32,
    pub z: f32,

    pub x_y: f32,
    pub x_z: f32,
    pub y_z: f32,

    last_x_y: f32,
    last_x_z: f32,
    last_y_z: f32,
}

impl DepthPoint {
    pub fn new(x: f32, y: f32, z: f32) -> DepthPoint {
        DepthPoint {
            x: x,
            y: y,
            z: z,

            x_y: 0.0,
            x_z: 0.0,
            y_z: 0.0,

            last_x_y: 0.0,
            last_x_z: 0.0,
            last_y_z: 0.0,
        }
    }

    pub fn flat_point(&mut self, engine_scr_x: u32, engine_scr_y: u32, offset_x: f32, offset_y: f32, offset_z: f32) -> FlatPoint {
        if self.z > -0.01 && self.z < 0.0 {
            self.z = 0.001
        }

        else if self.z < 0.1 { // Prevents division by nearly 0, that cause integer overflow/underflow
            self.z = 0.11;
        }

        FlatPoint {
            x: ((engine_scr_x as f32 * (self.x + offset_x) as f32/(self.z + offset_z)) + engine_scr_x as f32 / 2.0) as i32,
            y: ((engine_scr_x as f32 * (self.y + offset_y) as f32/(self.z + offset_z)) + engine_scr_y as f32 / 2.0) as i32,
        }
    }

    pub fn apply_camera_rotations(&mut self, engine: &start::Window) {
        use std::f32::consts::PI;

        let x_y = self.x_y;
        let x_z = self.x_z;
        let y_z = self.y_z;

        let last_x_y = self.last_x_y;
        let last_x_z = self.last_x_z;
        let last_y_z = self.last_y_z;

        self.camera_rotate_x_y(&engine, x_y - last_x_y);
        self.camera_rotate_x_z(&engine, x_z - last_x_z);
        self.camera_rotate_y_z(&engine, y_z - last_y_z);

        self.last_x_y = x_y;
        self.last_x_z = x_z;
        self.last_y_z = y_z;

        //normalize rotations
        if self.x_z > (PI * 2.0) {
            self.x_z -= (PI * 2.0);
        }

        if self.x_y > (PI * 2.0) {
            self.x_y -= (PI * 2.0);
        }

        if self.y_z > (PI * 2.0) {
            self.y_z -= (PI * 2.0);
        }
    }

    pub fn camera_rotate_x_y(&mut self, engine: &start::Window, angle: f32) {
        use std::f32;
        let s = f32::sin(angle);
        let c = f32::cos(angle);

        self.x -= engine.camera_x;
        self.y -= engine.camera_y;

        let new_x = self.x * c - self.y * s;
        let new_y = self.x * s + self.y * c;

        self.x = new_x + engine.camera_x;
        self.y = new_y + engine.camera_y;
    }

    pub fn camera_rotate_x_z(&mut self, engine: &start::Window, angle: f32) {
        use std::f32;
        let s = f32::sin(angle);
        let c = f32::cos(angle);

        self.x -= engine.camera_x;
        self.z -= engine.camera_z;

        let new_x = self.x * c - self.z * s;
        let new_z = self.x * s + self.z * c;

        self.x = new_x + engine.camera_x;
        self.z = new_z + engine.camera_z;
    }

    pub fn camera_rotate_y_z(&mut self, engine: &start::Window, angle: f32) {
        use std::f32;
        let s = f32::sin(angle);
        let c = f32::cos(angle);

        self.y -= engine.camera_y;
        self.z -= engine.camera_z;

        let new_y = self.y * c - self.z * s;
        let new_z = self.y * s + self.z * c;

        self.y = new_y + engine.camera_y;
        self.z = new_z + engine.camera_z;
    }

    pub fn coord_rotate_x_y(&mut self, x: f32, y: f32, angle: f32) {
        use std::f32;
        let s = f32::sin(angle);
        let c = f32::cos(angle);

        self.x -= x;
        self.y -= y;

        let new_x = self.x * c - self.y * s;
        let new_y = self.x * s + self.y * c;

        self.x = new_x + x;
        self.y = new_y + y;
    }

    pub fn coord_rotate_x_z(&mut self, x: f32, z: f32, angle: f32) {
        use std::f32;
        let s = f32::sin(angle);
        let c = f32::cos(angle);

        self.x -= x;
        self.z -= z;

        let new_x = self.x * c - self.z * s;
        let new_z = self.x * s + self.z * c;

        self.x = new_x + x;
        self.z = new_z + z;
    }

    pub fn coord_rotate_y_z(&mut self, y: f32, z: f32, angle: f32) {
        use std::f32;
        let s = f32::sin(angle);
        let c = f32::cos(angle);

        self.y -= y;
        self.z -= z;

        let new_y = self.y * c - self.z * s;
        let new_z = self.y * s + self.z * c;

        self.y = new_y + y;
        self.z = new_z + z;
    }
}

#[derive(Clone, Copy, Debug)]
pub struct Triangle {
    pub p1: DepthPoint,
    pub p2: DepthPoint,
    pub p3: DepthPoint,

    pub x: f32,
    pub y: f32,
    pub z: f32,

    pub x_y: f32,
    pub x_z: f32,
    pub y_z: f32,

    pub color: Color,
}

impl Triangle {
    pub fn new(p1: DepthPoint, p2: DepthPoint, p3: DepthPoint, x: f32, y: f32, z: f32, color: Color) -> Triangle {
        Triangle {
            p1: p1,
            p2: p2,
            p3: p3,

            x: x,
            y: y,
            z: z,

            x_y: 0.0,
            x_z: 0.0,
            y_z: 0.0,

            color: color,
        }
    }

    pub fn apply_camera_rotations(&mut self, engine: &start::Window) {
        self.p1.x_y += self.x_y;
        self.p1.x_z += self.x_z;
        self.p1.y_z += self.y_z;

        self.p2.x_y += self.x_y;
        self.p2.x_z += self.x_z;
        self.p2.y_z += self.y_z;

        self.p3.x_y += self.x_y;
        self.p3.x_z += self.x_z;
        self.p3.y_z += self.y_z;

        self.p1.apply_camera_rotations(&engine);
        self.p2.apply_camera_rotations(&engine);
        self.p3.apply_camera_rotations(&engine);

        self.p1.x_y -= self.x_y;
        self.p1.x_z -= self.x_z;
        self.p1.y_z -= self.y_z;

        self.p2.x_y -= self.x_y;
        self.p2.x_z -= self.x_z;
        self.p2.y_z -= self.y_z;

        self.p3.x_y -= self.x_y;
        self.p3.x_z -= self.x_z;
        self.p3.y_z -= self.y_z;
    }

    pub fn coord_rotate_x_y(&mut self, x: f32, y: f32, angle: f32) {
        self.p1.coord_rotate_x_y(x, y, angle);
        self.p2.coord_rotate_x_y(x, y, angle);
        self.p3.coord_rotate_x_y(x, y, angle);
    }

    pub fn coord_rotate_x_z(&mut self, x: f32, z: f32, angle: f32) {
        self.p1.coord_rotate_x_z(x, z, angle);
        self.p2.coord_rotate_x_z(x, z, angle);
        self.p3.coord_rotate_x_z(x, z, angle);
    }

    pub fn coord_rotate_y_z(&mut self, y: f32, z: f32, angle: f32) {
        self.p1.coord_rotate_y_z(y, z, angle);
        self.p2.coord_rotate_y_z(y, z, angle);
        self.p3.coord_rotate_y_z(y, z, angle);
    }
}

#[derive(Clone, Debug)]
pub struct TriangleGroup {
    pub triangles: Vec<Triangle>,
}

impl TriangleGroup {
    pub fn new(triangles: Vec<Triangle>) -> TriangleGroup {
        TriangleGroup {
            triangles: triangles
        }
    }
}
<|endoftext|>


<commit_before>//! Rust bindings for [libressl](http://libressl.org)'s libtls
//!
//! For the authoritative source on the inner workings of libtls check
//! the [manpage](http://www.openbsd.org/cgi-bin/man.cgi/OpenBSD-current/man3/tls_accept_fds.3?query=tls_init&sec=3).
//!
//! This is a minimal wrapper around the API. For higher level APIs check the **net** module.
//!

extern crate tls_sys as ffi;
extern crate libc;

use std::ffi::{CStr, CString};
use libc::{c_char, time_t, c_void, size_t};
use std::ptr;
use std::error::Error;
use std::fmt;
use std::sync::{Once, ONCE_INIT};
use std::io;
use std::convert;
#[cfg(unix)]
use std::os::unix::io::IntoRawFd;
#[cfg(windows)]
use std::os::windows::io::IntoRawSocket;

mod util;

fn from_cstr(s: *const c_char) -> String {
    unsafe {
        if s == ptr::null_mut() {
            String::new()
        } else {
            let slice = CStr::from_ptr(s);
            String::from_utf8_lossy(slice.to_bytes()).into_owned()
        }
    }
}

/// Get C string ptr, but use NULL if the string is empty.
/// Because some C functions treat NULL and "\0" differently
fn str_c_ptr(s: &str) -> *const i8 {
    if s.is_empty() {
        ptr::null()
    } else {
        unsafe { CString::from_vec_unchecked(s.bytes().collect()).as_ptr() }
    }
}

/// A structure that represents all TLS context
///
/// This can be a client connection, a server, or a connection accepted by the server
pub struct TlsContext {
    ptr: ffi::Tls,
    cfg: Option<TlsConfig>,
}

impl TlsContext {
    /// Create a new client context
    pub fn new_client() -> Option<TlsContext> {
        let p = unsafe { ffi::tls_client() };
        if p == ptr::null_mut() {
            None
        } else {
            Some(TlsContext {
                ptr: p,
                cfg: None,
            })
        }
    }

    fn error(&self) -> String {
        unsafe { from_cstr(ffi::tls_error(self.ptr)) }
    }

    fn rv_to_result(&self, rv: i64) -> TlsResult<()> {
        if rv == 0 {
            Ok(())
        } else {
            Err(TlsError {
                msg: self.error(),
                code: rv,
            })
        }
    }

    /// If port is empty, the port value is assumed to be part of the hostname string as host:port.
    /// If servername is not empty it is used instead of the hostname for verification.
    pub fn connect_servername(&mut self,
                              hostname: &str,
                              port: &str,
                              servername: &str)
                              -> TlsResult<()> {
        let rv = unsafe {
            let hostname_c = CString::from_vec_unchecked(hostname.bytes().collect()).as_ptr();
            // Both port and servername can be NULL
            let port_c = str_c_ptr(port);
            let servername_c = str_c_ptr(servername);
            ffi::tls_connect_servername(self.ptr, hostname_c, port_c, servername_c)
        };
        self.rv_to_result(rv as i64)
    }

    #[cfg(unix)]
    /// Establish a TLS connection over the given socket
    pub fn connect_socket<F: IntoRawFd>(&mut self, fd: F, servername: &str) -> TlsResult<()> {
        let rv = unsafe {
            let servername_c = str_c_ptr(servername);
            ffi::tls_connect_socket(self.ptr, fd.into_raw_fd(), servername_c)
        };
        self.rv_to_result(rv as i64)
    }

    #[cfg(windows)]
    /// Establish a TLS connection over the given socket
    pub fn connect_socket<F: IntoRawSocket>(&mut self, fd: F, servername: &str) -> TlsResult<()> {
        let rv = unsafe {
            let servername_c = str_c_ptr(servername);
            // This cast is not exactly safe
            // http://stackoverflow.com/questions/1953639/
            ffi::tls_connect_socket(self.ptr, fd.into_raw_socket() as i32, servername_c)
        };
        self.rv_to_result(rv as i64)
    }

    pub fn conn_version(&self) -> String {
        unsafe { from_cstr(ffi::tls_conn_version(self.ptr)) }
    }
    pub fn conn_cipher(&self) -> String {
        unsafe { from_cstr(ffi::tls_conn_version(self.ptr)) }
    }

    /// Apply configuration settings to the context, consuming the config struct
    ///
    /// This should be called BEFORE trying to establish/accept
    /// a connection
    pub fn configure(&mut self, cfg: TlsConfig) -> TlsResult<()> {
        let rv = unsafe { ffi::tls_configure(self.ptr, cfg.cfg) };
        self.cfg = Some(cfg);
        self.rv_to_result(rv as i64)
    }

    pub fn peer_cert_notbefore(&self) -> Option<time_t> {
        let rv = unsafe { ffi::tls_peer_cert_notbefore(self.ptr) };
        if rv == -1 {
            None
        } else {
            Some(rv)
        }
    }

    pub fn peer_cert_notafter(&self) -> Option<time_t> {
        let rv = unsafe { ffi::tls_peer_cert_notafter(self.ptr) };
        if rv == -1 {
            None
        } else {
            Some(rv)
        }
    }

    pub fn peer_cert_hash(&self) -> String {
        unsafe { from_cstr(ffi::tls_peer_cert_hash(self.ptr)) }
    }

    pub fn peer_cert_issuer(&self) -> String {
        unsafe { from_cstr(ffi::tls_peer_cert_issuer(self.ptr)) }
    }

    pub fn peer_cert_subject(&self) -> String {
        unsafe { from_cstr(ffi::tls_peer_cert_subject(self.ptr)) }
    }

    pub fn peer_cert_contains_name(&self, name: &str) -> bool {
        let rv = unsafe {
            let name_c = CString::from_vec_unchecked(name.bytes().collect());
            ffi::tls_peer_cert_contains_name(self.ptr, name_c.as_ptr())
        };
        (rv == 1)
    }

    pub fn peer_cert_provided(&self) -> bool {
        let rv = unsafe { ffi::tls_peer_cert_provided(self.ptr) };
        (rv == 1)
    }

    fn rv_to_result_io(&self, rv: i64) -> TlsResult<usize> {
        match rv {
            ffi::WANT_POLLIN => {
                Err(TlsError {
                    msg: String::new(),
                    code: rv,
                })
            }
            ffi::WANT_POLLOUT => {
                Err(TlsError {
                    msg: String::new(),
                    code: rv,
                })
            }
            rv if rv < 0 => {
                Err(TlsError {
                    msg: self.error(),
                    code: -1,
                })
            }
            rv => Ok(rv as usize),
        }
    }

    /// Complete the TLS handshake
    ///
    /// This function will be called when needed by `read()` or `write()`, but
    /// can be called to complete the handshake.
    pub fn handshake(&mut self) -> TlsResult<()> {
        let rv = unsafe { ffi::tls_handshake(self.ptr) };
        self.rv_to_result_io(rv as i64).map(|_| ())
    }

    pub fn close(&mut self) -> TlsResult<()> {
        let rv = unsafe { ffi::tls_close(self.ptr) };
        self.rv_to_result_io(rv as i64).map(|_| ())
    }

    pub fn read(&mut self, buf: &mut [u8]) -> TlsResult<usize> {
        let buflen = buf.len() as size_t;
        let bptr = buf.as_mut_ptr() as *mut c_void;
        let rv = unsafe { ffi::tls_read(self.ptr, bptr, buflen) };
        self.rv_to_result_io(rv as i64)
    }

    pub fn write(&mut self, buf: &[u8]) -> TlsResult<usize> {
        let buflen = buf.len() as size_t;
        let bptr = buf.as_ptr() as *const c_void;
        let rv = unsafe { ffi::tls_write(self.ptr, bptr, buflen) };
        self.rv_to_result_io(rv as i64)
    }

    /// Create new server context
    pub fn new_server() -> Option<TlsContext> {
        let p = unsafe { ffi::tls_server() };
        if p == ptr::null_mut() {
            None
        } else {
            Some(TlsContext {
                ptr: p,
                cfg: None,
            })
        }
    }

    #[cfg(unix)]
    /// Accept a new TLS connection over an existing socket
    pub fn accept_socket<F: IntoRawFd>(&mut self, fd: F) -> TlsResult<TlsContext> {
        let mut cctx: ffi::Tls = ptr::null_mut();;
        let rv = unsafe { ffi::tls_accept_socket(self.ptr, &mut cctx, fd.into_raw_fd()) };
        self.rv_to_result(rv as i64)
            .map(|_| {
                TlsContext {
                    ptr: cctx,
                    cfg: None,
                }
            })
    }

    #[cfg(windows)]
    /// Accept a new TLS connection over an existing socket
    pub fn accept_socket<F: IntoRawSocket>(&mut self, fd: F) -> TlsResult<TlsContext> {
        let mut cctx: ffi::Tls = ptr::null_mut();;
        // This cast is not exactly safe
        // http://stackoverflow.com/questions/1953639/
        let rv = unsafe {
            ffi::tls_accept_socket(self.ptr, &mut cctx, fd.into_raw_socket() as i32)
        };
        self.rv_to_result(rv as i64)
            .map(|_| {
                TlsContext {
                    ptr: cctx,
                    cfg: None,
                }
            })
    }
}

impl Drop for TlsContext {
    fn drop(&mut self) {
        unsafe {
            ffi::tls_free(self.ptr);
        }
    }
}

/// TLS configuration settings, see `TlsContext::configure` to apply them
pub struct TlsConfig {
    cfg: ffi::Config,
}

impl TlsConfig {
    pub fn new() -> Option<TlsConfig> {
        let p = unsafe { ffi::tls_config_new() };
        if p == ptr::null_mut() {
            None
        } else {
            Some(TlsConfig { cfg: p })
        }
    }

    pub fn set_ca_file(&mut self, path: &str) -> Option<()> {
        let rv = unsafe {
            let path_c = CString::from_vec_unchecked(path.bytes().collect());
            ffi::tls_config_set_ca_file(self.cfg, path_c.as_ptr())
        };
        if rv == 0 {
            Some(())
        } else {
            None
        }
    }
    pub fn set_ca_path(&mut self, path: &str) -> Option<()> {
        let rv = unsafe {
            let path_c = str_c_ptr(path);
            ffi::tls_config_set_ca_path(self.cfg, path_c)
        };
        if rv == 0 {
            Some(())
        } else {
            None
        }
    }
    pub fn set_ca_mem(&mut self, ca: &str) -> Option<()> {
        let rv = unsafe { ffi::tls_config_set_ca_mem(self.cfg, ca.as_ptr(), ca.len()) };
        if rv == 0 {
            Some(())
        } else {
            None
        }
    }
    pub fn set_verify_depth(&mut self, depth: i32) {
        unsafe { ffi::tls_config_set_verify_depth(self.cfg, depth) }
    }
    pub fn insecure_noverifyname(&mut self) {
        unsafe { ffi::tls_config_insecure_noverifyname(self.cfg) }
    }
    pub fn insecure_noverifycert(&mut self) {
        unsafe { ffi::tls_config_insecure_noverifycert(self.cfg) }
    }
    pub fn set_key_file(&mut self, path: &str) -> Option<()> {
        let rv = unsafe {
            let path_c = CString::from_vec_unchecked(path.bytes().collect());
            ffi::tls_config_set_key_file(self.cfg, path_c.as_ptr())
        };
        if rv == 0 {
            Some(())
        } else {
            None
        }
    }
    pub fn set_cert_file(&mut self, path: &str) -> Option<()> {
        let rv = unsafe {
            let path_c = CString::from_vec_unchecked(path.bytes().collect());
            ffi::tls_config_set_cert_file(self.cfg, path_c.as_ptr())
        };
        if rv == 0 {
            Some(())
        } else {
            None
        }
    }
    pub fn set_protocols(&mut self, protocols: &str) -> Option<()> {
        let mut proto = 0;
        unsafe {
            let proto_c = CString::from_vec_unchecked(protocols.bytes().collect());
            if ffi::tls_config_parse_protocols(&mut proto, proto_c.as_ptr()) == -1 {
                return None;
            }
            ffi::tls_config_set_protocols(self.cfg, proto);
        }
        Some(())
    }
    pub fn set_ciphers(&mut self, ciphers: &str) -> Option<()> {
        let rv = unsafe {
            let ciphers_c = CString::from_vec_unchecked(ciphers.bytes().collect());
            ffi::tls_config_set_ciphers(self.cfg, ciphers_c.as_ptr())
        };
        if rv == 0 {
            Some(())
        } else {
            None
        }
    }
}

impl Drop for TlsConfig {
    fn drop(&mut self) {
        unsafe {
            ffi::tls_config_free(self.cfg);
        }
    }
}

#[derive(Debug)]
pub struct TlsError {
    msg: String,
    code: i64,
}

impl TlsError {
    /// The operation failed because it would block reading
    fn want_pollin(&self) -> bool {
        self.code == ffi::WANT_POLLIN
    }
    /// The operation failed because it would block writing
    fn want_pollout(&self) -> bool {
        self.code == ffi::WANT_POLLIN
    }
    fn wants_more(&self) -> bool {
        self.want_pollin() || self.want_pollout()
    }
}

impl fmt::Display for TlsError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.msg)
    }
}
impl Error for TlsError {
    fn description(&self) -> &str {
        &self.msg
    }
}
/// Convert TlsError to io::Error, use WouldBlock if applicable
impl convert::From<TlsError> for io::Error {
    fn from(err: TlsError) -> Self {
        match err.code {
            ffi::WANT_POLLIN | ffi::WANT_POLLOUT => io::Error::new(io::ErrorKind::WouldBlock, err),
            _ => io::Error::new(io::ErrorKind::Other, err.msg),
        }
    }
}

/// Base result type for TLS operations
pub type TlsResult<T> = Result<T, TlsError>;

/// Initialize libtls - make sure to call this before using the API
/// Returns false if libtls failed to initialise.
pub fn init() -> bool {
    static mut RET: i32 = -1;
    static ONCE: Once = ONCE_INIT;
    ONCE.call_once(|| {
        util::other_init();
        unsafe { RET = ffi::tls_init() };
    });
    unsafe { (RET == 0) }
}

pub mod net;
<commit_msg>Fix TlsContext::conn_cipher<commit_after>//! Rust bindings for [libressl](http://libressl.org)'s libtls
//!
//! For the authoritative source on the inner workings of libtls check
//! the [manpage](http://www.openbsd.org/cgi-bin/man.cgi/OpenBSD-current/man3/tls_accept_fds.3?query=tls_init&sec=3).
//!
//! This is a minimal wrapper around the API. For higher level APIs check the **net** module.
//!

extern crate tls_sys as ffi;
extern crate libc;

use std::ffi::{CStr, CString};
use libc::{c_char, time_t, c_void, size_t};
use std::ptr;
use std::error::Error;
use std::fmt;
use std::sync::{Once, ONCE_INIT};
use std::io;
use std::convert;
#[cfg(unix)]
use std::os::unix::io::IntoRawFd;
#[cfg(windows)]
use std::os::windows::io::IntoRawSocket;

mod util;

fn from_cstr(s: *const c_char) -> String {
    unsafe {
        if s == ptr::null_mut() {
            String::new()
        } else {
            let slice = CStr::from_ptr(s);
            String::from_utf8_lossy(slice.to_bytes()).into_owned()
        }
    }
}

/// Get C string ptr, but use NULL if the string is empty.
/// Because some C functions treat NULL and "\0" differently
fn str_c_ptr(s: &str) -> *const i8 {
    if s.is_empty() {
        ptr::null()
    } else {
        unsafe { CString::from_vec_unchecked(s.bytes().collect()).as_ptr() }
    }
}

/// A structure that represents all TLS context
///
/// This can be a client connection, a server, or a connection accepted by the server
pub struct TlsContext {
    ptr: ffi::Tls,
    cfg: Option<TlsConfig>,
}

impl TlsContext {
    /// Create a new client context
    pub fn new_client() -> Option<TlsContext> {
        let p = unsafe { ffi::tls_client() };
        if p == ptr::null_mut() {
            None
        } else {
            Some(TlsContext {
                ptr: p,
                cfg: None,
            })
        }
    }

    fn error(&self) -> String {
        unsafe { from_cstr(ffi::tls_error(self.ptr)) }
    }

    fn rv_to_result(&self, rv: i64) -> TlsResult<()> {
        if rv == 0 {
            Ok(())
        } else {
            Err(TlsError {
                msg: self.error(),
                code: rv,
            })
        }
    }

    /// If port is empty, the port value is assumed to be part of the hostname string as host:port.
    /// If servername is not empty it is used instead of the hostname for verification.
    pub fn connect_servername(&mut self,
                              hostname: &str,
                              port: &str,
                              servername: &str)
                              -> TlsResult<()> {
        let rv = unsafe {
            let hostname_c = CString::from_vec_unchecked(hostname.bytes().collect()).as_ptr();
            // Both port and servername can be NULL
            let port_c = str_c_ptr(port);
            let servername_c = str_c_ptr(servername);
            ffi::tls_connect_servername(self.ptr, hostname_c, port_c, servername_c)
        };
        self.rv_to_result(rv as i64)
    }

    #[cfg(unix)]
    /// Establish a TLS connection over the given socket
    pub fn connect_socket<F: IntoRawFd>(&mut self, fd: F, servername: &str) -> TlsResult<()> {
        let rv = unsafe {
            let servername_c = str_c_ptr(servername);
            ffi::tls_connect_socket(self.ptr, fd.into_raw_fd(), servername_c)
        };
        self.rv_to_result(rv as i64)
    }

    #[cfg(windows)]
    /// Establish a TLS connection over the given socket
    pub fn connect_socket<F: IntoRawSocket>(&mut self, fd: F, servername: &str) -> TlsResult<()> {
        let rv = unsafe {
            let servername_c = str_c_ptr(servername);
            // This cast is not exactly safe
            // http://stackoverflow.com/questions/1953639/
            ffi::tls_connect_socket(self.ptr, fd.into_raw_socket() as i32, servername_c)
        };
        self.rv_to_result(rv as i64)
    }

    pub fn conn_version(&self) -> String {
        unsafe { from_cstr(ffi::tls_conn_version(self.ptr)) }
    }
    pub fn conn_cipher(&self) -> String {
        unsafe { from_cstr(ffi::tls_conn_cipher(self.ptr)) }
    }

    /// Apply configuration settings to the context, consuming the config struct
    ///
    /// This should be called BEFORE trying to establish/accept
    /// a connection
    pub fn configure(&mut self, cfg: TlsConfig) -> TlsResult<()> {
        let rv = unsafe { ffi::tls_configure(self.ptr, cfg.cfg) };
        self.cfg = Some(cfg);
        self.rv_to_result(rv as i64)
    }

    pub fn peer_cert_notbefore(&self) -> Option<time_t> {
        let rv = unsafe { ffi::tls_peer_cert_notbefore(self.ptr) };
        if rv == -1 {
            None
        } else {
            Some(rv)
        }
    }

    pub fn peer_cert_notafter(&self) -> Option<time_t> {
        let rv = unsafe { ffi::tls_peer_cert_notafter(self.ptr) };
        if rv == -1 {
            None
        } else {
            Some(rv)
        }
    }

    pub fn peer_cert_hash(&self) -> String {
        unsafe { from_cstr(ffi::tls_peer_cert_hash(self.ptr)) }
    }

    pub fn peer_cert_issuer(&self) -> String {
        unsafe { from_cstr(ffi::tls_peer_cert_issuer(self.ptr)) }
    }

    pub fn peer_cert_subject(&self) -> String {
        unsafe { from_cstr(ffi::tls_peer_cert_subject(self.ptr)) }
    }

    pub fn peer_cert_contains_name(&self, name: &str) -> bool {
        let rv = unsafe {
            let name_c = CString::from_vec_unchecked(name.bytes().collect());
            ffi::tls_peer_cert_contains_name(self.ptr, name_c.as_ptr())
        };
        (rv == 1)
    }

    pub fn peer_cert_provided(&self) -> bool {
        let rv = unsafe { ffi::tls_peer_cert_provided(self.ptr) };
        (rv == 1)
    }

    fn rv_to_result_io(&self, rv: i64) -> TlsResult<usize> {
        match rv {
            ffi::WANT_POLLIN => {
                Err(TlsError {
                    msg: String::new(),
                    code: rv,
                })
            }
            ffi::WANT_POLLOUT => {
                Err(TlsError {
                    msg: String::new(),
                    code: rv,
                })
            }
            rv if rv < 0 => {
                Err(TlsError {
                    msg: self.error(),
                    code: -1,
                })
            }
            rv => Ok(rv as usize),
        }
    }

    /// Complete the TLS handshake
    ///
    /// This function will be called when needed by `read()` or `write()`, but
    /// can be called to complete the handshake.
    pub fn handshake(&mut self) -> TlsResult<()> {
        let rv = unsafe { ffi::tls_handshake(self.ptr) };
        self.rv_to_result_io(rv as i64).map(|_| ())
    }

    pub fn close(&mut self) -> TlsResult<()> {
        let rv = unsafe { ffi::tls_close(self.ptr) };
        self.rv_to_result_io(rv as i64).map(|_| ())
    }

    pub fn read(&mut self, buf: &mut [u8]) -> TlsResult<usize> {
        let buflen = buf.len() as size_t;
        let bptr = buf.as_mut_ptr() as *mut c_void;
        let rv = unsafe { ffi::tls_read(self.ptr, bptr, buflen) };
        self.rv_to_result_io(rv as i64)
    }

    pub fn write(&mut self, buf: &[u8]) -> TlsResult<usize> {
        let buflen = buf.len() as size_t;
        let bptr = buf.as_ptr() as *const c_void;
        let rv = unsafe { ffi::tls_write(self.ptr, bptr, buflen) };
        self.rv_to_result_io(rv as i64)
    }

    /// Create new server context
    pub fn new_server() -> Option<TlsContext> {
        let p = unsafe { ffi::tls_server() };
        if p == ptr::null_mut() {
            None
        } else {
            Some(TlsContext {
                ptr: p,
                cfg: None,
            })
        }
    }

    #[cfg(unix)]
    /// Accept a new TLS connection over an existing socket
    pub fn accept_socket<F: IntoRawFd>(&mut self, fd: F) -> TlsResult<TlsContext> {
        let mut cctx: ffi::Tls = ptr::null_mut();;
        let rv = unsafe { ffi::tls_accept_socket(self.ptr, &mut cctx, fd.into_raw_fd()) };
        self.rv_to_result(rv as i64)
            .map(|_| {
                TlsContext {
                    ptr: cctx,
                    cfg: None,
                }
            })
    }

    #[cfg(windows)]
    /// Accept a new TLS connection over an existing socket
    pub fn accept_socket<F: IntoRawSocket>(&mut self, fd: F) -> TlsResult<TlsContext> {
        let mut cctx: ffi::Tls = ptr::null_mut();;
        // This cast is not exactly safe
        // http://stackoverflow.com/questions/1953639/
        let rv = unsafe {
            ffi::tls_accept_socket(self.ptr, &mut cctx, fd.into_raw_socket() as i32)
        };
        self.rv_to_result(rv as i64)
            .map(|_| {
                TlsContext {
                    ptr: cctx,
                    cfg: None,
                }
            })
    }
}

impl Drop for TlsContext {
    fn drop(&mut self) {
        unsafe {
            ffi::tls_free(self.ptr);
        }
    }
}

/// TLS configuration settings, see `TlsContext::configure` to apply them
pub struct TlsConfig {
    cfg: ffi::Config,
}

impl TlsConfig {
    pub fn new() -> Option<TlsConfig> {
        let p = unsafe { ffi::tls_config_new() };
        if p == ptr::null_mut() {
            None
        } else {
            Some(TlsConfig { cfg: p })
        }
    }

    pub fn set_ca_file(&mut self, path: &str) -> Option<()> {
        let rv = unsafe {
            let path_c = CString::from_vec_unchecked(path.bytes().collect());
            ffi::tls_config_set_ca_file(self.cfg, path_c.as_ptr())
        };
        if rv == 0 {
            Some(())
        } else {
            None
        }
    }
    pub fn set_ca_path(&mut self, path: &str) -> Option<()> {
        let rv = unsafe {
            let path_c = str_c_ptr(path);
            ffi::tls_config_set_ca_path(self.cfg, path_c)
        };
        if rv == 0 {
            Some(())
        } else {
            None
        }
    }
    pub fn set_ca_mem(&mut self, ca: &str) -> Option<()> {
        let rv = unsafe { ffi::tls_config_set_ca_mem(self.cfg, ca.as_ptr(), ca.len()) };
        if rv == 0 {
            Some(())
        } else {
            None
        }
    }
    pub fn set_verify_depth(&mut self, depth: i32) {
        unsafe { ffi::tls_config_set_verify_depth(self.cfg, depth) }
    }
    pub fn insecure_noverifyname(&mut self) {
        unsafe { ffi::tls_config_insecure_noverifyname(self.cfg) }
    }
    pub fn insecure_noverifycert(&mut self) {
        unsafe { ffi::tls_config_insecure_noverifycert(self.cfg) }
    }
    pub fn set_key_file(&mut self, path: &str) -> Option<()> {
        let rv = unsafe {
            let path_c = CString::from_vec_unchecked(path.bytes().collect());
            ffi::tls_config_set_key_file(self.cfg, path_c.as_ptr())
        };
        if rv == 0 {
            Some(())
        } else {
            None
        }
    }
    pub fn set_cert_file(&mut self, path: &str) -> Option<()> {
        let rv = unsafe {
            let path_c = CString::from_vec_unchecked(path.bytes().collect());
            ffi::tls_config_set_cert_file(self.cfg, path_c.as_ptr())
        };
        if rv == 0 {
            Some(())
        } else {
            None
        }
    }
    pub fn set_protocols(&mut self, protocols: &str) -> Option<()> {
        let mut proto = 0;
        unsafe {
            let proto_c = CString::from_vec_unchecked(protocols.bytes().collect());
            if ffi::tls_config_parse_protocols(&mut proto, proto_c.as_ptr()) == -1 {
                return None;
            }
            ffi::tls_config_set_protocols(self.cfg, proto);
        }
        Some(())
    }
    pub fn set_ciphers(&mut self, ciphers: &str) -> Option<()> {
        let rv = unsafe {
            let ciphers_c = CString::from_vec_unchecked(ciphers.bytes().collect());
            ffi::tls_config_set_ciphers(self.cfg, ciphers_c.as_ptr())
        };
        if rv == 0 {
            Some(())
        } else {
            None
        }
    }
}

impl Drop for TlsConfig {
    fn drop(&mut self) {
        unsafe {
            ffi::tls_config_free(self.cfg);
        }
    }
}

#[derive(Debug)]
pub struct TlsError {
    msg: String,
    code: i64,
}

impl TlsError {
    /// The operation failed because it would block reading
    fn want_pollin(&self) -> bool {
        self.code == ffi::WANT_POLLIN
    }
    /// The operation failed because it would block writing
    fn want_pollout(&self) -> bool {
        self.code == ffi::WANT_POLLIN
    }
    fn wants_more(&self) -> bool {
        self.want_pollin() || self.want_pollout()
    }
}

impl fmt::Display for TlsError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.msg)
    }
}
impl Error for TlsError {
    fn description(&self) -> &str {
        &self.msg
    }
}
/// Convert TlsError to io::Error, use WouldBlock if applicable
impl convert::From<TlsError> for io::Error {
    fn from(err: TlsError) -> Self {
        match err.code {
            ffi::WANT_POLLIN | ffi::WANT_POLLOUT => io::Error::new(io::ErrorKind::WouldBlock, err),
            _ => io::Error::new(io::ErrorKind::Other, err.msg),
        }
    }
}

/// Base result type for TLS operations
pub type TlsResult<T> = Result<T, TlsError>;

/// Initialize libtls - make sure to call this before using the API
/// Returns false if libtls failed to initialise.
pub fn init() -> bool {
    static mut RET: i32 = -1;
    static ONCE: Once = ONCE_INIT;
    ONCE.call_once(|| {
        util::other_init();
        unsafe { RET = ffi::tls_init() };
    });
    unsafe { (RET == 0) }
}

pub mod net;
<|endoftext|>


<commit_before>// Copyright 2020 Pants project contributors (see CONTRIBUTORS.md).
// Licensed under the Apache License, Version 2.0 (see LICENSE).

use std::collections::HashMap;
use std::io;
use std::net::Ipv4Addr;
use std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
use std::path::PathBuf;
use std::sync::Arc;

use async_latch::AsyncLatch;
use bytes::Bytes;
use futures::channel::oneshot;
use futures::{future, sink, stream, FutureExt, SinkExt, StreamExt, TryStreamExt};
use log::{debug, info};
use nails::execution::{
  self, child_channel, sink_for, stream_for, ChildInput, ChildOutput, ExitCode,
};
use nails::Nail;
use task_executor::Executor;
use tokio::fs::File;
use tokio::net::TcpListener;
use tokio::sync::{Notify, RwLock};

pub struct Server {
  exit_sender: oneshot::Sender<()>,
  exited_receiver: oneshot::Receiver<Result<(), String>>,
  port: u16,
}

impl Server {
  ///
  /// Spawn the server on a background Task.
  ///
  /// The port provided here may be `0` in order to request a random port. A caller can use
  /// `Server.port()` to determine what port was actually selected.
  ///
  pub async fn new(
    executor: Executor,
    port_requested: u16,
    runner: impl RawFdRunner + 'static,
  ) -> Result<Server, String> {
    let listener = TcpListener::bind((Ipv4Addr::new(127, 0, 0, 1), port_requested))
      .await
      .map_err(|e| format!("Could not bind to port {}: {:?}", port_requested, e))?;
    let port_actual = listener
      .local_addr()
      .map_err(|e| format!("No local address for listener: {:?}", e))?
      .port();

    // NB: The C client requires noisy_stdin (see the `nails` crate for more info), but neither
    // `nails` nor the pants python client do.
    let config = nails::Config::default().noisy_stdin(false);
    let nail = RawFdNail {
      executor: executor.clone(),
      runner: Arc::new(runner),
    };

    let (exited_sender, exited_receiver) = oneshot::channel();
    let (exit_sender, exit_receiver) = oneshot::channel();

    let _join = executor.spawn(Self::serve(
      executor.clone(),
      config,
      nail,
      exit_receiver,
      exited_sender,
      listener,
    ));

    Ok(Server {
      exit_sender,
      exited_receiver,
      port: port_actual,
    })
  }

  ///
  /// The main loop of the server. Public for testing.
  ///
  pub(crate) async fn serve(
    executor: Executor,
    config: nails::Config,
    nail: impl Nail,
    should_exit: oneshot::Receiver<()>,
    exited: oneshot::Sender<Result<(), String>>,
    listener: TcpListener,
  ) {
    let exit_result = Self::accept_loop(executor, config, nail, should_exit, listener).await;
    info!("Server exiting with {:?}", exit_result);
    let _ = exited.send(exit_result);
  }

  async fn accept_loop(
    executor: Executor,
    config: nails::Config,
    nail: impl Nail,
    mut should_exit: oneshot::Receiver<()>,
    listener: TcpListener,
  ) -> Result<(), String> {
    // While connections are ongoing, they acquire `read`; before shutting down, the server
    // acquires `write`.
    let ongoing_connections = Arc::new(RwLock::new(()));

    let result = loop {
      let tcp_stream = match future::select(listener.accept().boxed(), should_exit).await {
        future::Either::Left((Ok((tcp_stream, _addr)), s_e)) => {
          // Got a connection.
          should_exit = s_e;
          tcp_stream
        }
        future::Either::Left((Err(e), _)) => {
          break Err(format!("Server failed to accept connections: {}", e));
        }
        future::Either::Right((_, _)) => {
          break Ok(());
        }
      };

      debug!("Accepted connection: {:?}", tcp_stream);

      // There is a slightly delicate dance here: we wait for a connection to have acquired the
      // ongoing connections lock before proceeding to the next iteration of the loop. This
      // prevents us from observing an empty lock and exiting before the connection has actually
      // acquired it. Unfortunately we cannot acquire the lock in this thread and then send the
      // guard to the other thread due to its lifetime bounds.
      let connection_started = Arc::new(Notify::new());
      let _join = executor.spawn({
        let config = config.clone();
        let nail = nail.clone();
        let connection_started = connection_started.clone();
        let ongoing_connections = ongoing_connections.clone();
        async move {
          let ongoing_connection_guard = ongoing_connections.read().await;
          connection_started.notify_one();
          let result = nails::server::handle_connection(config, nail, tcp_stream).await;
          std::mem::drop(ongoing_connection_guard);
          result
        }
      });
      connection_started.notified().await;
    };

    // Before exiting, acquire write access on the ongoing_connections lock to prove that all
    // connections have completed.
    debug!("Server waiting for connections to complete...");
    let _ = ongoing_connections.write().await;
    debug!("All connections completed.");
    result
  }

  ///
  /// The port that the server is listening on.
  ///
  pub fn port(&self) -> u16 {
    self.port
  }

  ///
  /// Returns a Future that will shut down the server by:
  /// 1. stopping accepting new connections
  /// 2. waiting for all ongoing connections to have completed
  ///
  pub async fn shutdown(self) -> Result<(), String> {
    // If we fail to send the exit signal, it's because the task is already shut down.
    let _ = self.exit_sender.send(());
    self
      .exited_receiver
      .await
      .map_err(|_| "Server exited uncleanly.".to_owned())?
  }
}

pub struct RawFdExecution {
  pub cmd: execution::Command,
  pub cancelled: AsyncLatch,
  pub stdin_fd: RawFd,
  pub stdout_fd: RawFd,
  pub stderr_fd: RawFd,
}

///
/// Implementations of this trait should _not_ close the input file handles, and should let the
/// caller do so instead.
///
pub trait RawFdRunner: Fn(RawFdExecution) -> ExitCode + Send + Sync {}

impl<T: Fn(RawFdExecution) -> ExitCode + Send + Sync> RawFdRunner for T {}

///
/// A Nail implementation that proxies stdio to file handles that can be consumed by the given
/// callback function.
///
/// If any of stdio is a tty (detected via environment variables special cased in our nailgun
/// client), we ignore the input fds and open new fds directly to the tty path, which happens to
/// be addressable as a file in OSX and Linux. In that case, there is no middle-man, and we
/// ignore the fds opened by the nailgun server for data sent via the protocol.
///
#[derive(Clone)]
struct RawFdNail {
  executor: Executor,
  runner: Arc<dyn RawFdRunner>,
}

impl Nail for RawFdNail {
  fn spawn(&self, cmd: execution::Command) -> Result<nails::server::Child, io::Error> {
    let env = cmd.env.iter().cloned().collect::<HashMap<_, _>>();

    // Handle stdin.
    let (stdin_handle, stdin_sink) = Self::input(Self::ttypath_from_env(&env, 0))?;
    let maybe_stdin_write = if let Some(mut stdin_sink) = stdin_sink {
      let (stdin_write, stdin_read) = child_channel::<ChildInput>();
      // Spawn a task that will propagate the input stream.
      let _join = self.executor.spawn(async move {
        let mut input_stream = stdin_read.map(|child_input| match child_input {
          ChildInput::Stdin(bytes) => Ok(bytes),
        });
        let _ = stdin_sink.send_all(&mut input_stream).await;
      });
      Some(stdin_write)
    } else {
      // Stdin will be handled directly by the TTY.
      None
    };

    // And stdout/stderr.
    let (stdout_stream, stdout_handle) = Self::output(Self::ttypath_from_env(&env, 1))?;
    let (stderr_stream, stderr_handle) = Self::output(Self::ttypath_from_env(&env, 2))?;

    // Set up a cancellation token that is triggered on client shutdown.
    let cancelled = AsyncLatch::new();
    let shutdown = {
      let cancelled = cancelled.clone();
      async move {
        cancelled.trigger();
      }
    };

    // Spawn the underlying function as a blocking task, and capture its exit code to append to the
    // output stream.
    let nail = self.clone();
    let exit_code = self
      .executor
      .spawn_blocking(move || {
        // NB: This closure captures the stdio handles, and will drop/close them when it completes.
        (nail.runner)(RawFdExecution {
          cmd,
          cancelled,
          stdin_fd: stdin_handle.as_raw_fd(),
          stdout_fd: stdout_handle.as_raw_fd(),
          stderr_fd: stderr_handle.as_raw_fd(),
        })
      })
      .boxed();

    // Select a single stdout/stderr stream.
    let stdout_stream = stdout_stream.map_ok(ChildOutput::Stdout);
    let stderr_stream = stderr_stream.map_ok(ChildOutput::Stderr);
    let output_stream = stream::select(stdout_stream, stderr_stream).boxed();

    Ok(nails::server::Child::new(
      output_stream,
      maybe_stdin_write,
      exit_code,
      Some(shutdown.boxed()),
    ))
  }
}

impl RawFdNail {
  ///
  /// Returns a tuple of a readable file handle and an optional sink for nails to send stdin to.
  ///
  /// In the case of a TTY, the file handle will point directly to the TTY, and no stdin data will
  /// flow over the protocol. Otherwise, it will be backed by a new anonymous pipe, and data should
  /// be copied to the returned Sink.
  ///
  fn input(
    tty_path: Option<PathBuf>,
  ) -> Result<(Box<dyn AsRawFd + Send>, Option<impl sink::Sink<Bytes>>), io::Error> {
    if let Some(tty_path) = tty_path {
      Ok((Box::new(std::fs::File::open(tty_path)?), None))
    } else {
      let (stdin_reader, stdin_writer) = os_pipe::pipe()?;
      let write_handle =
        File::from_std(unsafe { std::fs::File::from_raw_fd(stdin_writer.into_raw_fd()) });
      Ok((Box::new(stdin_reader), Some(sink_for(write_handle))))
    }
  }

  ///
  /// Returns a tuple of a possibly empty Stream for nails to read data from, and a writable file handle.
  ///
  /// See `Self::input` and the struct's rustdoc for more info on the TTY case.
  ///
  #[allow(clippy::type_complexity)]
  fn output(
    tty_path: Option<PathBuf>,
  ) -> Result<
    (
      stream::BoxStream<'static, Result<Bytes, io::Error>>,
      Box<dyn AsRawFd + Send>,
    ),
    io::Error,
  > {
    if let Some(tty_path) = tty_path {
      let tty = std::fs::OpenOptions::new()
        .write(true)
        .create(false)
        .open(tty_path)?;
      Ok((stream::empty().boxed(), Box::new(tty)))
    } else {
      let (stdin_reader, stdin_writer) = os_pipe::pipe()?;
      let read_handle =
        File::from_std(unsafe { std::fs::File::from_raw_fd(stdin_reader.into_raw_fd()) });
      Ok((stream_for(read_handle).boxed(), Box::new(stdin_writer)))
    }
  }

  ///
  /// Corresponds to `ttynames_to_env` in `nailgun_protocol.py`. See this struct's rustdocs.
  ///
  fn ttypath_from_env(env: &HashMap<String, String>, fd_number: usize) -> Option<PathBuf> {
    env
      .get(&format!("NAILGUN_TTY_PATH_{}", fd_number))
      .map(PathBuf::from)
  }
}
<commit_msg>`pantsd` falls back to socket usage if it cannot open a TTY. (#13155)<commit_after>// Copyright 2020 Pants project contributors (see CONTRIBUTORS.md).
// Licensed under the Apache License, Version 2.0 (see LICENSE).

use std::collections::HashMap;
use std::fs::OpenOptions;
use std::io;
use std::net::Ipv4Addr;
use std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
use std::path::PathBuf;
use std::sync::Arc;

use async_latch::AsyncLatch;
use bytes::Bytes;
use futures::channel::oneshot;
use futures::{future, sink, stream, FutureExt, SinkExt, StreamExt, TryStreamExt};
use log::{debug, info};
use nails::execution::{
  self, child_channel, sink_for, stream_for, ChildInput, ChildOutput, ExitCode,
};
use nails::Nail;
use task_executor::Executor;
use tokio::fs::File;
use tokio::net::TcpListener;
use tokio::sync::{Notify, RwLock};

pub struct Server {
  exit_sender: oneshot::Sender<()>,
  exited_receiver: oneshot::Receiver<Result<(), String>>,
  port: u16,
}

impl Server {
  ///
  /// Spawn the server on a background Task.
  ///
  /// The port provided here may be `0` in order to request a random port. A caller can use
  /// `Server.port()` to determine what port was actually selected.
  ///
  pub async fn new(
    executor: Executor,
    port_requested: u16,
    runner: impl RawFdRunner + 'static,
  ) -> Result<Server, String> {
    let listener = TcpListener::bind((Ipv4Addr::new(127, 0, 0, 1), port_requested))
      .await
      .map_err(|e| format!("Could not bind to port {}: {:?}", port_requested, e))?;
    let port_actual = listener
      .local_addr()
      .map_err(|e| format!("No local address for listener: {:?}", e))?
      .port();

    // NB: The C client requires noisy_stdin (see the `nails` crate for more info), but neither
    // `nails` nor the pants python client do.
    let config = nails::Config::default().noisy_stdin(false);
    let nail = RawFdNail {
      executor: executor.clone(),
      runner: Arc::new(runner),
    };

    let (exited_sender, exited_receiver) = oneshot::channel();
    let (exit_sender, exit_receiver) = oneshot::channel();

    let _join = executor.spawn(Self::serve(
      executor.clone(),
      config,
      nail,
      exit_receiver,
      exited_sender,
      listener,
    ));

    Ok(Server {
      exit_sender,
      exited_receiver,
      port: port_actual,
    })
  }

  ///
  /// The main loop of the server. Public for testing.
  ///
  pub(crate) async fn serve(
    executor: Executor,
    config: nails::Config,
    nail: impl Nail,
    should_exit: oneshot::Receiver<()>,
    exited: oneshot::Sender<Result<(), String>>,
    listener: TcpListener,
  ) {
    let exit_result = Self::accept_loop(executor, config, nail, should_exit, listener).await;
    info!("Server exiting with {:?}", exit_result);
    let _ = exited.send(exit_result);
  }

  async fn accept_loop(
    executor: Executor,
    config: nails::Config,
    nail: impl Nail,
    mut should_exit: oneshot::Receiver<()>,
    listener: TcpListener,
  ) -> Result<(), String> {
    // While connections are ongoing, they acquire `read`; before shutting down, the server
    // acquires `write`.
    let ongoing_connections = Arc::new(RwLock::new(()));

    let result = loop {
      let tcp_stream = match future::select(listener.accept().boxed(), should_exit).await {
        future::Either::Left((Ok((tcp_stream, _addr)), s_e)) => {
          // Got a connection.
          should_exit = s_e;
          tcp_stream
        }
        future::Either::Left((Err(e), _)) => {
          break Err(format!("Server failed to accept connections: {}", e));
        }
        future::Either::Right((_, _)) => {
          break Ok(());
        }
      };

      debug!("Accepted connection: {:?}", tcp_stream);

      // There is a slightly delicate dance here: we wait for a connection to have acquired the
      // ongoing connections lock before proceeding to the next iteration of the loop. This
      // prevents us from observing an empty lock and exiting before the connection has actually
      // acquired it. Unfortunately we cannot acquire the lock in this thread and then send the
      // guard to the other thread due to its lifetime bounds.
      let connection_started = Arc::new(Notify::new());
      let _join = executor.spawn({
        let config = config.clone();
        let nail = nail.clone();
        let connection_started = connection_started.clone();
        let ongoing_connections = ongoing_connections.clone();
        async move {
          let ongoing_connection_guard = ongoing_connections.read().await;
          connection_started.notify_one();
          let result = nails::server::handle_connection(config, nail, tcp_stream).await;
          std::mem::drop(ongoing_connection_guard);
          result
        }
      });
      connection_started.notified().await;
    };

    // Before exiting, acquire write access on the ongoing_connections lock to prove that all
    // connections have completed.
    debug!("Server waiting for connections to complete...");
    let _ = ongoing_connections.write().await;
    debug!("All connections completed.");
    result
  }

  ///
  /// The port that the server is listening on.
  ///
  pub fn port(&self) -> u16 {
    self.port
  }

  ///
  /// Returns a Future that will shut down the server by:
  /// 1. stopping accepting new connections
  /// 2. waiting for all ongoing connections to have completed
  ///
  pub async fn shutdown(self) -> Result<(), String> {
    // If we fail to send the exit signal, it's because the task is already shut down.
    let _ = self.exit_sender.send(());
    self
      .exited_receiver
      .await
      .map_err(|_| "Server exited uncleanly.".to_owned())?
  }
}

pub struct RawFdExecution {
  pub cmd: execution::Command,
  pub cancelled: AsyncLatch,
  pub stdin_fd: RawFd,
  pub stdout_fd: RawFd,
  pub stderr_fd: RawFd,
}

///
/// Implementations of this trait should _not_ close the input file handles, and should let the
/// caller do so instead.
///
pub trait RawFdRunner: Fn(RawFdExecution) -> ExitCode + Send + Sync {}

impl<T: Fn(RawFdExecution) -> ExitCode + Send + Sync> RawFdRunner for T {}

///
/// A Nail implementation that proxies stdio to file handles that can be consumed by the given
/// callback function.
///
/// If any of stdio is a tty (detected via environment variables special cased in our nailgun
/// client), we ignore the input fds and open new fds directly to the tty path, which happens to
/// be addressable as a file in OSX and Linux. In that case, there is no middle-man, and we
/// ignore the fds opened by the nailgun server for data sent via the protocol.
///
#[derive(Clone)]
struct RawFdNail {
  executor: Executor,
  runner: Arc<dyn RawFdRunner>,
}

impl Nail for RawFdNail {
  fn spawn(&self, cmd: execution::Command) -> Result<nails::server::Child, io::Error> {
    let env = cmd.env.iter().cloned().collect::<HashMap<_, _>>();

    // Handle stdin.
    let (stdin_handle, stdin_sink) = Self::input(Self::ttypath_from_env(&env, 0))?;
    let maybe_stdin_write = if let Some(mut stdin_sink) = stdin_sink {
      let (stdin_write, stdin_read) = child_channel::<ChildInput>();
      // Spawn a task that will propagate the input stream.
      let _join = self.executor.spawn(async move {
        let mut input_stream = stdin_read.map(|child_input| match child_input {
          ChildInput::Stdin(bytes) => Ok(bytes),
        });
        let _ = stdin_sink.send_all(&mut input_stream).await;
      });
      Some(stdin_write)
    } else {
      // Stdin will be handled directly by the TTY.
      None
    };

    // And stdout/stderr.
    let (stdout_stream, stdout_handle) = Self::output(Self::ttypath_from_env(&env, 1))?;
    let (stderr_stream, stderr_handle) = Self::output(Self::ttypath_from_env(&env, 2))?;

    // Set up a cancellation token that is triggered on client shutdown.
    let cancelled = AsyncLatch::new();
    let shutdown = {
      let cancelled = cancelled.clone();
      async move {
        cancelled.trigger();
      }
    };

    // Spawn the underlying function as a blocking task, and capture its exit code to append to the
    // output stream.
    let nail = self.clone();
    let exit_code = self
      .executor
      .spawn_blocking(move || {
        // NB: This closure captures the stdio handles, and will drop/close them when it completes.
        (nail.runner)(RawFdExecution {
          cmd,
          cancelled,
          stdin_fd: stdin_handle.as_raw_fd(),
          stdout_fd: stdout_handle.as_raw_fd(),
          stderr_fd: stderr_handle.as_raw_fd(),
        })
      })
      .boxed();

    // Select a single stdout/stderr stream.
    let stdout_stream = stdout_stream.map_ok(ChildOutput::Stdout);
    let stderr_stream = stderr_stream.map_ok(ChildOutput::Stderr);
    let output_stream = stream::select(stdout_stream, stderr_stream).boxed();

    Ok(nails::server::Child::new(
      output_stream,
      maybe_stdin_write,
      exit_code,
      Some(shutdown.boxed()),
    ))
  }
}

impl RawFdNail {
  ///
  /// Returns a tuple of a readable file handle and an optional sink for nails to send stdin to.
  ///
  /// In the case of a TTY, the file handle will point directly to the TTY, and no stdin data will
  /// flow over the protocol. Otherwise, it will be backed by a new anonymous pipe, and data should
  /// be copied to the returned Sink.
  ///
  fn input(
    tty_path: Option<PathBuf>,
  ) -> Result<(Box<dyn AsRawFd + Send>, Option<impl sink::Sink<Bytes>>), io::Error> {
    if let Some(tty) = Self::try_open_tty(tty_path, OpenOptions::new().read(true)) {
      Ok((Box::new(tty), None))
    } else {
      let (stdin_reader, stdin_writer) = os_pipe::pipe()?;
      let write_handle =
        File::from_std(unsafe { std::fs::File::from_raw_fd(stdin_writer.into_raw_fd()) });
      Ok((Box::new(stdin_reader), Some(sink_for(write_handle))))
    }
  }

  ///
  /// Returns a tuple of a possibly empty Stream for nails to read data from, and a writable file handle.
  ///
  /// See `Self::input` and the struct's rustdoc for more info on the TTY case.
  ///
  #[allow(clippy::type_complexity)]
  fn output(
    tty_path: Option<PathBuf>,
  ) -> Result<
    (
      stream::BoxStream<'static, Result<Bytes, io::Error>>,
      Box<dyn AsRawFd + Send>,
    ),
    io::Error,
  > {
    if let Some(tty) = Self::try_open_tty(tty_path, OpenOptions::new().write(true).create(false)) {
      Ok((stream::empty().boxed(), Box::new(tty)))
    } else {
      let (stdin_reader, stdin_writer) = os_pipe::pipe()?;
      let read_handle =
        File::from_std(unsafe { std::fs::File::from_raw_fd(stdin_reader.into_raw_fd()) });
      Ok((stream_for(read_handle).boxed(), Box::new(stdin_writer)))
    }
  }

  ///
  /// Attempt to open the given TTY-path, logging any errors.
  ///
  fn try_open_tty(tty_path: Option<PathBuf>, open_options: &OpenOptions) -> Option<std::fs::File> {
    let tty_path = tty_path?;
    open_options
      .open(&tty_path)
      .map_err(|e| {
        log::debug!(
          "Failed to open TTY at {}: {:?}, falling back to socket access.",
          tty_path.display(),
          e
        );
      })
      .ok()
  }

  ///
  /// Corresponds to `ttynames_to_env` in `nailgun_protocol.py`. See this struct's rustdocs.
  ///
  fn ttypath_from_env(env: &HashMap<String, String>, fd_number: usize) -> Option<PathBuf> {
    env
      .get(&format!("NAILGUN_TTY_PATH_{}", fd_number))
      .map(PathBuf::from)
  }
}
<|endoftext|>


<commit_before>use git2::Error as Git2Error;

use libimagstore::hook::error::HookError as HE;
use libimagstore::hook::error::HookErrorKind as HEK;
use libimagstore::hook::result::HookResult;

generate_error_module!(
    generate_error_types!(GitHookError, GitHookErrorKind,
        ConfigError => "Configuration Error",
        NoConfigError => "No Configuration",
        ConfigTypeError => "Configuration value type wrong",
        RuntimeInformationSetupError => "Couldn't setup runtime information for git hook",
        RepositoryBackendError            => "Error in the git library",
        RepositoryError                   => "Error while interacting with git repository",
        RepositoryBranchError             => "Error while interacting with git branch(es)",
        RepositoryBranchNameFetchingError => "Error while fetching branch name",
        RepositorySignatureFetchingError  => "Error while fetching Authors/Committers signature",
        RepositoryIndexFetchingError      => "Error while fetching Repository Index",
        RepositoryIndexWritingError       => "Error while writing Repository Index",
        RepositoryPathAddingError         => "Error while adding Path to Index",
        RepositoryTreeWritingError        => "Error while writing repository tree",
        RepositoryTreeFindingError        => "Error while finding repository tree",
        RepositoryCommitFindingError      => "Error while finding commit",
        RepositoryCommittingError         => "Error while committing",
        RepositoryHeadFetchingError       => "Error while fetching HEAD",
        RepositoryHeadTargetFetchingError => "Error while fetching target of HEAD",
        RepositoryParentFetchingError     => "Error while fetching parent of commit",
        HeadFetchError                    => "Error while getting HEAD",
        NotOnBranch                       => "No Branch is checked out",
        MkRepo => "Repository creation error",
        MkSignature => "Error while building Signature object",
        StoreIdHandlingError => "Error handling the store id object",
        StoreIdStripError => "Couldn't strip prefix from StoreID object",

        RepositoryFileStatusError => "Error while getting file status",

        GitConfigFetchError => "Error fetching git config",
        GitConfigEditorFetchError => "Error fetching 'editor' from git config",
        CommitEditorInstantiationError => "Error when trying to instantiate commit editor",
        EditorError => "Error while calling editor"
    );
);

impl GitHookError {

    pub fn inside_of<T>(self, h: HEK) -> HookResult<T> {
        Err(HE::new(h, Some(Box::new(self))))
    }

}

impl From<GitHookError> for HE {

    fn from(he: GitHookError) -> HE {
        HE::new(HEK::HookExecutionError, Some(Box::new(he)))
    }

}

impl From<Git2Error> for GitHookError {

    fn from(ge: Git2Error) -> GitHookError {
        GitHookError::new(GitHookErrorKind::RepositoryBackendError, Some(Box::new(ge)))
    }

}

pub trait MapIntoHookError<T> {
    fn map_into_hook_error(self) -> Result<T, HE>;
}

impl<T> MapIntoHookError<T> for Result<T, GitHookError> {

    fn map_into_hook_error(self) -> Result<T, HE> {
        self.map_err(|e| HE::new(HEK::HookExecutionError, Some(Box::new(e))))
    }

}

pub use self::error::GitHookError;
pub use self::error::GitHookErrorKind;
pub use self::error::MapErrInto;

<commit_msg>Remove unused error kinds<commit_after>use git2::Error as Git2Error;

use libimagstore::hook::error::HookError as HE;
use libimagstore::hook::error::HookErrorKind as HEK;
use libimagstore::hook::result::HookResult;

generate_error_module!(
    generate_error_types!(GitHookError, GitHookErrorKind,
        ConfigError => "Configuration Error",
        NoConfigError => "No Configuration",
        ConfigTypeError => "Configuration value type wrong",

        RepositoryError                   => "Error while interacting with git repository",
        RepositoryBackendError            => "Error in the git library",
        RepositoryBranchError             => "Error while interacting with git branch(es)",
        RepositoryBranchNameFetchingError => "Error while fetching branch name",
        RepositoryIndexFetchingError      => "Error while fetching Repository Index",
        RepositoryIndexWritingError       => "Error while writing Repository Index",
        RepositoryPathAddingError         => "Error while adding Path to Index",
        RepositoryCommittingError         => "Error while committing",
        RepositoryParentFetchingError     => "Error while fetching parent of commit",

        HeadFetchError                    => "Error while getting HEAD",
        NotOnBranch                       => "No Branch is checked out",
        MkRepo                            => "Repository creation error",
        MkSignature                       => "Error while building Signature object",

        RepositoryFileStatusError         => "Error while getting file status",

        GitConfigFetchError               => "Error fetching git config",
        GitConfigEditorFetchError         => "Error fetching 'editor' from git config",
        EditorError                       => "Error while calling editor"
    );
);

impl GitHookError {

    pub fn inside_of<T>(self, h: HEK) -> HookResult<T> {
        Err(HE::new(h, Some(Box::new(self))))
    }

}

impl From<GitHookError> for HE {

    fn from(he: GitHookError) -> HE {
        HE::new(HEK::HookExecutionError, Some(Box::new(he)))
    }

}

impl From<Git2Error> for GitHookError {

    fn from(ge: Git2Error) -> GitHookError {
        GitHookError::new(GitHookErrorKind::RepositoryBackendError, Some(Box::new(ge)))
    }

}

pub trait MapIntoHookError<T> {
    fn map_into_hook_error(self) -> Result<T, HE>;
}

impl<T> MapIntoHookError<T> for Result<T, GitHookError> {

    fn map_into_hook_error(self) -> Result<T, HE> {
        self.map_err(|e| HE::new(HEK::HookExecutionError, Some(Box::new(e))))
    }

}

pub use self::error::GitHookError;
pub use self::error::GitHookErrorKind;
pub use self::error::MapErrInto;

<|endoftext|>


<commit_before>// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// Based on threadring.erlang by Jira Isa
extern mod std;

const n_threads: int = 503;

fn start(+token: int) {
    use iter::*;

    let p = comm::Port();
    let mut ch = comm::Chan(&p);
    for int::range(2, n_threads + 1) |i| {
        let id = n_threads + 2 - i;
        let to_child = do task::spawn_listener::<int> |p, copy ch| {
            roundtrip(id, p, ch)
        };
        ch = to_child;
    }
    comm::send(ch, token);
    roundtrip(1, p, ch);
}

fn roundtrip(id: int, p: comm::Port<int>, ch: comm::Chan<int>) {
    while (true) {
        match comm::recv(p) {
          1 => {
            io::println(fmt!("%d\n", id));
            return;
          }
          token => {
            debug!("%d %d", id, token);
            comm::send(ch, token - 1);
            if token <= n_threads {
                return;
            }
          }
        }
    }
}

fn main() {
    let args = os::args();
    let args = if os::getenv(~"RUST_BENCH").is_some() {
        ~[~"", ~"2000000"]
    } else if args.len() <= 1u {
        ~[~"", ~"1000"]
    } else {
        args
    };

    let token = int::from_str(args[1]).get();

    start(token);
}
<commit_msg>Remove bench/shootout-threadring.rs<commit_after><|endoftext|>