<commit_before>// External modules:
use darwin_rs::{Individual, SimulationBuilder, Population, PopulationBuilder};
use image;
use image::{GenericImage, FilterType, DynamicImage};
use rand::Rng;
use rand;

// Std modules:
use std::cmp;

// Internal modules:
use config::PanolutionConfig;

#[derive(Clone)]
pub struct ImageArrangement {
    file_name: String, // TODO: Share path between individuals
    // TODO: Add image and share it, so it doesn't have to be re-loaded every time
    x: u32,
    y: u32,
    angle: f64,
    // TODO: add more image operations
}

#[derive(Clone)]
pub struct Solution {
    arrangement: Vec<ImageArrangement>,
}

#[derive(PartialEq, Eq, Debug)]
struct Rectangle {
    x: u32,
    y: u32,
    w: u32,
    h: u32,
}

fn calc_intersection(x1: u32, x2: u32, y1: u32, y2: u32, w1: u32, w2: u32, h1: u32, h2: u32) -> (Rectangle, Rectangle) {
    // rect1 and rect2 refer to positions inside the images. Not the absolute positions.
    let mut rect1 = Rectangle{x: 0, y: 0, w: 0, h: 0};
    let mut rect2 = Rectangle{x: 0, y: 0, w: 0, h: 0};

    if x1 == x2 {
        rect1.x = 0;
        rect2.x = 0;

        if w1 < w2 {
            rect1.w = w1;
            rect2.w = w1;
        } else {
            rect1.w = w2;
            rect2.w = w2;
        }
    }

    if y1 == y2 {
        rect1.y = 0;
        rect2.y = 0;

        if h1 < h2 {
            rect1.h = h1;
            rect2.h = h1;
        } else {
            rect1.h = h2;
            rect2.h = h2;
        }
    }

    let dx = (x2 as i32 - x1 as i32).abs() as u32;
    let dy = (y2 as i32 - y1 as i32).abs() as u32;

    if x1 < x2 && dx < w1 {
        rect1.x = dx;
        rect1.w = w1 - dx;
        rect2.x = 0;
        rect2.w = rect1.w;
    }

    if x2 < x1 && dx < w2 {
        rect2.x = dx;
        rect2.w = w2 - dx;
        rect1.x = 0;
        rect1.w = rect2.w;
    }

    if y1 < y2 && dy < h1 {
        rect1.y = dy;
        rect1.h = h1 - dy;
        rect2.y = 0;
        rect2.h = rect1.h;
    }

    if y2 < y1 && dy < h2 {
        rect2.y = dy;
        rect2.h = h2 - dy;
        rect1.y = 0;
        rect1.h = rect2.h;
    }

    (rect1, rect2)
}

fn make_all_populations(num_of_individuals: u32, num_of_populations: u32, initial_solution: &Solution) -> Vec<Population<Solution>> {
    let mut result = Vec::new();

    let mut initial_population = Vec::new();

    for _ in 0..num_of_individuals {
        initial_population.push(initial_solution.clone());
    }

    for i in 0..num_of_populations {
        let pop = PopulationBuilder::<Solution>::new()
            .set_id(i + 1)
            .initial_population(&initial_population)
            .reset_limit_end(0)
            .increasing_mutation_rate()
            .finalize().unwrap();

        result.push(pop);
    }

    result
}

impl Individual for Solution {
    fn mutate(&mut self) {
        let mut rng = rand::thread_rng();
        let num_of_operations: u8 = 4;

        let index1: usize = rng.gen_range(0, self.arrangement.len());

        // Probably use this create and enums:
        // https://github.com/andersk/enum_primitive-rs

        let operation: u8 = rng.gen_range(0, num_of_operations);

        match operation {
            0 => {
                // Change image order
                let mut index2: usize = rng.gen_range(0, self.arrangement.len());
                while index1 == index2 {
                    index2 = rng.gen_range(0, self.arrangement.len());
                }

                self.arrangement.swap(index1, index2);
            },
            1 => {
                // Move x
                self.arrangement[index1].x = self.arrangement[index1].x + (rng.gen_range(0, 3) - 1);
            },
            2 => {
                // Move y
                self.arrangement[index1].y = self.arrangement[index1].y + (rng.gen_range(0, 3) - 1);
            },
            3 => {
                // Rotate
                let angle: f64 = ((rng.gen_range(0, 21) - 10) as f64) * 0.1;
                self.arrangement[index1].angle = self.arrangement[index1].angle + angle;
            },
            op => {
                warn!("mutate(): unknown operation: {}", op)
            }
        }
    }

    fn calculate_fitness(&mut self) -> f64 {
        let mut fitness = 0.0;

        for i in 0..self.arrangement.len() {
            let arrangement1 = &self.arrangement[i];
            let arrangement2 = &self.arrangement[i + 1];

            let image1 = image::open(&arrangement1.file_name).unwrap();
            let image2 = image::open(&arrangement2.file_name).unwrap();

            let w1 = image1.width();
            let w2 = image2.width();
            let h1 = image1.height();
            let h2 = image2.height();

            let (rect1, rect2) = calc_intersection(
                arrangement1.x, arrangement2.x, arrangement1.y, arrangement2.y,
                w1, w2, h1, h2
            );

            if rect1.w == 0 || rect1.h == 0 {
                // Images don't intersect, add penalty
                fitness = fitness + cmp::max(w1 * h1, w2 * h2) as f64;
            } else {
                let intersection_area = rect1.w * rect1.h;
            }
        }

        fitness
    }

    fn reset(&mut self) {
        for arrangement in &mut self.arrangement {
            // Reset all image operation to original image
            arrangement.x = 0;
            arrangement.y = 0;
            arrangement.angle = 0.0;
        }
    }
}

fn run_darwin(solution: Solution, max_iteration: u32) -> Solution {
    info!("Run darwin with maximum number of iterations: {}", max_iteration);

    let pano = SimulationBuilder::<Solution>::new()
        .iterations(max_iteration)
        .threads(4) // TODO: Make this configurable
        .add_multiple_populations(make_all_populations(100, 8, &solution))
        .finalize();

    match pano {
        Err(e) => {
            error!("An error occured");

            for e in e.iter().skip(1) {
                error!("Caused by '{}'", e)
            }

            solution
        },
        Ok(mut pano_simulation) => {
            pano_simulation.run();

            info!("Total run time: {} ms", pano_simulation.total_time_in_ms);
            info!("Improvement factor: {}", pano_simulation.simulation_result.improvement_factor);
            info!("Number of iterations: {}", pano_simulation.simulation_result.iteration_counter);

            pano_simulation.simulation_result.fittest[0].individual.clone()
        }
    }
}

pub fn optimize(solution: Option<&Solution>, config: &PanolutionConfig, thumbnail_path: &Vec<String>) -> Solution {
    let mut result = Solution{ arrangement: Vec::new() };

    // Prepare data
    if let Some(solution) = solution {
        result.arrangement = solution.arrangement.iter().zip(thumbnail_path).map(|(arrangement, path)| ImageArrangement {
                file_name: path.clone(),
                x: arrangement.x,
                y: arrangement.y,
                angle: arrangement.angle,
            }
        ).collect();
    } else {
        result.arrangement = thumbnail_path.iter().map(|path| ImageArrangement {
                file_name: path.clone(),
                x: 0,
                y: 0,
                angle: 0.0
            }
        ).collect();
    }

    run_darwin(result, config.max_iteration)
}

#[cfg(test)]
mod test {
    use super::{calc_intersection, Rectangle};

    #[test]
    fn calc_intersection1() {
        let (r1, r2) = calc_intersection(0, 0, 0, 0, 10, 15, 20, 25);

        assert_eq!(r1, Rectangle{x: 0, y: 0, w: 10, h: 20});
        assert_eq!(r2, Rectangle{x: 0, y: 0, w: 10, h: 20});
    }

    #[test]
    fn calc_intersection2() {
        let (r1, r2) = calc_intersection(0, 0, 0, 0, 15, 10, 25, 20);

        assert_eq!(r1, Rectangle{x: 0, y: 0, w: 10, h: 20});
        assert_eq!(r2, Rectangle{x: 0, y: 0, w: 10, h: 20});
    }

}
<commit_msg>add more test cases, check for overflow<commit_after>// External modules:
use darwin_rs::{Individual, SimulationBuilder, Population, PopulationBuilder};
use image;
use image::{GenericImage, FilterType, DynamicImage};
use rand::Rng;
use rand;

// Std modules:
use std::cmp;

// Internal modules:
use config::PanolutionConfig;

#[derive(Clone)]
pub struct ImageArrangement {
    file_name: String, // TODO: Share path between individuals
    // TODO: Add image and share it, so it doesn't have to be re-loaded every time
    x: u32,
    y: u32,
    angle: f64,
    // TODO: add more image operations
}

#[derive(Clone)]
pub struct Solution {
    arrangement: Vec<ImageArrangement>,
}

#[derive(PartialEq, Eq, Debug)]
struct Rectangle {
    x: u32,
    y: u32,
    w: u32,
    h: u32,
}

fn calc_intersection(x1: u32, x2: u32, y1: u32, y2: u32, w1: u32, w2: u32, h1: u32, h2: u32) -> (Rectangle, Rectangle) {
    // rect1 and rect2 refer to positions inside the images. Not the absolute positions.
    let mut rect1 = Rectangle{x: 0, y: 0, w: 0, h: 0};
    let mut rect2 = Rectangle{x: 0, y: 0, w: 0, h: 0};

    if x1 == x2 {
        rect1.x = 0;
        rect2.x = 0;

        if w1 < w2 {
            rect1.w = w1;
            rect2.w = w1;
        } else {
            rect1.w = w2;
            rect2.w = w2;
        }
    }

    if y1 == y2 {
        rect1.y = 0;
        rect2.y = 0;

        if h1 < h2 {
            rect1.h = h1;
            rect2.h = h1;
        } else {
            rect1.h = h2;
            rect2.h = h2;
        }
    }

    let dx = (x2 as i32 - x1 as i32).abs() as u32;
    let dy = (y2 as i32 - y1 as i32).abs() as u32;

    if x1 < x2 && dx < w1 {
        rect1.x = dx;
        rect1.w = cmp::min(w1 - dx, w2);
        rect2.x = 0;
        rect2.w = rect1.w;
    }

    if x2 < x1 && dx < w2 {
        rect2.x = dx;
        rect2.w = cmp::min(w2 - dx, w1);
        rect1.x = 0;
        rect1.w = rect2.w;
    }

    if y1 < y2 && dy < h1 {
        rect1.y = dy;
        rect1.h = cmp::min(h1 - dy, h2);
        rect2.y = 0;
        rect2.h = rect1.h;
    }

    if y2 < y1 && dy < h2 {
        rect2.y = dy;
        rect2.h = cmp::min(h2 - dy, h1);
        rect1.y = 0;
        rect1.h = rect2.h;
    }

    (rect1, rect2)
}

fn make_all_populations(num_of_individuals: u32, num_of_populations: u32, initial_solution: &Solution) -> Vec<Population<Solution>> {
    let mut result = Vec::new();

    let mut initial_population = Vec::new();

    for _ in 0..num_of_individuals {
        initial_population.push(initial_solution.clone());
    }

    for i in 0..num_of_populations {
        let pop = PopulationBuilder::<Solution>::new()
            .set_id(i + 1)
            .initial_population(&initial_population)
            .reset_limit_end(0)
            .increasing_mutation_rate()
            .finalize().unwrap();

        result.push(pop);
    }

    result
}

impl Individual for Solution {
    fn mutate(&mut self) {
        let mut rng = rand::thread_rng();
        let num_of_operations: u8 = 4;

        let index1: usize = rng.gen_range(0, self.arrangement.len());

        // Probably use this create and enums:
        // https://github.com/andersk/enum_primitive-rs

        let operation: u8 = rng.gen_range(0, num_of_operations);

        match operation {
            0 => {
                // Change image order
                let mut index2: usize = rng.gen_range(0, self.arrangement.len());
                while index1 == index2 {
                    index2 = rng.gen_range(0, self.arrangement.len());
                }

                self.arrangement.swap(index1, index2);
            },
            1 => {
                // Move x
                if self.arrangement[index1].x > 0 {
                    self.arrangement[index1].x = self.arrangement[index1].x + (rng.gen_range(0, 3) - 1);
                } else {
                    self.arrangement[index1].x = self.arrangement[index1].x + rng.gen_range(0, 2);
                }
            },
            2 => {
                // Move y
                if self.arrangement[index1].y > 0 {
                    self.arrangement[index1].y = self.arrangement[index1].y + (rng.gen_range(0, 3) - 1);
                } else {
                    self.arrangement[index1].y = self.arrangement[index1].y + rng.gen_range(0, 2);
                }
            },
            3 => {
                // Rotate
                let angle: f64 = ((rng.gen_range(0, 21) - 10) as f64) * 0.1;
                self.arrangement[index1].angle = self.arrangement[index1].angle + angle;
            },
            op => {
                warn!("mutate(): unknown operation: {}", op)
            }
        }
    }

