<commit_before>use std::io::prelude::*;
use std::fs::File;
use std::ops::Rem;

#[derive(Debug)]
enum Direction {
    Up,
    Left,
    Down,
    Right,
}

type Cursor = usize;
type Numpad = Vec<char>;

fn main() {
    // read input from the file
    let mut f = File::open("input.txt").unwrap();
    let mut input = String::new();
    f.read_to_string(&mut input).ok();

    // split into lines
    let lines : Vec<&str> = input.split('\n').collect();

    let mut digits : Vec<char> = Vec::new();

    // recreate the keypad with three rows of three keys
    let keypad : Numpad = vec!['1','2','3','4','5','6','7','8','9'];

    // and lets create our cursor, starting at the Five key
    let mut cursor : Cursor = 4;

    // convert characters to directions
    for line in lines {

        let sequence : Vec<Direction> = line.chars().map(char_to_direction).collect();

        let updated_cursor_after_sequence : Cursor = sequence.iter().fold(cursor, |prev_cursor, dir| {
            move_cursor(&keypad, &prev_cursor, dir)
        });

        digits.push(digit_for_cursor(&keypad, &updated_cursor_after_sequence));
        cursor = updated_cursor_after_sequence;
    }

    println!("Digits: {:?}", digits);
    assert_eq!(digits, vec!['9', '9', '3', '3', '2']); //challange (live) digits
}

fn char_to_direction(c : char) -> Direction {
    match c {
        'U' => Direction::Up,
        'D' => Direction::Down,
        'L' => Direction::Left,
        'R' => Direction::Right,
         _  => Direction::Up,
    }
}

fn move_cursor(numpad : &Numpad, cursor: &Cursor, dir : &Direction) -> Cursor {
    // calculate new position of the cursor, based on the direction
    // and have it be constraint to the bounds of the numpad
    let row_length = f32::sqrt(numpad.len() as f32) as usize;

    match *dir {
        Direction::Left => {
            // left most options? Cant move left any further..
            if cursor.rem(row_length) == 0 { *cursor } else { cursor -1 }
        },

        Direction::Right => {
            // right most options? Cant move right any further..
            if (cursor).rem(row_length) == row_length - 1 { *cursor } else { cursor +1 }
        },

        Direction::Up => {
            // only can move up if theres another row up top
            if *cursor > row_length - 1 { cursor - row_length } else { *cursor }
        },

        Direction::Down => {
            // only can move down if theres another row below
            if *cursor < numpad.len() - row_length { cursor + row_length } else { *cursor }
        },
    }
}

fn digit_for_cursor(numpad : &Numpad, cursor : &Cursor) -> char {
   numpad.get(*cursor).unwrap().to_owned()
}<commit_msg>For part B well need some optionals<commit_after>use std::io::prelude::*;
use std::fs::File;
use std::ops::Rem;

#[derive(Debug)]
enum Direction {
    Up,
    Left,
    Down,
    Right,
}

type Cursor = usize;
type Numpad = Vec<Option<char>>;

fn main() {
    // read input from the file
    let mut f = File::open("input.txt").unwrap();
    let mut input = String::new();
    f.read_to_string(&mut input).ok();

    // split into lines
    let lines : Vec<&str> = input.split('\n').collect();

    let mut digits : Vec<char> = Vec::new();

    // recreate the keypad with three rows of three keys
    let keypad : Numpad = vec![Some('1'), Some('2'), Some('3'),
                               Some('4'), Some('5'), Some('6'),
                               Some('7'), Some('8'), Some('9')];

    // and lets create our cursor, starting at the Five key
    let mut cursor : Cursor = 4;

    // convert characters to directions
    for line in lines {
        let sequence : Vec<Direction> = line.chars().map(char_to_direction).collect();

        let updated_cursor_after_sequence : Cursor = sequence.iter().fold(cursor, |prev_cursor, dir| {
            move_cursor(&keypad, &prev_cursor, dir)
        });

        digits.push(digit_for_cursor(&keypad, &updated_cursor_after_sequence));
        cursor = updated_cursor_after_sequence;
    }

    println!("Digits: {:?}", digits);
    assert_eq!(digits, vec!['9', '9', '3', '3', '2']); //challange (live) digits
}

fn char_to_direction(c : char) -> Direction {
    match c {
        'U' => Direction::Up,
        'D' => Direction::Down,
        'L' => Direction::Left,
        'R' => Direction::Right,
         _  => Direction::Up,
    }
}

fn move_cursor(numpad : &Numpad, cursor: &Cursor, dir : &Direction) -> Cursor {
    // calculate new position of the cursor, based on the direction
    // and have it be constraint to the bounds of the numpad
    let row_length = f32::sqrt(numpad.len() as f32) as usize;

    match *dir {
        Direction::Left => {
            // left most options? Cant move left any further..
            if cursor.rem(row_length) == 0 { *cursor } else { cursor -1 }
        },

        Direction::Right => {
            // right most options? Cant move right any further..
            if (cursor).rem(row_length) == row_length - 1 { *cursor } else { cursor +1 }
        },

        Direction::Up => {
            // only can move up if theres another row up top
            if *cursor > row_length - 1 { cursor - row_length } else { *cursor }
        },

        Direction::Down => {
            // only can move down if theres another row below
            if *cursor < numpad.len() - row_length { cursor + row_length } else { *cursor }
        },
    }
}

fn digit_for_cursor(numpad : &Numpad, cursor : &Cursor) -> char {
   numpad.get(*cursor).unwrap().unwrap().to_owned()
}<|endoftext|>


<commit_before>use serde_json::{Value, from_str};
use serde_json::error::Result as R;
use serde_json::Serializer;
use serde::ser::Serialize;
use serde::ser::Serializer as Ser;

use std::collections::HashMap;
use std::io::stdout;
use std::error::Error;

use super::super::parser::{FileHeaderParser, ParserError};
use super::super::file::{FileHeaderSpec, FileHeaderData};

pub struct JsonHeaderParser {
    spec: Option<FileHeaderSpec>,
}

impl JsonHeaderParser {

    pub fn new(spec: Option<FileHeaderSpec>) -> JsonHeaderParser {
        JsonHeaderParser {
            spec: spec
        }
    }

}

impl FileHeaderParser for JsonHeaderParser {

    fn read(&self, string: Option<String>)
        -> Result<FileHeaderData, ParserError>
    {
        if string.is_some() {
            let s = string.unwrap();
            debug!("Deserializing: {}", s);
            let fromstr : R<Value> = from_str(&s[..]);
            if let Ok(ref content) = fromstr {
                return Ok(visit_json(&content))
            }
            let oe = fromstr.err().unwrap();
            let s = format!("JSON parser error: {}", oe.description());
            let e = ParserError::short(&s[..], s.clone(), 0);
            Err(e)
        } else {
            Ok(FileHeaderData::Null)
        }
    }

    fn write(&self, data: &FileHeaderData) -> Result<String, ParserError> {
        let mut s = Vec::<u8>::new();
        {
            let mut ser = Serializer::pretty(&mut s);
            data.serialize(&mut ser);
        }

        String::from_utf8(s).or(
            Err(ParserError::short("Cannot parse utf8 bytes",
                                   String::from("<not printable>"),
                                   0)))
    }

}

// TODO: This function must be able to return a parser error
fn visit_json(v: &Value) -> FileHeaderData {
    match v {
        &Value::Null             => FileHeaderData::Null,
        &Value::Bool(b)          => FileHeaderData::Bool(b),
        &Value::I64(i)           => FileHeaderData::Integer(i),
        &Value::U64(u)           => FileHeaderData::UInteger(u),
        &Value::F64(f)           => FileHeaderData::Float(f),
        &Value::String(ref s)        => FileHeaderData::Text(s.clone()),
        &Value::Array(ref vec)       => {
            FileHeaderData::Array {
                values: Box::new(vec.clone().into_iter().map(|i| visit_json(&i)).collect())
            }
        },
        &Value::Object(ref btree)    => {
            let btree = btree.clone();
            FileHeaderData::Map{
                keys: btree.into_iter().map(|(k, v)|
                    FileHeaderData::Key {
                        name: k,
                        value: Box::new(visit_json(&v)),
                    }
                ).collect()
            }
        }
    }
}

impl Serialize for FileHeaderData {

    fn serialize<S>(&self, ser: &mut S) -> Result<(), S::Error>
        where S: Ser
    {
        match self {
            &FileHeaderData::Null               => {
                let o : Option<bool> = None;
                o.serialize(ser)
            },
            &FileHeaderData::Bool(ref b)            => b.serialize(ser),
            &FileHeaderData::Integer(ref i)         => i.serialize(ser),
            &FileHeaderData::UInteger(ref u)        => u.serialize(ser),
            &FileHeaderData::Float(ref f)           => f.serialize(ser),
            &FileHeaderData::Text(ref s)            => (&s[..]).serialize(ser),
            &FileHeaderData::Array{values: ref vs}  => vs.serialize(ser),
            &FileHeaderData::Map{keys: ref ks}      => {
                let mut hm = HashMap::new();

                for key in ks {
                    if let &FileHeaderData::Key{name: ref n, value: ref v} = key {
                        hm.insert(n, v);
                    } else {
                        panic!("Not a key: {:?}", key);
                    }
                }

                hm.serialize(ser)
            },
            &FileHeaderData::Key{name: ref n, value: ref v} => unreachable!(),

        }
    }

}

#[cfg(test)]
mod test {

    use super::JsonHeaderParser;
    use storage::parser::{FileHeaderParser, ParserError};
    use storage::file::{FileHeaderSpec, FileHeaderData};

