<commit_before>use nom::{Err, ErrorKind, IResult, Needed};

/*
struct Document {
    header: Header,
    body: Vec<Element>,
}

struct Header {}

#[derive(Debug)]
enum ElementData {
    Signed(i64),
    Unsigned(u64),
    Float(f64),
    PlainString(String),
    UTF8String(String),
    Date(u64),
    Master(Vec<Element>),
    Binary(Vec<u8>),
    Unknown(u64),
}

#[derive(Debug)]
pub struct Element {
    id: u64,
    size: u64,
    data: ElementData,
}
*/

pub fn vint(input: &[u8]) -> IResult<&[u8], u64> {
    if input.len() == 0 {
        return Err(Err::Incomplete(Needed::Size(1)));
    }

    let v = input[0];
    let len = v.leading_zeros();

    if len == 8 {
        return Err(Err::Error(error_position!(input, ErrorKind::Custom(100))));
    }

    if input.len() <= len as usize {
        return Err(Err::Incomplete(Needed::Size(1)));
    }

    let mut val = (v ^ (1 << (7 - len))) as u64;

    // trace!("vint {:08b} {:08b} {:08b} {}", val, v, (1 << (8 - len)), len);

    for i in 0..len as usize {
        val = (val << 8) | input[i + 1] as u64;
    }

    Ok((&input[len as usize + 1..], val))
}

// The ID are represented in the specification as their binary representation
// do not drop the marker bit.
pub fn vid(input: &[u8]) -> IResult<&[u8], u64> {
    if input.len() == 0 {
        return Err(Err::Incomplete(Needed::Size(1)));
    }

    let v = input[0];
    let len = v.leading_zeros();

    if len == 8 {
        return Err(Err::Error(error_position!(input, ErrorKind::Custom(101))));
    }

    if input.len() <= len as usize {
        return Err(Err::Incomplete(Needed::Size(1)));
    }

    let mut val = v as u64;

    // trace!("vint {:08b} {:08b} {:08b} {}", val, v, (1 << (8 - len)), len);

    for i in 0..len as usize {
        val = (val << 8) | input[i + 1] as u64;
    }

    Ok((&input[len as usize + 1..], val))
}

/*
fn parse_master(input: &[u8], _: u64) -> IResult<&[u8], ElementData> {
    map!(input,
         many0!(parse_element),
         |elem| ElementData::Master(elem))
}

fn parse_uint(input: &[u8], size: u64) -> IResult<&[u8], ElementData> {
    let mut val = 0;

    if size > 8 {
        return IResult::Error(ErrorKind::Custom(1));
    }

    for i in 0..size as usize {
        val = (val << 8) | input[i] as u64;
    }

    IResult::Done(&input[size as usize..], ElementData::Unsigned(val))
}
*/
pub fn parse_uint_data(input: &[u8], size: u64) -> IResult<&[u8], u64> {
    let mut val = 0;

    if size > 8 {
        return Err(Err::Error(error_position!(input, ErrorKind::Custom(102))));
    }

    for i in 0..size as usize {
        val = (val << 8) | input[i] as u64;
    }

    Ok((&input[size as usize..], val))
}

pub fn parse_int_data(input: &[u8], size: u64) -> IResult<&[u8], i64> {
    let mut val = 0;

    if size > 8 {
        return Err(Err::Error(error_position!(input, ErrorKind::Custom(103))));
    }

    for i in 0..size as usize {
        val = (val << 8) | input[i] as u64;
    }

    //FIXME: is that right?
    Ok((&input[size as usize..], val as i64))
}

/*
fn parse_str(input: &[u8], size: u64) -> IResult<&[u8], ElementData> {
    do_parse!(input,
        s: take_s!(size as usize) >>
        ( ElementData::PlainString(String::from_utf8(s.to_owned()).unwrap()) )
    )
}
*/
pub fn parse_str_data(input: &[u8], size: u64) -> IResult<&[u8], String> {
    do_parse!(
        input,
        s: take_s!(size as usize) >> (String::from_utf8(s.to_owned()).unwrap()) //FIXME: maybe do not unwrap here
    )
}

pub fn parse_binary_data(input: &[u8], size: u64) -> IResult<&[u8], Vec<u8>> {
    do_parse!(input, s: take_s!(size as usize) >> (s.to_owned()))
}

//FIXME: handle default values
//FIXME: is that really following IEEE_754-1985 ?
pub fn parse_float_data(input: &[u8], size: u64) -> IResult<&[u8], f64> {
    use nom::{be_f32, be_f64};
    if size == 0 {
        Ok((input, 0f64))
    } else if size == 4 {
        map!(input, flat_map!(take!(4), be_f32), |val| val as f64)
    } else if size == 8 {
        flat_map!(input, take!(8), be_f64)
    } else {
        Err(Err::Error(error_position!(input, ErrorKind::Custom(104))))
    }
}
/*
fn parse_element_id(input: &[u8], id: u64, size: u64) -> IResult<&[u8], ElementData> {
    // trace!("id: 0x{:X} size: {}", id, size);
    if input.len() < size as usize {
        return IResult::Incomplete(Needed::Size(size as usize));
    }

    match id {
        0x1A45DFA3 => parse_master(input, size),
        0x4286 => parse_uint(input, size),
        0x42F7 => parse_uint(input, size),
        0x42F2 => parse_uint(input, size),
        0x42F3 => parse_uint(input, size),
        0x4282 => parse_str(input, size),
        0x4287 => parse_uint(input, size),
        0x4285 => parse_uint(input, size),
        _ => IResult::Done(&input[size as usize..], ElementData::Unknown(id)),
    }
}

named!(pub parse_element<Element>,
    do_parse!(
        id : vid >>
        size: vint >>
        data: call!(parse_element_id, id, size) >>
        (Element { id, size, data })
    )
);
*/
#[macro_export]
macro_rules! ebml_uint (
  ($i: expr, $id:expr) => ({
    use $crate::ebml::{vid, vint, parse_uint_data};
    do_parse!($i,
               verify!(vid, |val:u64| val == $id)
      >> size: vint
      >> data: apply!(parse_uint_data, size)
      >> (data)
    )
  })
);

#[macro_export]
macro_rules! ebml_int (
  ($i: expr, $id:expr) => ({
    use $crate::ebml::{vid, vint, parse_int_data};
    do_parse!($i,
               verify!(vid, |val:u64| val == $id)
      >> size: vint
      >> data: apply!(parse_int_data, size)
      >> (data)
    )
  })
);

#[macro_export]
macro_rules! ebml_float (
  ($i: expr, $id:expr) => ({
    use $crate::ebml::{vid, vint, parse_float_data};
    do_parse!($i,
               verify!(vid, |val:u64| val == $id)
      >> size: vint
      >> data: apply!(parse_float_data, size)
      >> (data)
    )
  })
);

#[macro_export]
macro_rules! ebml_str (
  ($i: expr, $id:expr) => ({
    use $crate::ebml::{vid, vint, parse_str_data};

    do_parse!($i,
               verify!(vid, |val:u64| val == $id)
      >> size: vint
      >> data: apply!(parse_str_data, size)
      >> (data)
    )
  })
);

#[macro_export]
macro_rules! ebml_binary (
  ($i: expr, $id:expr) => ({
    use $crate::ebml::{vid, vint, parse_binary_data};

    do_parse!($i,
               verify!(vid, |val:u64| val == $id)
      >> size: vint
      >> data: apply!(parse_binary_data, size)
      >> (data)
    )
  })
);

#[macro_export]
macro_rules! ebml_binary_ref (
  ($i: expr, $id:expr) => ({
    use $crate::ebml::{vid, vint};

    do_parse!($i,
               verify!(vid, |val:u64| val == $id)
      >> size: vint
      >> data: take!(size)
      >> (data)
    )
  })
);

#[macro_export]
macro_rules! ebml_master (
  ($i: expr, $id:expr, $submac:ident!( $($args:tt)* )) => ({
    use $crate::ebml::{vid, vint};
    do_parse!($i,
               verify!(vid, |val:u64| val == $id)
      >> size: vint
      >> data: flat_map!(take!(size as usize), $submac!($($args)*))
      >> (data)
    )
  })
);

#[macro_export]
macro_rules! eat_void (
  ($i: expr, $submac:ident!( $($args:tt)* )) => ({
    preceded!($i,
      opt!($crate::ebml::skip_void),
      $submac!($($args)*)
    )
  });
  ($i: expr, $e:expr) => ({
    eat_void!($i, call!($e))
  });
);

named!(pub skip_void,
do_parse!(
        verify!(vid, |val:u64| val == 0xEC) >>
  size: vint >>
  data: take!(size) >>
  (data)
  ));

#[derive(Debug, Clone, PartialEq)]
pub struct EBMLHeader {
    pub version: u64,
    pub read_version: u64,
    pub max_id_length: u64,
    pub max_size_length: u64,
    pub doc_type: String,
    pub doc_type_version: u64,
    pub doc_type_read_version: u64,
}

named!(pub ebml_header<EBMLHeader>,
  ebml_master!(0x1A45DFA3,
    do_parse!(
      t: permutation_opt!(
        ebml_uint!(0x4286), // version
        ebml_uint!(0x42F7), // read_version
        ebml_uint!(0x42F2), // max id length
        ebml_uint!(0x42F3), // max size length
        ebml_str!(0x4282),  // doctype
        ebml_uint!(0x4287), // doctype version
        ebml_uint!(0x4285),  // doctype_read version
        complete!(skip_void)?
      ) >>
      ({
        EBMLHeader {
          version:               t.0,
          read_version:          t.1,
          max_id_length:         t.2,
          max_size_length:       t.3,
          doc_type:              t.4,
          doc_type_version:      t.5,
          doc_type_read_version: t.6,

        }
      })
    )
  )
);

#[cfg(test)]
#[allow(non_upper_case_globals)]
mod tests {
    use super::*;
    use nom::{HexDisplay, Offset};

    const single_stream: &'static [u8] = include_bytes!("../assets/single_stream.mkv");
    const webm: &'static [u8] = include_bytes!("../assets/big-buck-bunny_trailer.webm");

    #[test]
    fn variable_integer() {
        let val01 = [0b10000000];
        //        let val01 = [0b01000000, 0b1];

        match vint(&val01) {
            Ok((_, v)) => assert!(0 == v),
            _ => panic!(),
        }
    }

    /*
    #[test]
    fn header() {
        trace!("{}", single_stream[..8].to_hex(8));
        trace!("{:b} {:b}", single_stream[0], single_stream[1]);
        trace!("{:#?}", parse_element(single_stream));
        panic!();
    }*/

    #[test]
    fn mkv_header() {
        trace!("{}", single_stream[..8].to_hex(8));
        trace!("{:b} {:b}", single_stream[0], single_stream[1]);
        trace!("{:?}", ebml_header(&single_stream[..100]).unwrap());
    }

    #[test]
    fn webm_header() {
        trace!("{}", webm[..8].to_hex(8));
        let res = ebml_header(&webm[..100]);
        trace!("{:?}", res);

        if let Ok((i, _)) = res {
            trace!("offset: {} bytes", webm.offset(i));
        } else {
            panic!();
        }
    }
}
<commit_msg>Enable some traces<commit_after>use nom::{Err, ErrorKind, IResult, Needed};

/*
struct Document {
    header: Header,
    body: Vec<Element>,
}

struct Header {}

#[derive(Debug)]
enum ElementData {
    Signed(i64),
    Unsigned(u64),
    Float(f64),
    PlainString(String),
    UTF8String(String),
    Date(u64),
    Master(Vec<Element>),
    Binary(Vec<u8>),
    Unknown(u64),
}

#[derive(Debug)]
pub struct Element {
    id: u64,
    size: u64,
    data: ElementData,
}
*/

pub fn vint(input: &[u8]) -> IResult<&[u8], u64> {
    if input.len() == 0 {
        return Err(Err::Incomplete(Needed::Size(1)));
    }

    let v = input[0];
    let len = v.leading_zeros();

    if len == 8 {
        return Err(Err::Error(error_position!(input, ErrorKind::Custom(100))));
    }

    if input.len() <= len as usize {
        return Err(Err::Incomplete(Needed::Size(1)));
    }

    let mut val = (v ^ (1 << (7 - len))) as u64;

    trace!("vint {:08b} {:08b} {:08b} {}", val, v, (1 << (8 - len)), len);

    for i in 0..len as usize {
        val = (val << 8) | input[i + 1] as u64;
    }

    trace!("     result {:08x}", val);

    Ok((&input[len as usize + 1..], val))
}