    fn calculate_fitness(&mut self) -> f64 {
        let mut fitness = 0.0;

        for i in 0..self.arrangement.len() {
            let arrangement1 = &self.arrangement[i];
            let arrangement2 = &self.arrangement[i + 1];

            let image1 = image::open(&arrangement1.file_name).unwrap();
            let image2 = image::open(&arrangement2.file_name).unwrap();

            let w1 = image1.width();
            let w2 = image2.width();
            let h1 = image1.height();
            let h2 = image2.height();

            let (rect1, rect2) = calc_intersection(
                arrangement1.x, arrangement2.x, arrangement1.y, arrangement2.y,
                w1, w2, h1, h2
            );

            if rect1.w == 0 || rect1.h == 0 {
                // Images don't intersect, add penalty
                fitness = fitness + cmp::max(w1 * h1, w2 * h2) as f64;
            } else {
                let intersection_area = rect1.w * rect1.h;
            }
        }

        fitness
    }

    fn reset(&mut self) {
        for arrangement in &mut self.arrangement {
            // Reset all image operation to original image
            arrangement.x = 0;
            arrangement.y = 0;
            arrangement.angle = 0.0;
        }
    }
}

fn run_darwin(solution: Solution, max_iteration: u32) -> Solution {
    info!("Run darwin with maximum number of iterations: {}", max_iteration);

    let pano = SimulationBuilder::<Solution>::new()
        .iterations(max_iteration)
        .threads(4) // TODO: Make this configurable
        .add_multiple_populations(make_all_populations(100, 8, &solution))
        .finalize();

    match pano {
        Err(e) => {
            error!("An error occured");

            for e in e.iter().skip(1) {
                error!("Caused by '{}'", e)
            }

            solution
        },
        Ok(mut pano_simulation) => {
            pano_simulation.run();

            info!("Total run time: {} ms", pano_simulation.total_time_in_ms);
            info!("Improvement factor: {}", pano_simulation.simulation_result.improvement_factor);
            info!("Number of iterations: {}", pano_simulation.simulation_result.iteration_counter);

            pano_simulation.simulation_result.fittest[0].individual.clone()
        }
    }
}

pub fn optimize(solution: Option<&Solution>, config: &PanolutionConfig, thumbnail_path: &Vec<String>) -> Solution {
    let mut result = Solution{ arrangement: Vec::new() };

    // Prepare data
    if let Some(solution) = solution {
        result.arrangement = solution.arrangement.iter().zip(thumbnail_path).map(|(arrangement, path)| ImageArrangement {
                file_name: path.clone(),
                x: arrangement.x,
                y: arrangement.y,
                angle: arrangement.angle,
            }
        ).collect();
    } else {
        result.arrangement = thumbnail_path.iter().map(|path| ImageArrangement {
                file_name: path.clone(),
                x: 0,
                y: 0,
                angle: 0.0
            }
        ).collect();
    }

    run_darwin(result, config.max_iteration)
}

#[cfg(test)]
mod test {
    use super::{calc_intersection, Rectangle};

    #[test]
    fn calc_intersection1() {
        let (r1, r2) = calc_intersection(0, 0, 0, 0, 10, 15, 20, 25);

        assert_eq!(r1, Rectangle{x: 0, y: 0, w: 10, h: 20});
        assert_eq!(r2, Rectangle{x: 0, y: 0, w: 10, h: 20});
    }

    #[test]
    fn calc_intersection2() {
        let (r1, r2) = calc_intersection(0, 0, 0, 0, 15, 10, 25, 20);

        assert_eq!(r1, Rectangle{x: 0, y: 0, w: 10, h: 20});
        assert_eq!(r2, Rectangle{x: 0, y: 0, w: 10, h: 20});
    }

    #[test]
    fn calc_intersection3() {
        let (r1, r2) = calc_intersection(50, 0, 0, 0, 10, 15, 20, 25);

        assert_eq!(r1, Rectangle{x: 0, y: 0, w: 0, h: 20});
        assert_eq!(r2, Rectangle{x: 0, y: 0, w: 0, h: 20});
    }

    #[test]
    fn calc_intersection4() {
        let (r1, r2) = calc_intersection(0, 50, 0, 0, 10, 15, 20, 25);

        assert_eq!(r1, Rectangle{x: 0, y: 0, w: 0, h: 20});
        assert_eq!(r2, Rectangle{x: 0, y: 0, w: 0, h: 20});
    }

    #[test]
    fn calc_intersection5() {
        let (r1, r2) = calc_intersection(0, 0, 50, 0, 10, 15, 20, 25);

        assert_eq!(r1, Rectangle{x: 0, y: 0, w: 10, h: 0});
        assert_eq!(r2, Rectangle{x: 0, y: 0, w: 10, h: 0});
    }

    #[test]
    fn calc_intersection6() {
        let (r1, r2) = calc_intersection(0, 0, 0, 50, 10, 15, 20, 25);

        assert_eq!(r1, Rectangle{x: 0, y: 0, w: 10, h: 0});
        assert_eq!(r2, Rectangle{x: 0, y: 0, w: 10, h: 0});
    }

    #[test]
    fn calc_intersection7() {
        let (r1, r2) = calc_intersection(50, 0, 50, 0, 10, 15, 20, 25);

        assert_eq!(r1, Rectangle{x: 0, y: 0, w: 0, h: 0});
        assert_eq!(r2, Rectangle{x: 0, y: 0, w: 0, h: 0});
    }

    #[test]
    fn calc_intersection8() {
        let (r1, r2) = calc_intersection(0, 50, 0, 50, 10, 15, 20, 25);

        assert_eq!(r1, Rectangle{x: 0, y: 0, w: 0, h: 0});
        assert_eq!(r2, Rectangle{x: 0, y: 0, w: 0, h: 0});
    }

    #[test]
    fn calc_intersection9() {
        let (r1, r2) = calc_intersection(3, 0, 0, 0, 10, 15, 20, 25);

        assert_eq!(r1, Rectangle{x: 0, y: 0, w: 10, h: 20});
        assert_eq!(r2, Rectangle{x: 3, y: 0, w: 10, h: 20});
    }

    #[test]
    fn calc_intersection10() {
        let (r1, r2) = calc_intersection(7, 0, 0, 0, 10, 15, 20, 25);

        assert_eq!(r1, Rectangle{x: 0, y: 0, w: 8, h: 20});
        assert_eq!(r2, Rectangle{x: 7, y: 0, w: 8, h: 20});
    }

    #[test]
    fn calc_intersection11() {
        let (r1, r2) = calc_intersection(0, 8, 0, 0, 10, 15, 20, 25);

        assert_eq!(r1, Rectangle{x: 8, y: 0, w: 2, h: 20});
        assert_eq!(r2, Rectangle{x: 0, y: 0, w: 2, h: 20});
    }

    #[test]
    fn calc_intersection12() {
        let (r1, r2) = calc_intersection(0, 0, 4, 0, 10, 15, 20, 25);

        assert_eq!(r1, Rectangle{x: 0, y: 0, w: 10, h: 20});
        assert_eq!(r2, Rectangle{x: 0, y: 4, w: 10, h: 20});
    }

    #[test]
    fn calc_intersection13() {
        let (r1, r2) = calc_intersection(0, 0, 9, 0, 10, 15, 20, 25);

        assert_eq!(r1, Rectangle{x: 0, y: 0, w: 10, h: 16});
        assert_eq!(r2, Rectangle{x: 0, y: 9, w: 10, h: 16});
    }

    #[test]
    fn calc_intersection14() {
        let (r1, r2) = calc_intersection(0, 0, 0, 12, 10, 15, 20, 25);

        assert_eq!(r1, Rectangle{x: 0, y: 12, w: 10, h: 8});
        assert_eq!(r2, Rectangle{x: 0, y: 0, w: 10, h: 8});
    }

    #[test]
    fn calc_intersection15() {
        let (r1, r2) = calc_intersection(0, 8, 0, 9, 10, 10, 10, 10);

        assert_eq!(r1, Rectangle{x: 8, y: 9, w: 2, h: 1});
        assert_eq!(r2, Rectangle{x: 0, y: 0, w: 2, h: 1});
    }

}
<|endoftext|>


<commit_before>use polynomial::Polynomial;
use nalgebra::Vector2;
use std::cmp::max;
use roots::find_roots_quartic;

use std::io::Write;
macro_rules! printlnerr(
    ($($arg:tt)*) => { {
        let r = writeln!(&mut ::std::io::stderr(), $($arg)*);
        r.expect("failed printing to stderr");
    } }
);

fn multiply_and_shift_avoiding_overflow_by_rounding (stuff: & [Coordinate], shift: i32)->Coordinate {
let mut product = 1;
let mut shift = shift;
for thing in stuff {
let mut factor = thing.clone();
while product >= (1 as Coordinate) << 32 && shift >0 {product >>= 1; shift -= 1;}
while factor >= (1 as Coordinate) << 32 && shift >0 {factor >>= 1; shift -= 1;}
product = product*factor;
}
product >> shift
}

// TODO: polymorphic in number of dimensions, and numeric type
// TODO: optimize away the unnecessary heap-allocation and other inefficiencies of Polynomial, and other pointless inefficiencies I introduced
// TODO replace f64 with a deterministic type (probably mpfr)
// note: the third time is not acceleration, but the coefficient of X squared, which is 2 times acceleration
pub type Coordinate = i64;
#[derive (Clone,)]
pub struct QuadraticTrajectory {
  data: Vector2<Polynomial<Coordinate>>,
  time_scale_shift: i32,
}
fn updated_by(poly: &Polynomial<Coordinate>,
              time: Coordinate,
              time_scale_shift: i32)
              -> Polynomial<Coordinate> {
  &*poly +
  Polynomial::new(vec![multiply_and_shift_avoiding_overflow_by_rounding (& [poly.data().get(1).cloned().unwrap_or(0), time], time_scale_shift) +
                       multiply_and_shift_avoiding_overflow_by_rounding (& [poly.data().get(2).cloned().unwrap_or(0), time, time], time_scale_shift * 2),
                       multiply_and_shift_avoiding_overflow_by_rounding (& [poly.data().get(2).cloned().unwrap_or(0), time * 2], time_scale_shift),
                       0i64])
}
impl QuadraticTrajectory {
  pub fn new(time_scale_shift: i32, coordinates: [Coordinate; 6]) -> QuadraticTrajectory {
    QuadraticTrajectory {
      time_scale_shift: time_scale_shift,
      data: Vector2::new(Polynomial::new(vec![coordinates[0], coordinates[2], coordinates[4]]),
                         Polynomial::new(vec![coordinates[1], coordinates[3], coordinates[5]])),
    }
  }

  pub fn updated_by(&self, time: Coordinate) -> QuadraticTrajectory {
    QuadraticTrajectory {
      data: Vector2::new(updated_by(&self.data[0], time, self.time_scale_shift),
                         updated_by(&self.data[1], time, self.time_scale_shift)),
      ..self.clone()
    }
  }

  pub fn update_by(&mut self, time: Coordinate) {
    *self = self.updated_by(time);
  }

  pub fn add_acceleration(&mut self, acceleration: Vector2<Coordinate>) {
    let changed = &self.data[0] + Polynomial::new(vec![0, 0, acceleration[0]*2]);
    self.data[0].clone_from(&changed);
    let changed = &self.data[1] + Polynomial::new(vec![0, 0, acceleration[1]*2]);
    self.data[1].clone_from(&changed);
  }
  pub fn evaluate(&self) -> Vector2<Coordinate> {
    Vector2::new(self.data[0].data().get(0).cloned().unwrap_or(0),
                 self.data[1].data().get(0).cloned().unwrap_or(0))

  }