    #[test]
    fn test_deserialization() {
        use storage::file::FileHeaderData as FHD;
        use storage::file::FileHeaderSpec as FHS;

        let text = String::from("{\"a\": 1, \"b\": -2}");
        let spec = FHS::Map {
            keys: vec![
                FHS::Key {
                    name: String::from("a"),
                    value_type: Box::new(FHS::UInteger)
                },
                FHS::Key {
                    name: String::from("b"),
                    value_type: Box::new(FHS::Integer)
                }
            ]
        };

        let parser = JsonHeaderParser::new(Some(spec));
        let parsed = parser.read(Some(text));
        assert!(parsed.is_ok(), "Parsed is not ok: {:?}", parsed);

        match parsed.ok() {
            Some(FHD::Map{keys: keys}) => {
                for k in keys {
                    match k {
                        FHD::Key{name: name, value: box value} => {
                            assert!(name == "a" || name == "b", "Key unknown");
                            match &value {
                                &FHD::UInteger(u) => assert_eq!(u, 1),
                                &FHD::Integer(i) => assert_eq!(i, -2),
                                _ => assert!(false, "Integers are not here"),
                            }
                        },
                        _ => assert!(false, "Key is not a Key"),
                    }
                }
            },

            _ => assert!(false, "Parsed is not a map"),
        }
    }

}
<commit_msg>Add test: Deserialization without Specification should match as well<commit_after>use serde_json::{Value, from_str};
use serde_json::error::Result as R;
use serde_json::Serializer;
use serde::ser::Serialize;
use serde::ser::Serializer as Ser;

use std::collections::HashMap;
use std::io::stdout;
use std::error::Error;

use super::super::parser::{FileHeaderParser, ParserError};
use super::super::file::{FileHeaderSpec, FileHeaderData};

pub struct JsonHeaderParser {
    spec: Option<FileHeaderSpec>,
}

impl JsonHeaderParser {

    pub fn new(spec: Option<FileHeaderSpec>) -> JsonHeaderParser {
        JsonHeaderParser {
            spec: spec
        }
    }

}

impl FileHeaderParser for JsonHeaderParser {

    fn read(&self, string: Option<String>)
        -> Result<FileHeaderData, ParserError>
    {
        if string.is_some() {
            let s = string.unwrap();
            debug!("Deserializing: {}", s);
            let fromstr : R<Value> = from_str(&s[..]);
            if let Ok(ref content) = fromstr {
                return Ok(visit_json(&content))
            }
            let oe = fromstr.err().unwrap();
            let s = format!("JSON parser error: {}", oe.description());
            let e = ParserError::short(&s[..], s.clone(), 0);
            Err(e)
        } else {
            Ok(FileHeaderData::Null)
        }
    }

    fn write(&self, data: &FileHeaderData) -> Result<String, ParserError> {
        let mut s = Vec::<u8>::new();
        {
            let mut ser = Serializer::pretty(&mut s);
            data.serialize(&mut ser);
        }

        String::from_utf8(s).or(
            Err(ParserError::short("Cannot parse utf8 bytes",
                                   String::from("<not printable>"),
                                   0)))
    }

}

// TODO: This function must be able to return a parser error
fn visit_json(v: &Value) -> FileHeaderData {
    match v {
        &Value::Null             => FileHeaderData::Null,
        &Value::Bool(b)          => FileHeaderData::Bool(b),
        &Value::I64(i)           => FileHeaderData::Integer(i),
        &Value::U64(u)           => FileHeaderData::UInteger(u),
        &Value::F64(f)           => FileHeaderData::Float(f),
        &Value::String(ref s)        => FileHeaderData::Text(s.clone()),
        &Value::Array(ref vec)       => {
            FileHeaderData::Array {
                values: Box::new(vec.clone().into_iter().map(|i| visit_json(&i)).collect())
            }
        },
        &Value::Object(ref btree)    => {
            let btree = btree.clone();
            FileHeaderData::Map{
                keys: btree.into_iter().map(|(k, v)|
                    FileHeaderData::Key {
                        name: k,
                        value: Box::new(visit_json(&v)),
                    }
                ).collect()
            }
        }
    }
}

impl Serialize for FileHeaderData {

    fn serialize<S>(&self, ser: &mut S) -> Result<(), S::Error>
        where S: Ser
    {
        match self {
            &FileHeaderData::Null               => {
                let o : Option<bool> = None;
                o.serialize(ser)
            },
            &FileHeaderData::Bool(ref b)            => b.serialize(ser),
            &FileHeaderData::Integer(ref i)         => i.serialize(ser),
            &FileHeaderData::UInteger(ref u)        => u.serialize(ser),
            &FileHeaderData::Float(ref f)           => f.serialize(ser),
            &FileHeaderData::Text(ref s)            => (&s[..]).serialize(ser),
            &FileHeaderData::Array{values: ref vs}  => vs.serialize(ser),
            &FileHeaderData::Map{keys: ref ks}      => {
                let mut hm = HashMap::new();

                for key in ks {
                    if let &FileHeaderData::Key{name: ref n, value: ref v} = key {
                        hm.insert(n, v);
                    } else {
                        panic!("Not a key: {:?}", key);
                    }
                }

                hm.serialize(ser)
            },
            &FileHeaderData::Key{name: ref n, value: ref v} => unreachable!(),

        }
    }

}

#[cfg(test)]
mod test {

    use super::JsonHeaderParser;
    use storage::parser::{FileHeaderParser, ParserError};
    use storage::file::FileHeaderData as FHD;
    use storage::file::FileHeaderSpec as FHS;

    #[test]
    fn test_deserialization() {
        let text = String::from("{\"a\": 1, \"b\": -2}");
        let spec = FHS::Map {
            keys: vec![
                FHS::Key {
                    name: String::from("a"),
                    value_type: Box::new(FHS::UInteger)
                },
                FHS::Key {
                    name: String::from("b"),
                    value_type: Box::new(FHS::Integer)
                }
            ]
        };

        let parser = JsonHeaderParser::new(Some(spec));
        let parsed = parser.read(Some(text));
        assert!(parsed.is_ok(), "Parsed is not ok: {:?}", parsed);

        match parsed.ok() {
            Some(FHD::Map{keys: keys}) => {
                for k in keys {
                    match k {
                        FHD::Key{name: name, value: box value} => {
                            assert!(name == "a" || name == "b", "Key unknown");
                            match &value {
                                &FHD::UInteger(u) => assert_eq!(u, 1),
                                &FHD::Integer(i) => assert_eq!(i, -2),
                                _ => assert!(false, "Integers are not here"),
                            }
                        },
                        _ => assert!(false, "Key is not a Key"),
                    }
                }
            },

            _ => assert!(false, "Parsed is not a map"),
        }
    }

    #[test]
    fn test_deserialization_without_spec() {
        let text    = String::from("{\"a\": [1], \"b\": {\"c\": -2}}");
        let parser  = JsonHeaderParser::new(None);
        let parsed  = parser.read(Some(text));

        assert!(parsed.is_ok(), "Parsed is not ok: {:?}", parsed);

        match parsed.ok() {
            Some(FHD::Map{keys: keys}) => {
                for k in keys {
                    match_key(&k);
                }
            },

            _ => assert!(false, "Parsed is not a map"),
        }
    }

    fn match_key(k: &FHD) {
        use std::ops::Deref;

        match k {
            &FHD::Key{name: ref name, value: ref value} => {
                assert!(name == "a" || name == "b", "Key unknown");
                match value.deref() {
                    &FHD::Array{values: ref vs} => {
                        for value in vs.iter() {
                            match value {
                                &FHD::UInteger(u) => assert_eq!(u, 1),
                                _ => assert!(false, "UInt is not an UInt"),
                            }
                        }
                    }

                    &FHD::Map{keys: ref ks} => {
                        for key in ks.iter() {
                            match key {
                                &FHD::Key{name: ref name, value: ref value} => {
                                    match value.deref() {
                                        &FHD::Integer(i) => {
                                            assert_eq!(i, -2);
                                            assert_eq!(name, "c");
                                        },
                                        _ => assert!(false, "Int is not an Int"),
                                    };
                                },
                                _ => assert!(false, "Key is not a Key"),
                            }
                        }
                    }
                    _ => assert!(false, "Integers are not here"),
                }
            },
            _ => assert!(false, "Key in main Map is not a Key"),
        }
    }

}
<|endoftext|>


<commit_before>use std::convert::From;
use std::ops::{Add, Sub, Mul};

use structs::{FloatPoint, Point};
use traits::HasValues;

/// Translate 2D QRS coordinates to XY coordinates on a screen
#[derive(Debug, PartialEq)]
pub struct PixelPoint {

  /// Axis X on the screen
  pub x: f32,

  /// Axis Y on the screen
  pub y: f32,

}

impl PixelPoint {

  /// Factory function for making new points
  pub fn new(x: f32, y: f32) -> PixelPoint {
    PixelPoint {x: x, y: y}
  }

}

/// Add one point to another
impl<'a, 'b> Add<&'b PixelPoint> for &'a PixelPoint {

  type Output = PixelPoint;

  fn add(self, rhs: &'b PixelPoint) -> PixelPoint {
    PixelPoint::new(self.x + rhs.x, self.y + rhs.y)
  }

}

/// Subtract one point from another
impl<'a, 'b> Sub<&'b PixelPoint> for &'a PixelPoint {

  type Output = PixelPoint;

  fn sub(self, rhs: &'b PixelPoint) -> PixelPoint {
    PixelPoint::new(self.x - rhs.x, self.y - rhs.y)
  }

}

/// Multiply one point by another
///
/// This might most obviously be used to scale resolutions. However, consider
/// that pixel points are created from ordinary points at a scale where one
/// side is one pixel in length. Therefore, multiplying a pixel point by five
/// would result in the coordinate values at a scale where one side is five
/// pixels in length.
impl <'a, 'b> Mul<&'b PixelPoint> for &'a PixelPoint {

  type Output = PixelPoint;

  fn mul(self, rhs: &'b PixelPoint) -> PixelPoint {
    PixelPoint::new(self.x * rhs.x, self.y * rhs.y)
  }

}

/// Conveniently convert a point into a pixel point
impl<'a> From<&'a Point> for PixelPoint {

  fn from(point: &'a Point) -> PixelPoint {

    let point: FloatPoint = FloatPoint::from(point.values());
    let result: PixelPoint = PixelPoint::from(&point);

    result

  }

}

/// Conveniently convert a float point into a pixel point
impl <'a> From<&'a FloatPoint> for PixelPoint {