// The ID are represented in the specification as their binary representation
// do not drop the marker bit.
pub fn vid(input: &[u8]) -> IResult<&[u8], u64> {
    if input.len() == 0 {
        return Err(Err::Incomplete(Needed::Size(1)));
    }

    let v = input[0];
    let len = v.leading_zeros();

    if len == 8 {
        return Err(Err::Error(error_position!(input, ErrorKind::Custom(101))));
    }

    if input.len() <= len as usize {
        return Err(Err::Incomplete(Needed::Size(1)));
    }

    let mut val = v as u64;

    trace!("vid {:08b} {:08b} {:08b} {}", val, v, (1 << (8 - len)), len);

    for i in 0..len as usize {
        val = (val << 8) | input[i + 1] as u64;
    }

    trace!("     result {:08x}", val);

    Ok((&input[len as usize + 1..], val))
}

/*
fn parse_master(input: &[u8], _: u64) -> IResult<&[u8], ElementData> {
    map!(input,
         many0!(parse_element),
         |elem| ElementData::Master(elem))
}

fn parse_uint(input: &[u8], size: u64) -> IResult<&[u8], ElementData> {
    let mut val = 0;

    if size > 8 {
        return IResult::Error(ErrorKind::Custom(1));
    }

    for i in 0..size as usize {
        val = (val << 8) | input[i] as u64;
    }

    IResult::Done(&input[size as usize..], ElementData::Unsigned(val))
}
*/
pub fn parse_uint_data(input: &[u8], size: u64) -> IResult<&[u8], u64> {
    let mut val = 0;

    if size > 8 {
        return Err(Err::Error(error_position!(input, ErrorKind::Custom(102))));
    }

    for i in 0..size as usize {
        val = (val << 8) | input[i] as u64;
    }

    Ok((&input[size as usize..], val))
}

pub fn parse_int_data(input: &[u8], size: u64) -> IResult<&[u8], i64> {
    let mut val = 0;

    if size > 8 {
        return Err(Err::Error(error_position!(input, ErrorKind::Custom(103))));
    }

    for i in 0..size as usize {
        val = (val << 8) | input[i] as u64;
    }

    //FIXME: is that right?
    Ok((&input[size as usize..], val as i64))
}

/*
fn parse_str(input: &[u8], size: u64) -> IResult<&[u8], ElementData> {
    do_parse!(input,
        s: take_s!(size as usize) >>
        ( ElementData::PlainString(String::from_utf8(s.to_owned()).unwrap()) )
    )
}
*/
pub fn parse_str_data(input: &[u8], size: u64) -> IResult<&[u8], String> {
    do_parse!(
        input,
        s: take_s!(size as usize) >> (String::from_utf8(s.to_owned()).unwrap()) //FIXME: maybe do not unwrap here
    )
}

pub fn parse_binary_data(input: &[u8], size: u64) -> IResult<&[u8], Vec<u8>> {
    do_parse!(input, s: take_s!(size as usize) >> (s.to_owned()))
}

//FIXME: handle default values
//FIXME: is that really following IEEE_754-1985 ?
pub fn parse_float_data(input: &[u8], size: u64) -> IResult<&[u8], f64> {
    use nom::{be_f32, be_f64};
    if size == 0 {
        Ok((input, 0f64))
    } else if size == 4 {
        map!(input, flat_map!(take!(4), be_f32), |val| val as f64)
    } else if size == 8 {
        flat_map!(input, take!(8), be_f64)
    } else {
        Err(Err::Error(error_position!(input, ErrorKind::Custom(104))))
    }
}
/*
fn parse_element_id(input: &[u8], id: u64, size: u64) -> IResult<&[u8], ElementData> {
    // trace!("id: 0x{:X} size: {}", id, size);
    if input.len() < size as usize {
        return IResult::Incomplete(Needed::Size(size as usize));
    }

    match id {
        0x1A45DFA3 => parse_master(input, size),
        0x4286 => parse_uint(input, size),
        0x42F7 => parse_uint(input, size),
        0x42F2 => parse_uint(input, size),
        0x42F3 => parse_uint(input, size),
        0x4282 => parse_str(input, size),
        0x4287 => parse_uint(input, size),
        0x4285 => parse_uint(input, size),
        _ => IResult::Done(&input[size as usize..], ElementData::Unknown(id)),
    }
}

named!(pub parse_element<Element>,
    do_parse!(
        id : vid >>
        size: vint >>
        data: call!(parse_element_id, id, size) >>
        (Element { id, size, data })
    )
);
*/
#[macro_export]
macro_rules! ebml_uint (
  ($i: expr, $id:expr) => ({
    use $crate::ebml::{vid, vint, parse_uint_data};
    do_parse!($i,
               verify!(vid, |val:u64| val == $id)
      >> size: vint
      >> data: apply!(parse_uint_data, size)
      >> (data)
    )
  })
);

#[macro_export]
macro_rules! ebml_int (
  ($i: expr, $id:expr) => ({
    use $crate::ebml::{vid, vint, parse_int_data};
    do_parse!($i,
               verify!(vid, |val:u64| val == $id)
      >> size: vint
      >> data: apply!(parse_int_data, size)
      >> (data)
    )
  })
);

#[macro_export]
macro_rules! ebml_float (
  ($i: expr, $id:expr) => ({
    use $crate::ebml::{vid, vint, parse_float_data};
    do_parse!($i,
               verify!(vid, |val:u64| val == $id)
      >> size: vint
      >> data: apply!(parse_float_data, size)
      >> (data)
    )
  })
);

#[macro_export]
macro_rules! ebml_str (
  ($i: expr, $id:expr) => ({
    use $crate::ebml::{vid, vint, parse_str_data};

    do_parse!($i,
               verify!(vid, |val:u64| val == $id)
      >> size: vint
      >> data: apply!(parse_str_data, size)
      >> (data)
    )
  })
);

#[macro_export]
macro_rules! ebml_binary (
  ($i: expr, $id:expr) => ({
    use $crate::ebml::{vid, vint, parse_binary_data};

    do_parse!($i,
               verify!(vid, |val:u64| val == $id)
      >> size: vint
      >> data: apply!(parse_binary_data, size)
      >> (data)
    )
  })
);

#[macro_export]
macro_rules! ebml_binary_ref (
  ($i: expr, $id:expr) => ({
    use $crate::ebml::{vid, vint};

    do_parse!($i,
               verify!(vid, |val:u64| val == $id)
      >> size: vint
      >> data: take!(size)
      >> (data)
    )
  })
);

#[macro_export]
macro_rules! ebml_master (
  ($i: expr, $id:expr, $submac:ident!( $($args:tt)* )) => ({
    use $crate::ebml::{vid, vint};
    do_parse!($i,
               verify!(vid, |val:u64| val == $id)
      >> size: vint
      >> data: flat_map!(take!(size as usize), $submac!($($args)*))
      >> (data)
    )
  })
);

#[macro_export]
macro_rules! eat_void (
  ($i: expr, $submac:ident!( $($args:tt)* )) => ({
    preceded!($i,
      opt!($crate::ebml::skip_void),
      $submac!($($args)*)
    )
  });
  ($i: expr, $e:expr) => ({
    eat_void!($i, call!($e))
  });
);

named!(pub skip_void,
do_parse!(
        verify!(vid, |val:u64| val == 0xEC) >>
  size: vint >>
  data: take!(size) >>
  (data)
  ));

#[derive(Debug, Clone, PartialEq)]
pub struct EBMLHeader {
    pub version: u64,
    pub read_version: u64,
    pub max_id_length: u64,
    pub max_size_length: u64,
    pub doc_type: String,
    pub doc_type_version: u64,
    pub doc_type_read_version: u64,
}

named!(pub ebml_header<EBMLHeader>,
  ebml_master!(0x1A45DFA3,
    do_parse!(
      t: permutation_opt!(
        ebml_uint!(0x4286), // version
        ebml_uint!(0x42F7), // read_version
        ebml_uint!(0x42F2), // max id length
        ebml_uint!(0x42F3), // max size length
        ebml_str!(0x4282),  // doctype
        ebml_uint!(0x4287), // doctype version
        ebml_uint!(0x4285),  // doctype_read version
        complete!(skip_void)?
      ) >>
      ({
        EBMLHeader {
          version:               t.0,
          read_version:          t.1,
          max_id_length:         t.2,
          max_size_length:       t.3,
          doc_type:              t.4,
          doc_type_version:      t.5,
          doc_type_read_version: t.6,

        }
      })
    )
  )
);

#[cfg(test)]
#[allow(non_upper_case_globals)]
mod tests {
    use super::*;
    use nom::{HexDisplay, Offset};

    const single_stream: &'static [u8] = include_bytes!("../assets/single_stream.mkv");
    const webm: &'static [u8] = include_bytes!("../assets/big-buck-bunny_trailer.webm");

    #[test]
    fn variable_integer() {
        let val01 = [0b10000000];
        //        let val01 = [0b01000000, 0b1];

        match vint(&val01) {
            Ok((_, v)) => assert!(0 == v),
            _ => panic!(),
        }
    }

    /*
    #[test]
    fn header() {
        trace!("{}", single_stream[..8].to_hex(8));
        trace!("{:b} {:b}", single_stream[0], single_stream[1]);
        trace!("{:#?}", parse_element(single_stream));
        panic!();
    }*/

    #[test]
    fn mkv_header() {
        trace!("{}", single_stream[..8].to_hex(8));
        trace!("{:b} {:b}", single_stream[0], single_stream[1]);
        trace!("{:?}", ebml_header(&single_stream[..100]).unwrap());
    }

    #[test]
    fn webm_header() {
        trace!("{}", webm[..8].to_hex(8));
        let res = ebml_header(&webm[..100]);
        trace!("{:?}", res);

        if let Ok((i, _)) = res {
            trace!("offset: {} bytes", webm.offset(i));
        } else {
            panic!();
        }
    }
}
<|endoftext|>


<commit_before>use ::cairo;
use ::cairo_sys;

use std::f64;
use std::f64::consts::*;

#[repr(C)]
pub struct RsvgPathBuilder {
    path_segments: Vec<cairo::PathSegment>,
}

impl RsvgPathBuilder {
    pub fn new () -> RsvgPathBuilder {
        let builder = RsvgPathBuilder {
            path_segments: Vec::new ()
        };

        builder
    }

    pub fn move_to (&mut self, x: f64, y: f64) {
        self.path_segments.push (cairo::PathSegment::MoveTo ((x, y)));
    }

    pub fn line_to (&mut self, x: f64, y: f64) {
        self.path_segments.push (cairo::PathSegment::LineTo ((x, y)));
    }

    pub fn curve_to (&mut self, x2: f64, y2: f64, x3: f64, y3: f64, x4: f64, y4: f64) {
        self.path_segments.push (cairo::PathSegment::CurveTo ((x2, y2), (x3, y3), (x4, y4)));
    }

    pub fn close_path (&mut self) {
        self.path_segments.push (cairo::PathSegment::ClosePath);
    }

    pub fn get_path_segments (&self) -> &Vec<cairo::PathSegment> {
        &self.path_segments
    }