  // direction == -1->"when the distance between the trajectories drops below the distance argument"
  // direction == 1->"when the distance between the trajectories exceeds the distance argument"
  pub fn approximately_when_distance_passes(distance: Coordinate,
                                            direction: Coordinate,
                                            first: (Coordinate, &QuadraticTrajectory),
                                            second: (Coordinate, &QuadraticTrajectory))
                                            -> Option<Coordinate> {
    assert!(first.1.time_scale_shift == second.1.time_scale_shift,
            "we don't actually support interactions between trajectories with different scales");
    let error = distance * 6 + 3;
    let ratio = (1i64 << first.1.time_scale_shift) as f64;

    let base = max(first.0, second.0);
    let third = first.1.updated_by(base - first.0);
    let more = second.1.updated_by(base - second.0);
    let displacement_function: Vector2<Polynomial<Coordinate>> = third.data.clone() - more.data.clone();
    let distance_function = &displacement_function[0] * &displacement_function[0] +
                            &displacement_function[1] * &displacement_function[1];
                            //printlnerr!(" distance function {:?} {:?} {:?} {:?} {:?} {:?} {:?} {:?}", first.1.data, second.1.data, error, ratio, third.data, more.data, displacement_function, distance_function);
    let roots = find_roots_quartic(distance_function.data().get(4).cloned().unwrap_or(0) as f64 /
                                   ratio.powi(4),
                                   distance_function.data().get(3).cloned().unwrap_or(0) as f64 /
                                   ratio.powi(3),
                                   distance_function.data().get(2).cloned().unwrap_or(0) as f64 /
                                   ratio.powi(2),
                                   distance_function.data().get(1).cloned().unwrap_or(0) as f64 /
                                   ratio.powi(1),
                                   (distance_function.data().get(0).cloned().unwrap_or(0) -
                                    (distance * distance +
                                     error * direction)) as f64);

    for root in roots.as_ref() {
    //printlnerr!(" found group {}", root);
      let result = root.ceil() as Coordinate;
      if result > 0 {
        let checker = Vector2::new(updated_by(&displacement_function[0],
                                              result,
                                              first.1.time_scale_shift),
                                   updated_by(&displacement_function[1],
                                              result,
                                              first.1.time_scale_shift));

        let real_distance_squared = checker[0].data().get(0).cloned().unwrap_or(0) *
                                    checker[0].data().get(0).cloned().unwrap_or(0) +
                                    checker[1].data().get(0).cloned().unwrap_or(0) *
                                    checker[1].data().get(0).cloned().unwrap_or(0);

        if (real_distance_squared - distance * distance) * direction > 0 {
        //printlnerr!(" check past");
          return Some(base + result);
        }
      }
    }
    None
  }
}
<commit_msg>Fix overflow and directionality<commit_after>use polynomial::Polynomial;
use nalgebra::Vector2;
use std::cmp::max;
use roots::find_roots_quartic;

use std::io::Write;
macro_rules! printlnerr(
    ($($arg:tt)*) => { {
        let r = writeln!(&mut ::std::io::stderr(), $($arg)*);
        r.expect("failed printing to stderr");
    } }
);

fn multiply_and_shift_avoiding_overflow_by_rounding (stuff: & [Coordinate], shift: i32)->Coordinate {
let mut sign: Coordinate = 1;
let mut product = 1u64;
let mut shift = shift;
for thing in stuff {
let mut factor = thing.clone();
if factor <0 {factor*= -1; sign *= -1;}
let mut factor = factor as u64;
while product >= (1u64) << 32 && shift >0 {product >>= 1; shift -= 1;}
while factor >= (1u64) << 32 && shift >0 {factor >>= 1; shift -= 1;}
//printlnerr!(" {}, {}, {}", product, factor, shift);
product = product*factor;
}
((product as Coordinate)*sign) >> shift
}

// TODO: polymorphic in number of dimensions, and numeric type
// TODO: optimize away the unnecessary heap-allocation and other inefficiencies of Polynomial, and other pointless inefficiencies I introduced
// TODO replace f64 with a deterministic type (probably mpfr)
// note: the third time is not acceleration, but the coefficient of X squared, which is 2 times acceleration
pub type Coordinate = i64;
#[derive (Clone,)]
pub struct QuadraticTrajectory {
  data: Vector2<Polynomial<Coordinate>>,
  time_scale_shift: i32,
}
fn updated_by(poly: &Polynomial<Coordinate>,
              time: Coordinate,
              time_scale_shift: i32)
              -> Polynomial<Coordinate> {
  &*poly +
  Polynomial::new(vec![multiply_and_shift_avoiding_overflow_by_rounding (& [poly.data().get(1).cloned().unwrap_or(0), time], time_scale_shift) +
                       multiply_and_shift_avoiding_overflow_by_rounding (& [poly.data().get(2).cloned().unwrap_or(0), time, time], time_scale_shift * 2),
                       multiply_and_shift_avoiding_overflow_by_rounding (& [poly.data().get(2).cloned().unwrap_or(0), time * 2], time_scale_shift),
                       0i64])
}
impl QuadraticTrajectory {
  pub fn new(time_scale_shift: i32, coordinates: [Coordinate; 6]) -> QuadraticTrajectory {
    QuadraticTrajectory {
      time_scale_shift: time_scale_shift,
      data: Vector2::new(Polynomial::new(vec![coordinates[0], coordinates[2], coordinates[4]]),
                         Polynomial::new(vec![coordinates[1], coordinates[3], coordinates[5]])),
    }
  }

  pub fn updated_by(&self, time: Coordinate) -> QuadraticTrajectory {
    QuadraticTrajectory {
      data: Vector2::new(updated_by(&self.data[0], time, self.time_scale_shift),
                         updated_by(&self.data[1], time, self.time_scale_shift)),
      ..self.clone()
    }
  }

  pub fn update_by(&mut self, time: Coordinate) {
    *self = self.updated_by(time);
  }

  pub fn add_acceleration(&mut self, acceleration: Vector2<Coordinate>) {
    let changed = &self.data[0] + Polynomial::new(vec![0, 0, acceleration[0]*2]);
    self.data[0].clone_from(&changed);
    let changed = &self.data[1] + Polynomial::new(vec![0, 0, acceleration[1]*2]);
    self.data[1].clone_from(&changed);
  }
  pub fn evaluate(&self) -> Vector2<Coordinate> {
    Vector2::new(self.data[0].data().get(0).cloned().unwrap_or(0),
                 self.data[1].data().get(0).cloned().unwrap_or(0))

  }

  // direction == -1->"when the distance between the trajectories drops below the distance argument"
  // direction == 1->"when the distance between the trajectories exceeds the distance argument"
  pub fn approximately_when_distance_passes(distance: Coordinate,
                                            direction: Coordinate,
                                            first: (Coordinate, &QuadraticTrajectory),
                                            second: (Coordinate, &QuadraticTrajectory))
                                            -> Option<Coordinate> {
    assert!(first.1.time_scale_shift == second.1.time_scale_shift,
            "we don't actually support interactions between trajectories with different scales");
    let error = distance * 6 + 3;
    let ratio = (1i64 << first.1.time_scale_shift) as f64;

    let base = max(first.0, second.0);
    let third = first.1.updated_by(base - first.0);
    let more = second.1.updated_by(base - second.0);
    let displacement_function: Vector2<Polynomial<Coordinate>> = third.data.clone() - more.data.clone();
    let distance_function = &displacement_function[0] * &displacement_function[0] +
                            &displacement_function[1] * &displacement_function[1];
                            //printlnerr!(" distance function {:?} {:?} {:?} {:?} {:?} {:?} {:?} {:?}", first.1.data, second.1.data, error, ratio, third.data, more.data, displacement_function, distance_function);
    let roots = find_roots_quartic(distance_function.data().get(4).cloned().unwrap_or(0) as f64 /
                                   ratio.powi(4),
                                   distance_function.data().get(3).cloned().unwrap_or(0) as f64 /
                                   ratio.powi(3),
                                   distance_function.data().get(2).cloned().unwrap_or(0) as f64 /
                                   ratio.powi(2),
                                   distance_function.data().get(1).cloned().unwrap_or(0) as f64 /
                                   ratio.powi(1),
                                   (distance_function.data().get(0).cloned().unwrap_or(0) -
                                    (distance * distance +
                                     error * direction)) as f64);

    for root in roots.as_ref() {
    //printlnerr!(" found group {}", root);
      let result = root.ceil() as Coordinate;
      if result > 0 {
        let checker = Vector2::new(updated_by(&displacement_function[0],
                                              result,
                                              first.1.time_scale_shift),
                                   updated_by(&displacement_function[1],
                                              result,
                                              first.1.time_scale_shift));

        let real_distance_squared = checker[0].data().get(0).cloned().unwrap_or(0) *
                                    checker[0].data().get(0).cloned().unwrap_or(0) +
                                    checker[1].data().get(0).cloned().unwrap_or(0) *
                                    checker[1].data().get(0).cloned().unwrap_or(0);

        if (real_distance_squared - distance * distance) * direction > 0 {
        //printlnerr!(" check past");
          return Some(base + result);
        }
      }
    }
    None
  }
}
<|endoftext|>


<commit_before>use crate::vec::Vec2;
use crate::view::{SizeConstraint, View, ViewWrapper};
use crate::With;
use crate::XY;

/// Wrapper around another view, with a controlled size.
///
/// Each axis can independently be set to:
///
/// * Keep a **fixed** size
/// * Use **all** available size
/// * Use **at most** a given size
/// * Use **at least** a given size
/// * Let the wrapped view decide.
///
/// # Examples
///
/// ```
/// # use cursive::views::{BoxView,TextView};
/// // Creates a 20x4 BoxView with a TextView content.
/// let view = BoxView::with_fixed_size((20,4), TextView::new("Hello!"));
/// ```
pub struct BoxView<T: View> {
    /// Constraint on each axis
    size: XY<SizeConstraint>,

    /// `true` if the view can be squished.
    ///
    /// This means if the required size is less than the computed size,
    /// consider returning a smaller size.
    /// For instance, try to return the child's desired size.
    squishable: bool, // TODO: remove?

    /// Set to `true` whenever we change some settings. Means we should re-layout just in case.
    invalidated: bool,

    /// The actual view we're wrapping.
    view: T,
}

impl<T: View> BoxView<T> {
    /// Creates a new `BoxView` with the given width and height requirements.
    ///
    /// `None` values will use the wrapped view's preferences.
    pub fn new(
        width: SizeConstraint,
        height: SizeConstraint,
        view: T,
    ) -> Self {
        BoxView {
            size: (width, height).into(),
            squishable: false,
            invalidated: true,
            view,
        }
    }

    /// Sets the size constraints for this view.
    pub fn set_constraints(
        &mut self,
        width: SizeConstraint,
        height: SizeConstraint,
    ) {
        self.set_width(width);
        self.set_height(height);
    }

    /// Sets the width constraint for this view.
    ///
    /// Leaves the height unchanged.
    pub fn set_width(&mut self, width: SizeConstraint) {
        self.size.x = width;
        self.invalidate();
    }

    /// Sets the height constraint for this view.
    ///
    /// Leaves the width unchanged.
    pub fn set_height(&mut self, height: SizeConstraint) {
        self.size.y = height;
        self.invalidate();
    }

    /// Sets `self` to be squishable.
    ///
    /// A squishable `BoxView` will take a smaller size than it should when
    /// the available space is too small. In that case, it will allow the
    /// child view to contract, if it can.
    ///
    /// More specifically, if the available space is less than the size we
    /// would normally ask for, return the child size.
    pub fn squishable(self) -> Self {
        self.with(|s| s.set_squishable(true))
    }

    /// Controls the "squishability" of `self`.
    pub fn set_squishable(&mut self, squishable: bool) {
        self.squishable = squishable;
        self.invalidate();
    }

    /// Wraps `view` in a new `BoxView` with the given size.
    pub fn with_fixed_size<S: Into<Vec2>>(size: S, view: T) -> Self {
        let size = size.into();

        BoxView::new(
            SizeConstraint::Fixed(size.x),
            SizeConstraint::Fixed(size.y),
            view,
        )
    }

    /// Wraps `view` in a new `BoxView` with fixed width.
    pub fn with_fixed_width(width: usize, view: T) -> Self {
        BoxView::new(SizeConstraint::Fixed(width), SizeConstraint::Free, view)
    }

    /// Wraps `view` in a new `BoxView` with fixed height.
    pub fn with_fixed_height(height: usize, view: T) -> Self {
        BoxView::new(SizeConstraint::Free, SizeConstraint::Fixed(height), view)
    }

    /// Wraps `view` in a `BoxView` which will take all available space.
    pub fn with_full_screen(view: T) -> Self {
        BoxView::new(SizeConstraint::Full, SizeConstraint::Full, view)
    }