  fn from(point: &'a FloatPoint) -> PixelPoint {
    let &FloatPoint(q, r, _) = point;
    let x: f32 = 3f32.sqrt() * (q + (r / 2f32));
    let y: f32 = 1.5f32 * r;
    let result: PixelPoint = PixelPoint::new(x, y);

    result
  }

}

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

  #[test]
  fn new() {
    let point: PixelPoint = PixelPoint::new(1f32, 2f32);

    assert!(point.x == 1f32);
    assert!(point.y == 2f32);
  }

  #[test]
  fn add() {
    let point: PixelPoint = PixelPoint::new(1f32, 2f32);
    let other: PixelPoint = PixelPoint::new(3f32, 4f32);
    let result: PixelPoint = &point + &other;

    assert!(4f32 == result.x);
    assert!(6f32 == result.y);
  }

  #[test]
  fn sub() {
    let point: PixelPoint = PixelPoint::new(1f32, 2f32);
    let other: PixelPoint = PixelPoint::new(3f32, 4f32);
    let result: PixelPoint = &point - &other;

    assert!(-2f32 == result.x);
    assert!(-2f32 == result.y);
  }

  #[test]
  fn mul() {
    let point: PixelPoint = PixelPoint::new(1280f32, 720f32);
    let other: PixelPoint = PixelPoint::new(1.5f32, 1.5f32);
    let result: PixelPoint = &point * &other;

    assert!(1920f32 == result.x);
    assert!(1080f32 == result.y);
  }

  #[test]
  fn mul_scale_coordinates() {
    let point: Point = Point(1, 2, 5);
    let other: PixelPoint = PixelPoint::from(&point);
    let scale: PixelPoint = PixelPoint::new(5f32, 5f32);
    let result: PixelPoint = &other * &scale;

    assert!(3f32.sqrt() * 10f32 == result.x);
    assert!(15f32 == result.y);
  }

  #[test]
  fn from_point() {
    let point: Point = Point(1, 2, 5);
    let other: PixelPoint = PixelPoint::from(&point);

    assert!(3f32.sqrt() * 2f32 == other.x);
    assert!(3f32 == other.y);
  }

  #[test]
  fn from_float_point() {
    let point: FloatPoint = FloatPoint(1f32, 2f32, 0f32);
    let other: PixelPoint = PixelPoint::from(&point);

    assert!(3f32.sqrt() * 2f32 == other.x);
    assert!(3f32 == other.y);
  }
}
<commit_msg>Issue #70: Refactor PixelPoint<commit_after>use std::convert::From;
use std::ops::{Add, Sub, Mul};

use structs::{FloatPoint, Point};
use traits::HasValues;

/// Translate 2D QRS coordinates to XY coordinates on a screen
#[derive(Debug, PartialEq)]
pub struct PixelPoint(pub f32, pub f32);

/// Add one point to another
impl<'a, 'b> Add<&'b PixelPoint> for &'a PixelPoint {
  type Output = PixelPoint;

  fn add(self, other: &'b PixelPoint) -> PixelPoint {
    let &PixelPoint(x0, y0) = self;
    let &PixelPoint(x1, y1) = other;

    PixelPoint(x0 + x1, y0 + y1)
  }
}

/// Subtract one point from another
impl<'a, 'b> Sub<&'b PixelPoint> for &'a PixelPoint {
  type Output = PixelPoint;

  fn sub(self, other: &'b PixelPoint) -> PixelPoint {
    let &PixelPoint(x0, y0) = self;
    let &PixelPoint(x1, y1) = other;

    PixelPoint(x0 - x1, y0 - y1)
  }
}

/// Multiply one point by another
///
/// This might most obviously be used to scale resolutions. However, consider
/// that pixel points are created from ordinary points at a scale where one
/// side is one pixel in length. Therefore, multiplying a pixel point by five
/// would result in the coordinate values at a scale where one side is five
/// pixels in length.
impl <'a, 'b> Mul<&'b PixelPoint> for &'a PixelPoint {
  type Output = PixelPoint;

  fn mul(self, other: &'b PixelPoint) -> PixelPoint {
    let &PixelPoint(x0, y0) = self;
    let &PixelPoint(x1, y1) = other;

    PixelPoint(x0 * x1, y0 * y1)
  }
}

/// Conveniently convert a point into a pixel point
impl<'a> From<&'a Point> for PixelPoint {
  fn from(point: &'a Point) -> PixelPoint {
    let point: FloatPoint = FloatPoint::from(point.values());
    let result: PixelPoint = PixelPoint::from(&point);

    result
  }
}

/// Conveniently convert a float point into a pixel point
impl <'a> From<&'a FloatPoint> for PixelPoint {
  fn from(point: &'a FloatPoint) -> PixelPoint {
    let &FloatPoint(q, r, _) = point;
    let x: f32 = 3f32.sqrt() * (q + (r / 2f32));
    let y: f32 = 1.5f32 * r;
    let result: PixelPoint = PixelPoint(x, y);

    result
  }
}

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

  #[test]
  fn add() {
    let point: PixelPoint = PixelPoint(1f32, 2f32);
    let other: PixelPoint = PixelPoint(3f32, 4f32);
    let PixelPoint(x, y) = &point + &other;

    assert!(4f32 == x);
    assert!(6f32 == y);
  }

  #[test]
  fn sub() {
    let point: PixelPoint = PixelPoint(1f32, 2f32);
    let other: PixelPoint = PixelPoint(3f32, 4f32);
    let PixelPoint(x, y) = &point - &other;

    assert!(-2f32 == x);
    assert!(-2f32 == y);
  }

  #[test]
  fn mul() {
    let point: PixelPoint = PixelPoint(1280f32, 720f32);
    let other: PixelPoint = PixelPoint(1.5f32, 1.5f32);
    let PixelPoint(x, y) = &point * &other;

    assert!(1920f32 == x);
    assert!(1080f32 == y);
  }

  #[test]
  fn mul_scale_coordinates() {
    let point: Point = Point(1, 2, 5);
    let other: PixelPoint = PixelPoint::from(&point);
    let scale: PixelPoint = PixelPoint(5f32, 5f32);
    let PixelPoint(x, y) = &other * &scale;

    assert!(3f32.sqrt() * 10f32 == x);
    assert!(15f32 == y);
  }

  #[test]
  fn from_point() {
    let point: Point = Point(1, 2, 5);
    let PixelPoint(x, y) = PixelPoint::from(&point);

    assert!(3f32.sqrt() * 2f32 == x);
    assert!(3f32 == y);
  }

  #[test]
  fn from_float_point() {
    let point: FloatPoint = FloatPoint(1f32, 2f32, 0f32);
    let PixelPoint(x, y) = PixelPoint::from(&point);

    assert!(3f32.sqrt() * 2f32 == x);
    assert!(3f32 == y);
  }
}
<|endoftext|>


<commit_before>use module::Module;
use error::DottyError;
use config::Config;
use data::{InstalledModuleData, store_module_data, is_module_installed};
use utils::recursive_symlink;

use std::path::PathBuf;

pub struct InstallOptions {
    pub module_name : String,
    pub module_path : PathBuf
}