    /**
     * x1/y1: starting coordinates
     * rx/ry: radiuses before rotation
     * x_axis_rotation: Rotation angle for axes, in degrees
     * is_large_arc: false for arc length <= 180, true for arc >= 180
     * is_sweep: false for negative angle, true for positive angle
     * x2/y2: ending coordinates
     */
    pub fn arc (&mut self,
                x1: f64, y1: f64,
                mut rx: f64, mut ry: f64,
                x_axis_rotation: f64,
                is_large_arc: bool,
                is_sweep: bool,
                x2: f64, y2: f64) {
        /* See Appendix F.6 Elliptical arc implementation notes
        http://www.w3.org/TR/SVG/implnote.html#ArcImplementationNotes */

        let f: f64;
        let sinf: f64;
        let cosf: f64;
        let x1_: f64;
        let y1_: f64;
        let cx_: f64;
        let cy_: f64;
        let cx: f64;
        let cy: f64;
        let gamma: f64;
        let mut theta1: f64;
        let mut delta_theta: f64;
        let mut k1: f64;
        let mut k2: f64;
        let k3: f64;
        let k4: f64;
        let mut k5: f64;
        let n_segs: i32;

        if x1 == x2 && y1 == y2 {
            return;
        }

        /* X-axis */
        f = x_axis_rotation * PI / 180.0;
        sinf = f.sin ();
        cosf = f.cos ();

        rx = rx.abs ();
        ry = ry.abs ();

        /* Check the radius against floading point underflow.
        See http://bugs.debian.org/508443 */
        if (rx < f64::EPSILON) || (ry < f64::EPSILON) {
            self.line_to (x2, y2);
            return;
        }

        k1 = (x1 - x2) / 2.0;
        k2 = (y1 - y2) / 2.0;

        x1_ = cosf * k1 + sinf * k2;
        y1_ = -sinf * k1 + cosf * k2;

        gamma = (x1_ * x1_) / (rx * rx) + (y1_ * y1_) / (ry * ry);
        if gamma > 1.0 {
            rx *= gamma.sqrt ();
            ry *= gamma.sqrt ();
        }

        /* Compute the center */

        k1 = rx * rx * y1_ * y1_ + ry * ry * x1_ * x1_;
        if k1 == 0.0 {
            return;
        }

        k1 = ((rx * rx * ry * ry) / k1 - 1.0).abs ().sqrt ();
        if is_sweep == is_large_arc {
            k1 = -k1;
        }

        cx_ = k1 * rx * y1_ / ry;
        cy_ = -k1 * ry * x1_ / rx;

        cx = cosf * cx_ - sinf * cy_ + (x1 + x2) / 2.0;
        cy = sinf * cx_ + cosf * cy_ + (y1 + y2) / 2.0;

        /* Compute start angle */

        k1 = (x1_ - cx_) / rx;
        k2 = (y1_ - cy_) / ry;
        k3 = (-x1_ - cx_) / rx;
        k4 = (-y1_ - cy_) / ry;

        k5 = (k1 * k1 + k2 * k2).abs ().sqrt ();
        if k5 == 0.0 {
            return;
        }

        k5 = k1 / k5;
        k5 = clamp (k5, -1.0, 1.0);
        theta1 = k5.acos ();
        if k2 < 0.0 {
            theta1 = -theta1;
        }

        /* Compute delta_theta */

        k5 = ((k1 * k1 + k2 * k2) * (k3 * k3 + k4 * k4)).abs ().sqrt ();
        if k5 == 0.0 {
            return;
        }

        k5 = (k1 * k3 + k2 * k4) / k5;
        k5 = clamp (k5, -1.0, 1.0);
        delta_theta = k5.acos ();
        if k1 * k4 - k3 * k2 < 0.0 {
            delta_theta = -delta_theta;
        }

        if is_sweep && delta_theta < 0.0 {
            delta_theta += PI * 2.0;
        } else if !is_sweep && delta_theta > 0.0 {
            delta_theta -= PI * 2.0;
        }

        /* Now draw the arc */

        n_segs = (delta_theta / (PI * 0.5 + 0.001)).abs ().ceil () as i32;
        let n_segs_dbl = n_segs as f64;

        for i in 0 .. n_segs {
            self.arc_segment (cx, cy,
                              theta1 + i as f64 * delta_theta / n_segs_dbl,
                              theta1 + (i + 1) as f64 * delta_theta / n_segs_dbl,
                              rx, ry,
                              x_axis_rotation);
        }
    }

    fn arc_segment (&mut self,
                    xc: f64, yc: f64,
                    th0: f64, th1: f64,
                    rx: f64, ry: f64,
                    x_axis_rotation: f64) {
        let x1: f64;
        let y1: f64;
        let x2: f64;
        let y2: f64;
        let x3: f64;
        let y3: f64;
        let t: f64;
        let th_half: f64;
        let f: f64;
        let sinf: f64;
        let cosf: f64;

        f = x_axis_rotation * PI / 180.0;
        sinf = f.sin ();
        cosf = f.cos ();

        th_half = 0.5 * (th1 - th0);
        t = (8.0 / 3.0) * (th_half * 0.5).sin () * (th_half * 0.5).sin () / th_half.sin ();
        x1 = rx * (th0.cos () - t * th0.sin ());
        y1 = ry * (th0.sin () + t * th0.cos ());
        x3 = rx * th1.cos ();
        y3 = ry * th1.sin ();
        x2 = x3 + rx * (t * th1.sin ());
        y2 = y3 + ry * (-t * th1.cos ());

        self.curve_to (xc + cosf * x1 - sinf * y1,
                       yc + sinf * x1 + cosf * y1,
                       xc + cosf * x2 - sinf * y2,
                       yc + sinf * x2 + cosf * y2,
                       xc + cosf * x3 - sinf * y3,
                       yc + sinf * x3 + cosf * y3);
    }
}

fn clamp (val: f64, low: f64, high: f64) -> f64 {
    if val < low {
        low
    } else if val > high {
        high
    } else {
        val
    }
}

#[no_mangle]
pub extern fn rsvg_path_builder_add_to_cairo_context (raw_builder: *mut RsvgPathBuilder, cr: *mut cairo_sys::cairo_t) {
    assert! (!raw_builder.is_null ());

    let builder: &mut RsvgPathBuilder = unsafe { &mut (*raw_builder) };

    unsafe {
        let path_segments = builder.get_path_segments ();

        for s in path_segments {
            match *s {
                cairo::PathSegment::MoveTo ((x, y)) => {
                    cairo_sys::cairo_move_to (cr, x, y);
                },

                cairo::PathSegment::LineTo ((x, y)) => {
                    cairo_sys::cairo_line_to (cr, x, y);
                },

                cairo::PathSegment::CurveTo ((x2, y2), (x3, y3), (x4, y4)) => {
                    cairo_sys::cairo_curve_to (cr, x2, y2, x3, y3, x4, y4);
                },

                cairo::PathSegment::ClosePath => {
                    cairo_sys::cairo_close_path (cr);
                }
            }
        }
    }
}
<commit_msg>path_builder.rs: Declare a PathCommand enum<commit_after>use ::cairo;
use ::cairo_sys;

use std::f64;
use std::f64::consts::*;

pub enum PathCommand {
    MoveTo (f64, f64),
    LineTo (f64, f64),
    CurveTo ((f64, f64), (f64, f64), (f64, f64)), // (x2, y2), (x3, y3), (x4, y4) <- this is the destination point
    ClosePath
}

#[repr(C)]
pub struct RsvgPathBuilder {
    path_segments: Vec<cairo::PathSegment>,
}

impl RsvgPathBuilder {
    pub fn new () -> RsvgPathBuilder {
        let builder = RsvgPathBuilder {
            path_segments: Vec::new ()
        };

        builder
    }

    pub fn move_to (&mut self, x: f64, y: f64) {
        self.path_segments.push (cairo::PathSegment::MoveTo ((x, y)));
    }

    pub fn line_to (&mut self, x: f64, y: f64) {
        self.path_segments.push (cairo::PathSegment::LineTo ((x, y)));
    }

    pub fn curve_to (&mut self, x2: f64, y2: f64, x3: f64, y3: f64, x4: f64, y4: f64) {
        self.path_segments.push (cairo::PathSegment::CurveTo ((x2, y2), (x3, y3), (x4, y4)));
    }

    pub fn close_path (&mut self) {
        self.path_segments.push (cairo::PathSegment::ClosePath);
    }

    pub fn get_path_segments (&self) -> &Vec<cairo::PathSegment> {
        &self.path_segments
    }

    /**
     * x1/y1: starting coordinates
     * rx/ry: radiuses before rotation
     * x_axis_rotation: Rotation angle for axes, in degrees
     * is_large_arc: false for arc length <= 180, true for arc >= 180
     * is_sweep: false for negative angle, true for positive angle
     * x2/y2: ending coordinates
     */
    pub fn arc (&mut self,
                x1: f64, y1: f64,
                mut rx: f64, mut ry: f64,
                x_axis_rotation: f64,
                is_large_arc: bool,
                is_sweep: bool,
                x2: f64, y2: f64) {
        /* See Appendix F.6 Elliptical arc implementation notes
        http://www.w3.org/TR/SVG/implnote.html#ArcImplementationNotes */

        let f: f64;
        let sinf: f64;
        let cosf: f64;
        let x1_: f64;
        let y1_: f64;
        let cx_: f64;
        let cy_: f64;
        let cx: f64;
        let cy: f64;
        let gamma: f64;
        let mut theta1: f64;
        let mut delta_theta: f64;
        let mut k1: f64;
        let mut k2: f64;
        let k3: f64;
        let k4: f64;
        let mut k5: f64;
        let n_segs: i32;

        if x1 == x2 && y1 == y2 {
            return;
        }

        /* X-axis */
        f = x_axis_rotation * PI / 180.0;
        sinf = f.sin ();
        cosf = f.cos ();

        rx = rx.abs ();
        ry = ry.abs ();

        /* Check the radius against floading point underflow.
        See http://bugs.debian.org/508443 */
        if (rx < f64::EPSILON) || (ry < f64::EPSILON) {
            self.line_to (x2, y2);
            return;
        }

        k1 = (x1 - x2) / 2.0;
        k2 = (y1 - y2) / 2.0;

        x1_ = cosf * k1 + sinf * k2;
        y1_ = -sinf * k1 + cosf * k2;

        gamma = (x1_ * x1_) / (rx * rx) + (y1_ * y1_) / (ry * ry);
        if gamma > 1.0 {
            rx *= gamma.sqrt ();
            ry *= gamma.sqrt ();
        }

        /* Compute the center */

        k1 = rx * rx * y1_ * y1_ + ry * ry * x1_ * x1_;
        if k1 == 0.0 {
            return;
        }

        k1 = ((rx * rx * ry * ry) / k1 - 1.0).abs ().sqrt ();
        if is_sweep == is_large_arc {
            k1 = -k1;
        }

        cx_ = k1 * rx * y1_ / ry;
        cy_ = -k1 * ry * x1_ / rx;

        cx = cosf * cx_ - sinf * cy_ + (x1 + x2) / 2.0;
        cy = sinf * cx_ + cosf * cy_ + (y1 + y2) / 2.0;

        /* Compute start angle */

        k1 = (x1_ - cx_) / rx;
        k2 = (y1_ - cy_) / ry;
        k3 = (-x1_ - cx_) / rx;
        k4 = (-y1_ - cy_) / ry;

        k5 = (k1 * k1 + k2 * k2).abs ().sqrt ();
        if k5 == 0.0 {
            return;
        }

        k5 = k1 / k5;
        k5 = clamp (k5, -1.0, 1.0);
        theta1 = k5.acos ();
        if k2 < 0.0 {
            theta1 = -theta1;
        }

        /* Compute delta_theta */

        k5 = ((k1 * k1 + k2 * k2) * (k3 * k3 + k4 * k4)).abs ().sqrt ();
        if k5 == 0.0 {
            return;
        }

        k5 = (k1 * k3 + k2 * k4) / k5;
        k5 = clamp (k5, -1.0, 1.0);
        delta_theta = k5.acos ();
        if k1 * k4 - k3 * k2 < 0.0 {
            delta_theta = -delta_theta;
        }

        if is_sweep && delta_theta < 0.0 {
            delta_theta += PI * 2.0;
        } else if !is_sweep && delta_theta > 0.0 {
            delta_theta -= PI * 2.0;
        }

        /* Now draw the arc */

        n_segs = (delta_theta / (PI * 0.5 + 0.001)).abs ().ceil () as i32;
        let n_segs_dbl = n_segs as f64;

        for i in 0 .. n_segs {
            self.arc_segment (cx, cy,
                              theta1 + i as f64 * delta_theta / n_segs_dbl,
                              theta1 + (i + 1) as f64 * delta_theta / n_segs_dbl,
                              rx, ry,
                              x_axis_rotation);
        }
    }