    /// Wraps `view` in a `BoxView` which will take all available width.
    pub fn with_full_width(view: T) -> Self {
        BoxView::new(SizeConstraint::Full, SizeConstraint::Free, view)
    }

    /// Wraps `view` in a `BoxView` which will take all available height.
    pub fn with_full_height(view: T) -> Self {
        BoxView::new(SizeConstraint::Free, SizeConstraint::Full, view)
    }

    /// Wraps `view` in a `BoxView` which will never be bigger than `size`.
    pub fn with_max_size<S: Into<Vec2>>(size: S, view: T) -> Self {
        let size = size.into();

        BoxView::new(
            SizeConstraint::AtMost(size.x),
            SizeConstraint::AtMost(size.y),
            view,
        )
    }

    /// Wraps `view` in a `BoxView` which will enforce a maximum width.
    ///
    /// The resulting width will never be more than `max_width`.
    pub fn with_max_width(max_width: usize, view: T) -> Self {
        BoxView::new(
            SizeConstraint::AtMost(max_width),
            SizeConstraint::Free,
            view,
        )
    }

    /// Wraps `view` in a `BoxView` which will enforce a maximum height.
    ///
    /// The resulting height will never be more than `max_height`.
    pub fn with_max_height(max_height: usize, view: T) -> Self {
        BoxView::new(
            SizeConstraint::Free,
            SizeConstraint::AtMost(max_height),
            view,
        )
    }

    /// Wraps `view` in a `BoxView` which will never be smaller than `size`.
    pub fn with_min_size<S: Into<Vec2>>(size: S, view: T) -> Self {
        let size = size.into();

        BoxView::new(
            SizeConstraint::AtLeast(size.x),
            SizeConstraint::AtLeast(size.y),
            view,
        )
    }

    /// Wraps `view` in a `BoxView` which will enforce a minimum width.
    ///
    /// The resulting width will never be less than `min_width`.
    pub fn with_min_width(min_width: usize, view: T) -> Self {
        BoxView::new(
            SizeConstraint::AtLeast(min_width),
            SizeConstraint::Free,
            view,
        )
    }

    /// Wraps `view` in a `BoxView` which will enforce a minimum height.
    ///
    /// The resulting height will never be less than `min_height`.
    pub fn with_min_height(min_height: usize, view: T) -> Self {
        BoxView::new(
            SizeConstraint::Free,
            SizeConstraint::AtLeast(min_height),
            view,
        )
    }

    /// Should be called anytime something changes.
    fn invalidate(&mut self) {
        self.invalidated = true;
    }

    inner_getters!(self.view: T);
}

impl<T: View> ViewWrapper for BoxView<T> {
    wrap_impl!(self.view: T);

    fn wrap_required_size(&mut self, req: Vec2) -> Vec2 {
        // This is what the child will see as request.
        let req = self.size.zip_map(req, SizeConstraint::available);

        // This is the size the child would like to have.
        let child_size = self.view.required_size(req);

        // Some of this request will be granted, but maybe not all.
        let result = self
            .size
            .zip_map(child_size.zip(req), SizeConstraint::result);

        if self.squishable {
            // When we're squishable, special behaviour:
            //

            // We respect the request if we're less or equal.
            let respect_req = result.zip_map(req, |res, req| res <= req);

            // If we respect the request, keep the result
            // Otherwise, take the child as squish attempt.
            respect_req.select_or(result, child_size)
        } else {
            result
        }
    }

    fn wrap_layout(&mut self, size: Vec2) {
        self.invalidated = false;
        self.view.layout(size);
    }

    fn wrap_needs_relayout(&self) -> bool {
        self.invalidated || self.view.needs_relayout()
    }
}

#[cfg(test)]
mod tests {

    use crate::vec::Vec2;
    use crate::view::{Boxable, View};
    use crate::views::DummyView;

    // No need to test `draw()` method as it's directly forwarded.

    #[test]
    fn min_size() {
        let mut min_w = DummyView.full_screen().min_width(5);

        assert_eq!(Vec2::new(5, 1), min_w.required_size(Vec2::new(1, 1)));
        assert_eq!(Vec2::new(5, 10), min_w.required_size(Vec2::new(1, 10)));
        assert_eq!(Vec2::new(10, 1), min_w.required_size(Vec2::new(10, 1)));
        assert_eq!(Vec2::new(10, 10), min_w.required_size(Vec2::new(10, 10)));

        let mut min_h = DummyView.full_screen().min_height(5);

        assert_eq!(Vec2::new(1, 5), min_h.required_size(Vec2::new(1, 1)));
        assert_eq!(Vec2::new(1, 10), min_h.required_size(Vec2::new(1, 10)));
        assert_eq!(Vec2::new(10, 5), min_h.required_size(Vec2::new(10, 1)));
        assert_eq!(Vec2::new(10, 10), min_h.required_size(Vec2::new(10, 10)));

        let mut min_s = DummyView.full_screen().min_size((5, 5));

        assert_eq!(Vec2::new(5, 5), min_s.required_size(Vec2::new(1, 1)));
        assert_eq!(Vec2::new(5, 10), min_s.required_size(Vec2::new(1, 10)));
        assert_eq!(Vec2::new(10, 5), min_s.required_size(Vec2::new(10, 1)));
        assert_eq!(Vec2::new(10, 10), min_s.required_size(Vec2::new(10, 10)));
    }

    #[test]
    fn max_size() {
        let mut max_w = DummyView.full_screen().max_width(5);

        assert_eq!(Vec2::new(1, 1), max_w.required_size(Vec2::new(1, 1)));
        assert_eq!(Vec2::new(1, 10), max_w.required_size(Vec2::new(1, 10)));
        assert_eq!(Vec2::new(5, 1), max_w.required_size(Vec2::new(10, 1)));
        assert_eq!(Vec2::new(5, 10), max_w.required_size(Vec2::new(10, 10)));

        let mut max_h = DummyView.full_screen().max_height(5);

        assert_eq!(Vec2::new(1, 1), max_h.required_size(Vec2::new(1, 1)));
        assert_eq!(Vec2::new(1, 5), max_h.required_size(Vec2::new(1, 10)));
        assert_eq!(Vec2::new(10, 1), max_h.required_size(Vec2::new(10, 1)));
        assert_eq!(Vec2::new(10, 5), max_h.required_size(Vec2::new(10, 10)));

        let mut max_s = DummyView.full_screen().max_size((5, 5));

        assert_eq!(Vec2::new(1, 1), max_s.required_size(Vec2::new(1, 1)));
        assert_eq!(Vec2::new(1, 5), max_s.required_size(Vec2::new(1, 10)));
        assert_eq!(Vec2::new(5, 1), max_s.required_size(Vec2::new(10, 1)));
        assert_eq!(Vec2::new(5, 5), max_s.required_size(Vec2::new(10, 10)));
    }

    #[test]
    fn full_screen() {
        let mut full = DummyView.full_screen();

        assert_eq!(Vec2::new(1, 1), full.required_size(Vec2::new(1, 1)));
        assert_eq!(Vec2::new(1, 10), full.required_size(Vec2::new(1, 10)));
        assert_eq!(Vec2::new(10, 1), full.required_size(Vec2::new(10, 1)));
        assert_eq!(Vec2::new(10, 10), full.required_size(Vec2::new(10, 10)));
    }