/// Installs a module by running it's hooks, symlinking
/// and generating files as needed
pub fn install(opts : &InstallOptions, conf : &Config) -> Result<(), DottyError> {
    if is_module_installed(&conf, opts.module_name.as_str()) {
        return Err(DottyError::ModuleAlreadyInstalled(opts.module_name.clone()))
    }

    println!("Installing module '{}'...", &opts.module_name);
    let m = try!(Module::load(&opts.module_path));

    // Validate module options and config so we don't have a half-broken install
    for link in &m.links {
        let (source, dest) = (&link.0, &link.1);

        println!("Linking '{}' to '{}'...", source.display(), dest.display());

        if !source.exists() {
            return Err(DottyError::ModuleMissingFile(source.clone()));
        }
        /*if dest.exists() {
            return Err(DottyError::ModuleFileAlreadyExists(dest.clone()));
        }*/
    }

    // Install the module
    let mut installed_links : Vec<PathBuf> = vec![];
    for link in m.links {
        let (source, dest) = (link.0, link.1);
        match recursive_symlink(&source, &dest) {
            Ok(v) => installed_links.extend_from_slice(&v),
            Err(e) => println!("Unable to symlink '{}' to '{}' : {}",
                                    source.display(), dest.display(), e)
        }
    }

    try!(store_module_data(&conf, &InstalledModuleData{
        name: opts.module_name.clone(),
        symlinks: installed_links,
    }));

    Ok(())
}<commit_msg>Symlinks are now removed when install fails (#33)<commit_after>use module::Module;
use error::DottyError;
use config::Config;
use data::{InstalledModuleData, store_module_data, is_module_installed};
use utils::recursive_symlink;
use file::remove_file;

use std::path::PathBuf;

pub struct InstallOptions {
    pub module_name : String,
    pub module_path : PathBuf
}

/// Installs a module by running it's hooks, symlinking
/// and generating files as needed
pub fn install(opts : &InstallOptions, conf : &Config) -> Result<(), DottyError> {
    if is_module_installed(&conf, opts.module_name.as_str()) {
        return Err(DottyError::ModuleAlreadyInstalled(opts.module_name.clone()))
    }

    println!("Installing module '{}'...", &opts.module_name);
    let m = try!(Module::load(&opts.module_path));

    // Validate module options and config so we don't have a half-broken install
    for link in &m.links {
        let (source, dest) = (&link.0, &link.1);

        println!("Linking '{}' to '{}'...", source.display(), dest.display());

        if !source.exists() {
            return Err(DottyError::ModuleMissingFile(source.clone()));
        }
        /*if dest.exists() {
            return Err(DottyError::ModuleFileAlreadyExists(dest.clone()));
        }*/
    }

    // Install the module
    let mut installed_links : Vec<PathBuf> = vec![];
    let mut did_error = false;
    for link in m.links {
        let (source, dest) = (link.0, link.1);
        match recursive_symlink(&source, &dest) {
            Ok(v) => installed_links.extend_from_slice(&v),
            Err(e) => {
                println!("Unable to symlink '{}' to '{}' : {}",
                                    source.display(), dest.display(), e);
                did_error = true;
            }
        }
    }
    // Remove installed links if it failed
    if did_error {
        for link in &installed_links {
            if remove_file(&link).is_err() {
                println!("Failed to remove link: {}", link.display());
            }
        }
    }

    try!(store_module_data(&conf, &InstalledModuleData{
        name: opts.module_name.clone(),
        symlinks: installed_links,
    }));

    Ok(())
}<|endoftext|>


<commit_before>//! Contains the `Row` trait

use crate::backend::{self, Backend};
use crate::deserialize::{self, FromSql};

/// Represents a single database row.
/// Apps should not need to concern themselves with this trait.
///
/// This trait is only used as an argument to [`FromSqlRow`].
///
/// [`FromSqlRow`]: ../deserialize/trait.FromSqlRow.html
pub trait Row<DB: Backend> {
    /// Returns the value of the next column in the row.
    fn take(&mut self) -> Option<backend::RawValue<DB>>;

    /// Returns whether the next `count` columns are all `NULL`.
    ///
    /// If this method returns `true`, then the next `count` calls to `take`
    /// would all return `None`.
    fn next_is_null(&self, count: usize) -> bool;

    /// Skips the next `count` columns. This method must be called if you are
    /// choosing not to call `take` as a result of `next_is_null` returning
    /// `true`.
    fn advance(&mut self, count: usize) {
        for _ in 0..count {
            self.take();
        }
    }

    /// Number of columns in the current result set
    fn column_count(&self) -> usize;

    /// Name of the current column
    ///
    /// May return `None` in cases where the field is not
    /// named on sql side
    fn column_name(&self) -> Option<&str>;
}

/// Represents a row of a SQL query, where the values are accessed by name
/// rather than by index.
///
/// This trait is used by implementations of
/// [`QueryableByName`](../deserialize/trait.QueryableByName.html)
pub trait NamedRow<DB: Backend> {
    /// Retrieve and deserialize a single value from the query
    ///
    /// Note that `ST` *must* be the exact type of the value with that name in
    /// the query. The compiler will not be able to verify that you have
    /// provided the correct type. If there is a mismatch, you may receive an
    /// incorrect value, or a runtime error.
    ///
    /// If two or more fields in the query have the given name, the result of
    /// this function is undefined.
    fn get<ST, T>(&self, column_name: &str) -> deserialize::Result<T>
    where
        T: FromSql<ST, DB>,
    {
        let idx = self
            .index_of(column_name)
            .ok_or_else(|| format!("Column `{}` was not present in query", column_name).into());
        let idx = match idx {
            Ok(x) => x,
            Err(e) => return Err(e),
        };
        let raw_value = self.get_raw_value(idx);
        T::from_sql(raw_value)
    }

    #[doc(hidden)]
    fn index_of(&self, column_name: &str) -> Option<usize>;
    #[doc(hidden)]
    fn get_raw_value(&self, index: usize) -> Option<backend::RawValue<DB>>;
}
<commit_msg>Allow to get a list of all named column names from `NamedRow`<commit_after>//! Contains the `Row` trait

use crate::backend::{self, Backend};
use crate::deserialize::{self, FromSql};

/// Represents a single database row.
/// Apps should not need to concern themselves with this trait.
///
/// This trait is only used as an argument to [`FromSqlRow`].
///
/// [`FromSqlRow`]: ../deserialize/trait.FromSqlRow.html
pub trait Row<DB: Backend> {
    /// Returns the value of the next column in the row.
    fn take(&mut self) -> Option<backend::RawValue<DB>>;

    /// Returns whether the next `count` columns are all `NULL`.
    ///
    /// If this method returns `true`, then the next `count` calls to `take`
    /// would all return `None`.
    fn next_is_null(&self, count: usize) -> bool;

    /// Skips the next `count` columns. This method must be called if you are
    /// choosing not to call `take` as a result of `next_is_null` returning
    /// `true`.
    fn advance(&mut self, count: usize) {
        for _ in 0..count {
            self.take();
        }
    }

    /// Number of columns in the current result set
    fn column_count(&self) -> usize;

    /// Name of the current column
    ///
    /// May return `None` in cases where the field is not
    /// named on sql side
    fn column_name(&self) -> Option<&str>;
}

/// Represents a row of a SQL query, where the values are accessed by name
/// rather than by index.
///
/// This trait is used by implementations of
/// [`QueryableByName`](../deserialize/trait.QueryableByName.html)
pub trait NamedRow<DB: Backend> {
    /// Retrieve and deserialize a single value from the query
    ///
    /// Note that `ST` *must* be the exact type of the value with that name in
    /// the query. The compiler will not be able to verify that you have
    /// provided the correct type. If there is a mismatch, you may receive an
    /// incorrect value, or a runtime error.
    ///
    /// If two or more fields in the query have the given name, the result of
    /// this function is undefined.
    fn get<ST, T>(&self, column_name: &str) -> deserialize::Result<T>
    where
        T: FromSql<ST, DB>,
    {
        let idx = self
            .index_of(column_name)
            .ok_or_else(|| format!("Column `{}` was not present in query", column_name).into());
        let idx = match idx {
            Ok(x) => x,
            Err(e) => return Err(e),
        };
        let raw_value = self.get_raw_value(idx);
        T::from_sql(raw_value)
    }

    #[doc(hidden)]
    fn index_of(&self, column_name: &str) -> Option<usize>;
    #[doc(hidden)]
    fn get_raw_value(&self, index: usize) -> Option<backend::RawValue<DB>>;

    /// Get a list of all field names in the current row
    fn field_names(&self) -> Vec<&str>;
}
<|endoftext|>


<commit_before>use std::{cmp::min, fs::File, io, mem, num::Wrapping, path::PathBuf, time::Duration};

use clap::Parser;
use pgn_reader::{BufferedReader, Color, RawHeader, SanPlus, Skip, Visitor};
use rand::{distributions::OpenClosed01, rngs::SmallRng, Rng, SeedableRng};
use serde::Serialize;
use serde_with::{serde_as, DisplayFromStr, SpaceSeparator, StringWithSeparator};

const BATCH_SIZE: usize = 100;

#[derive(Debug, Serialize, Copy, Clone)]
#[serde(rename_all = "camelCase")]
enum Speed {
    UltraBullet,
    Bullet,
    Blitz,
    Rapid,
    Classical,
    Correspondence,
}

impl Speed {
    fn from_seconds_and_increment(seconds: u64, increment: u64) -> Speed {
        let total = seconds + 40 * increment;

        if total < 30 {
            Speed::UltraBullet
        } else if total < 180 {
            Speed::Bullet
        } else if total < 480 {
            Speed::Blitz
        } else if total < 1500 {
            Speed::Rapid
        } else if total < 21_600 {
            Speed::Classical
        } else {
            Speed::Correspondence
        }
    }

    fn from_bytes(bytes: &[u8]) -> Result<Speed, ()> {
        if bytes == b"-" {
            return Ok(Speed::Correspondence);
        }

        let mut parts = bytes.splitn(2, |ch| *ch == b'+');
        let seconds = btoi::btou(parts.next().ok_or(())?).map_err(|_| ())?;
        let increment = btoi::btou(parts.next().ok_or(())?).map_err(|_| ())?;
        Ok(Speed::from_seconds_and_increment(seconds, increment))
    }
}

struct Importer {
    endpoint: String,
    filename: PathBuf,
    client: reqwest::blocking::Client,
    rng: SmallRng,
    spinner_idx: Wrapping<usize>,

    current: Game,
    skip: bool,
    batch: Vec<Game>,
}

#[serde_as]
#[derive(Default, Serialize, Debug)]
struct Game {
    variant: Option<String>,
    speed: Option<Speed>,
    fen: Option<String>,
    id: Option<String>,
    date: Option<String>,
    white: Player,
    black: Player,
    #[serde_as(as = "Option<DisplayFromStr>")]
    winner: Option<Color>,
    #[serde_as(as = "StringWithSeparator<SpaceSeparator, SanPlus>")]
    moves: Vec<SanPlus>,
}

#[derive(Default, Serialize, Debug)]
struct Player {
    name: Option<String>,
    rating: Option<u16>,
}

impl Importer {
    fn new(endpoint: &str, filename: PathBuf) -> Importer {
        Importer {
            endpoint: endpoint.to_owned(),
            filename,
            client: reqwest::blocking::Client::builder()
                .timeout(Duration::from_secs(60))
                .build()
                .expect("client"),
            rng: SmallRng::from_seed([
                0x19, 0x29, 0xab, 0x17, 0xc6, 0xfa, 0xb0, 0xe9, 0x4b, 0x44, 0xd8, 0x07, 0x09, 0xbf,
                0x1d, 0x87, 0xbd, 0xd8, 0xb3, 0x2f, 0xe1, 0xe2, 0xa0, 0x1a, 0x9e, 0x30, 0x98, 0xd7,
                0xef, 0xd5, 0x7a, 0x1d,
            ]),
            spinner_idx: Wrapping(0),
            current: Game::default(),
            skip: false,
            batch: Vec::with_capacity(BATCH_SIZE),
        }
    }

    pub fn send(&mut self) {
        // println!("{}", serde_json::to_string(&self.batch).expect("serialize"));

        let res = self
            .client
            .put(format!("{}/import/lichess", self.endpoint))
            .json(&self.batch)
            .send()
            .expect("send batch");

        self.spinner_idx += Wrapping(1);
        let spinner = &['⣾', '⣽', '⣻', '⢿', '⡿', '⣟', '⣯', '⣷'];

        println!(
            "{} {:?}: {}: {} - {}",
            spinner[self.spinner_idx.0 % spinner.len()],
            self.filename,
            self.batch
                .last()
                .and_then(|g| g.date.as_ref())
                .unwrap_or(&String::new()),
            res.status(),
            res.text().expect("decode response")
        );

        self.batch.clear();
    }
}

impl Visitor for Importer {
    type Result = ();

    fn begin_game(&mut self) {
        self.skip = false;
        self.current = Game::default();
    }

    fn header(&mut self, key: &[u8], value: RawHeader<'_>) {
        if key == b"White" {
            self.current.white.name = Some(value.decode_utf8().expect("White").into_owned());
        } else if key == b"Black" {
            self.current.black.name = Some(value.decode_utf8().expect("Black").into_owned());
        } else if key == b"WhiteElo" {
            if value.as_bytes() != b"?" {
                self.current.white.rating = Some(btoi::btoi(value.as_bytes()).expect("WhiteElo"));
            }
        } else if key == b"BlackElo" {
            if value.as_bytes() != b"?" {
                self.current.black.rating = Some(btoi::btoi(value.as_bytes()).expect("BlackElo"));
            }
        } else if key == b"TimeControl" {
            self.current.speed = Some(Speed::from_bytes(value.as_bytes()).expect("TimeControl"));
        } else if key == b"Variant" {
            self.current.variant = Some(value.decode_utf8().expect("Variant").into_owned());
        } else if key == b"Date" || key == b"UTCDate" {
            self.current.date = Some(value.decode_utf8().expect("Date").into_owned());
        } else if key == b"WhiteTitle" || key == b"BlackTitle" {
            if value.as_bytes() == b"BOT" {
                self.skip = true;
            }
        } else if key == b"Site" {
            self.current.id = Some(
                String::from_utf8(
                    value
                        .as_bytes()
                        .rsplitn(2, |ch| *ch == b'/')
                        .next()
                        .expect("Site")
                        .to_owned(),
                )
                .expect("Site"),
            );
        } else if key == b"Result" {
            match value.as_bytes() {
                b"1-0" => self.current.winner = Some(Color::White),
                b"0-1" => self.current.winner = Some(Color::Black),
                b"1/2-1/2" => self.current.winner = None,
                _ => self.skip = true,
            }
        } else if key == b"FEN" {
            if value.as_bytes() == b"rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1" {
                // https://github.com/ornicar/lichess-db/issues/40
                self.current.fen = None;
            } else {
                self.current.fen = Some(value.decode_utf8().expect("FEN").into_owned());
            }
        }
    }

    fn end_headers(&mut self) -> Skip {
        let rating =
            (self.current.white.rating.unwrap_or(0) + self.current.black.rating.unwrap_or(0)) / 2;

        let standard = self
            .current
            .variant
            .as_ref()
            .map_or(true, |name| name == "Standard");

        let probability = if standard {
            match self.current.speed.unwrap_or(Speed::Correspondence) {
                Speed::Correspondence | Speed::Classical => 1.00,

                _ if rating >= 2500 => 1.00,

                Speed::Rapid if rating >= 2200 => 1.00,
                Speed::Rapid if rating >= 2000 => 0.50,
                Speed::Rapid if rating >= 1800 => 0.28,
                Speed::Rapid if rating >= 1600 => 0.24,

                Speed::Blitz if rating >= 2200 => 0.24,
                Speed::Blitz if rating >= 2000 => 0.11,
                Speed::Blitz if rating >= 1600 => 0.08,

                Speed::Bullet if rating >= 2200 => 0.30,
                Speed::Bullet if rating >= 2000 => 0.17,
                Speed::Bullet if rating >= 1600 => 0.11,

                Speed::UltraBullet => 1.00,

                _ => 0.02,
            }
        } else {
            // variant games
            if rating >= 1600 {
                1.00
            } else {
                0.50
            }
        };

        let accept = min(
            self.current.white.rating.unwrap_or(0),
            self.current.black.rating.unwrap_or(0),
        ) >= 1501
            && probability >= self.rng.sample(OpenClosed01)
            && !self.skip;

        self.skip = !accept;
        Skip(self.skip)
    }

    fn san(&mut self, san: SanPlus) {
        self.current.moves.push(san);
    }

    fn begin_variation(&mut self) -> Skip {
        Skip(true) // stay in the mainline
    }

    fn end_game(&mut self) {
        if !self.skip {
            self.batch
                .push(mem::replace(&mut self.current, Default::default()));

            if self.batch.len() >= BATCH_SIZE {
                self.send();
            }
        }
    }
}

#[derive(Parser)]
struct Args {
    #[clap(long, default_value = "http://locahost:9002")]
    endpoint: String,
    pgns: Vec<PathBuf>,
}

fn main() -> Result<(), io::Error> {
    let args = Args::parse();

    for arg in args.pgns {
        let file = File::open(&arg)?;

        let uncompressed: Box<dyn io::Read> = if arg.ends_with(".bz2") {
            Box::new(bzip2::read::MultiBzDecoder::new(file))
        } else {
            Box::new(file)
        };

        let mut reader = BufferedReader::new(uncompressed);

        let mut importer = Importer::new(&args.endpoint, arg);
        reader.read_all(&mut importer)?;
    }

    Ok(())
}
<commit_msg>locahost -> localhost<commit_after>use std::{cmp::min, fs::File, io, mem, num::Wrapping, path::PathBuf, time::Duration};

use clap::Parser;
use pgn_reader::{BufferedReader, Color, RawHeader, SanPlus, Skip, Visitor};
use rand::{distributions::OpenClosed01, rngs::SmallRng, Rng, SeedableRng};
use serde::Serialize;
use serde_with::{serde_as, DisplayFromStr, SpaceSeparator, StringWithSeparator};

const BATCH_SIZE: usize = 100;

#[derive(Debug, Serialize, Copy, Clone)]
#[serde(rename_all = "camelCase")]
enum Speed {
    UltraBullet,
    Bullet,
    Blitz,
    Rapid,
    Classical,
    Correspondence,
}

impl Speed {
    fn from_seconds_and_increment(seconds: u64, increment: u64) -> Speed {
        let total = seconds + 40 * increment;

        if total < 30 {
            Speed::UltraBullet
        } else if total < 180 {
            Speed::Bullet
        } else if total < 480 {
            Speed::Blitz
        } else if total < 1500 {
            Speed::Rapid
        } else if total < 21_600 {
            Speed::Classical
        } else {
            Speed::Correspondence
        }
    }

    fn from_bytes(bytes: &[u8]) -> Result<Speed, ()> {
        if bytes == b"-" {
            return Ok(Speed::Correspondence);
        }

        let mut parts = bytes.splitn(2, |ch| *ch == b'+');
        let seconds = btoi::btou(parts.next().ok_or(())?).map_err(|_| ())?;
        let increment = btoi::btou(parts.next().ok_or(())?).map_err(|_| ())?;
        Ok(Speed::from_seconds_and_increment(seconds, increment))
    }
}

struct Importer {
    endpoint: String,
    filename: PathBuf,
    client: reqwest::blocking::Client,
    rng: SmallRng,
    spinner_idx: Wrapping<usize>,

    current: Game,
    skip: bool,
    batch: Vec<Game>,
}

#[serde_as]
#[derive(Default, Serialize, Debug)]
struct Game {
    variant: Option<String>,
    speed: Option<Speed>,
    fen: Option<String>,
    id: Option<String>,
    date: Option<String>,
    white: Player,
    black: Player,
    #[serde_as(as = "Option<DisplayFromStr>")]
    winner: Option<Color>,
    #[serde_as(as = "StringWithSeparator<SpaceSeparator, SanPlus>")]
    moves: Vec<SanPlus>,
}

#[derive(Default, Serialize, Debug)]
struct Player {
    name: Option<String>,
    rating: Option<u16>,
}

impl Importer {
    fn new(endpoint: &str, filename: PathBuf) -> Importer {
        Importer {
            endpoint: endpoint.to_owned(),
            filename,
            client: reqwest::blocking::Client::builder()
                .timeout(Duration::from_secs(60))
                .build()
                .expect("client"),
            rng: SmallRng::from_seed([
                0x19, 0x29, 0xab, 0x17, 0xc6, 0xfa, 0xb0, 0xe9, 0x4b, 0x44, 0xd8, 0x07, 0x09, 0xbf,
                0x1d, 0x87, 0xbd, 0xd8, 0xb3, 0x2f, 0xe1, 0xe2, 0xa0, 0x1a, 0x9e, 0x30, 0x98, 0xd7,
                0xef, 0xd5, 0x7a, 0x1d,
            ]),
            spinner_idx: Wrapping(0),
            current: Game::default(),
            skip: false,
            batch: Vec::with_capacity(BATCH_SIZE),
        }
    }

    pub fn send(&mut self) {
        // println!("{}", serde_json::to_string(&self.batch).expect("serialize"));

        let res = self
            .client
            .put(format!("{}/import/lichess", self.endpoint))
            .json(&self.batch)
            .send()
            .expect("send batch");

        self.spinner_idx += Wrapping(1);
        let spinner = &['⣾', '⣽', '⣻', '⢿', '⡿', '⣟', '⣯', '⣷'];

        println!(
            "{} {:?}: {}: {} - {}",
            spinner[self.spinner_idx.0 % spinner.len()],
            self.filename,
            self.batch
                .last()
                .and_then(|g| g.date.as_ref())
                .unwrap_or(&String::new()),
            res.status(),
            res.text().expect("decode response")
        );

        self.batch.clear();
    }
}

impl Visitor for Importer {
    type Result = ();

    fn begin_game(&mut self) {
        self.skip = false;
        self.current = Game::default();
    }

    fn header(&mut self, key: &[u8], value: RawHeader<'_>) {
        if key == b"White" {
            self.current.white.name = Some(value.decode_utf8().expect("White").into_owned());
        } else if key == b"Black" {
            self.current.black.name = Some(value.decode_utf8().expect("Black").into_owned());
        } else if key == b"WhiteElo" {
            if value.as_bytes() != b"?" {
                self.current.white.rating = Some(btoi::btoi(value.as_bytes()).expect("WhiteElo"));
            }
        } else if key == b"BlackElo" {
            if value.as_bytes() != b"?" {
                self.current.black.rating = Some(btoi::btoi(value.as_bytes()).expect("BlackElo"));
            }
        } else if key == b"TimeControl" {
            self.current.speed = Some(Speed::from_bytes(value.as_bytes()).expect("TimeControl"));
        } else if key == b"Variant" {
            self.current.variant = Some(value.decode_utf8().expect("Variant").into_owned());
        } else if key == b"Date" || key == b"UTCDate" {
            self.current.date = Some(value.decode_utf8().expect("Date").into_owned());
        } else if key == b"WhiteTitle" || key == b"BlackTitle" {
            if value.as_bytes() == b"BOT" {
                self.skip = true;
            }
        } else if key == b"Site" {
            self.current.id = Some(
                String::from_utf8(
                    value
                        .as_bytes()
                        .rsplitn(2, |ch| *ch == b'/')
                        .next()
                        .expect("Site")
                        .to_owned(),
                )
                .expect("Site"),
            );
        } else if key == b"Result" {
            match value.as_bytes() {
                b"1-0" => self.current.winner = Some(Color::White),
                b"0-1" => self.current.winner = Some(Color::Black),
                b"1/2-1/2" => self.current.winner = None,
                _ => self.skip = true,
            }
        } else if key == b"FEN" {
            if value.as_bytes() == b"rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1" {
                // https://github.com/ornicar/lichess-db/issues/40
                self.current.fen = None;
            } else {
                self.current.fen = Some(value.decode_utf8().expect("FEN").into_owned());
            }
        }
    }

    fn end_headers(&mut self) -> Skip {
        let rating =
            (self.current.white.rating.unwrap_or(0) + self.current.black.rating.unwrap_or(0)) / 2;

        let standard = self
            .current
            .variant
            .as_ref()
            .map_or(true, |name| name == "Standard");

        let probability = if standard {
            match self.current.speed.unwrap_or(Speed::Correspondence) {
                Speed::Correspondence | Speed::Classical => 1.00,

                _ if rating >= 2500 => 1.00,

                Speed::Rapid if rating >= 2200 => 1.00,
                Speed::Rapid if rating >= 2000 => 0.50,
                Speed::Rapid if rating >= 1800 => 0.28,
                Speed::Rapid if rating >= 1600 => 0.24,

                Speed::Blitz if rating >= 2200 => 0.24,
                Speed::Blitz if rating >= 2000 => 0.11,
                Speed::Blitz if rating >= 1600 => 0.08,

                Speed::Bullet if rating >= 2200 => 0.30,
                Speed::Bullet if rating >= 2000 => 0.17,
                Speed::Bullet if rating >= 1600 => 0.11,

                Speed::UltraBullet => 1.00,

                _ => 0.02,
            }
        } else {
            // variant games
            if rating >= 1600 {
                1.00
            } else {
                0.50
            }
        };

        let accept = min(
            self.current.white.rating.unwrap_or(0),
            self.current.black.rating.unwrap_or(0),
        ) >= 1501
            && probability >= self.rng.sample(OpenClosed01)
            && !self.skip;

        self.skip = !accept;
        Skip(self.skip)
    }

    fn san(&mut self, san: SanPlus) {
        self.current.moves.push(san);
    }

    fn begin_variation(&mut self) -> Skip {
        Skip(true) // stay in the mainline
    }

    fn end_game(&mut self) {
        if !self.skip {
            self.batch
                .push(mem::replace(&mut self.current, Default::default()));

            if self.batch.len() >= BATCH_SIZE {
                self.send();
            }
        }
    }
}

#[derive(Parser)]
struct Args {
    #[clap(long, default_value = "http://localhost:9002")]
    endpoint: String,
    pgns: Vec<PathBuf>,
}

fn main() -> Result<(), io::Error> {
    let args = Args::parse();

    for arg in args.pgns {
        let file = File::open(&arg)?;

        let uncompressed: Box<dyn io::Read> = if arg.ends_with(".bz2") {
            Box::new(bzip2::read::MultiBzDecoder::new(file))
        } else {
            Box::new(file)
        };

        let mut reader = BufferedReader::new(uncompressed);

        let mut importer = Importer::new(&args.endpoint, arg);
        reader.read_all(&mut importer)?;
    }

    Ok(())
}
<|endoftext|>


<commit_before>use types;

#[link(name = "ruby")]
extern "C" {
    pub fn rb_intern(name: *const types::c_char) -> types::rb_value;
    pub fn rb_const_get(klass: types::rb_value, id: types::rb_value) -> types::rb_value;
    pub fn rb_funcall(receiver: types::rb_value,
                      method: types::rb_value,
                      argc: types::c_int,
                      ...) -> types::rb_value;
}
<commit_msg>Bind rb_funcall2 instead of rb_funcall<commit_after>use types;

#[link(name = "ruby")]
extern "C" {
    pub fn rb_intern(name: *const types::c_char) -> types::rb_value;
    pub fn rb_const_get(klass: types::rb_value, id: types::rb_value) -> types::rb_value;
    pub fn rb_funcall2(receiver: types::rb_value,
                       method: types::rb_value,
                       argc: types::c_int,
                       argv: *const types::rb_value) -> types::rb_value;
}
<|endoftext|>


<commit_before>use Printer;
use With;
use XY;
use direction;
use event::{Event, EventResult, Key};
use std::any::Any;
use std::cmp::min;
use vec::Vec2;
use view::{Selector, SizeCache};
use view::View;

/// Arranges its children linearly according to its orientation.
pub struct LinearLayout {
    children: Vec<Child>,
    orientation: direction::Orientation,
    focus: usize,

    cache: Option<XY<SizeCache>>,
}

struct Child {
    view: Box<View>,
    size: Vec2,
    weight: usize,
}

impl Child {
    // Compute and caches the required size.
    fn required_size(&mut self, req: Vec2) -> Vec2 {
        self.size = self.view.required_size(req);
        self.size
    }

    fn as_view(&self) -> &View {
        &*self.view
    }
}

fn cap<'a, I: Iterator<Item = &'a mut usize>>(iter: I, max: usize) {
    let mut available = max;
    for item in iter {
        if *item > available {
            *item = available;
        }

        available -= *item;
    }
}

impl LinearLayout {
    /// Creates a new layout with the given orientation.
    pub fn new(orientation: direction::Orientation) -> Self {
        LinearLayout {
            children: Vec::new(),
            orientation: orientation,
            focus: 0,
            cache: None,
        }
    }

    /// Modifies the weight of the last child added.
    ///
    /// It is an error to call this before adding a child (and it will panic).
    pub fn weight(mut self, weight: usize) -> Self {
        self.children.last_mut().unwrap().weight = weight;

        self
    }

    /// Adds a child to the layout.
    ///
    /// Chainable variant.
    pub fn child<V: View + 'static>(self, view: V) -> Self {
        self.with(|s| s.add_child(view))
    }

    /// Adds a child to the layout.
    pub fn add_child<V: View + 'static>(&mut self, view: V) {
        self.children.push(Child {
            view: Box::new(view),
            size: Vec2::zero(),
            weight: 0,
        });
        self.invalidate();
    }

    // Invalidate the view, to request a layout next time
    fn invalidate(&mut self) {
        self.cache = None;
    }

    /// Creates a new vertical layout.
    pub fn vertical() -> Self {
        LinearLayout::new(direction::Orientation::Vertical)
    }

    /// Creates a new horizontal layout.
    pub fn horizontal() -> Self {
        LinearLayout::new(direction::Orientation::Horizontal)
    }

    // If the cache can be used, return the cached size.
    // Otherwise, return None.
    fn get_cache(&self, req: Vec2) -> Option<Vec2> {
        match self.cache {
            None => None,
            Some(ref cache) => {
                // Is our cache even valid?
                // Also, is any child invalidating the layout?
                if cache.zip_map(req, SizeCache::accept).both()
                    && self.children_are_sleeping()
                {
                    Some(cache.map(|s| s.value))
                } else {
                    None
                }
            }
        }
    }

    fn children_are_sleeping(&self) -> bool {
        !self.children
            .iter()
            .map(Child::as_view)
            .any(View::needs_relayout)
    }

    /// Returns a cyclic mutable iterator starting with the child in focus
    fn iter_mut<'a>(
        &'a mut self, from_focus: bool, source: direction::Relative
    ) -> Box<Iterator<Item = (usize, &mut Child)> + 'a> {
        match source {
            direction::Relative::Front => {
                let start = if from_focus { self.focus } else { 0 };

                Box::new(self.children.iter_mut().enumerate().skip(start))
            }
            direction::Relative::Back => {
                let end = if from_focus {
                    self.focus + 1
                } else {
                    self.children.len()
                };
                Box::new(self.children[..end].iter_mut().enumerate().rev())
            }
        }
    }

    fn move_focus(&mut self, source: direction::Direction) -> EventResult {
        let i = if let Some(i) =
            source.relative(self.orientation).and_then(|rel| {
                // The iterator starts at the focused element.
                // We don't want that one.
                self.iter_mut(true, rel)
                    .skip(1)
                    .filter_map(|p| try_focus(p, source))
                    .next()
            }) {
            i
        } else {
            return EventResult::Ignored;
        };
        self.focus = i;
        EventResult::Consumed(None)
    }
}