    fn arc_segment (&mut self,
                    xc: f64, yc: f64,
                    th0: f64, th1: f64,
                    rx: f64, ry: f64,
                    x_axis_rotation: f64) {
        let x1: f64;
        let y1: f64;
        let x2: f64;
        let y2: f64;
        let x3: f64;
        let y3: f64;
        let t: f64;
        let th_half: f64;
        let f: f64;
        let sinf: f64;
        let cosf: f64;

        f = x_axis_rotation * PI / 180.0;
        sinf = f.sin ();
        cosf = f.cos ();

        th_half = 0.5 * (th1 - th0);
        t = (8.0 / 3.0) * (th_half * 0.5).sin () * (th_half * 0.5).sin () / th_half.sin ();
        x1 = rx * (th0.cos () - t * th0.sin ());
        y1 = ry * (th0.sin () + t * th0.cos ());
        x3 = rx * th1.cos ();
        y3 = ry * th1.sin ();
        x2 = x3 + rx * (t * th1.sin ());
        y2 = y3 + ry * (-t * th1.cos ());

        self.curve_to (xc + cosf * x1 - sinf * y1,
                       yc + sinf * x1 + cosf * y1,
                       xc + cosf * x2 - sinf * y2,
                       yc + sinf * x2 + cosf * y2,
                       xc + cosf * x3 - sinf * y3,
                       yc + sinf * x3 + cosf * y3);
    }
}

fn clamp (val: f64, low: f64, high: f64) -> f64 {
    if val < low {
        low
    } else if val > high {
        high
    } else {
        val
    }
}