    #[test]
    fn test_get_inner() {
        use crate::views::TextView;

        let parent = TextView::new("abc").full_screen();
        let child = parent.get_inner();
        assert_eq!(child.get_content().source(), "abc");
    }
    #[test]
    fn test_get_inner_mut() {
        use crate::views::TextView;

        let mut parent = TextView::new("").full_screen();
        let new_value = "new";
        let child = parent.get_inner_mut();

        child.set_content(new_value);

        assert_eq!(child.get_content().source(), new_value);
    }
}
<commit_msg>BoxView Fixed, AtLeast, AtMost SizeConstraints (#368)<commit_after>use crate::printer::Printer;
use crate::vec::Vec2;
use crate::view::{SizeConstraint, View, ViewWrapper};
use crate::With;
use crate::XY;

/// Wrapper around another view, with a controlled size.
///
/// Each axis can independently be set to:
///
/// * Keep a **fixed** size
/// * Use **all** available size
/// * Use **at most** a given size
/// * Use **at least** a given size
/// * Let the wrapped view decide.
///
/// # Examples
///
/// ```
/// # use cursive::views::{BoxView,TextView};
/// // Creates a 20x4 BoxView with a TextView content.
/// let view = BoxView::with_fixed_size((20,4), TextView::new("Hello!"));
/// ```
pub struct BoxView<T: View> {
    /// Constraint on each axis
    size: XY<SizeConstraint>,

    /// `true` if the view can be squished.
    ///
    /// This means if the required size is less than the computed size,
    /// consider returning a smaller size.
    /// For instance, try to return the child's desired size.
    squishable: bool, // TODO: remove?

    /// Set to `true` whenever we change some settings. Means we should re-layout just in case.
    invalidated: bool,

    /// The actual view we're wrapping.
    view: T,
}

impl<T: View> BoxView<T> {
    /// Creates a new `BoxView` with the given width and height requirements.
    ///
    /// `None` values will use the wrapped view's preferences.
    pub fn new(
        width: SizeConstraint,
        height: SizeConstraint,
        view: T,
    ) -> Self {
        BoxView {
            size: (width, height).into(),
            squishable: false,
            invalidated: true,
            view,
        }
    }

    /// Sets the size constraints for this view.
    pub fn set_constraints(
        &mut self,
        width: SizeConstraint,
        height: SizeConstraint,
    ) {
        self.set_width(width);
        self.set_height(height);
    }

    /// Sets the width constraint for this view.
    ///
    /// Leaves the height unchanged.
    pub fn set_width(&mut self, width: SizeConstraint) {
        self.size.x = width;
        self.invalidate();
    }

    /// Sets the height constraint for this view.
    ///
    /// Leaves the width unchanged.
    pub fn set_height(&mut self, height: SizeConstraint) {
        self.size.y = height;
        self.invalidate();
    }

    /// Sets `self` to be squishable.
    ///
    /// A squishable `BoxView` will take a smaller size than it should when
    /// the available space is too small. In that case, it will allow the
    /// child view to contract, if it can.
    ///
    /// More specifically, if the available space is less than the size we
    /// would normally ask for, return the child size.
    pub fn squishable(self) -> Self {
        self.with(|s| s.set_squishable(true))
    }

    /// Controls the "squishability" of `self`.
    pub fn set_squishable(&mut self, squishable: bool) {
        self.squishable = squishable;
        self.invalidate();
    }

    /// Wraps `view` in a new `BoxView` with the given size.
    pub fn with_fixed_size<S: Into<Vec2>>(size: S, view: T) -> Self {
        let size = size.into();

        BoxView::new(
            SizeConstraint::Fixed(size.x),
            SizeConstraint::Fixed(size.y),
            view,
        )
    }

    /// Wraps `view` in a new `BoxView` with fixed width.
    pub fn with_fixed_width(width: usize, view: T) -> Self {
        BoxView::new(SizeConstraint::Fixed(width), SizeConstraint::Free, view)
    }

    /// Wraps `view` in a new `BoxView` with fixed height.
    pub fn with_fixed_height(height: usize, view: T) -> Self {
        BoxView::new(SizeConstraint::Free, SizeConstraint::Fixed(height), view)
    }

    /// Wraps `view` in a `BoxView` which will take all available space.
    pub fn with_full_screen(view: T) -> Self {
        BoxView::new(SizeConstraint::Full, SizeConstraint::Full, view)
    }

    /// Wraps `view` in a `BoxView` which will take all available width.
    pub fn with_full_width(view: T) -> Self {
        BoxView::new(SizeConstraint::Full, SizeConstraint::Free, view)
    }

    /// Wraps `view` in a `BoxView` which will take all available height.
    pub fn with_full_height(view: T) -> Self {
        BoxView::new(SizeConstraint::Free, SizeConstraint::Full, view)
    }

    /// Wraps `view` in a `BoxView` which will never be bigger than `size`.
    pub fn with_max_size<S: Into<Vec2>>(size: S, view: T) -> Self {
        let size = size.into();

        BoxView::new(
            SizeConstraint::AtMost(size.x),
            SizeConstraint::AtMost(size.y),
            view,
        )
    }

    /// Wraps `view` in a `BoxView` which will enforce a maximum width.
    ///
    /// The resulting width will never be more than `max_width`.
    pub fn with_max_width(max_width: usize, view: T) -> Self {
        BoxView::new(
            SizeConstraint::AtMost(max_width),
            SizeConstraint::Free,
            view,
        )
    }

    /// Wraps `view` in a `BoxView` which will enforce a maximum height.
    ///
    /// The resulting height will never be more than `max_height`.
    pub fn with_max_height(max_height: usize, view: T) -> Self {
        BoxView::new(
            SizeConstraint::Free,
            SizeConstraint::AtMost(max_height),
            view,
        )
    }

    /// Wraps `view` in a `BoxView` which will never be smaller than `size`.
    pub fn with_min_size<S: Into<Vec2>>(size: S, view: T) -> Self {
        let size = size.into();

        BoxView::new(
            SizeConstraint::AtLeast(size.x),
            SizeConstraint::AtLeast(size.y),
            view,
        )
    }

    /// Wraps `view` in a `BoxView` which will enforce a minimum width.
    ///
    /// The resulting width will never be less than `min_width`.
    pub fn with_min_width(min_width: usize, view: T) -> Self {
        BoxView::new(
            SizeConstraint::AtLeast(min_width),
            SizeConstraint::Free,
            view,
        )
    }

    /// Wraps `view` in a `BoxView` which will enforce a minimum height.
    ///
    /// The resulting height will never be less than `min_height`.
    pub fn with_min_height(min_height: usize, view: T) -> Self {
        BoxView::new(
            SizeConstraint::Free,
            SizeConstraint::AtLeast(min_height),
            view,
        )
    }

    /// Should be called anytime something changes.
    fn invalidate(&mut self) {
        self.invalidated = true;
    }

    inner_getters!(self.view: T);
}

impl<T: View> ViewWrapper for BoxView<T> {
    wrap_impl!(self.view: T);

    fn wrap_draw(&self, printer: &Printer) {
        self.view.draw(&printer.inner_size(
            self.size.zip_map(printer.size, |c, s| c.result((s, s))),
        ));
    }

    fn wrap_required_size(&mut self, req: Vec2) -> Vec2 {
        // This is what the child will see as request.
        let req = self.size.zip_map(req, SizeConstraint::available);

        // This is the size the child would like to have.
        // Given the constraints of our box.
        let child_size = self.size.zip_map(req, |c, s| c.result((s, s)));

        // Some of this request will be granted, but maybe not all.
        let result = self
            .size
            .zip_map(child_size.zip(req), SizeConstraint::result);

        if self.squishable {
            // When we're squishable, special behaviour:
            //

            // We respect the request if we're less or equal.
            let respect_req = result.zip_map(req, |res, req| res <= req);

            // If we respect the request, keep the result
            // Otherwise, take the child as squish attempt.
            respect_req.select_or(result, child_size)
        } else {
            result
        }
    }

    fn wrap_layout(&mut self, size: Vec2) {
        self.invalidated = false;
        self.view.layout(size);
    }

    fn wrap_needs_relayout(&self) -> bool {
        self.invalidated || self.view.needs_relayout()
    }
}

#[cfg(test)]
mod tests {

    use crate::vec::Vec2;
    use crate::view::{Boxable, View};
    use crate::views::DummyView;

    // No need to test `draw()` method as it's directly forwarded.

    #[test]
    fn min_size() {
        let mut min_w = DummyView.full_screen().min_width(5);

        assert_eq!(Vec2::new(5, 1), min_w.required_size(Vec2::new(1, 1)));
        assert_eq!(Vec2::new(5, 10), min_w.required_size(Vec2::new(1, 10)));
        assert_eq!(Vec2::new(10, 1), min_w.required_size(Vec2::new(10, 1)));
        assert_eq!(Vec2::new(10, 10), min_w.required_size(Vec2::new(10, 10)));

        let mut min_h = DummyView.full_screen().min_height(5);

        assert_eq!(Vec2::new(1, 5), min_h.required_size(Vec2::new(1, 1)));
        assert_eq!(Vec2::new(1, 10), min_h.required_size(Vec2::new(1, 10)));
        assert_eq!(Vec2::new(10, 5), min_h.required_size(Vec2::new(10, 1)));
        assert_eq!(Vec2::new(10, 10), min_h.required_size(Vec2::new(10, 10)));

        let mut min_s = DummyView.full_screen().min_size((5, 5));

        assert_eq!(Vec2::new(5, 5), min_s.required_size(Vec2::new(1, 1)));
        assert_eq!(Vec2::new(5, 10), min_s.required_size(Vec2::new(1, 10)));
        assert_eq!(Vec2::new(10, 5), min_s.required_size(Vec2::new(10, 1)));
        assert_eq!(Vec2::new(10, 10), min_s.required_size(Vec2::new(10, 10)));
    }

    #[test]
    fn max_size() {
        let mut max_w = DummyView.full_screen().max_width(5);

        assert_eq!(Vec2::new(1, 1), max_w.required_size(Vec2::new(1, 1)));
        assert_eq!(Vec2::new(1, 10), max_w.required_size(Vec2::new(1, 10)));
        assert_eq!(Vec2::new(5, 1), max_w.required_size(Vec2::new(10, 1)));
        assert_eq!(Vec2::new(5, 10), max_w.required_size(Vec2::new(10, 10)));

        let mut max_h = DummyView.full_screen().max_height(5);

        assert_eq!(Vec2::new(1, 1), max_h.required_size(Vec2::new(1, 1)));
        assert_eq!(Vec2::new(1, 5), max_h.required_size(Vec2::new(1, 10)));
        assert_eq!(Vec2::new(10, 1), max_h.required_size(Vec2::new(10, 1)));
        assert_eq!(Vec2::new(10, 5), max_h.required_size(Vec2::new(10, 10)));

        let mut max_s = DummyView.full_screen().max_size((5, 5));

        assert_eq!(Vec2::new(1, 1), max_s.required_size(Vec2::new(1, 1)));
        assert_eq!(Vec2::new(1, 5), max_s.required_size(Vec2::new(1, 10)));
        assert_eq!(Vec2::new(5, 1), max_s.required_size(Vec2::new(10, 1)));
        assert_eq!(Vec2::new(5, 5), max_s.required_size(Vec2::new(10, 10)));
    }

    #[test]
    fn full_screen() {
        let mut full = DummyView.full_screen();

        assert_eq!(Vec2::new(1, 1), full.required_size(Vec2::new(1, 1)));
        assert_eq!(Vec2::new(1, 10), full.required_size(Vec2::new(1, 10)));
        assert_eq!(Vec2::new(10, 1), full.required_size(Vec2::new(10, 1)));
        assert_eq!(Vec2::new(10, 10), full.required_size(Vec2::new(10, 10)));
    }

    #[test]
    fn test_get_inner() {
        use crate::views::TextView;

        let parent = TextView::new("abc").full_screen();
        let child = parent.get_inner();
        assert_eq!(child.get_content().source(), "abc");
    }
    #[test]
    fn test_get_inner_mut() {
        use crate::views::TextView;

        let mut parent = TextView::new("").full_screen();
        let new_value = "new";
        let child = parent.get_inner_mut();

        child.set_content(new_value);

        assert_eq!(child.get_content().source(), new_value);
    }
}
<|endoftext|>


<commit_before>// Copyright 2014 Michael Yang. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
use std::mem;
use std::ptr;
use libc::c_int;
use num::complex::{
    Complex,
};
use error::Error;
use ll::*;
use Matrix;
use Vector;
use scalar::Scalar;
use types::Compute;
use util::ColMem;

pub trait Geev<Eigenvalues>: Sized {
    fn geev(a: &mut Matrix<Self>, values: &mut Vector<Eigenvalues>,
        left: Option<&mut Matrix<Self>>, right: Option<&mut Matrix<Self>>) -> Result<(), Error> {

        let job_l = match &left {
            &Some(_) => Compute::Value,
            _ => Compute::None,
        };

        let job_r = match &right {
            &Some(_) => Compute::Value,
            _ => Compute::None,
        };

        let work_len = try!(Geev::work_len(a, job_l, job_r));
        let mut work: Vec<_> = Vec::with_capacity(work_len as usize);
        unsafe {
            work.set_len(work_len as usize);
        }

        Geev::work(a, values, left, right, &mut work[..])
    }
    fn work(a: &mut Matrix<Self>, values: &mut Vector<Eigenvalues>,
        left: Option<&mut Matrix<Self>>, right: Option<&mut Matrix<Self>>, work: &mut [Self]) -> Result<(), Error>;
    fn work_len(a: &mut Matrix<Self>, left: Compute, right: Compute) -> Result<usize, Error>;
}

macro_rules! real_eigen_impl(($($t: ident), +) => ($(
    impl Geev<Complex<$t>> for $t {
        fn work(a: &mut Matrix<Self>, values: &mut Vector<Complex<$t>>,
            left: Option<&mut Matrix<Self>>, right: Option<&mut Matrix<Self>>, work: &mut [Self]) -> Result<(), Error> {

            let mut info: c_int = 0;
            let n = a.rows();
            if n != a.cols() {
                return Err(Error::DimensionMismatch);
            }
            let mut a_mem = ColMem::new(a.order(), a);

            let (job_l, lead_l, ptr_l) = match left {
                Some(m) => (Compute::Value, m.rows(), m.as_mut_ptr()),
                None => (Compute::None, 1, ptr::null::<$t>() as *mut _),
            };

            let (job_r, lead_r, ptr_r) = match right {
                Some(m) => (Compute::Value, m.rows(), m.as_mut_ptr()),
                None => (Compute::None, 1, ptr::null::<$t>() as *mut _),
            };

            //TODO: this is really bad
            let (real, imag) = unsafe {
                let start = values.as_mut_ptr();
                let mid = start.offset(n as isize);
                (start as *mut $t, mid as *mut $t)
            };

            unsafe {
                prefix!($t, geev_)(
                    job_l.as_i8().as_mut(), job_r.as_i8().as_mut(),
                    n.as_mut(),
                    a_mem.as_mut_ptr(), a_mem.lead().as_mut(),
                    real, imag,
                    ptr_l, lead_l.as_mut(),
                    ptr_r, lead_r.as_mut(),
                    work.as_mut_ptr(), (work.len() as c_int).as_mut(),
                    &mut info as *mut c_int);
            };

            match info {
                0 => Ok(()),
                x if x < 0 => Err(Error::IllegalParameter(-x as usize)),
                x => Err(Error::DiagonalElementZero(x as usize)),
            }
        }

        fn work_len(a: &mut Matrix<Self>, left: Compute, right: Compute) -> Result<usize, Error> {
            let mut info: c_int = 0;
            let mut len_info: $t = unsafe { mem::zeroed() };
            let len_ptr = (&mut len_info) as *mut $t;

            let n = a.rows();
            if n != a.cols() {
                return Err(Error::DimensionMismatch);
            }
            let lda = n;

            unsafe {
                prefix!($t, geev_)(
                    left.as_i8().as_mut(), right.as_i8().as_mut(),
                    n.as_mut(),
                    a.as_mut_ptr(), lda.as_mut(),
                    ptr::null::<$t>() as *mut _, ptr::null::<$t>() as *mut _,
                    ptr::null::<$t>() as *mut _, n.as_mut(),
                    ptr::null::<$t>() as *mut _, n.as_mut(),
                    len_ptr, (-1 as c_int).as_mut(),
                    &mut info as *mut c_int);
            };

            match info {
                0 => Ok(len_info.as_work()),
                x if x < 0 => Err(Error::IllegalParameter(-x as usize)),
                x => Err(Error::DiagonalElementZero(x as usize)),
            }
        }
    }
)+));

real_eigen_impl!(f32, f64);

#[cfg(test)]
mod geev_tests {
    use eigenvalues::Geev;
    use matrix::tests::M;
    use types::Order::*;

    #[test]
    fn real() {
        let mut a = M(RowMajor, 2i32, 2i32, vec![2.0f64, 7.0, -1.0, -6.0]);
        let mut v = Vec::with_capacity(2);
        unsafe { v.set_len(2) };

        Geev::geev(&mut a, &mut v, None, None).unwrap();

        assert_eq!(v, vec![]);
    }
}

<commit_msg>Return values in result<commit_after>// Copyright 2014 Michael Yang. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
use std::mem;
use std::ptr;
use libc::c_int;
use num::complex::{
    Complex,
};
use error::Error;
use ll::*;
use Matrix;
use Vector;
use scalar::Scalar;
use types::Compute;
use util::ColMem;

pub trait Geev<Eigenvalues>: Sized {
    fn geev(a: &mut Matrix<Self>, left: Option<&mut Matrix<Self>>, right: Option<&mut Matrix<Self>>) -> Result<Vec<Eigenvalues>, Error> {

        let job_l = match &left {
            &Some(_) => Compute::Value,
            _ => Compute::None,
        };

        let job_r = match &right {
            &Some(_) => Compute::Value,
            _ => Compute::None,
        };

        let work_len = try!(Geev::work_len(a, job_l, job_r));
        let mut work: Vec<_> = Vec::with_capacity(work_len as usize);
        unsafe {
            work.set_len(work_len as usize);
        }

        Geev::work(a, left, right, &mut work[..])
    }
    fn work(a: &mut Matrix<Self>,
        left: Option<&mut Matrix<Self>>, right: Option<&mut Matrix<Self>>, work: &mut [Self]) -> Result<Vec<Eigenvalues>, Error>;
    fn work_len(a: &mut Matrix<Self>, left: Compute, right: Compute) -> Result<usize, Error>;
}

macro_rules! real_eigen_impl(($($t: ident), +) => ($(
    impl Geev<Complex<$t>> for $t {
        fn work(a: &mut Matrix<Self>, left: Option<&mut Matrix<Self>>, right: Option<&mut Matrix<Self>>, work: &mut [Self]) -> Result<Vec<Complex<$t>>, Error> {

            let mut info: c_int = 0;
            let n = a.rows();
            if n != a.cols() {
                return Err(Error::DimensionMismatch);
            }
            let mut a_mem = ColMem::new(a.order(), a);

            let (job_l, lead_l, ptr_l) = match left {
                Some(m) => (Compute::Value, m.rows(), m.as_mut_ptr()),
                None => (Compute::None, 1, ptr::null::<$t>() as *mut _),
            };

            let (job_r, lead_r, ptr_r) = match right {
                Some(m) => (Compute::Value, m.rows(), m.as_mut_ptr()),
                None => (Compute::None, 1, ptr::null::<$t>() as *mut _),
            };

            let mut real: Vec<_> = Vec::with_capacity(n as usize);
            let mut imag: Vec<_> = Vec::with_capacity(n as usize);

            unsafe {
                real.set_len(n as usize);
                imag.set_len(n as usize);

                prefix!($t, geev_)(
                    job_l.as_i8().as_mut(), job_r.as_i8().as_mut(),
                    n.as_mut(),
                    a_mem.as_mut_ptr(), a_mem.lead().as_mut(),
                    real.as_mut_ptr(), imag.as_mut_ptr(),
                    ptr_l, lead_l.as_mut(),
                    ptr_r, lead_r.as_mut(),
                    work.as_mut_ptr(), (work.len() as c_int).as_mut(),
                    &mut info as *mut c_int);
            };

            let values = real.into_iter().zip(imag.into_iter())
                .map(|(r, i)| Complex::new(r, i)).collect();

            match info {
                0 => Ok(values),
                x if x < 0 => Err(Error::IllegalParameter(-x as usize)),
                x => Err(Error::DiagonalElementZero(x as usize)),
            }
        }

        fn work_len(a: &mut Matrix<Self>, left: Compute, right: Compute) -> Result<usize, Error> {
            let mut info: c_int = 0;
            let mut len_info: $t = unsafe { mem::zeroed() };
            let len_ptr = (&mut len_info) as *mut $t;

            let n = a.rows();
            if n != a.cols() {
                return Err(Error::DimensionMismatch);
            }
            let lda = n;

            unsafe {
                prefix!($t, geev_)(
                    left.as_i8().as_mut(), right.as_i8().as_mut(),
                    n.as_mut(),
                    a.as_mut_ptr(), lda.as_mut(),
                    ptr::null::<$t>() as *mut _, ptr::null::<$t>() as *mut _,
                    ptr::null::<$t>() as *mut _, n.as_mut(),
                    ptr::null::<$t>() as *mut _, n.as_mut(),
                    len_ptr, (-1 as c_int).as_mut(),
                    &mut info as *mut c_int);
            };

            match info {
                0 => Ok(len_info.as_work()),
                x if x < 0 => Err(Error::IllegalParameter(-x as usize)),
                x => Err(Error::DiagonalElementZero(x as usize)),
            }
        }
    }
)+));

real_eigen_impl!(f32, f64);

#[cfg(test)]
mod geev_tests {
    use num::Complex;
    use eigenvalues::Geev;
    use matrix::tests::M;
    use types::Order::*;

    #[test]
    fn real() {
        let mut a = M(RowMajor, 2i32, 2i32, vec![2.0f64, 7.0, -1.0, -6.0]);
        let lambda = Geev::geev(&mut a, None, None).unwrap();

        assert_eq!(lambda, vec![Complex::new(1.0, 0.0), Complex::new(-5.0, 0.0)]);
    }
}
<|endoftext|>


<commit_before>use super::{Feature, KEY_SIZE};
use crate::ram::types::Id;
use byteorder::{BigEndian, WriteBytesExt};
use serde::de::{SeqAccess, Visitor};
use serde::ser::SerializeSeq;
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use std::cmp;
use std::fmt;
use std::io::Cursor;
use std::io::Write;
use std::ops::{Index, IndexMut};
use std::ptr;
use std::slice::Iter;
use std::slice::SliceIndex;

type InnerSlice = [u8; KEY_SIZE];
pub const ID_SIZE: usize = 16;

#[derive(Clone, Eq, PartialEq, Debug, Hash)]
pub struct EntryKey {
    slice: InnerSlice,
}

impl EntryKey {
    pub fn from_props(id: &Id, feature: &Feature, field: u64, schema_id: u32) -> Self {
        let mut key = Self::new();
        let mut cursor = Cursor::new(&mut key.slice[..]);
        cursor.write_u32::<BigEndian>(schema_id).unwrap();
        cursor.write_u32::<BigEndian>(field as u32).unwrap();
        cursor.write(feature).unwrap();
        cursor.write_u64::<BigEndian>(id.higher).unwrap();
        cursor.write_u64::<BigEndian>(id.lower).unwrap();
        key
    }

    pub fn for_scannable(id: &Id, schema_id: u32) -> Self {
        Self::from_props(id, &Default::default(), 0, schema_id)
    }

    #[inline(always)]
    pub fn new() -> Self {
        Self::default()
    }

    #[inline(always)]
    pub fn len(&self) -> usize {
        self.slice.len()
    }

    #[inline(always)]
    pub fn as_slice(&self) -> &[u8] {
        &self.slice
    }

    #[inline(always)]
    pub fn as_mut_slice(&mut self) -> &mut [u8] {
        &mut self.slice
    }

    #[inline(always)]
    pub fn max() -> Self {
        Self {
            slice: [u8::MAX; KEY_SIZE],
        }
    }
    pub fn from_slice(s: &[u8]) -> Self {
        let mut key = EntryKey::new();
        key.copy_slice(s);
        key
    }
    pub fn copy_slice(&mut self, slice: &[u8]) {
        let len = cmp::min(slice.len(), KEY_SIZE);
        unsafe {
            ptr::copy_nonoverlapping(slice.as_ptr(), self.slice.as_mut_ptr(), len);
        }
    }
    pub fn id(&self) -> Id {
        let mut id_cursor = Cursor::new(&self.slice[KEY_SIZE - ID_SIZE..]);
        let id = Id::from_binary(&mut id_cursor).unwrap(); // read id from tailing 128 bits
        if cfg!(debug_assertions) && id.is_unit_id() {
            warn!("id is unit id from key {:?}", self.slice)
        }
        id
    }
    pub fn set_id(&mut self, id: &Id) {
        let id_data = id.to_binary();
        unsafe {
            ptr::copy_nonoverlapping(
                id_data.as_ptr(),
                self.slice[KEY_SIZE - ID_SIZE..].as_mut_ptr(),
                ID_SIZE,
            );
        }
    }
    pub fn from_id(id: &Id) -> Self {
        let mut key = EntryKey::new();
        key.set_id(id);
        key
    }
}

impl Default for EntryKey {
    fn default() -> Self {
        Self {
            slice: [0u8; KEY_SIZE],
        }
    }
}

impl<I: SliceIndex<[u8]>> Index<I> for EntryKey {
    type Output = I::Output;
    fn index(&self, index: I) -> &I::Output {
        &(self.slice)[index]
    }
}

impl<I: SliceIndex<[u8]>> IndexMut<I> for EntryKey {
    fn index_mut(&mut self, index: I) -> &mut I::Output {
        &mut (self.slice)[index]
    }
}

impl<'a> IntoIterator for &'a EntryKey {
    type Item = &'a u8;
    type IntoIter = Iter<'a, u8>;
    fn into_iter(self) -> Self::IntoIter {
        self.slice.iter()
    }
}

impl Serialize for EntryKey {
    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
        let mut state = serializer.serialize_seq(Some(self.len()))?;
        for item in self {
            state.serialize_element(&item)?;
        }
        state.end()
    }
}