fn try_focus(
    (i, child): (usize, &mut Child), source: direction::Direction
) -> Option<usize> {
    if child.view.take_focus(source) {
        Some(i)
    } else {
        None
    }
}

impl View for LinearLayout {
    fn draw(&self, printer: &Printer) {
        // Use pre-computed sizes
        let mut offset = Vec2::zero();
        for (i, child) in self.children.iter().enumerate() {
            let printer =
                &printer.sub_printer(offset, child.size, i == self.focus);
            child.view.draw(printer);

            // On the axis given by the orientation,
            // add the child size to the offset.
            *self.orientation.get_ref(&mut offset) +=
                self.orientation.get(&child.size);
        }
    }

    fn needs_relayout(&self) -> bool {
        if self.cache.is_none() {
            return true;
        }

        !self.children_are_sleeping()
    }

    fn layout(&mut self, size: Vec2) {
        // If we can get away without breaking a sweat, you can bet we will.
        if self.get_cache(size).is_none() {
            self.required_size(size);
        }

        let o = self.orientation;

        for child in &mut self.children {
            // Every item has the same size orthogonal to the layout
            child.size.set_axis_from(o.swap(), &size);
            child.view.layout(size.with_axis_from(o, &child.size));
        }
    }

    fn required_size(&mut self, req: Vec2) -> Vec2 {
        // Did anything change since last time?
        if let Some(size) = self.get_cache(req) {
            return size;
        }

        // First, make a naive scenario: everything will work fine.
        let sizes: Vec<Vec2> = self.children
            .iter_mut()
            .map(|c| c.required_size(req))
            .collect();
        debug!("Ideal sizes: {:?}", sizes);
        let ideal = self.orientation.stack(sizes.iter());
        debug!("Ideal result: {:?}", ideal);

        // Does it fit?
        if ideal.fits_in(req) {
            // Champagne!
            self.cache = Some(SizeCache::build(ideal, req));
            return ideal;
        }

        // Ok, so maybe it didn't. Budget cuts, everyone.
        // Let's pretend we have almost no space in this direction.
        let budget_req = req.with_axis(self.orientation, 1);
        debug!("Budget req: {:?}", budget_req);

        // See how they like it that way
        let min_sizes: Vec<Vec2> = self.children
            .iter_mut()
            .map(|c| c.required_size(budget_req))
            .collect();
        let desperate = self.orientation.stack(min_sizes.iter());
        debug!("Min sizes: {:?}", min_sizes);
        debug!("Desperate: {:?}", desperate);

        // This is the lowest we'll ever go. It better fit at least.
        let orientation = self.orientation;
        if !desperate.fits_in(req) {
            // Just give up...
            // TODO: hard-cut
            cap(
                self.children
                    .iter_mut()
                    .map(|c| c.size.get_mut(orientation)),
                *req.get(self.orientation),
            );

            // TODO: print some error message or something
            debug!("Seriously? {:?} > {:?}???", desperate, req);
            // self.cache = Some(SizeCache::build(desperate, req));
            self.cache = None;
            return desperate;
        }

        // This here is how much we're generously offered
        // (We just checked that req >= desperate, so the subtraction is safe
        let mut available = self.orientation.get(&(req - desperate));
        debug!("Available: {:?}", available);

        // Here, we have to make a compromise between the ideal
        // and the desperate solutions.
        let mut overweight: Vec<(usize, usize)> = sizes
            .iter()
            .map(|v| self.orientation.get(v))
            .zip(min_sizes.iter().map(|v| self.orientation.get(v)))
            .map(|(a, b)| a.saturating_sub(b))
            .enumerate()
            .collect();
        debug!("Overweight: {:?}", overweight);

        // So... distribute `available` to reduce the overweight...
        // TODO: use child weight in the distribution...

        // We'll give everyone his share of what we have left,
        // starting with those who ask the least.
        overweight.sort_by_key(|&(_, weight)| weight);
        let mut allocations = vec![0; overweight.len()];

        for (i, &(j, weight)) in overweight.iter().enumerate() {
            // This is the number of people we still have to feed.
            let remaining = overweight.len() - i;
            // How much we can spare on each one
            let budget = available / remaining;
            // Maybe he doesn't even need that much?
            let spent = min(budget, weight);
            allocations[j] = spent;
            available -= spent;
        }
        debug!("Allocations: {:?}", allocations);

        // Final lengths are the minimum ones + generous allocations
        let final_lengths: Vec<Vec2> = min_sizes
            .iter()
            .map(|v| self.orientation.get(v))
            .zip(allocations.iter())
            .map(|(a, b)| a + b)
            .map(|l| req.with_axis(self.orientation, l))
            .collect();
        debug!("Final sizes: {:?}", final_lengths);

        // Let's ask everyone one last time. Everyone should be happy.
        // (But they may ask more on the other axis.)
        let final_sizes: Vec<Vec2> = self.children
            .iter_mut()
            .enumerate()
            .map(|(i, c)| c.required_size(final_lengths[i]))
            .collect();
        debug!("Final sizes2: {:?}", final_sizes);

        // Let's stack everything to see what it looks like.
        let compromise = self.orientation.stack(final_sizes.iter());

        // Phew, that was a lot of work! I'm not doing it again.
        self.cache = Some(SizeCache::build(compromise, req));

        compromise
    }