#[no_mangle]
pub extern fn rsvg_path_builder_add_to_cairo_context (raw_builder: *mut RsvgPathBuilder, cr: *mut cairo_sys::cairo_t) {
    assert! (!raw_builder.is_null ());

    let builder: &mut RsvgPathBuilder = unsafe { &mut (*raw_builder) };

    unsafe {
        let path_segments = builder.get_path_segments ();

        for s in path_segments {
            match *s {
                cairo::PathSegment::MoveTo ((x, y)) => {
                    cairo_sys::cairo_move_to (cr, x, y);
                },

                cairo::PathSegment::LineTo ((x, y)) => {
                    cairo_sys::cairo_line_to (cr, x, y);
                },

                cairo::PathSegment::CurveTo ((x2, y2), (x3, y3), (x4, y4)) => {
                    cairo_sys::cairo_curve_to (cr, x2, y2, x3, y3, x4, y4);
                },

                cairo::PathSegment::ClosePath => {
                    cairo_sys::cairo_close_path (cr);
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>pub mod search;

use std::thread;
use std::cmp::min;
use std::collections::VecDeque;
use std::sync::Arc;
use std::sync::mpsc::{channel, Sender, Receiver};
use std::time::SystemTime;
use std::num::Wrapping;
use basetypes::*;
use uci::{UciEngine, UciEngineFactory, EngineReply, OptionName, OptionDescription};
use position::Position;
use chess_move::*;
use tt::*;

const VERSION: &'static str = "0.1";
const MAX_DEPTH: u8 = 126;

/// Implements `UciEngine` trait.
pub struct Engine {
    tt: Arc<TranspositionTable>,
    reply_queue: VecDeque<EngineReply>,
    position: Position,
    is_thinking: bool,
    is_pondering: bool,

    // Tells the engine if it will be allowed to ponder. This option
    // is needed because the engine might change its time management
    // algorithm when pondering is allowed.
    pondering_is_allowed: bool,

    // A channel for sending commands to the search thread.
    commands: Sender<search::Command>,

    // A channel for receiving reports from the search thread.
    reports: Receiver<search::Report>,

    // Search status info
    search_id: usize,
    thinking_since: SystemTime,
    silent_since: SystemTime,
    current_depth: u8,
    searched_nodes: NodeCount,
    searched_time: u64, // milliseconds
    nps: u64, // nodes per second
    mangled_pv: bool, // `true` if the primary variation is imperfect
    stop_when: TimeManagement,
}

impl Engine {
    /// Creates a new instance.
    ///
    /// `tt_size_mb` is the preferred size of the transposition
    /// table in Mbytes.
    pub fn new(tt_size_mb: usize) -> Engine {
        let mut tt = TranspositionTable::new();
        tt.resize(tt_size_mb);
        let tt1 = Arc::new(tt);
        let tt2 = tt1.clone();
        let (commands_tx, commands_rx) = channel();
        let (reports_tx, reports_rx) = channel();
        thread::spawn(move || {
            search::run_deepening(tt2, commands_rx, reports_tx);
        });

        Engine {
            tt: tt1,
            reply_queue: VecDeque::new(),
            position: Position::from_fen("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w QKqk - 0 \
                                          1")
                          .ok()
                          .unwrap(),
            is_thinking: false,
            is_pondering: false,
            pondering_is_allowed: false,
            commands: commands_tx,
            reports: reports_rx,
            search_id: 0,
            thinking_since: SystemTime::now(),
            silent_since: SystemTime::now(),
            current_depth: 0,
            searched_nodes: 0,
            searched_time: 0,
            nps: 0,
            mangled_pv: false,
            stop_when: TimeManagement::Infinite,
        }
    }
}

impl UciEngine for Engine {
    fn set_option(&mut self, name: &str, value: &str) {
        match name {
            "Ponder" => {
                self.pondering_is_allowed = value == "true";
            }

            // An invalid option. Notice that we do not support
            // re-sizing of the transposition table once the engine
            // had started.
            _ => (),
        }
    }

    fn new_game(&mut self) {
        // Clearing the transposition table would not change anything,
        // so we do nothing.
    }

    fn position(&mut self, fen: &str, moves: &mut Iterator<Item = &str>) {
        if !self.is_thinking {
            if let Ok(p) = Position::from_history(fen, moves) {
                self.position = p;
                self.tt.new_search();
            }
        }
    }

    #[allow(unused_variables)]
    fn go(&mut self,
          searchmoves: Option<Vec<String>>,
          ponder: bool,
          wtime: Option<u64>,
          btime: Option<u64>,
          winc: Option<u64>,
          binc: Option<u64>,
          movestogo: Option<u64>,
          depth: Option<u64>,
          nodes: Option<u64>,
          mate: Option<u64>,
          movetime: Option<u64>,
          infinite: bool) {
        if !self.is_thinking {
            // Note: We ignore "searchmoves" and "mate" parameters.

            self.is_thinking = true;
            self.is_pondering = ponder;
            self.search_id = (Wrapping(self.search_id) + Wrapping(1)).0;
            self.thinking_since = SystemTime::now();
            self.silent_since = SystemTime::now();
            self.current_depth = 0;
            self.searched_nodes = 0;
            self.searched_time = 0;
            self.mangled_pv = false;

            // Figure out when we should stop thinking.
            //
            // TODO: Implement smarter time management.
            let (time, inc) = if self.position.board().to_move() == WHITE {
                (wtime, winc.unwrap_or(0))
            } else {
                (btime, binc.unwrap_or(0))
            };
            self.stop_when = if infinite {
                TimeManagement::Infinite
            } else if movetime.is_some() {
                TimeManagement::MoveTime(movetime.unwrap())
            } else if nodes.is_some() {
                TimeManagement::Nodes(nodes.unwrap())
            } else if depth.is_some() {
                TimeManagement::Depth(depth.unwrap() as u8)
            } else {
                let time = time.unwrap_or(0);
                let movestogo = movestogo.unwrap_or(40);
                let movetime = (time + inc * movestogo) / movestogo;
                TimeManagement::MoveTimeHint(min(movetime, time / 2))
            };

            // Start deepening search to the maximum possible depth.
            self.commands
                .send(search::Command::Search {
                    search_id: self.search_id,
                    position: self.position.clone(),
                    depth: MAX_DEPTH,
                    lower_bound: -20000,
                    upper_bound: 20000,
                })
                .unwrap();
        }
    }

    fn ponder_hit(&mut self) {
        if self.is_thinking && self.is_pondering {
            self.is_pondering = false;
        }
    }

    fn stop(&mut self) {
        if self.is_thinking {
            self.commands.send(search::Command::Stop).unwrap();
            let mut p = self.position.clone();
            let (best_move, ponder_move) = if let Some(m) = self.do_best_move(&mut p) {
                (m.notation(), self.do_best_move(&mut p).map(|m| m.notation()))
            } else {
                ("0000".to_string(), None)
            };
            self.reply_queue.push_back(EngineReply::BestMove {
                best_move: best_move,
                ponder_move: ponder_move,
            });
            self.is_thinking = false;
        }
    }

    fn is_thinking(&self) -> bool {
        self.is_thinking
    }

    fn get_reply(&mut self) -> Option<EngineReply> {
        // Check if we should stop thinking.
        if self.is_thinking && !self.is_pondering {
            if match self.stop_when {
                TimeManagement::MoveTime(t) => self.searched_time >= t,
                TimeManagement::MoveTimeHint(t) => self.searched_time >= t,
                TimeManagement::Nodes(n) => self.searched_nodes >= n,
                TimeManagement::Depth(d) => self.current_depth > d,
                TimeManagement::Infinite => false,
            } {
                self.stop();
            }
        }

        // Check the reports queue.
        while let Ok(report) = self.reports.try_recv() {
            if self.is_thinking {
                match report {
                    search::Report::Progress { search_id, depth, searched_nodes }
                        if search_id == self.search_id => {
                        // Register search progress.
                        self.register_progress(depth, searched_nodes);
                        if self.silent_since.elapsed().unwrap().as_secs() > 20 {
                            if self.mangled_pv {
                                self.report_pv(depth - 1);
                            } else {
                                self.report_progress();
                            }
                        }
                    }
                    search::Report::Done { search_id, .. } if search_id == self.search_id => {
                        // Terminate the search if not infinite.
                        self.stop_when = match self.stop_when {
                            TimeManagement::Infinite => TimeManagement::Infinite,
                            _ => TimeManagement::MoveTime(0),
                        };
                    }
                    // We may still receive stale reports from already
                    // stopped searches.
                    _ => (),
                }
            }
        }

        self.reply_queue.pop_front()
    }
}

impl Engine {
    // A helper method. It updates the search status info and makes
    // sure that a new PV is sent to the GUI for every newly reached
    // depth.
    fn register_progress(&mut self, depth: u8, searched_nodes: NodeCount) {
        let thinking_duration = self.thinking_since.elapsed().unwrap();
        self.searched_time = 1000 * thinking_duration.as_secs() +
                             (thinking_duration.subsec_nanos() / 1000000) as u64;
        self.searched_nodes = searched_nodes;
        self.nps = 1000 * (self.nps + self.searched_nodes) / (1000 + self.searched_time);
        if self.current_depth < depth {
            self.current_depth = depth;
            self.report_pv(depth - 1);
            if !self.mangled_pv {
                self.report_progress();
            }
        }
    }

    // A helper method. It extracts the primary variation (PV) from
    // the transposition table (TT) and sends it to the GUI.
    fn report_pv(&mut self, depth: u8) {
        if depth == 0 {
            return;
        }
        let mut prev_move = None;
        let mut p = self.position.clone();

        // Extract the PV, the value, and the bound from the TT.
        let mut pv = Vec::new();
        let mut value = -30000;
        let mut bound = BOUND_LOWER;
        while let Some(entry) = self.tt.probe(p.hash()) {
            if pv.len() < depth as usize && entry.bound() != BOUND_NONE {
                if let Some(m) = prev_move {
                    // Extend the PV.
                    pv.push(m);
                }

                // Get the value and the bound type. In half of the
                // cases the value stored in `entry` is from other
                // side's perspective.
                if pv.len() & 1 == 0 {
                    value = entry.value();
                    bound = entry.bound();
                } else {
                    value = -entry.value();
                    bound = match entry.bound() {
                        BOUND_UPPER => BOUND_LOWER,
                        BOUND_LOWER => BOUND_UPPER,
                        x => x,
                    };
                }

                // The values under -19999 and over 19999 carry
                // information in how many moves is the inevitable
                // checkmate. We choose to not show this to the user,
                // because it would complicate unnecessarily the PV
                // extraction procedure.
                if value >= 20000 && bound != BOUND_UPPER {
                    value = 19999;
                    bound = BOUND_EXACT
                }
                if value <= -20000 && bound != BOUND_LOWER {
                    value = -19999;
                    bound = BOUND_EXACT
                }

                // Try to extend the PV.
                if bound == BOUND_EXACT {
                    if let Some(m) = p.try_move_digest(entry.move16()) {
                        if p.do_move(m) && !p.is_repeated() {
                            prev_move = Some(m);
                            continue;
                        }
                    }
                }
            }
            break;
        }

        // Check if the extracted PV is imperfect.
        self.mangled_pv = bound != BOUND_EXACT || pv.len() < depth as usize;

        // Send the newly extracted PV to the GUI.
        let value_suffix = match bound {
            BOUND_EXACT => "",
            BOUND_UPPER => " upperbound",
            BOUND_LOWER => " lowerbound",
            _ => panic!("unexpected bound type"),
        };
        let mut pv_string = String::new();
        for m in &pv {
            pv_string.push_str(&m.notation());
            pv_string.push(' ');
        }
        self.reply_queue.push_back(EngineReply::Info(vec![
            ("depth".to_string(), format!("{}", depth)),
            ("score".to_string(), format!("cp {}{}", value, value_suffix)),
            ("time".to_string(), format!("{}", self.searched_time)),
            ("nodes".to_string(), format!("{}", self.searched_nodes)),
            ("nps".to_string(), format!("{}", self.nps)),
            ("pv".to_string(), pv_string),
        ]));
        self.silent_since = SystemTime::now();
    }

    // A helper method. It reports the current depth, the searched
    // node count, and the nodes per second to the GUI.
    fn report_progress(&mut self) {
        self.reply_queue.push_back(EngineReply::Info(vec![
            ("depth".to_string(), format!("{}", self.current_depth)),
            ("nodes".to_string(), format!("{}", self.searched_nodes)),
            ("nps".to_string(), format!("{}", self.nps)),
        ]));
        self.silent_since = SystemTime::now();
    }

    // A helper method for `Engine::stop`. It probes the TT for the
    // best move in the position `p`, plays it, and returns it. If the
    // TT gives no move this function will play and return the first
    // legal move. `None` is returned only when there are no legal
    // moves.
    fn do_best_move(&self, p: &mut Position) -> Option<Move> {
        // Try to get best move from the TT.
        let move16 = self.tt.probe(p.hash()).map_or(0, |entry| entry.move16());
        if let Some(m) = p.try_move_digest(move16) {
            if p.do_move(m) {
                return Some(m);
            }
        }

        // Otherwise, pick the first legal move.
        let mut s = MoveStack::new();
        p.generate_moves(&mut s);
        while let Some(m) = s.pop() {
            if p.do_move(m) {
                return Some(m);
            }
        }

        // No legal moves.
        None
    }
}

/// Implements `UciEngineFactory` trait.
pub struct EngineFactory;

impl UciEngineFactory<Engine> for EngineFactory {
    fn name(&self) -> String {
        format!("Alcibiades {}", VERSION)
    }

    fn author(&self) -> String {
        "Evgeni Pandurski".to_string()
    }

    fn options(&self) -> Vec<(OptionName, OptionDescription)> {
        vec![
            // TODO: Calculate a sane limit for the hash size.
            ("Hash".to_string(), OptionDescription::Spin { min: 1, max: 2048, default: 16 }),
            ("Ponder".to_string(), OptionDescription::Check { default: false }),
        ]
    }

    fn create(&self, hash_size_mb: Option<usize>) -> Engine {
        Engine::new(hash_size_mb.unwrap_or(16))
    }
}

enum TimeManagement {
    MoveTime(u64),
    MoveTimeHint(u64),
    Nodes(NodeCount),
    Depth(u8),
    Infinite,
}
<commit_msg>comment<commit_after>pub mod search;

use std::thread;
use std::cmp::min;
use std::collections::VecDeque;
use std::sync::Arc;
use std::sync::mpsc::{channel, Sender, Receiver};
use std::time::SystemTime;
use std::num::Wrapping;
use basetypes::*;
use uci::{UciEngine, UciEngineFactory, EngineReply, OptionName, OptionDescription};
use position::Position;
use chess_move::*;
use tt::*;

const VERSION: &'static str = "0.1";
const MAX_DEPTH: u8 = 126;

/// Implements `UciEngine` trait.
pub struct Engine {
    tt: Arc<TranspositionTable>,
    reply_queue: VecDeque<EngineReply>,
    position: Position,
    is_thinking: bool,
    is_pondering: bool,

    // Tells the engine if it will be allowed to ponder. This option
    // is needed because the engine might change its time management
    // algorithm when pondering is allowed.
    pondering_is_allowed: bool,

    // A channel for sending commands to the search thread.
    commands: Sender<search::Command>,

    // A channel for receiving reports from the search thread.
    reports: Receiver<search::Report>,

    // Search status info
    search_id: usize,
    thinking_since: SystemTime,
    silent_since: SystemTime,
    current_depth: u8,
    searched_nodes: NodeCount,
    searched_time: u64, // milliseconds
    nps: u64, // nodes per second
    mangled_pv: bool, // `true` if the primary variation is imperfect
    stop_when: TimeManagement,
}

impl Engine {
    /// Creates a new instance.
    ///
    /// `tt_size_mb` is the preferred size of the transposition
    /// table in Mbytes.
    pub fn new(tt_size_mb: usize) -> Engine {
        let mut tt = TranspositionTable::new();
        tt.resize(tt_size_mb);
        let tt1 = Arc::new(tt);
        let tt2 = tt1.clone();
        let (commands_tx, commands_rx) = channel();
        let (reports_tx, reports_rx) = channel();
        thread::spawn(move || {
            search::run_deepening(tt2, commands_rx, reports_tx);
        });

        Engine {
            tt: tt1,
            reply_queue: VecDeque::new(),
            position: Position::from_fen("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w QKqk - 0 \
                                          1")
                          .ok()
                          .unwrap(),
            is_thinking: false,
            is_pondering: false,
            pondering_is_allowed: false,
            commands: commands_tx,
            reports: reports_rx,
            search_id: 0,
            thinking_since: SystemTime::now(),
            silent_since: SystemTime::now(),
            current_depth: 0,
            searched_nodes: 0,
            searched_time: 0,
            nps: 0,
            mangled_pv: false,
            stop_when: TimeManagement::Infinite,
        }
    }
}

impl UciEngine for Engine {
    fn set_option(&mut self, name: &str, value: &str) {
        match name {
            "Ponder" => {
                self.pondering_is_allowed = value == "true";
            }

            // An invalid option. Notice that we do not support
            // re-sizing of the transposition table once the engine
            // had started.
            _ => (),
        }
    }

    fn new_game(&mut self) {
        // Clearing the transposition table would not do any good, so
        // we do nothing.
    }

    fn position(&mut self, fen: &str, moves: &mut Iterator<Item = &str>) {
        if !self.is_thinking {
            if let Ok(p) = Position::from_history(fen, moves) {
                self.position = p;
                self.tt.new_search();
            }
        }
    }

    #[allow(unused_variables)]
    fn go(&mut self,
          searchmoves: Option<Vec<String>>,
          ponder: bool,
          wtime: Option<u64>,
          btime: Option<u64>,
          winc: Option<u64>,
          binc: Option<u64>,
          movestogo: Option<u64>,
          depth: Option<u64>,
          nodes: Option<u64>,
          mate: Option<u64>,
          movetime: Option<u64>,
          infinite: bool) {
        if !self.is_thinking {
            // Note: We ignore "searchmoves" and "mate" parameters.

            self.is_thinking = true;
            self.is_pondering = ponder;
            self.search_id = (Wrapping(self.search_id) + Wrapping(1)).0;
            self.thinking_since = SystemTime::now();
            self.silent_since = SystemTime::now();
            self.current_depth = 0;
            self.searched_nodes = 0;
            self.searched_time = 0;
            self.mangled_pv = false;

            // Figure out when we should stop thinking.
            //
            // TODO: Implement smarter time management.
            let (time, inc) = if self.position.board().to_move() == WHITE {
                (wtime, winc.unwrap_or(0))
            } else {
                (btime, binc.unwrap_or(0))
            };
            self.stop_when = if infinite {
                TimeManagement::Infinite
            } else if movetime.is_some() {
                TimeManagement::MoveTime(movetime.unwrap())
            } else if nodes.is_some() {
                TimeManagement::Nodes(nodes.unwrap())
            } else if depth.is_some() {
                TimeManagement::Depth(depth.unwrap() as u8)
            } else {
                let time = time.unwrap_or(0);
                let movestogo = movestogo.unwrap_or(40);
                let movetime = (time + inc * movestogo) / movestogo;
                TimeManagement::MoveTimeHint(min(movetime, time / 2))
            };

            // Start deepening search to the maximum possible depth.
            self.commands
                .send(search::Command::Search {
                    search_id: self.search_id,
                    position: self.position.clone(),
                    depth: MAX_DEPTH,
                    lower_bound: -20000,
                    upper_bound: 20000,
                })
                .unwrap();
        }
    }

    fn ponder_hit(&mut self) {
        if self.is_thinking && self.is_pondering {
            self.is_pondering = false;
        }
    }

    fn stop(&mut self) {
        if self.is_thinking {
            self.commands.send(search::Command::Stop).unwrap();
            let mut p = self.position.clone();
            let (best_move, ponder_move) = if let Some(m) = self.do_best_move(&mut p) {
                (m.notation(), self.do_best_move(&mut p).map(|m| m.notation()))
            } else {
                ("0000".to_string(), None)
            };
            self.reply_queue.push_back(EngineReply::BestMove {
                best_move: best_move,
                ponder_move: ponder_move,
            });
            self.is_thinking = false;
        }
    }

    fn is_thinking(&self) -> bool {
        self.is_thinking
    }

    fn get_reply(&mut self) -> Option<EngineReply> {
        // Check if we should stop thinking.
        if self.is_thinking && !self.is_pondering {
            if match self.stop_when {
                TimeManagement::MoveTime(t) => self.searched_time >= t,
                TimeManagement::MoveTimeHint(t) => self.searched_time >= t,
                TimeManagement::Nodes(n) => self.searched_nodes >= n,
                TimeManagement::Depth(d) => self.current_depth > d,
                TimeManagement::Infinite => false,
            } {
                self.stop();
            }
        }

        // Check the reports queue.
        while let Ok(report) = self.reports.try_recv() {
            if self.is_thinking {
                match report {
                    search::Report::Progress { search_id, depth, searched_nodes }
                        if search_id == self.search_id => {
                        // Register search progress.
                        self.register_progress(depth, searched_nodes);
                        if self.silent_since.elapsed().unwrap().as_secs() > 20 {
                            if self.mangled_pv {
                                self.report_pv(depth - 1);
                            } else {
                                self.report_progress();
                            }
                        }
                    }
                    search::Report::Done { search_id, .. } if search_id == self.search_id => {
                        // Terminate the search if not infinite.
                        self.stop_when = match self.stop_when {
                            TimeManagement::Infinite => TimeManagement::Infinite,
                            _ => TimeManagement::MoveTime(0),
                        };
                    }
                    // We may still receive stale reports from already
                    // stopped searches.
                    _ => (),
                }
            }
        }

        self.reply_queue.pop_front()
    }
}

impl Engine {
    // A helper method. It updates the search status info and makes
    // sure that a new PV is sent to the GUI for every newly reached
    // depth.
    fn register_progress(&mut self, depth: u8, searched_nodes: NodeCount) {
        let thinking_duration = self.thinking_since.elapsed().unwrap();
        self.searched_time = 1000 * thinking_duration.as_secs() +
                             (thinking_duration.subsec_nanos() / 1000000) as u64;
        self.searched_nodes = searched_nodes;
        self.nps = 1000 * (self.nps + self.searched_nodes) / (1000 + self.searched_time);
        if self.current_depth < depth {
            self.current_depth = depth;
            self.report_pv(depth - 1);
            if !self.mangled_pv {
                self.report_progress();
            }
        }
    }

    // A helper method. It extracts the primary variation (PV) from
    // the transposition table (TT) and sends it to the GUI.
    fn report_pv(&mut self, depth: u8) {
        if depth == 0 {
            return;
        }
        let mut prev_move = None;
        let mut p = self.position.clone();

        // Extract the PV, the value, and the bound from the TT.
        let mut pv = Vec::new();
        let mut value = -30000;
        let mut bound = BOUND_LOWER;
        while let Some(entry) = self.tt.probe(p.hash()) {
            if pv.len() < depth as usize && entry.bound() != BOUND_NONE {
                if let Some(m) = prev_move {
                    // Extend the PV.
                    pv.push(m);
                }

                // Get the value and the bound type. In half of the
                // cases the value stored in `entry` is from other
                // side's perspective.
                if pv.len() & 1 == 0 {
                    value = entry.value();
                    bound = entry.bound();
                } else {
                    value = -entry.value();
                    bound = match entry.bound() {
                        BOUND_UPPER => BOUND_LOWER,
                        BOUND_LOWER => BOUND_UPPER,
                        x => x,
                    };
                }

                // The values under -19999 and over 19999 carry
                // information in how many moves is the inevitable
                // checkmate. We choose to not show this to the user,
                // because it would complicate unnecessarily the PV
                // extraction procedure.
                if value >= 20000 && bound != BOUND_UPPER {
                    value = 19999;
                    bound = BOUND_EXACT
                }
                if value <= -20000 && bound != BOUND_LOWER {
                    value = -19999;
                    bound = BOUND_EXACT
                }

                // Try to extend the PV.
                if bound == BOUND_EXACT {
                    if let Some(m) = p.try_move_digest(entry.move16()) {
                        if p.do_move(m) && !p.is_repeated() {
                            prev_move = Some(m);
                            continue;
                        }
                    }
                }
            }
            break;
        }

        // Check if the extracted PV is imperfect.
        self.mangled_pv = bound != BOUND_EXACT || pv.len() < depth as usize;

        // Send the newly extracted PV to the GUI.
        let value_suffix = match bound {
            BOUND_EXACT => "",
            BOUND_UPPER => " upperbound",
            BOUND_LOWER => " lowerbound",
            _ => panic!("unexpected bound type"),
        };
        let mut pv_string = String::new();
        for m in &pv {
            pv_string.push_str(&m.notation());
            pv_string.push(' ');
        }
        self.reply_queue.push_back(EngineReply::Info(vec![
            ("depth".to_string(), format!("{}", depth)),
            ("score".to_string(), format!("cp {}{}", value, value_suffix)),
            ("time".to_string(), format!("{}", self.searched_time)),
            ("nodes".to_string(), format!("{}", self.searched_nodes)),
            ("nps".to_string(), format!("{}", self.nps)),
            ("pv".to_string(), pv_string),
        ]));
        self.silent_since = SystemTime::now();
    }

    // A helper method. It reports the current depth, the searched
    // node count, and the nodes per second to the GUI.
    fn report_progress(&mut self) {
        self.reply_queue.push_back(EngineReply::Info(vec![
            ("depth".to_string(), format!("{}", self.current_depth)),
            ("nodes".to_string(), format!("{}", self.searched_nodes)),
            ("nps".to_string(), format!("{}", self.nps)),
        ]));
        self.silent_since = SystemTime::now();
    }

    // A helper method for `Engine::stop`. It probes the TT for the
    // best move in the position `p`, plays it, and returns it. If the
    // TT gives no move this function will play and return the first
    // legal move. `None` is returned only when there are no legal
    // moves.
    fn do_best_move(&self, p: &mut Position) -> Option<Move> {
        // Try to get best move from the TT.
        let move16 = self.tt.probe(p.hash()).map_or(0, |entry| entry.move16());
        if let Some(m) = p.try_move_digest(move16) {
            if p.do_move(m) {
                return Some(m);
            }
        }

        // Otherwise, pick the first legal move.
        let mut s = MoveStack::new();
        p.generate_moves(&mut s);
        while let Some(m) = s.pop() {
            if p.do_move(m) {
                return Some(m);
            }
        }

        // No legal moves.
        None
    }
}

/// Implements `UciEngineFactory` trait.
pub struct EngineFactory;

impl UciEngineFactory<Engine> for EngineFactory {
    fn name(&self) -> String {
        format!("Alcibiades {}", VERSION)
    }

    fn author(&self) -> String {
        "Evgeni Pandurski".to_string()
    }

    fn options(&self) -> Vec<(OptionName, OptionDescription)> {
        vec![
            // TODO: Calculate a sane limit for the hash size.
            ("Hash".to_string(), OptionDescription::Spin { min: 1, max: 2048, default: 16 }),
            ("Ponder".to_string(), OptionDescription::Check { default: false }),
        ]
    }

    fn create(&self, hash_size_mb: Option<usize>) -> Engine {
        Engine::new(hash_size_mb.unwrap_or(16))
    }
}

enum TimeManagement {
    MoveTime(u64),
    MoveTimeHint(u64),
    Nodes(NodeCount),
    Depth(u8),
    Infinite,
}
<|endoftext|>


<commit_before>use dataflow::channels::Content;
use progress::count_map::CountMap;
use Pull;

pub struct Counter<T: Eq+Clone+'static, D> {
    pullable: Box<Pull<(T, Content<D>)>>,
    consumed: CountMap<T>,
    phantom: ::std::marker::PhantomData<D>,
}

impl<T:Eq+Clone+'static, D> Counter<T, D> {
    #[inline]
    pub fn next(&mut self) -> Option<(&T, &mut Content<D>)> {
        if let Some((ref time, ref mut data)) = *self.pullable.pull() {
            if data.len() > 0 {
                self.consumed.update(time, data.len() as i64);
                Some((time, data))
            }
            else { None }
        }
        else { None }
    }
}

impl<T:Eq+Clone+'static, D> Counter<T, D> {
    pub fn new(pullable: Box<Pull<(T, Content<D>)>>) -> Counter<T, D> {
        Counter {
            phantom: ::std::marker::PhantomData,
            pullable: pullable,
            consumed: CountMap::new(),
        }
    }
    pub fn pull_progress(&mut self, consumed: &mut CountMap<T>) {
        while let Some((ref time, value)) = self.consumed.pop() {
            consumed.update(time, value);
        }
    }
    #[inline]
    pub fn for_each<F: FnMut(&T, &mut Content<D>)>(&mut self, mut logic: F) {
        while let Some((time, data)) = self.next() {
            ::logging::log(&::logging::GUARDED_MESSAGE, true);
            logic(time, data);
            ::logging::log(&::logging::GUARDED_MESSAGE, false);
        }
    }
}
<commit_msg>remove unused for_each (guarded message) from pullers::Counter<commit_after>use dataflow::channels::Content;
use progress::count_map::CountMap;
use Pull;

pub struct Counter<T: Eq+Clone+'static, D> {
    pullable: Box<Pull<(T, Content<D>)>>,
    consumed: CountMap<T>,
    phantom: ::std::marker::PhantomData<D>,
}

impl<T:Eq+Clone+'static, D> Counter<T, D> {
    #[inline]
    pub fn next(&mut self) -> Option<(&T, &mut Content<D>)> {
        if let Some((ref time, ref mut data)) = *self.pullable.pull() {
            if data.len() > 0 {
                self.consumed.update(time, data.len() as i64);
                Some((time, data))
            }
            else { None }
        }
        else { None }
    }
}