impl<'de> Deserialize<'de> for EntryKey {
    fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
        deserializer.deserialize_seq(EntryKeyVisitor)
    }
}

struct EntryKeyVisitor;

impl<'de> Visitor<'de> for EntryKeyVisitor {
    type Value = EntryKey;

    fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
        formatter.write_str("a sequence")
    }

    fn visit_seq<B>(self, mut seq: B) -> Result<Self::Value, B::Error>
    where
        B: SeqAccess<'de>,
    {
        let mut values = EntryKey::new();
        let mut counter = 0;
        while let Some(value) = seq.next_element()? {
            values.as_mut_slice()[counter] = value;
            counter += 1;
        }

        Ok(values)
    }
}

impl PartialOrd for EntryKey {
    fn partial_cmp(&self, other: &EntryKey) -> Option<cmp::Ordering> {
        Some(self.slice.cmp(&other.slice))
    }
}

impl Ord for EntryKey {
    fn cmp(&self, other: &EntryKey) -> cmp::Ordering {
        self.slice.cmp(&other.slice)
    }
}
<commit_msg>entry generator<commit_after>use super::{Feature, KEY_SIZE};
use crate::ram::types::Id;
use byteorder::{BigEndian, WriteBytesExt};
use serde::de::{SeqAccess, Visitor};
use serde::ser::SerializeSeq;
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use std::cmp;
use std::fmt;
use std::io::Cursor;
use std::io::Write;
use std::ops::{Index, IndexMut};
use std::ptr;
use std::slice::Iter;
use std::slice::SliceIndex;

type InnerSlice = [u8; KEY_SIZE];
pub const ID_SIZE: usize = 16;

#[derive(Clone, Eq, PartialEq, Debug, Hash)]
pub struct EntryKey {
    slice: InnerSlice,
}

impl EntryKey {
    pub fn from_props(id: &Id, feature: &Feature, field: u64, schema_id: u32) -> Self {
        let mut key = Self::new();
        let mut cursor = Cursor::new(&mut key.slice[..]);
        cursor.write_u32::<BigEndian>(schema_id).unwrap();
        cursor.write_u32::<BigEndian>(field as u32).unwrap();
        cursor.write(feature).unwrap();
        cursor.write_u64::<BigEndian>(id.higher).unwrap();
        cursor.write_u64::<BigEndian>(id.lower).unwrap();
        key
    }

    pub fn for_scannable(id: &Id, schema_id: u32) -> Self {
        Self::from_props(id, &Default::default(), 0, schema_id)
    }

    pub fn for_schema(schema_id: u32) -> Self {
        Self::from_props(&Id::unit_id(), &Default::default(), 0, schema_id)
    }

    pub fn for_schema_field_feature(schema_id: u32, field: u64, feature: &Feature) -> Self {
        Self::from_props(&Id::unit_id(), feature, field, schema_id)
    }

    #[inline(always)]
    pub fn new() -> Self {
        Self::default()
    }

    #[inline(always)]
    pub fn len(&self) -> usize {
        self.slice.len()
    }

    #[inline(always)]
    pub fn as_slice(&self) -> &[u8] {
        &self.slice
    }

    #[inline(always)]
    pub fn as_mut_slice(&mut self) -> &mut [u8] {
        &mut self.slice
    }