    fn take_focus(&mut self, source: direction::Direction) -> bool {
        // In what order will we iterate on the children?
        let rel = source.relative(self.orientation);
        // We activate from_focus only if coming from the "sides".
        let i = if let Some(i) = self.iter_mut(
            rel.is_none(),
            rel.unwrap_or(direction::Relative::Front),
        ).filter_map(|p| try_focus(p, source))
            .next()
        {
            // ... we can't update `self.focus` here,
            // because rustc thinks we still borrow `self`.
            // :(
            i
        } else {
            return false;
        };

        self.focus = i;
        true
    }

    fn on_event(&mut self, event: Event) -> EventResult {
        match self.children[self.focus].view.on_event(event.clone()) {
            EventResult::Ignored => match event {
                Event::Shift(Key::Tab) if self.focus > 0 => {
                    self.move_focus(direction::Direction::back())
                }
                Event::Key(Key::Tab)
                    if self.focus + 1 < self.children.len() =>
                {
                    self.move_focus(direction::Direction::front())
                }
                Event::Key(Key::Left)
                    if self.orientation == direction::Orientation::Horizontal
                        && self.focus > 0 =>
                {
                    self.move_focus(direction::Direction::right())
                }
                Event::Key(Key::Up)
                    if self.orientation == direction::Orientation::Vertical
                        && self.focus > 0 =>
                {
                    self.move_focus(direction::Direction::down())
                }
                Event::Key(Key::Right)
                    if self.orientation == direction::Orientation::Horizontal
                        && self.focus + 1 < self.children.len() =>
                {
                    self.move_focus(direction::Direction::left())
                }
                Event::Key(Key::Down)
                    if self.orientation == direction::Orientation::Vertical
                        && self.focus + 1 < self.children.len() =>
                {
                    self.move_focus(direction::Direction::up())
                }
                _ => EventResult::Ignored,
            },
            res => res,
        }
    }