impl<T:Eq+Clone+'static, D> Counter<T, D> {
    pub fn new(pullable: Box<Pull<(T, Content<D>)>>) -> Counter<T, D> {
        Counter {
            phantom: ::std::marker::PhantomData,
            pullable: pullable,
            consumed: CountMap::new(),
        }
    }
    pub fn pull_progress(&mut self, consumed: &mut CountMap<T>) {
        while let Some((ref time, value)) = self.consumed.pop() {
            consumed.update(time, value);
        }
    }
}
<|endoftext|>


<commit_before>pub use defaults::Defaults;
pub use serde::{Deserialize, Serialize};
pub use serde_json::Value;
pub use serde_with::skip_serializing_none;
pub use std::{
    collections::BTreeMap,
    convert::AsRef,
    fmt::{self, Display},
    sync::Arc,
};
pub use strum::AsRefStr;

/// A null value
///
/// This is a struct, rather than a unit variant of `Primitive`, so that
/// it can be treated the same way as other variants when dispatching to
/// trait methods.
#[derive(Clone, Debug)]
pub struct Null {}

impl Display for Null {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "null")
    }
}

impl Serialize for Null {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: serde::Serializer,
    {
        serializer.serialize_none()
    }
}

impl<'de> Deserialize<'de> for Null {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: serde::Deserializer<'de>,
    {
        let value = serde_json::Value::deserialize(deserializer)?;
        match value.is_null() {
            true => Ok(Null {}),
            false => Err(serde::de::Error::custom("Exepected")),
        }
    }
}

/// A boolean value
pub type Boolean = bool;

/// An integer value
///
/// Uses `i64` for maximum precision.
pub type Integer = i64;

/// A floating point value (a.k.a real number)
///
/// Uses `i64` for maximum precision.
pub type Number = f64;

/// An array value (a.k.a. vector)
pub type Array = Vec<Primitive>;

/// An object value (a.k.a map, dictionary)
///
/// Uses `BTreeMap` to preserve order.
pub type Object = BTreeMap<String, Primitive>;

/// The set of primitive (non-Entity) node types
#[derive(Clone, Debug, Serialize, Deserialize)]
#[serde(untagged)]
pub enum Primitive {
    Null(Null),
    Boolean(Boolean),
    Integer(Integer),
    Number(Number),
    String(String),
    Object(Object),
    Array(Array),
}
<commit_msg>fix(Rust): Fix error message<commit_after>pub use defaults::Defaults;
pub use serde::{Deserialize, Serialize};
pub use serde_json::Value;
pub use serde_with::skip_serializing_none;
pub use std::{
    collections::BTreeMap,
    convert::AsRef,
    fmt::{self, Display},
    sync::Arc,
};
pub use strum::AsRefStr;

/// A null value
///
/// This is a struct, rather than a unit variant of `Primitive`, so that
/// it can be treated the same way as other variants when dispatching to
/// trait methods.
#[derive(Clone, Debug)]
pub struct Null {}

impl Display for Null {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "null")
    }
}

impl Serialize for Null {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: serde::Serializer,
    {
        serializer.serialize_none()
    }
}

impl<'de> Deserialize<'de> for Null {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: serde::Deserializer<'de>,
    {
        let value = serde_json::Value::deserialize(deserializer)?;
        match value.is_null() {
            true => Ok(Null {}),
            false => Err(serde::de::Error::custom("Expected a null value")),
        }
    }
}

/// A boolean value
pub type Boolean = bool;

/// An integer value
///
/// Uses `i64` for maximum precision.
pub type Integer = i64;

/// A floating point value (a.k.a real number)
///
/// Uses `i64` for maximum precision.
pub type Number = f64;

/// An array value (a.k.a. vector)
pub type Array = Vec<Primitive>;

/// An object value (a.k.a map, dictionary)
///
/// Uses `BTreeMap` to preserve order.
pub type Object = BTreeMap<String, Primitive>;

/// The set of primitive (non-Entity) node types
#[derive(Clone, Debug, Serialize, Deserialize)]
#[serde(untagged)]
pub enum Primitive {
    Null(Null),
    Boolean(Boolean),
    Integer(Integer),
    Number(Number),
    String(String),
    Object(Object),
    Array(Array),
}
<|endoftext|>


<commit_before>// Copyright 2013-2014 The CGMath Developers. For a full listing of the authors,
// refer to the Cargo.toml file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Angle units for type-safe, self-documenting code.

use std::fmt;
use std::f64;
use std::ops::*;

use rand::{Rand, Rng};
use rand::distributions::range::SampleRange;

use rust_num::{Float, Zero};
use rust_num::traits::cast;

use approx::ApproxEq;
use num::BaseFloat;

/// An angle, in radians
#[derive(Copy, Clone, PartialEq, PartialOrd, RustcEncodable, RustcDecodable)]
pub struct Rad<S> { pub s: S }
/// An angle, in degrees
#[derive(Copy, Clone, PartialEq, PartialOrd, RustcEncodable, RustcDecodable)]
pub struct Deg<S> { pub s: S }

/// Create a new angle, in radians
#[inline] pub fn rad<S: BaseFloat>(s: S) -> Rad<S> { Rad { s: s } }
/// Create a new angle, in degrees
#[inline] pub fn deg<S: BaseFloat>(s: S) -> Deg<S> { Deg { s: s } }

impl<S> From<Rad<S>> for Deg<S> where S: BaseFloat {
    #[inline]
    fn from(r: Rad<S>) -> Deg<S> {
        deg(r.s * cast(180.0 / f64::consts::PI).unwrap())
    }
}

impl<S> From<Deg<S>> for Rad<S> where S: BaseFloat {
    #[inline]
    fn from(d: Deg<S>) -> Rad<S> {
        rad(d.s * cast(f64::consts::PI / 180.0).unwrap())
    }
}

/// Private utility functions for converting to/from scalars
trait ScalarConv<S> {
    fn from(s: S) -> Self;
    fn s<'a>(&'a self) -> &'a S;
    fn mut_s<'a>(&'a mut self) -> &'a mut S;
}