    #[inline(always)]
    pub fn max() -> Self {
        Self {
            slice: [u8::MAX; KEY_SIZE],
        }
    }
    pub fn from_slice(s: &[u8]) -> Self {
        let mut key = EntryKey::new();
        key.copy_slice(s);
        key
    }
    pub fn copy_slice(&mut self, slice: &[u8]) {
        let len = cmp::min(slice.len(), KEY_SIZE);
        unsafe {
            ptr::copy_nonoverlapping(slice.as_ptr(), self.slice.as_mut_ptr(), len);
        }
    }
    pub fn id(&self) -> Id {
        let mut id_cursor = Cursor::new(&self.slice[KEY_SIZE - ID_SIZE..]);
        let id = Id::from_binary(&mut id_cursor).unwrap(); // read id from tailing 128 bits
        if cfg!(debug_assertions) && id.is_unit_id() {
            warn!("id is unit id from key {:?}", self.slice)
        }
        id
    }
    pub fn set_id(&mut self, id: &Id) {
        let id_data = id.to_binary();
        unsafe {
            ptr::copy_nonoverlapping(
                id_data.as_ptr(),
                self.slice[KEY_SIZE - ID_SIZE..].as_mut_ptr(),
                ID_SIZE,
            );
        }
    }
    pub fn from_id(id: &Id) -> Self {
        let mut key = EntryKey::new();
        key.set_id(id);
        key
    }
}

impl Default for EntryKey {
    fn default() -> Self {
        Self {
            slice: [0u8; KEY_SIZE],
        }
    }
}

impl<I: SliceIndex<[u8]>> Index<I> for EntryKey {
    type Output = I::Output;
    fn index(&self, index: I) -> &I::Output {
        &(self.slice)[index]
    }
}

impl<I: SliceIndex<[u8]>> IndexMut<I> for EntryKey {
    fn index_mut(&mut self, index: I) -> &mut I::Output {
        &mut (self.slice)[index]
    }
}

impl<'a> IntoIterator for &'a EntryKey {
    type Item = &'a u8;
    type IntoIter = Iter<'a, u8>;
    fn into_iter(self) -> Self::IntoIter {
        self.slice.iter()
    }
}

impl Serialize for EntryKey {
    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
        let mut state = serializer.serialize_seq(Some(self.len()))?;
        for item in self {
            state.serialize_element(&item)?;
        }
        state.end()
    }
}

impl<'de> Deserialize<'de> for EntryKey {
    fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
        deserializer.deserialize_seq(EntryKeyVisitor)
    }
}

struct EntryKeyVisitor;

impl<'de> Visitor<'de> for EntryKeyVisitor {
    type Value = EntryKey;

    fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
        formatter.write_str("a sequence")
    }

    fn visit_seq<B>(self, mut seq: B) -> Result<Self::Value, B::Error>
    where
        B: SeqAccess<'de>,
    {
        let mut values = EntryKey::new();
        let mut counter = 0;
        while let Some(value) = seq.next_element()? {
            values.as_mut_slice()[counter] = value;
            counter += 1;
        }

        Ok(values)
    }
}

impl PartialOrd for EntryKey {
    fn partial_cmp(&self, other: &EntryKey) -> Option<cmp::Ordering> {
        Some(self.slice.cmp(&other.slice))
    }
}

impl Ord for EntryKey {
    fn cmp(&self, other: &EntryKey) -> cmp::Ordering {
        self.slice.cmp(&other.slice)
    }
}
<|endoftext|>


<commit_before>extern crate bindgen;
extern crate cc;
extern crate glob;

use std::env;
use std::fs;
use std::path::PathBuf;

fn link(name: &str, bundled: bool) {
    use std::env::var;
    let target = var("TARGET").unwrap();
    let target: Vec<_> = target.split('-').collect();
    if target.get(2) == Some(&"windows") {
        println!("cargo:rustc-link-lib=dylib={}", name);
        if bundled && target.get(3) == Some(&"gnu") {
            let dir = var("CARGO_MANIFEST_DIR").unwrap();
            println!("cargo:rustc-link-search=native={}/{}", dir, target[0]);
        }
    }
}

fn fail_on_empty_directory(name: &str) {
    if fs::read_dir(name).unwrap().count() == 0 {
        println!(
            "The `{}` directory is empty, did you forget to pull the submodules?",
            name
        );
        println!("Try `git submodule update --init --recursive`");
        panic!();
    }
}

fn bindgen_rocksdb() {
    let bindings = bindgen::Builder::default()
        .header("rocksdb/include/rocksdb/c.h")
        .blacklist_type("max_align_t") // https://github.com/rust-lang-nursery/rust-bindgen/issues/550
        .ctypes_prefix("libc")
        .generate()
        .expect("unable to generate rocksdb bindings");

    let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());
    bindings
        .write_to_file(out_path.join("bindings.rs"))
        .expect("unable to write rocksdb bindings");
}

fn build_rocksdb() {
    let mut config = cc::Build::new();
    config.include("rocksdb/include/");
    config.include("rocksdb/");
    config.include("rocksdb/third-party/gtest-1.7.0/fused-src/");

    if cfg!(feature = "snappy") {
        config.define("SNAPPY", Some("1"));
        config.include("snappy/");
    }

    if cfg!(feature = "lz4") {
        config.define("LZ4", Some("1"));
        config.include("lz4/lib/");
    }

    if cfg!(feature = "zstd") {
        config.define("ZSTD", Some("1"));
        config.include("zstd/lib/");
        config.include("zstd/lib/dictBuilder/");
    }

    if cfg!(feature = "zlib") {
        config.define("ZLIB", Some("1"));
        config.include("zlib/");
    }

    if cfg!(feature = "bzip2") {
        config.define("BZIP2", Some("1"));
        config.include("bzip2/");
    }

    config.include(".");
    config.define("NDEBUG", Some("1"));

    let mut lib_sources = include_str!("rocksdb_lib_sources.txt")
        .split(" ")
        .collect::<Vec<&'static str>>();

    // We have a pregenerated a version of build_version.cc in the local directory
    lib_sources = lib_sources
        .iter()
        .cloned()
        .filter(|file| *file != "util/build_version.cc")
        .collect::<Vec<&'static str>>();

    if cfg!(target_os = "macos") {
        config.define("OS_MACOSX", Some("1"));
        config.define("ROCKSDB_PLATFORM_POSIX", Some("1"));
        config.define("ROCKSDB_LIB_IO_POSIX", Some("1"));
    }
    if cfg!(target_os = "linux") {
        config.define("OS_LINUX", Some("1"));
        config.define("ROCKSDB_PLATFORM_POSIX", Some("1"));
        config.define("ROCKSDB_LIB_IO_POSIX", Some("1"));
        // COMMON_FLAGS="$COMMON_FLAGS -fno-builtin-memcmp"
    }
    if cfg!(target_os = "freebsd") {
        config.define("OS_FREEBSD", Some("1"));
        config.define("ROCKSDB_PLATFORM_POSIX", Some("1"));
        config.define("ROCKSDB_LIB_IO_POSIX", Some("1"));
    }

    if cfg!(target_os = "windows") {
        link("rpcrt4", false);
        link("shlwapi", false);
        config.define("OS_WIN", Some("1"));

        // Remove POSIX-specific sources
        lib_sources = lib_sources
            .iter()
            .cloned()
            .filter(|file| match *file {
                "port/port_posix.cc" | "env/env_posix.cc" | "env/io_posix.cc" => false,
                _ => true,
            }).collect::<Vec<&'static str>>();

        // Add Windows-specific sources
        lib_sources.push("port/win/port_win.cc");
        lib_sources.push("port/win/env_win.cc");
        lib_sources.push("port/win/env_default.cc");
        lib_sources.push("port/win/win_logger.cc");
        lib_sources.push("port/win/io_win.cc");
        lib_sources.push("port/win/win_thread.cc");
    }

    if cfg!(target_env = "msvc") {
        config.flag("-EHsc");
    } else {
        config.flag("-std=c++11");
        // this was breaking the build on travis due to
        // > 4mb of warnings emitted.
        config.flag("-Wno-unused-parameter");
    }

    for file in lib_sources {
        let file = "rocksdb/".to_string() + file;
        config.file(&file);
    }

    config.file("build_version.cc");

    config.cpp(true);
    config.compile("librocksdb.a");
}

fn build_snappy() {
    let mut config = cc::Build::new();
    config.include("snappy/");
    config.include(".");

    config.define("NDEBUG", Some("1"));

    if cfg!(target_env = "msvc") {
        config.flag("-EHsc");
    } else {
        config.flag("-std=c++11");
    }

    config.file("snappy/snappy.cc");
    config.file("snappy/snappy-sinksource.cc");
    config.file("snappy/snappy-c.cc");
    config.cpp(true);
    config.compile("libsnappy.a");
}

fn build_lz4() {
    let mut compiler = cc::Build::new();

    compiler
        .file("lz4/lib/lz4.c")
        .file("lz4/lib/lz4frame.c")
        .file("lz4/lib/lz4hc.c")
        .file("lz4/lib/xxhash.c");

    compiler.opt_level(3);

    match env::var("TARGET").unwrap().as_str() {
        "i686-pc-windows-gnu" => {
            compiler.flag("-fno-tree-vectorize");
        }
        _ => {}
    }

    compiler.compile("liblz4.a");
}

fn build_zstd() {
    let mut compiler = cc::Build::new();

    compiler.include("zstd/lib/");
    compiler.include("zstd/lib/common");
    compiler.include("zstd/lib/legacy");

    let globs = &[
        "zstd/lib/common/*.c",
        "zstd/lib/compress/*.c",
        "zstd/lib/decompress/*.c",
        "zstd/lib/dictBuilder/*.c",
        "zstd/lib/legacy/*.c",
    ];

    for pattern in globs {
        for path in glob::glob(pattern).unwrap() {
            let path = path.unwrap();
            compiler.file(path);
        }
    }

    compiler.opt_level(3);

    compiler.define("ZSTD_LIB_DEPRECATED", Some("0"));
    compiler.compile("libzstd.a");
}

fn build_zlib() {
    let mut compiler = cc::Build::new();

    let globs = &["zlib/*.c"];

    for pattern in globs {
        for path in glob::glob(pattern).unwrap() {
            let path = path.unwrap();
            compiler.file(path);
        }
    }

    compiler.opt_level(3);
    compiler.compile("libz.a");
}

fn build_bzip2() {
    let mut compiler = cc::Build::new();

    compiler
        .file("bzip2/blocksort.c")
        .file("bzip2/bzlib.c")
        .file("bzip2/compress.c")
        .file("bzip2/crctable.c")
        .file("bzip2/decompress.c")
        .file("bzip2/huffman.c")
        .file("bzip2/randtable.c");

    compiler
        .define("_FILE_OFFSET_BITS", Some("64"))
        .define("BZ_NO_STDIO", None);

    compiler.opt_level(3);
    compiler.compile("libbz2.a");
}

fn try_to_find_and_link_lib(lib_name: &str) -> bool {
    if let Ok(lib_dir) = env::var(&format!("{}_LIB_DIR", lib_name)) {
        println!("cargo:rustc-link-search=native={}", lib_dir);
        let mode = match env::var_os(&format!("{}_STATIC", lib_name)) {
            Some(_) => "static",
            None => "dylib",
        };
        println!("cargo:rustc-link-lib={}={}", mode, lib_name.to_lowercase());
        return true;
    }
    false
}

fn main() {
    println!("cargo:rerun-if-changed=build.rs");
    println!("cargo:rerun-if-changed=rocksdb/");
    println!("cargo:rerun-if-changed=snappy/");
    println!("cargo:rerun-if-changed=lz4/");
    println!("cargo:rerun-if-changed=zstd/");
    println!("cargo:rerun-if-changed=zlib/");
    println!("cargo:rerun-if-changed=bzip2/");

    fail_on_empty_directory("rocksdb");
    fail_on_empty_directory("snappy");
    fail_on_empty_directory("lz4");
    fail_on_empty_directory("zstd");
    fail_on_empty_directory("zlib");
    fail_on_empty_directory("bzip2");

    bindgen_rocksdb();

    if !try_to_find_and_link_lib("ROCKSDB") {
        build_rocksdb();
    }
    if cfg!(feature = "snappy") && !try_to_find_and_link_lib("SNAPPY") {
        build_snappy();
    }
    if cfg!(feature = "lz4") && !try_to_find_and_link_lib("LZ4") {
        build_lz4();
    }
    if cfg!(feature = "zstd") && !try_to_find_and_link_lib("ZSTD") {
        build_zstd();
    }
    if cfg!(feature = "zlib") && !try_to_find_and_link_lib("ZLIB") {
        build_zlib();
    }
    if cfg!(feature = "bzip2") && !try_to_find_and_link_lib("BZIP2") {
        build_bzip2();
    }
}
<commit_msg>Disabled warnings when builds c++ deps<commit_after>extern crate bindgen;
extern crate cc;
extern crate glob;

use std::env;
use std::fs;
use std::path::PathBuf;