    fn call_on_any<'a>(
        &mut self, selector: &Selector,
        mut callback: Box<FnMut(&mut Any) + 'a>,
    ) {
        for child in &mut self.children {
            child
                .view
                .call_on_any(selector, Box::new(|any| callback(any)));
        }
    }

    fn focus_view(&mut self, selector: &Selector) -> Result<(), ()> {
        for (i, child) in self.children.iter_mut().enumerate() {
            if child.view.focus_view(selector).is_ok() {
                self.focus = i;
                return Ok(());
            }
        }

        Err(())
    }
}
<commit_msg>Add mouse support to LinearLayout<commit_after>use Printer;
use With;
use XY;
use direction;
use event::{Event, EventResult, Key};
use std::any::Any;
use std::cmp::min;
use std::ops::Deref;
use vec::Vec2;
use view::{Selector, SizeCache};
use view::View;

/// Arranges its children linearly according to its orientation.
pub struct LinearLayout {
    children: Vec<Child>,
    orientation: direction::Orientation,
    focus: usize,

    cache: Option<XY<SizeCache>>,
}

struct Child {
    view: Box<View>,
    size: Vec2,
    weight: usize,
}

impl Child {
    // Compute and caches the required size.
    fn required_size(&mut self, req: Vec2) -> Vec2 {
        self.size = self.view.required_size(req);
        self.size
    }

    fn as_view(&self) -> &View {
        &*self.view
    }
}

struct ChildIterator<I> {
    inner: I,
    offset: usize,
    orientation: direction::Orientation,
}

impl <'a,T: Deref<Target=Child>, I: Iterator<Item=T>> Iterator for ChildIterator<I> {
    type Item = (usize, T);

    fn next(&mut self) -> Option<Self::Item> {
        self.inner.next().map(|child| {
            let previous = self.offset;
            self.offset += child.size.get(self.orientation);
            (previous, child)
        })
    }
}

fn cap<'a, I: Iterator<Item = &'a mut usize>>(iter: I, max: usize) {
    let mut available = max;
    for item in iter {
        if *item > available {
            *item = available;
        }

        available -= *item;
    }
}

impl LinearLayout {
    /// Creates a new layout with the given orientation.
    pub fn new(orientation: direction::Orientation) -> Self {
        LinearLayout {
            children: Vec::new(),
            orientation: orientation,
            focus: 0,
            cache: None,
        }
    }

    /// Modifies the weight of the last child added.
    ///
    /// It is an error to call this before adding a child (and it will panic).
    pub fn weight(mut self, weight: usize) -> Self {
        self.children.last_mut().unwrap().weight = weight;

        self
    }