impl<S: BaseFloat> ScalarConv<S> for Rad<S> {
    #[inline] fn from(s: S) -> Rad<S> { rad(s) }
    #[inline] fn s<'a>(&'a self) -> &'a S { &self.s }
    #[inline] fn mut_s<'a>(&'a mut self) -> &'a mut S { &mut self.s }
}

impl<S: BaseFloat> ScalarConv<S> for Deg<S> {
    #[inline] fn from(s: S) -> Deg<S> { deg(s) }
    #[inline] fn s<'a>(&'a self) -> &'a S { &self.s }
    #[inline] fn mut_s<'a>(&'a mut self) -> &'a mut S { &mut self.s }
}

/// Operations on angles.
pub trait Angle where
    Self: Copy + Clone,
    Self: PartialEq + PartialOrd,
    // FIXME: Ugly type signatures - blocked by rust-lang/rust#24092
    Self: ApproxEq<Epsilon = <Self as Angle>::Unitless>,
    Self: Into<Rad<<Self as Angle>::Unitless>>,
    Self: Into<Deg<<Self as Angle>::Unitless>>,
    Self: ScalarConv<<Self as Angle>::Unitless>,
    Self: fmt::Debug,

    Self: Neg<Output = Self>,

    Self: Add<Self, Output = Self>,
    Self: Sub<Self, Output = Self>,
    Self: Div<Self, Output = <Self as Angle>::Unitless>,
    Self: Rem<Self, Output = <Self as Angle>::Unitless>,

    Self: Mul<<Self as Angle>::Unitless, Output = Self>,
    Self: Div<<Self as Angle>::Unitless, Output = Self>,
    Self: Rem<<Self as Angle>::Unitless, Output = Self>,
{
    type Unitless: BaseFloat;

    /// Create a new angle from any other valid angle.
    fn from<A: Angle<Unitless = Self::Unitless>>(theta: A) -> Self;

    /// Negate this angle, in-place.
    #[inline] fn neg_self(&mut self) { *self = -*self }

    /// Add this angle with another, in-place.
    #[inline] fn add_self_a(&mut self, other: Self) { *self = *self + other }
    /// Subtract another angle from this one, in-place.
    #[inline] fn sub_self_a(&mut self, other: Self) { *self = *self - other }

    /// Multiply this angle by a scalar, in-place.
    #[inline] fn mul_self_s(&mut self, scalar: Self::Unitless) { *self = *self * scalar }
    /// Divide this angle by a scalar, in-place.
    #[inline] fn div_self_s(&mut self, scalar: Self::Unitless) { *self = *self / scalar }
    /// Take the remainder of this angle by a scalar, in-place.
    #[inline] fn rem_self_s(&mut self, scalar: Self::Unitless) { *self = *self % scalar }

    /// Return the angle, normalized to the range `[0, full_turn)`.
    #[inline]
    fn normalize(mut self) -> Self {
        self.normalize_self();
        self
    }

    /// Normalize the angle to the range `[0, full_turn)`.
    #[inline]
    fn normalize_self(&mut self) {
        let full_turn = Self::full_turn();
        self.rem_self_s(full_turn.s().clone());
        if *self < Self::zero() { self.add_self_a(full_turn) };
    }

    /// Return the angle rotated by half a turn
    #[inline]
    fn opposite(self) -> Self {
        Self::normalize(self + Self::turn_div_2())
    }

    /// Returns the interior bisector of the two angles
    #[inline]
    fn bisect(self, other: Self) -> Self {
        let half = cast(0.5f64).unwrap();
        Self::normalize((self - other) * half + self)
    }

    fn zero() -> Self;
    fn full_turn() -> Self;
    fn turn_div_2() -> Self;
    fn turn_div_3() -> Self;
    fn turn_div_4() -> Self;
    fn turn_div_6() -> Self;

    #[inline]
    fn equiv(&self, other: &Self) -> bool {
        self.normalize() == other.normalize()
    }
}

#[inline] pub fn bisect<A: Angle>(a: A, b: A) -> A { a.bisect(b) }

#[inline] pub fn sin<S: BaseFloat, R: Into<Rad<S>>>(theta: R) -> S { theta.into().s.sin() }
#[inline] pub fn cos<S: BaseFloat, R: Into<Rad<S>>>(theta: R) -> S { theta.into().s.cos() }
#[inline] pub fn tan<S: BaseFloat, R: Into<Rad<S>>>(theta: R) -> S { theta.into().s.tan() }
#[inline] pub fn sin_cos<S: BaseFloat, R: Into<Rad<S>>>(theta: R) -> (S, S) { theta.into().s.sin_cos() }

#[inline] pub fn cot<S: BaseFloat, R: Into<Rad<S>>>(theta: R) -> S { tan(theta.into()).recip() }
#[inline] pub fn sec<S: BaseFloat, R: Into<Rad<S>>>(theta: R) -> S { cos(theta.into()).recip() }
#[inline] pub fn csc<S: BaseFloat, R: Into<Rad<S>>>(theta: R) -> S { sin(theta.into()).recip() }

#[inline] pub fn asin<S: BaseFloat, R: From<Rad<S>>>(s: S) -> R { rad(s.asin()).into() }
#[inline] pub fn acos<S: BaseFloat, R: From<Rad<S>>>(s: S) -> R { rad(s.acos()).into() }
#[inline] pub fn atan<S: BaseFloat, R: From<Rad<S>>>(s: S) -> R { rad(s.atan()).into() }
#[inline] pub fn atan2<S: BaseFloat, R: From<Rad<S>>>(a: S, b: S) -> R { rad(a.atan2(b)).into() }

macro_rules! impl_angle {
    ($Angle:ident, $fmt:expr, $full_turn:expr, $hi:expr) => {
        impl<S: BaseFloat> Angle for $Angle<S> {
            type Unitless = S;

            #[inline]
            fn zero() -> $Angle<S> { ScalarConv::from(S::zero()) }

            #[inline]
            fn from<A: Angle<Unitless = S>>(theta: A) -> $Angle<S> { theta.into() }

            #[inline] fn full_turn() -> $Angle<S> { ScalarConv::from(cast($full_turn).unwrap()) }
            #[inline] fn turn_div_2() -> $Angle<S> { let factor: S = cast(2).unwrap(); $Angle::full_turn() / factor }
            #[inline] fn turn_div_3() -> $Angle<S> { let factor: S = cast(3).unwrap(); $Angle::full_turn() / factor }
            #[inline] fn turn_div_4() -> $Angle<S> { let factor: S = cast(4).unwrap(); $Angle::full_turn() / factor }
            #[inline] fn turn_div_6() -> $Angle<S> { let factor: S = cast(6).unwrap(); $Angle::full_turn() / factor }
        }

        impl<S: BaseFloat> Neg for $Angle<S> {
            type Output = $Angle<S>;

            #[inline]
            fn neg(self) -> $Angle<S> { ScalarConv::from(-self.s) }
        }

        impl<'a, S: BaseFloat> Neg for &'a $Angle<S> {
            type Output = $Angle<S>;

            #[inline]
            fn neg(self) -> $Angle<S> { ScalarConv::from(-self.s) }
        }

        impl_binary_operator!(<S: BaseFloat> Add<$Angle<S> > for $Angle<S> {
            fn add(lhs, rhs) -> $Angle<S> { ScalarConv::from(lhs.s + rhs.s) }
        });
        impl_binary_operator!(<S: BaseFloat> Sub<$Angle<S> > for $Angle<S> {
            fn sub(lhs, rhs) -> $Angle<S> { ScalarConv::from(lhs.s - rhs.s) }
        });
        impl_binary_operator!(<S: BaseFloat> Div<$Angle<S> > for $Angle<S> {
            fn div(lhs, rhs) -> S { lhs.s / rhs.s }
        });
        impl_binary_operator!(<S: BaseFloat> Rem<$Angle<S> > for $Angle<S> {
            fn rem(lhs, rhs) -> S { lhs.s % rhs.s }
        });

        impl_binary_operator!(<S: BaseFloat> Mul<S> for $Angle<S> {
            fn mul(lhs, scalar) -> $Angle<S> { ScalarConv::from(lhs.s * scalar) }
        });
        impl_binary_operator!(<S: BaseFloat> Div<S> for $Angle<S> {
            fn div(lhs, scalar) -> $Angle<S> { ScalarConv::from(lhs.s / scalar) }
        });
        impl_binary_operator!(<S: BaseFloat> Rem<S> for $Angle<S> {
            fn rem(lhs, scalar) -> $Angle<S> { ScalarConv::from(lhs.s % scalar) }
        });

        impl<S: BaseFloat> ApproxEq for $Angle<S> {
            type Epsilon = S;

            #[inline]
            fn approx_eq_eps(&self, other: &$Angle<S>, epsilon: &S) -> bool {
                self.s.approx_eq_eps(&other.s, epsilon)
            }
        }

        impl<S: BaseFloat + SampleRange> Rand for $Angle<S> {
            #[inline]
            fn rand<R: Rng>(rng: &mut R) -> $Angle<S> {
                let angle: S = rng.gen_range(cast(-$hi).unwrap(), cast($hi).unwrap());
                ScalarConv::from(angle)
            }
        }

        impl<S: BaseFloat> fmt::Debug for $Angle<S> {
            fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
                write!(f, $fmt, self.s)
            }
        }
    }
}

impl_angle!(Rad, "{:?} rad", f64::consts::PI * 2.0, f64::consts::PI);
impl_angle!(Deg, "{:?}°", 360, 180);
<commit_msg>Remove *_self methods from Angle<commit_after>// Copyright 2013-2014 The CGMath Developers. For a full listing of the authors,
// refer to the Cargo.toml file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Angle units for type-safe, self-documenting code.

use std::fmt;
use std::f64;
use std::ops::*;

use rand::{Rand, Rng};
use rand::distributions::range::SampleRange;

use rust_num::{Float, Zero};
use rust_num::traits::cast;

use approx::ApproxEq;
use num::BaseFloat;

/// An angle, in radians
#[derive(Copy, Clone, PartialEq, PartialOrd, RustcEncodable, RustcDecodable)]
pub struct Rad<S> { pub s: S }
/// An angle, in degrees
#[derive(Copy, Clone, PartialEq, PartialOrd, RustcEncodable, RustcDecodable)]
pub struct Deg<S> { pub s: S }

/// Create a new angle, in radians
#[inline] pub fn rad<S: BaseFloat>(s: S) -> Rad<S> { Rad { s: s } }
/// Create a new angle, in degrees
#[inline] pub fn deg<S: BaseFloat>(s: S) -> Deg<S> { Deg { s: s } }

impl<S> From<Rad<S>> for Deg<S> where S: BaseFloat {
    #[inline]
    fn from(r: Rad<S>) -> Deg<S> {
        deg(r.s * cast(180.0 / f64::consts::PI).unwrap())
    }
}

impl<S> From<Deg<S>> for Rad<S> where S: BaseFloat {
    #[inline]
    fn from(d: Deg<S>) -> Rad<S> {
        rad(d.s * cast(f64::consts::PI / 180.0).unwrap())
    }
}

/// Private utility functions for converting to/from scalars
trait ScalarConv<S> {
    fn from(s: S) -> Self;
    fn s<'a>(&'a self) -> &'a S;
    fn mut_s<'a>(&'a mut self) -> &'a mut S;
}

impl<S: BaseFloat> ScalarConv<S> for Rad<S> {
    #[inline] fn from(s: S) -> Rad<S> { rad(s) }
    #[inline] fn s<'a>(&'a self) -> &'a S { &self.s }
    #[inline] fn mut_s<'a>(&'a mut self) -> &'a mut S { &mut self.s }
}

impl<S: BaseFloat> ScalarConv<S> for Deg<S> {
    #[inline] fn from(s: S) -> Deg<S> { deg(s) }
    #[inline] fn s<'a>(&'a self) -> &'a S { &self.s }
    #[inline] fn mut_s<'a>(&'a mut self) -> &'a mut S { &mut self.s }
}