fn link(name: &str, bundled: bool) {
    use std::env::var;
    let target = var("TARGET").unwrap();
    let target: Vec<_> = target.split('-').collect();
    if target.get(2) == Some(&"windows") {
        println!("cargo:rustc-link-lib=dylib={}", name);
        if bundled && target.get(3) == Some(&"gnu") {
            let dir = var("CARGO_MANIFEST_DIR").unwrap();
            println!("cargo:rustc-link-search=native={}/{}", dir, target[0]);
        }
    }
}

fn fail_on_empty_directory(name: &str) {
    if fs::read_dir(name).unwrap().count() == 0 {
        println!(
            "The `{}` directory is empty, did you forget to pull the submodules?",
            name
        );
        println!("Try `git submodule update --init --recursive`");
        panic!();
    }
}

fn bindgen_rocksdb() {
    let bindings = bindgen::Builder::default()
        .header("rocksdb/include/rocksdb/c.h")
        .blacklist_type("max_align_t") // https://github.com/rust-lang-nursery/rust-bindgen/issues/550
        .ctypes_prefix("libc")
        .generate()
        .expect("unable to generate rocksdb bindings");

    let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());
    bindings
        .write_to_file(out_path.join("bindings.rs"))
        .expect("unable to write rocksdb bindings");
}

fn build_rocksdb() {
    let mut config = cc::Build::new();
    config.include("rocksdb/include/");
    config.include("rocksdb/");
    config.include("rocksdb/third-party/gtest-1.7.0/fused-src/");

    if cfg!(feature = "snappy") {
        config.define("SNAPPY", Some("1"));
        config.include("snappy/");
    }

    if cfg!(feature = "lz4") {
        config.define("LZ4", Some("1"));
        config.include("lz4/lib/");
    }

    if cfg!(feature = "zstd") {
        config.define("ZSTD", Some("1"));
        config.include("zstd/lib/");
        config.include("zstd/lib/dictBuilder/");
    }

    if cfg!(feature = "zlib") {
        config.define("ZLIB", Some("1"));
        config.include("zlib/");
    }

    if cfg!(feature = "bzip2") {
        config.define("BZIP2", Some("1"));
        config.include("bzip2/");
    }

    config.include(".");
    config.define("NDEBUG", Some("1"));

    let mut lib_sources = include_str!("rocksdb_lib_sources.txt")
        .split(" ")
        .collect::<Vec<&'static str>>();

    // We have a pregenerated a version of build_version.cc in the local directory
    lib_sources = lib_sources
        .iter()
        .cloned()
        .filter(|file| *file != "util/build_version.cc")
        .collect::<Vec<&'static str>>();

    if cfg!(target_os = "macos") {
        config.define("OS_MACOSX", Some("1"));
        config.define("ROCKSDB_PLATFORM_POSIX", Some("1"));
        config.define("ROCKSDB_LIB_IO_POSIX", Some("1"));
    }
    if cfg!(target_os = "linux") {
        config.define("OS_LINUX", Some("1"));
        config.define("ROCKSDB_PLATFORM_POSIX", Some("1"));
        config.define("ROCKSDB_LIB_IO_POSIX", Some("1"));
        // COMMON_FLAGS="$COMMON_FLAGS -fno-builtin-memcmp"
    }
    if cfg!(target_os = "freebsd") {
        config.define("OS_FREEBSD", Some("1"));
        config.define("ROCKSDB_PLATFORM_POSIX", Some("1"));
        config.define("ROCKSDB_LIB_IO_POSIX", Some("1"));
    }

    if cfg!(target_os = "windows") {
        link("rpcrt4", false);
        link("shlwapi", false);
        config.define("OS_WIN", Some("1"));

        // Remove POSIX-specific sources
        lib_sources = lib_sources
            .iter()
            .cloned()
            .filter(|file| match *file {
                "port/port_posix.cc" | "env/env_posix.cc" | "env/io_posix.cc" => false,
                _ => true,
            }).collect::<Vec<&'static str>>();

        // Add Windows-specific sources
        lib_sources.push("port/win/port_win.cc");
        lib_sources.push("port/win/env_win.cc");
        lib_sources.push("port/win/env_default.cc");
        lib_sources.push("port/win/win_logger.cc");
        lib_sources.push("port/win/io_win.cc");
        lib_sources.push("port/win/win_thread.cc");
    }

    if cfg!(target_env = "msvc") {
        config.flag("-EHsc");
    } else {
        config.flag("-std=c++11");
        // this was breaking the build on travis due to
        // > 4mb of warnings emitted.
        config.flag("-Wno-unused-parameter");
    }

    for file in lib_sources {
        let file = "rocksdb/".to_string() + file;
        config.file(&file);
    }

    config.file("build_version.cc");

    config.cpp(true);
    config.compile("librocksdb.a");
}

fn build_snappy() {
    let mut config = cc::Build::new();
    config.include("snappy/");
    config.include(".");

    config.define("NDEBUG", Some("1"));

    if cfg!(target_env = "msvc") {
        config.flag("-EHsc");
    } else {
        config.flag("-std=c++11");
    }

    config.file("snappy/snappy.cc");
    config.file("snappy/snappy-sinksource.cc");
    config.file("snappy/snappy-c.cc");
    config.cpp(true);
    config.compile("libsnappy.a");
}

fn build_lz4() {
    let mut compiler = cc::Build::new();

    compiler
        .file("lz4/lib/lz4.c")
        .file("lz4/lib/lz4frame.c")
        .file("lz4/lib/lz4hc.c")
        .file("lz4/lib/xxhash.c");

    compiler.opt_level(3);

    match env::var("TARGET").unwrap().as_str() {
        "i686-pc-windows-gnu" => {
            compiler.flag("-fno-tree-vectorize");
        }
        _ => {}
    }

    compiler.compile("liblz4.a");
}

fn build_zstd() {
    let mut compiler = cc::Build::new();

    compiler.include("zstd/lib/");
    compiler.include("zstd/lib/common");
    compiler.include("zstd/lib/legacy");

    let globs = &[
        "zstd/lib/common/*.c",
        "zstd/lib/compress/*.c",
        "zstd/lib/decompress/*.c",
        "zstd/lib/dictBuilder/*.c",
        "zstd/lib/legacy/*.c",
    ];

    for pattern in globs {
        for path in glob::glob(pattern).unwrap() {
            let path = path.unwrap();
            compiler.file(path);
        }
    }

    compiler.opt_level(3);

    compiler.define("ZSTD_LIB_DEPRECATED", Some("0"));
    compiler.compile("libzstd.a");
}

fn build_zlib() {
    let mut compiler = cc::Build::new();

    let globs = &["zlib/*.c"];

    for pattern in globs {
        for path in glob::glob(pattern).unwrap() {
            let path = path.unwrap();
            compiler.file(path);
        }
    }

    compiler.flag_if_supported("-Wno-implicit-function-declaration");
    compiler.opt_level(3);
    compiler.compile("libz.a");
}

fn build_bzip2() {
    let mut compiler = cc::Build::new();

    compiler
        .file("bzip2/blocksort.c")
        .file("bzip2/bzlib.c")
        .file("bzip2/compress.c")
        .file("bzip2/crctable.c")
        .file("bzip2/decompress.c")
        .file("bzip2/huffman.c")
        .file("bzip2/randtable.c");

    compiler
        .define("_FILE_OFFSET_BITS", Some("64"))
        .define("BZ_NO_STDIO", None);

    compiler.extra_warnings(false);
    compiler.opt_level(3);
    compiler.compile("libbz2.a");
}

fn try_to_find_and_link_lib(lib_name: &str) -> bool {
    if let Ok(lib_dir) = env::var(&format!("{}_LIB_DIR", lib_name)) {
        println!("cargo:rustc-link-search=native={}", lib_dir);
        let mode = match env::var_os(&format!("{}_STATIC", lib_name)) {
            Some(_) => "static",
            None => "dylib",
        };
        println!("cargo:rustc-link-lib={}={}", mode, lib_name.to_lowercase());
        return true;
    }
    false
}

fn main() {
    println!("cargo:rerun-if-changed=build.rs");
    println!("cargo:rerun-if-changed=rocksdb/");
    println!("cargo:rerun-if-changed=snappy/");
    println!("cargo:rerun-if-changed=lz4/");
    println!("cargo:rerun-if-changed=zstd/");
    println!("cargo:rerun-if-changed=zlib/");
    println!("cargo:rerun-if-changed=bzip2/");

    fail_on_empty_directory("rocksdb");
    fail_on_empty_directory("snappy");
    fail_on_empty_directory("lz4");
    fail_on_empty_directory("zstd");
    fail_on_empty_directory("zlib");
    fail_on_empty_directory("bzip2");

    bindgen_rocksdb();

    if !try_to_find_and_link_lib("ROCKSDB") {
        build_rocksdb();
    }
    if cfg!(feature = "snappy") && !try_to_find_and_link_lib("SNAPPY") {
        build_snappy();
    }
    if cfg!(feature = "lz4") && !try_to_find_and_link_lib("LZ4") {
        build_lz4();
    }
    if cfg!(feature = "zstd") && !try_to_find_and_link_lib("ZSTD") {
        build_zstd();
    }
    if cfg!(feature = "zlib") && !try_to_find_and_link_lib("ZLIB") {
        build_zlib();
    }
    if cfg!(feature = "bzip2") && !try_to_find_and_link_lib("BZIP2") {
        build_bzip2();
    }
}
<|endoftext|>


<commit_before>use parser::ParseError;
use std::collections::HashSet;
use text_range::TextRange;

pub struct InputError {
    /// The error message
    pub msg: String,
    /// The columns in which the error occurred
    pub pos: TextRange,
}

impl InputError {
    pub fn from_parser_error(err: ParseError) -> InputError {
        InputError {
            msg: generate_expected_string(&err.expected),
            pos: TextRange {
                start: err.offset,
                end: err.column,
            },
        }
    }
}

fn generate_expected_string(expected: &HashSet<&'static str>) -> String {
    let expected = expected
        .iter()
        .map(|s| s.to_string())
        .collect::<Vec<String>>();

    format!("expected {}", or_list(&expected))
}

fn or_list(items: &[String]) -> String {
    let len = items.len();
    match len {
        0 => String::new(),
        1 => items[0].clone(),
        _ => {
            let last = len - 1;
            format!("{} or {}", items[0..last].join(", "), items[last])
        }
    }
}

#[test]
fn test_or_list() {
    assert_eq!(or_list(&vec![String::from("foo")]), String::from("foo"));

    assert_eq!(
        or_list(&vec![String::from("foo"), String::from("bar")]),
        String::from("foo or bar")
    );

    assert_eq!(
        or_list(
            &vec![
                String::from("foo"),
                String::from("bar"),
                String::from("baz"),
            ]
        ),
        String::from("foo, bar or baz")
    );

    assert_eq!(
        or_list(
            &vec![
                String::from("a"),
                String::from("b"),
                String::from("c"),
                String::from("d"),
                String::from("e"),
            ]
        ),
        String::from("a, b, c, d or e")
    );
}
<commit_msg>Refactor or_list to use str<commit_after>use parser::ParseError;
use std::collections::HashSet;
use text_range::TextRange;

pub struct InputError {
    /// The error message
    pub msg: String,
    /// The columns in which the error occurred
    pub pos: TextRange,
}

impl InputError {
    pub fn from_parser_error(err: ParseError) -> InputError {
        InputError {
            msg: generate_expected_string(&err.expected),
            pos: TextRange {
                start: err.offset,
                end: err.column,
            },
        }
    }
}

fn generate_expected_string(expected: &HashSet<&'static str>) -> String {
    let expected = expected.iter().map(|s| *s).collect::<Vec<&str>>();

    format!("expected {}", or_list(&expected))
}

fn or_list(items: &[&str]) -> String {
    let len = items.len();
    match len {
        0 => String::new(),
        1 => String::from(items[0]),
        _ => {
            let last = len - 1;
            format!("{} or {}", items[0..last].join(", "), items[last])
        }
    }
}

#[test]
fn test_or_list() {
    assert_eq!(or_list(&vec!["foo"]), String::from("foo"));

    assert_eq!(or_list(&vec!["foo", "bar"]), String::from("foo or bar"));

    assert_eq!(
        or_list(&vec!["foo", "bar", "baz"]),
        String::from("foo, bar or baz")
    );

    assert_eq!(
        or_list(&vec!["a", "b", "c", "d", "e"]),
        String::from("a, b, c, d or e")
    );
}
<|endoftext|>