    /// Adds a child to the layout.
    ///
    /// Chainable variant.
    pub fn child<V: View + 'static>(self, view: V) -> Self {
        self.with(|s| s.add_child(view))
    }

    /// Adds a child to the layout.
    pub fn add_child<V: View + 'static>(&mut self, view: V) {
        self.children.push(Child {
            view: Box::new(view),
            size: Vec2::zero(),
            weight: 0,
        });
        self.invalidate();
    }

    // Invalidate the view, to request a layout next time
    fn invalidate(&mut self) {
        self.cache = None;
    }

    /// Creates a new vertical layout.
    pub fn vertical() -> Self {
        LinearLayout::new(direction::Orientation::Vertical)
    }

    /// Creates a new horizontal layout.
    pub fn horizontal() -> Self {
        LinearLayout::new(direction::Orientation::Horizontal)
    }

    // If the cache can be used, return the cached size.
    // Otherwise, return None.
    fn get_cache(&self, req: Vec2) -> Option<Vec2> {
        match self.cache {
            None => None,
            Some(ref cache) => {
                // Is our cache even valid?
                // Also, is any child invalidating the layout?
                if cache.zip_map(req, SizeCache::accept).both()
                    && self.children_are_sleeping()
                {
                    Some(cache.map(|s| s.value))
                } else {
                    None
                }
            }
        }
    }

    fn children_are_sleeping(&self) -> bool {
        !self.children
            .iter()
            .map(Child::as_view)
            .any(View::needs_relayout)
    }

    /// Returns a cyclic mutable iterator starting with the child in focus
    fn iter_mut<'a>(
        &'a mut self, from_focus: bool, source: direction::Relative
    ) -> Box<Iterator<Item = (usize, &mut Child)> + 'a> {
        match source {
            direction::Relative::Front => {
                let start = if from_focus { self.focus } else { 0 };

                Box::new(self.children.iter_mut().enumerate().skip(start))
            }
            direction::Relative::Back => {
                let end = if from_focus {
                    self.focus + 1
                } else {
                    self.children.len()
                };
                Box::new(self.children[..end].iter_mut().enumerate().rev())
            }
        }
    }

    fn move_focus(&mut self, source: direction::Direction) -> EventResult {
        let i = if let Some(i) =
            source.relative(self.orientation).and_then(|rel| {
                // The iterator starts at the focused element.
                // We don't want that one.
                self.iter_mut(true, rel)
                    .skip(1)
                    .filter_map(|p| try_focus(p, source))
                    .next()
            }) {
            i
        } else {
            return EventResult::Ignored;
        };
        self.focus = i;
        EventResult::Consumed(None)
    }

    fn check_focus_grab(&mut self, event: &Event) {
        if let &Event::Mouse {
            offset,
            position,
            event,
        } = event
        {
            if !event.grabs_focus() {
                return;
            }

            let position = match position.checked_sub(offset) {
                None => return,
                Some(pos) => pos,
            };

            // Find the selected child
            let position = *position.get(self.orientation);
            let iterator = ChildIterator {
                inner: self.children.iter_mut(),
                offset: 0,
                orientation: self.orientation,
            };
            for (i, (offset, child)) in iterator.enumerate() {
                let child_size = child.size.get(self.orientation);
                        // eprintln!("Offset {:?}, size {:?}, position: {:?}", offset, child_size, position);
                if offset + child_size > position {
                    if child.view.take_focus(direction::Direction::none()) {
                        // eprintln!("It's a match!");
                        self.focus = i;
                        return;
                    }
                }
            }
        }
    }
}

fn try_focus(
    (i, child): (usize, &mut Child), source: direction::Direction
) -> Option<usize> {
    if child.view.take_focus(source) {
        Some(i)
    } else {
        None
    }
}

impl View for LinearLayout {
    fn draw(&self, printer: &Printer) {
        // Use pre-computed sizes
        let mut offset = Vec2::zero();
        for (i, child) in self.children.iter().enumerate() {
            let printer =
                &printer.sub_printer(offset, child.size, i == self.focus);
            child.view.draw(printer);

            // On the axis given by the orientation,
            // add the child size to the offset.
            *self.orientation.get_ref(&mut offset) +=
                self.orientation.get(&child.size);
        }
    }

    fn needs_relayout(&self) -> bool {
        if self.cache.is_none() {
            return true;
        }

        !self.children_are_sleeping()
    }

    fn layout(&mut self, size: Vec2) {
        // If we can get away without breaking a sweat, you can bet we will.
        if self.get_cache(size).is_none() {
            self.required_size(size);
        }

        let o = self.orientation;

        for child in &mut self.children {
            // Every item has the same size orthogonal to the layout
            child.size.set_axis_from(o.swap(), &size);
            child.view.layout(size.with_axis_from(o, &child.size));
        }
    }

    fn required_size(&mut self, req: Vec2) -> Vec2 {
        // Did anything change since last time?
        if let Some(size) = self.get_cache(req) {
            return size;
        }

        // First, make a naive scenario: everything will work fine.
        let sizes: Vec<Vec2> = self.children
            .iter_mut()
            .map(|c| c.required_size(req))
            .collect();
        debug!("Ideal sizes: {:?}", sizes);
        let ideal = self.orientation.stack(sizes.iter());
        debug!("Ideal result: {:?}", ideal);

        // Does it fit?
        if ideal.fits_in(req) {
            // Champagne!
            self.cache = Some(SizeCache::build(ideal, req));
            return ideal;
        }

        // Ok, so maybe it didn't. Budget cuts, everyone.
        // Let's pretend we have almost no space in this direction.
        let budget_req = req.with_axis(self.orientation, 1);
        debug!("Budget req: {:?}", budget_req);

        // See how they like it that way
        let min_sizes: Vec<Vec2> = self.children
            .iter_mut()
            .map(|c| c.required_size(budget_req))
            .collect();
        let desperate = self.orientation.stack(min_sizes.iter());
        debug!("Min sizes: {:?}", min_sizes);
        debug!("Desperate: {:?}", desperate);

        // This is the lowest we'll ever go. It better fit at least.
        let orientation = self.orientation;
        if !desperate.fits_in(req) {
            // Just give up...
            // TODO: hard-cut
            cap(
                self.children
                    .iter_mut()
                    .map(|c| c.size.get_mut(orientation)),
                *req.get(self.orientation),
            );

            // TODO: print some error message or something
            debug!("Seriously? {:?} > {:?}???", desperate, req);
            // self.cache = Some(SizeCache::build(desperate, req));
            self.cache = None;
            return desperate;
        }

        // This here is how much we're generously offered
        // (We just checked that req >= desperate, so the subtraction is safe
        let mut available = self.orientation.get(&(req - desperate));
        debug!("Available: {:?}", available);

        // Here, we have to make a compromise between the ideal
        // and the desperate solutions.
        let mut overweight: Vec<(usize, usize)> = sizes
            .iter()
            .map(|v| self.orientation.get(v))
            .zip(min_sizes.iter().map(|v| self.orientation.get(v)))
            .map(|(a, b)| a.saturating_sub(b))
            .enumerate()
            .collect();
        debug!("Overweight: {:?}", overweight);

        // So... distribute `available` to reduce the overweight...
        // TODO: use child weight in the distribution...

        // We'll give everyone his share of what we have left,
        // starting with those who ask the least.
        overweight.sort_by_key(|&(_, weight)| weight);
        let mut allocations = vec![0; overweight.len()];

        for (i, &(j, weight)) in overweight.iter().enumerate() {
            // This is the number of people we still have to feed.
            let remaining = overweight.len() - i;
            // How much we can spare on each one
            let budget = available / remaining;
            // Maybe he doesn't even need that much?
            let spent = min(budget, weight);
            allocations[j] = spent;
            available -= spent;
        }
        debug!("Allocations: {:?}", allocations);

        // Final lengths are the minimum ones + generous allocations
        let final_lengths: Vec<Vec2> = min_sizes
            .iter()
            .map(|v| self.orientation.get(v))
            .zip(allocations.iter())
            .map(|(a, b)| a + b)
            .map(|l| req.with_axis(self.orientation, l))
            .collect();
        debug!("Final sizes: {:?}", final_lengths);

        // Let's ask everyone one last time. Everyone should be happy.
        // (But they may ask more on the other axis.)
        let final_sizes: Vec<Vec2> = self.children
            .iter_mut()
            .enumerate()
            .map(|(i, c)| c.required_size(final_lengths[i]))
            .collect();
        debug!("Final sizes2: {:?}", final_sizes);

        // Let's stack everything to see what it looks like.
        let compromise = self.orientation.stack(final_sizes.iter());

        // Phew, that was a lot of work! I'm not doing it again.
        self.cache = Some(SizeCache::build(compromise, req));

        compromise
    }

    fn take_focus(&mut self, source: direction::Direction) -> bool {
        // In what order will we iterate on the children?
        let rel = source.relative(self.orientation);
        // We activate from_focus only if coming from the "sides".
        let i = if let Some(i) = self.iter_mut(
            rel.is_none(),
            rel.unwrap_or(direction::Relative::Front),
        ).filter_map(|p| try_focus(p, source))
            .next()
        {
            // ... we can't update `self.focus` here,
            // because rustc thinks we still borrow `self`.
            // :(
            i
        } else {
            return false;
        };

        self.focus = i;
        true
    }

    fn on_event(&mut self, event: Event) -> EventResult {
        self.check_focus_grab(&event);

        let result = {
            let mut iterator = ChildIterator {
                inner: self.children.iter_mut(),
                offset: 0,
                orientation: self.orientation,
            };
            let (offset, child) = iterator.nth(self.focus).unwrap();
            let offset = self.orientation.make_vec(offset, 0);
            child.view.on_event(event.relativized(offset))
        };
        match result {
            EventResult::Ignored => match event {
                Event::Shift(Key::Tab) if self.focus > 0 => {
                    self.move_focus(direction::Direction::back())
                }
                Event::Key(Key::Tab)
                    if self.focus + 1 < self.children.len() =>
                {
                    self.move_focus(direction::Direction::front())
                }
                Event::Key(Key::Left)
                    if self.orientation == direction::Orientation::Horizontal
                        && self.focus > 0 =>
                {
                    self.move_focus(direction::Direction::right())
                }
                Event::Key(Key::Up)
                    if self.orientation == direction::Orientation::Vertical
                        && self.focus > 0 =>
                {
                    self.move_focus(direction::Direction::down())
                }
                Event::Key(Key::Right)
                    if self.orientation == direction::Orientation::Horizontal
                        && self.focus + 1 < self.children.len() =>
                {
                    self.move_focus(direction::Direction::left())
                }
                Event::Key(Key::Down)
                    if self.orientation == direction::Orientation::Vertical
                        && self.focus + 1 < self.children.len() =>
                {
                    self.move_focus(direction::Direction::up())
                }
                _ => EventResult::Ignored,
            },
            res => res,
        }
    }

    fn call_on_any<'a>(
        &mut self, selector: &Selector,
        mut callback: Box<FnMut(&mut Any) + 'a>,
    ) {
        for child in &mut self.children {
            child
                .view
                .call_on_any(selector, Box::new(|any| callback(any)));
        }
    }

    fn focus_view(&mut self, selector: &Selector) -> Result<(), ()> {
        for (i, child) in self.children.iter_mut().enumerate() {
            if child.view.focus_view(selector).is_ok() {
                self.focus = i;
                return Ok(());
            }
        }

        Err(())
    }
}
<|endoftext|>