/// Operations on angles.
pub trait Angle where
    Self: Copy + Clone,
    Self: PartialEq + PartialOrd,
    // FIXME: Ugly type signatures - blocked by rust-lang/rust#24092
    Self: ApproxEq<Epsilon = <Self as Angle>::Unitless>,
    Self: Into<Rad<<Self as Angle>::Unitless>>,
    Self: Into<Deg<<Self as Angle>::Unitless>>,
    Self: ScalarConv<<Self as Angle>::Unitless>,
    Self: fmt::Debug,

    Self: Neg<Output = Self>,

    Self: Add<Self, Output = Self>,
    Self: Sub<Self, Output = Self>,
    Self: Div<Self, Output = <Self as Angle>::Unitless>,
    Self: Rem<Self, Output = <Self as Angle>::Unitless>,

    Self: Mul<<Self as Angle>::Unitless, Output = Self>,
    Self: Div<<Self as Angle>::Unitless, Output = Self>,
    Self: Rem<<Self as Angle>::Unitless, Output = Self>,
{
    type Unitless: BaseFloat;

    /// Create a new angle from any other valid angle.
    fn from<A: Angle<Unitless = Self::Unitless>>(theta: A) -> Self;

    /// Return the angle, normalized to the range `[0, full_turn)`.
    fn normalize(self) -> Self;

    /// Return the angle rotated by half a turn
    #[inline]
    fn opposite(self) -> Self {
        Self::normalize(self + Self::turn_div_2())
    }

    /// Returns the interior bisector of the two angles
    #[inline]
    fn bisect(self, other: Self) -> Self {
        let half = cast(0.5f64).unwrap();
        Self::normalize((self - other) * half + self)
    }

    fn zero() -> Self;
    fn full_turn() -> Self;
    fn turn_div_2() -> Self;
    fn turn_div_3() -> Self;
    fn turn_div_4() -> Self;
    fn turn_div_6() -> Self;

    #[inline]
    fn equiv(&self, other: &Self) -> bool {
        self.normalize() == other.normalize()
    }
}

#[inline] pub fn bisect<A: Angle>(a: A, b: A) -> A { a.bisect(b) }

#[inline] pub fn sin<S: BaseFloat, R: Into<Rad<S>>>(theta: R) -> S { theta.into().s.sin() }
#[inline] pub fn cos<S: BaseFloat, R: Into<Rad<S>>>(theta: R) -> S { theta.into().s.cos() }
#[inline] pub fn tan<S: BaseFloat, R: Into<Rad<S>>>(theta: R) -> S { theta.into().s.tan() }
#[inline] pub fn sin_cos<S: BaseFloat, R: Into<Rad<S>>>(theta: R) -> (S, S) { theta.into().s.sin_cos() }

#[inline] pub fn cot<S: BaseFloat, R: Into<Rad<S>>>(theta: R) -> S { tan(theta.into()).recip() }
#[inline] pub fn sec<S: BaseFloat, R: Into<Rad<S>>>(theta: R) -> S { cos(theta.into()).recip() }
#[inline] pub fn csc<S: BaseFloat, R: Into<Rad<S>>>(theta: R) -> S { sin(theta.into()).recip() }

#[inline] pub fn asin<S: BaseFloat, R: From<Rad<S>>>(s: S) -> R { rad(s.asin()).into() }
#[inline] pub fn acos<S: BaseFloat, R: From<Rad<S>>>(s: S) -> R { rad(s.acos()).into() }
#[inline] pub fn atan<S: BaseFloat, R: From<Rad<S>>>(s: S) -> R { rad(s.atan()).into() }
#[inline] pub fn atan2<S: BaseFloat, R: From<Rad<S>>>(a: S, b: S) -> R { rad(a.atan2(b)).into() }

macro_rules! impl_angle {
    ($Angle:ident, $fmt:expr, $full_turn:expr, $hi:expr) => {
        impl<S: BaseFloat> Angle for $Angle<S> {
            type Unitless = S;

            #[inline]
            fn zero() -> $Angle<S> { ScalarConv::from(S::zero()) }

            #[inline]
            fn from<A: Angle<Unitless = S>>(theta: A) -> $Angle<S> { theta.into() }

            #[inline]
            fn normalize(self) -> Self {
                let tmp = self % Self::full_turn().s;
                if tmp < Self::zero() { tmp + Self::full_turn() } else { tmp }
            }

            #[inline] fn full_turn() -> $Angle<S> { ScalarConv::from(cast($full_turn).unwrap()) }
            #[inline] fn turn_div_2() -> $Angle<S> { let factor: S = cast(2).unwrap(); $Angle::full_turn() / factor }
            #[inline] fn turn_div_3() -> $Angle<S> { let factor: S = cast(3).unwrap(); $Angle::full_turn() / factor }
            #[inline] fn turn_div_4() -> $Angle<S> { let factor: S = cast(4).unwrap(); $Angle::full_turn() / factor }
            #[inline] fn turn_div_6() -> $Angle<S> { let factor: S = cast(6).unwrap(); $Angle::full_turn() / factor }
        }

        impl<S: BaseFloat> Neg for $Angle<S> {
            type Output = $Angle<S>;

            #[inline]
            fn neg(self) -> $Angle<S> { ScalarConv::from(-self.s) }
        }

        impl<'a, S: BaseFloat> Neg for &'a $Angle<S> {
            type Output = $Angle<S>;

            #[inline]
            fn neg(self) -> $Angle<S> { ScalarConv::from(-self.s) }
        }

        impl_binary_operator!(<S: BaseFloat> Add<$Angle<S> > for $Angle<S> {
            fn add(lhs, rhs) -> $Angle<S> { ScalarConv::from(lhs.s + rhs.s) }
        });
        impl_binary_operator!(<S: BaseFloat> Sub<$Angle<S> > for $Angle<S> {
            fn sub(lhs, rhs) -> $Angle<S> { ScalarConv::from(lhs.s - rhs.s) }
        });
        impl_binary_operator!(<S: BaseFloat> Div<$Angle<S> > for $Angle<S> {
            fn div(lhs, rhs) -> S { lhs.s / rhs.s }
        });
        impl_binary_operator!(<S: BaseFloat> Rem<$Angle<S> > for $Angle<S> {
            fn rem(lhs, rhs) -> S { lhs.s % rhs.s }
        });

        impl_binary_operator!(<S: BaseFloat> Mul<S> for $Angle<S> {
            fn mul(lhs, scalar) -> $Angle<S> { ScalarConv::from(lhs.s * scalar) }
        });
        impl_binary_operator!(<S: BaseFloat> Div<S> for $Angle<S> {
            fn div(lhs, scalar) -> $Angle<S> { ScalarConv::from(lhs.s / scalar) }
        });
        impl_binary_operator!(<S: BaseFloat> Rem<S> for $Angle<S> {
            fn rem(lhs, scalar) -> $Angle<S> { ScalarConv::from(lhs.s % scalar) }
        });

        impl<S: BaseFloat> ApproxEq for $Angle<S> {
            type Epsilon = S;

            #[inline]
            fn approx_eq_eps(&self, other: &$Angle<S>, epsilon: &S) -> bool {
                self.s.approx_eq_eps(&other.s, epsilon)
            }
        }

        impl<S: BaseFloat + SampleRange> Rand for $Angle<S> {
            #[inline]
            fn rand<R: Rng>(rng: &mut R) -> $Angle<S> {
                ScalarConv::from(rng.gen_range(cast(-$hi).unwrap(), cast($hi).unwrap()))
            }
        }

        impl<S: BaseFloat> fmt::Debug for $Angle<S> {
            fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
                write!(f, $fmt, self.s)
            }
        }
    }
}

impl_angle!(Rad, "{:?} rad", f64::consts::PI * 2.0, f64::consts::PI);
impl_angle!(Deg, "{:?}°", 360, 180);
<|endoftext|>


<commit_before>// compile-flags: --document-private-items

#![feature(crate_visibility_modifier)]

#![crate_name = "foo"]

// @has 'foo/struct.FooPublic.html' '//pre' 'pub struct FooPublic'
pub struct FooPublic;
// @has 'foo/struct.FooJustCrate.html' '//pre' 'pub(crate) struct FooJustCrate'
crate struct FooJustCrate;
// @has 'foo/struct.FooPubCrate.html' '//pre' 'pub(crate) struct FooPubCrate'
pub(crate) struct FooPubCrate;
// @has 'foo/struct.FooSelf.html' '//pre' 'pub(crate) struct FooSelf'
pub(self) struct FooSelf;
// @has 'foo/struct.FooInSelf.html' '//pre' 'pub(crate) struct FooInSelf'
pub(in self) struct FooInSelf;
// @has 'foo/struct.FooPriv.html' '//pre' 'pub(crate) struct FooPriv'
struct FooPriv;

mod a {
    // @has 'foo/a/struct.FooASuper.html' '//pre' 'pub(crate) struct FooASuper'
    pub(super) struct FooASuper;
    // @has 'foo/a/struct.FooAInSuper.html' '//pre' 'pub(crate) struct FooAInSuper'
    pub(in super) struct FooAInSuper;
    // @has 'foo/a/struct.FooAInA.html' '//pre' 'struct FooAInA'
    pub(in a) struct FooAInA;
    // @has 'foo/a/struct.FooAPriv.html' '//pre' 'struct FooAPriv'
    struct FooAPriv;

    mod b {
        // @has 'foo/a/b/struct.FooBSuper.html' '//pre' 'pub(super) struct FooBSuper'
        pub(super) struct FooBSuper;
        // @has 'foo/a/b/struct.FooBInSuperSuper.html' '//pre' 'pub(crate) struct FooBInSuperSuper'
        pub(in super::super) struct FooBInSuperSuper;
        // @has 'foo/a/b/struct.FooBInAB.html' '//pre' 'struct FooBInAB'
        pub(in a::b) struct FooBInAB;
        // @has 'foo/a/b/struct.FooBPriv.html' '//pre' 'struct FooBPriv'
        struct FooBPriv;
    }
}
<commit_msg>Add `@!has` checks to ensure private items don't have `pub`<commit_after>// compile-flags: --document-private-items

#![feature(crate_visibility_modifier)]

#![crate_name = "foo"]

// @has 'foo/struct.FooPublic.html' '//pre' 'pub struct FooPublic'
pub struct FooPublic;
// @has 'foo/struct.FooJustCrate.html' '//pre' 'pub(crate) struct FooJustCrate'
crate struct FooJustCrate;
// @has 'foo/struct.FooPubCrate.html' '//pre' 'pub(crate) struct FooPubCrate'
pub(crate) struct FooPubCrate;
// @has 'foo/struct.FooSelf.html' '//pre' 'pub(crate) struct FooSelf'
pub(self) struct FooSelf;
// @has 'foo/struct.FooInSelf.html' '//pre' 'pub(crate) struct FooInSelf'
pub(in self) struct FooInSelf;
// @has 'foo/struct.FooPriv.html' '//pre' 'pub(crate) struct FooPriv'
struct FooPriv;

mod a {
    // @has 'foo/a/struct.FooASuper.html' '//pre' 'pub(crate) struct FooASuper'
    pub(super) struct FooASuper;
    // @has 'foo/a/struct.FooAInSuper.html' '//pre' 'pub(crate) struct FooAInSuper'
    pub(in super) struct FooAInSuper;
    // @has 'foo/a/struct.FooAInA.html' '//pre' 'struct FooAInA'
    // @!has 'foo/a/struct.FooAInA.html' '//pre' 'pub'
    pub(in a) struct FooAInA;
    // @has 'foo/a/struct.FooAPriv.html' '//pre' 'struct FooAPriv'
    // @!has 'foo/a/struct.FooAPriv.html' '//pre' 'pub'
    struct FooAPriv;

    mod b {
        // @has 'foo/a/b/struct.FooBSuper.html' '//pre' 'pub(super) struct FooBSuper'
        pub(super) struct FooBSuper;
        // @has 'foo/a/b/struct.FooBInSuperSuper.html' '//pre' 'pub(crate) struct FooBInSuperSuper'
        pub(in super::super) struct FooBInSuperSuper;
        // @has 'foo/a/b/struct.FooBInAB.html' '//pre' 'struct FooBInAB'
        // @!has 'foo/a/b/struct.FooBInAB.html' '//pre' 'pub'
        pub(in a::b) struct FooBInAB;
        // @has 'foo/a/b/struct.FooBPriv.html' '//pre' 'struct FooBPriv'
        // @!has 'foo/a/b/struct.FooBPriv.html' '//pre' 'pub'
        struct FooBPriv;
    }
}
<|endoftext|>