<commit_before>use na::{Mat2, DMat};
use std::collections::HashMap;
use std::num::*;
use itertools::Itertools;
use std::cell::RefCell;
use std::rc::Rc;

mod test;

#[test]
fn test_which_grid() {
    let loc = (-6., 6.);
    let i_rn = (-10.0, 10.0);
    let j_rn = (-10.0, 10.0);
    let i_bins = 10 as usize;
    let j_bins = 10 as usize;

    let result = grid_helpers::which_grid(loc, i_rn, j_rn, i_bins, j_bins).unwrap();
    assert_eq!((2, 8), result);

}

mod grid_helpers {
    pub fn which_grid(val: (f64, f64), i_range: (f64, f64), j_range: (f64, f64), i_bins: usize, j_bins: usize) -> Result<(usize, usize), String> {
        let i_size = (i_range.1 - i_range.0) / i_bins as f64;
        let i_number_of_sizes = ((val.0 - i_range.0) / i_size) as usize;
        let j_size = (j_range.1 - j_range.0) / j_bins as f64;
        let j_number_of_sizes = ((val.1 - j_range.0) / j_size) as usize;

        assert!(i_number_of_sizes < i_bins);
        assert!(j_number_of_sizes < j_bins);

        Ok((i_number_of_sizes, j_number_of_sizes))
    }
}

pub trait DensityGrid {

    fn get_value_at_time(&self, time: u32, lambda: f64, dats: Vec<((usize,usize),Dat)>) -> Result<f64, String>;

    fn compute_decay_coeff_at_time(&self, t_n: u32, t_l: u32, lambda: f64) -> f64 {
        lambda.powf((t_n - t_l) as f64)
    }
}

pub trait DensityGridSpace {

    fn put(&mut self, loc2d: (f64, f64), val: f64, t: u32) -> Result<(), String>;

}

impl Default for DStreamProps {
    fn default() -> DStreamProps {
        DStreamProps {
            c_m: 3.0,
            c_l: 0.8,
            lambda: 0.998,
            beta: 0.3,
            i_bins: 10 as usize,
            j_bins: 10 as usize,
            i_range: (-10.0, 10.0),
            j_range: (-10.0, 10.0),
        }
    }
}
pub struct DStreamProps {
    c_m: f64,
    c_l: f64,
    lambda: f64,
    beta: f64,
    i_bins: usize,
    j_bins: usize,
    i_range: (f64, f64),
    j_range: (f64, f64),
}

/*

input data: [(x, y, v)]

///some impl
for some time t in 0..:
  _.put t, [(x, y, v)]

//some other impl
fn put (t, [(x, y, v)]):
  [(i, j, sum_vals)] = [x,y,v].map(i,j,v).groupby(i,j).reduce(_+_)
  foreach:
    g = density_grids[i, j]
    g.update(t, sum_vals)
    print g.get()
*/

#[derive(Clone)]
struct RawData {
    x: f64,
    y: f64,
    v: f64,
}

#[derive(Clone)]
#[derive(Debug)]
struct BucketPoint {
    t: u32,
    v: f64,
}
#[derive(Clone)]
struct GridData {
    i: usize,
    j: usize,
    v: f64,
}
struct TheWorld {
//    gs: HashMap<(usize, usize), DG>,
    g_vec: Vec<((usize, usize), DG)>,
}

#[test]
fn test_new_put_works() {
    let raw_data_1 = RawData{x: 1.0, y: -1.0, v: 123.45};
    let raw_data_2 = RawData{x: 5.0, y: -7.0, v: 23.45};
    let raw_data_3 = RawData{x: 5.0, y: -7.0, v: 83.45};

    let rd_vec = vec!(raw_data_1, raw_data_2, raw_data_3);

    let t = 1;

    let default_vec : Vec<BucketPoint> = Vec::new();
    let mut world = TheWorld{g_vec: Vec::new()};
    world.init(default_vec);
    let res = world.put(t, rd_vec);

}

impl TheWorld {
    fn init(&mut self, def_bucket: Vec<BucketPoint>) {
        println!("init");
        let props: DStreamProps = DStreamProps { ..Default::default() };

        for i in 0..props.i_bins {
            for j in 0..props.j_bins {
                let z_clone = def_bucket.clone();
                let some_default_dg = DG {i: i, j: j, updates_and_vals: z_clone};
                (self.g_vec).push(((i as usize, j as usize), some_default_dg));
            }
        }
    }
    fn do_time_steps() {}
    fn do_one_time_step(t: u32, data: Vec<RawData>) {}

    fn get_by_idx(&mut self, idx: (usize, usize))-> DG {
        let  vec_f: Vec<((usize, usize), DG)> = self.g_vec.clone().into_iter().filter(|i| i.0 == idx).collect();
        vec_f[0].1.clone()
    }
    fn put(&mut self, t: u32, dat: Vec<RawData>) -> Result<(), String> {

        let with_idxs: Vec<GridData> = dat
            .iter()
            .map(|rd| self.which_idxs(rd).unwrap())
            .collect();

        let props: DStreamProps = DStreamProps { ..Default::default() };

        for (key, group) in with_idxs.iter().group_by(|gd| (gd.i, gd.j)) {
            println!("key, g size: {}{} : {}", key.0, key.1, group.len());

            let the_vec_of_vals: Vec<f64> = group.iter().map(|t| t.v).collect();

            let mut some_default_dg = DG {i: key.0, j: key.1, updates_and_vals: Vec::<BucketPoint>::new()};

            let teh_dg = self.get_by_idx(key);

//
//
//            if let Some(dg) = self.g_vec.borrow_mut().get_mut(&key) {
//                //TODO
//                //some default should be the one with new values added in:
////                dg;
//
//                (dg).borrow_mut().update(t, the_vec_of_vals);
////                (*dg) = dg.update(t, the_vec_of_vals);
//            } else {
//                //TODO
//                //this is bad
//            }

        }

//        for kv in keys_and_vals.iter() {
//            let dg_to_add = match self.gs.get(&kv.0) {
//                Some(dg) => dg ,
//                None => some_default_dg
//            };
//            dg_to_add.update(t, kv._1);
//        }

//        shared_map.borrow_mut().insert("africa", 92388);
//        shared_map.borrow_mut()["asd"] = 232;
//        shared_map.borrow_mut().insert("africa", 999992388);
//        shared_map.borrow_mut().insert("kyoto", 11837);
//        shared_map.borrow_mut().insert("piccadilly", 11826);
//        shared_map.borrow_mut().insert("marbles", 38);
//        assert!(shared_map.borrow_mut().len() == 4);

        Ok(())
    }
    fn which_idxs(&self, dat: &RawData) -> Result<GridData, String> {Ok((GridData{i:1,j:1,v:0.1}))}
}

#[derive(Debug)]
#[derive(Clone)]
struct DG {
    i: usize,
    j: usize,
    updates_and_vals: Vec<BucketPoint>,
}
impl DG {
    fn get_at_time(&self, t: u32) -> f64 {
        let last_update_time_and_value = self.get_last_update_and_value_to(t);
        let coeff = self.coeff(t, last_update_time_and_value.0);
        let d = coeff * last_update_time_and_value.1 + 1.0;

        d
    }
    fn update(mut self, t: u32, vals: Vec<f64>) {
        let sum = vals.iter().fold(0.0, |sum, x| sum + x);
        self.updates_and_vals.push(BucketPoint {t: t, v: sum});
    }

    fn get_last_update_and_value_to(&self, t: u32) -> (u32, f64) {
        //TODO
        (1, 123.232)
    }

    fn coeff(&self, t_n: u32, t_l: u32) -> f64 {
        //TODO
        100.0343
    }

 }

#[derive(Debug)]
#[derive(Copy)]
#[derive(Clone)]
pub struct GridPoint {
    i: usize, //location
    j: usize,
    density: f64,
    data_time: u32,
}

#[derive(Clone)]
pub struct Dat {
    x: f64,
    y: f64,
    val: f64,
    t: u32,
}

pub struct TheGrid {
    mat: DMat<GridPoint>,
    props: DStreamProps,
    dats: Vec<((usize, usize), Dat)>,
}

impl DensityGrid for GridPoint {

    fn get_value_at_time(&self, time: u32, lambda: f64, dats: Vec<((usize,usize),Dat)>) -> Result<f64, String> {

        //TODO time - 1 is wrong, it should be biggest time smaller than current
        let coeff = self.compute_decay_coeff_at_time(time, time - 5, lambda);

        let sum_vals = dats.iter().fold(0.0, |sum, x| sum + x.1.val);
        println!("sum vals: {}", sum_vals);
        let new_d = coeff * sum_vals + 1.0;
        println!("new D: {}", new_d);

        Ok(new_d)
    }

//    fn update_with_values(&mut self, vals: &[f64], current_time: u32, lambda: f64) -> Result<(), String> {
//        //        D(g, t n ) = λ t n −t l D(g, t l ) + 1
//        let coeff = self.compute_decay_coeff_at_time(current_time, self.data_time, lambda);
//        println!("coeff: {}", coeff);
//        let sum_vals = vals.iter().fold(0.0, |sum, x| sum + x);
//        let new_d = coeff * coeff * sum_vals + 1.0;
//        println!("sum vals: {}", sum_vals);
//        println!("new D: {}", new_d);
//        self.density = new_d;
//        self.data_time = current_time;
//        Ok(())
//    }

}

impl DensityGridSpace for TheGrid {

    fn put(&mut self, loc2d: (f64, f64), val: f64, t: u32) -> Result<(), String> {

//        println!("{}", self.density);
//        let props: DStreamProps = DStreamProps { ..Default::default() };
//        let idxs = grid_helpers::which_grid(val, props.i_range, props.j_range, props.i_bins, props.j_bins);
//        let res_update = self.update_grid_pt_density(val, 0, props.lambda);
//        println!("{}", self.density);

        if ((loc2d.0 <= self.props.i_range.1) &&
            (loc2d.0 >= self.props.i_range.0) &&
            (loc2d.1 <= self.props.j_range.1) &&
            (loc2d.1 >= self.props.j_range.0)) {

            println!("valid!");
            let idxs =
                grid_helpers::which_grid(loc2d, self.props.i_range, self.props.j_range,
                                         self.props.i_bins, self.props.j_bins).unwrap();
            let gp = &mut self.mat[idxs];

//            gp.update_with_values(&[100.0], t, self.props.lambda);

            self.dats.push((idxs, Dat {x: loc2d.0, y: loc2d.1, val: val, t:t}));

            println!("value at next time: {}",
                gp.get_value_at_time(
                    t+10,
                    self.props.lambda,
                        self.dats
                            .clone()
                            .into_iter()
                            .filter(|i| i.0 == idxs)
                            .collect::<Vec<((usize, usize), Dat)>>()).unwrap());

            println!("dats len: {}", self.dats.len());

            Ok(())
        } else {
            println!("invalid");
            Err(String::from("Invalid range"))
        }
    }
}
#[test]
fn test_put() {

    let mut grid_pt_1: GridPoint = GridPoint {i: 0, j: 0,
        density: 0.0, data_time: 0,};

    let mut grid_pt_2: GridPoint = GridPoint {i: 1, j: 0,
        density: 0.0, data_time: 0, };

    let mut grid_pt_3: GridPoint = GridPoint {i: 0, j: 1,
        density: 0.0, data_time: 0, };

    let mut grid_pt_4: GridPoint = GridPoint {i: 1, j: 1,
        density: 0.0, data_time: 0,};

    let mut v = Vec::new();
    for i in 0..100 {
        v.push(grid_pt_1)
    }

    let mut mat_thing = DMat::from_col_vec(
        10,
        10,
        &v
    );

    for i in 0..10 {

        for j in 0..10 {

            let mut g1= GridPoint
            {i: i, j: j,
                density: 0.0, data_time: 0, };

            mat_thing[(i,j)] = g1;
        }

    }

    let mut the_grid = TheGrid {mat: mat_thing, props: DStreamProps { ..Default::default() }, dats: Vec::new()};

    let res_put = the_grid.put((-6.0, 6.0), 100.0, 1).unwrap();
    let res_put = the_grid.put((-6.0, 6.0), 100.0, 10).unwrap();
    let res_put = the_grid.put((-6.0, 6.0), 100.0, 100).unwrap();
    let res_put = the_grid.put((-6.0, 6.0), 100.0, 1000).unwrap();
    let res_put = the_grid.put((-6.0, 6.0), 100.0, 10000).unwrap();

    for i in 0..10 {
        for j in 0..10 {
            let gp: &GridPoint = &the_grid.mat[(i as usize, j as usize)];
            assert_eq!(0.0, gp.density)
        }
    }
}

#[test]
fn test_initialize_clustering() {
    const loc_i: usize = 0 as usize;
    const loc_j: usize = 0 as usize;
    const G1: GridPoint = GridPoint
    {i: loc_i, j: loc_j,
        density: 0.0, data_time: 0, };
    let result = initialize_clustering(DMat::from_row_vec(2,2, &[G1, G1, G1, G1]));
    assert_eq!(Ok(()), result);
}

pub fn initialize_clustering(grid_list: DMat<GridPoint>) -> Result<(), String> {
    //update density of all grids in grid_list
    //assign each dense grid to a distinct cluster
    //label all other grids as NO_CLASS; bad grids!
    /*
    do until no change in cluster labels
          foreach cluster c
            foreach outside grid g of c
                foreach neighboring grid h of g
                    if h belongs to cluster c'
                        if |c| > |c'| label all grids in c' as c
                        else label all grids in c as c'
                    else if (h is translational) label h as in c
    end do
    */
    Ok(())
}

pub fn adjust_clustering(grid_list: DMat<GridPoint>) -> Result<(), String> {
    //update the density of all grids in grid_list
    /*
    foreach grid g whose attribute (dense/sparse/transitional) is changed since last call to adjust_clustering()
        if g is a sparse grid
            delete g from its cluster c, label g as NO_CLASS
            if (c becomes unconnected) split c into two clusters
        else if g is a dense grid
            among all neighboring grids of g, find out the grid h whoe cluster c_h has the largest size
            if h is a dense grid
                if (g is labelled as NO_CLASS) label g as in c_h
                else if (g is in cluster c and |c| > |c_h|)
                    label all grids in c_h as in c
                else if (g is in cluster c and |c| <= |c_h|)
                    label all grids in c as in c_h
            else if h is a transitional grid
                if ((g is NO_CLASS) and (h is an outside grid if g is added to c_h)) label g as in c_h
                else if (g is in cluster c and |c| >= |c_h|)
                    move h from cluster c_h to c
        else if (g is transitional grid)
            among neighboring clusters of g, find the largest one c'
            satisfying that g is an outside grid if added to it and
            label g as in c'
    */

    Ok(())
}<commit_msg>remove old impl<commit_after>use na::{Mat2, DMat};
use std::collections::HashMap;
use std::num::*;
use itertools::Itertools;
use std::cell::RefCell;
use std::rc::Rc;

mod test;

#[test]
fn test_which_grid() {
    let loc = (-6., 6.);
    let i_rn = (-10.0, 10.0);
    let j_rn = (-10.0, 10.0);
    let i_bins = 10 as usize;
    let j_bins = 10 as usize;

    let result = grid_helpers::which_grid(loc, i_rn, j_rn, i_bins, j_bins).unwrap();
    assert_eq!((2, 8), result);

}

mod grid_helpers {
    pub fn which_grid(val: (f64, f64), i_range: (f64, f64), j_range: (f64, f64), i_bins: usize, j_bins: usize) -> Result<(usize, usize), String> {
        let i_size = (i_range.1 - i_range.0) / i_bins as f64;
        let i_number_of_sizes = ((val.0 - i_range.0) / i_size) as usize;
        let j_size = (j_range.1 - j_range.0) / j_bins as f64;
        let j_number_of_sizes = ((val.1 - j_range.0) / j_size) as usize;

        assert!(i_number_of_sizes < i_bins);
        assert!(j_number_of_sizes < j_bins);

        Ok((i_number_of_sizes, j_number_of_sizes))
    }

//
//        fn get_value_at_time(&self, time: u32, lambda: f64, dats: Vec<((usize,usize),Dat)>) -> Result<f64, String> {
//
//    //TODO time - 1 is wrong, it should be biggest time smaller than current
//    let coeff = self.compute_decay_coeff_at_time(time, time - 5, lambda);
//
//    let sum_vals = dats.iter().fold(0.0, |sum, x| sum + x.1.val);
//    println!("sum vals: {}", sum_vals);
//    let new_d = coeff * sum_vals + 1.0;
//    println!("new D: {}", new_d);
//
//    Ok(new_d)
//    }

//        fn compute_decay_coeff_at_time(&self, t_n: u32, t_l: u32, lambda: f64) -> f64 {
//    lambda.powf((t_n - t_l) as f64)
//    }
}

impl Default for DStreamProps {
    fn default() -> DStreamProps {
        DStreamProps {
            c_m: 3.0,
            c_l: 0.8,
            lambda: 0.998,
            beta: 0.3,
            i_bins: 10 as usize,
            j_bins: 10 as usize,
            i_range: (-10.0, 10.0),
            j_range: (-10.0, 10.0),
        }
    }
}
pub struct DStreamProps {
    c_m: f64,
    c_l: f64,
    lambda: f64,
    beta: f64,
    i_bins: usize,
    j_bins: usize,
    i_range: (f64, f64),
    j_range: (f64, f64),
}

/*

input data: [(x, y, v)]

///some impl
for some time t in 0..:
  _.put t, [(x, y, v)]

//some other impl
fn put (t, [(x, y, v)]):
  [(i, j, sum_vals)] = [x,y,v].map(i,j,v).groupby(i,j).reduce(_+_)
  foreach:
    g = density_grids[i, j]
    g.update(t, sum_vals)
    print g.get()
*/

#[derive(Clone)]
pub struct RawData {
    x: f64,
    y: f64,
    v: f64,
}

#[derive(Clone)]
#[derive(Debug)]
#[derive(Copy)]
struct BucketPoint {
    t: u32,
    v: f64,
}
#[derive(Clone)]
struct GridData {
    i: usize,
    j: usize,
    v: f64,
}
struct TheWorld {
    g_vec: Vec<((usize, usize), DG)>,
}

#[test]
fn test_new_put_works() {
    let raw_data_1 = RawData{x: 1.0, y: -1.0, v: 123.45};
    let raw_data_2 = RawData{x: 5.0, y: -7.0, v: 23.45};
    let raw_data_3 = RawData{x: 5.0, y: -7.0, v: 83.45};

    let rd_vec = vec!(raw_data_1, raw_data_2, raw_data_3);

    let t = 1;

    let default_vec : Vec<BucketPoint> = Vec::new();
    let mut world = TheWorld{g_vec: Vec::new()};
    world.init(default_vec);
    let res1 = world.put(t, rd_vec.clone());
    let res2 = world.put(t + 1, rd_vec.clone());
    let res3 = world.put(t + 2, rd_vec.clone());

}

impl TheWorld {
    fn init(&mut self, def_bucket: Vec<BucketPoint>) {
        println!("init");
        let props: DStreamProps = DStreamProps { ..Default::default() };

        for i in 0..props.i_bins {
            for j in 0..props.j_bins {
                let z_clone = def_bucket.clone();
                let some_default_dg = DG {i: i, j: j, updates_and_vals: z_clone};
                (self.g_vec).push(((i as usize, j as usize), some_default_dg));
            }
        }
    }
    fn do_time_steps() {}
    fn do_one_time_step(t: u32, data: Vec<RawData>) {}

    fn get_by_idx(&mut self, idx: (usize, usize))-> DG {
        let  vec_f: Vec<((usize, usize), DG)> = self.g_vec.clone().into_iter().filter(|i| i.0 == idx).collect();
        vec_f[0].1.clone()
    }
    fn update_by_idx(&mut self, idx: (usize, usize), dg: DG) -> Result<(), String> {
        self.g_vec.retain(|i| i.0 != idx);
        self.g_vec.push((idx, dg));
        Ok(())
    }
    fn put(&mut self, t: u32, dat: Vec<RawData>) -> Result<(), String> {

//        if ((loc2d.0 <= self.props.i_range.1) &&
//        (loc2d.0 >= self.props.i_range.0) &&
//        (loc2d.1 <= self.props.j_range.1) &&
//        (loc2d.1 >= self.props.j_range.0)) {
//
//            println!("valid!");
//            let idxs =
//            grid_helpers::which_grid(loc2d, self.props.i_range, self.props.j_range,
//                                     self.props.i_bins, self.props.j_bins).unwrap();

        let with_idxs: Vec<GridData> = dat
            .iter()
            .map(|rd| self.which_idxs(rd).unwrap())
            .collect();

        let props: DStreamProps = DStreamProps { ..Default::default() };

        for (key, group) in with_idxs.iter().group_by(|gd| (gd.i, gd.j)) {
            println!("--put: key, g size: {}{} : {}", key.0, key.1, group.len());

            let the_vec_of_vals: Vec<f64> = group.iter().map(|t| t.v).collect();

            let mut some_default_dg = DG {i: key.0, j: key.1, updates_and_vals: Vec::<BucketPoint>::new()};

            let teh_dg: &mut DG = &mut self.get_by_idx(key);
            let update_dg_result = teh_dg.update(t, the_vec_of_vals);
            let udpate_world_result = self.update_by_idx(key, teh_dg.clone());
        }
        Ok(())
    }
    fn which_idxs(&self, dat: &RawData) -> Result<GridData, String> {Ok((GridData{i:1,j:1,v:0.1}))}
}

#[derive(Debug)]
#[derive(Clone)]
//#[derive(Copy)] TODO: how to make this work?
struct DG {
    i: usize,
    j: usize,
    updates_and_vals: Vec<BucketPoint>,
}
impl DG {
    fn get_at_time(&self, t: u32) -> f64 {
        let last_update_time_and_value = self.get_last_update_and_value_to(t);
        let coeff = self.coeff(t, last_update_time_and_value.0);
        let d = coeff * last_update_time_and_value.1 + 1.0;

        d
    }
    fn update(&mut self, t: u32, vals: Vec<f64>) -> Result<(), String> {
        let sum = vals.clone().iter().fold(0.0, |sum, x| sum + x);
        self.updates_and_vals.push(BucketPoint {t: t, v: sum});
        println!("vals len from dg: {}", self.updates_and_vals.len());
        Ok(())
    }

    fn get_last_update_and_value_to(&self, t: u32) -> (u32, f64) {
        //TODO
        (1, 123.232)
    }

    fn coeff(&self, t_n: u32, t_l: u32) -> f64 {
        //TODO
        100.0343
    }

 }

#[test]
fn test_initialize_clustering() {

    let result = initialize_clustering(Vec::new());
    assert_eq!(Ok(()), result);
}

pub fn initialize_clustering(grid_list: Vec<RawData>) -> Result<(), String> {
    //update density of all grids in grid_list
    //assign each dense grid to a distinct cluster
    //label all other grids as NO_CLASS; bad grids!
    /*
    do until no change in cluster labels
          foreach cluster c
            foreach outside grid g of c
                foreach neighboring grid h of g
                    if h belongs to cluster c'
                        if |c| > |c'| label all grids in c' as c
                        else label all grids in c as c'
                    else if (h is translational) label h as in c
    end do
    */
    Ok(())
}

pub fn adjust_clustering(grid_list: Vec<RawData>) -> Result<(), String> {
    //update the density of all grids in grid_list
    /*
    foreach grid g whose attribute (dense/sparse/transitional) is changed since last call to adjust_clustering()
        if g is a sparse grid
            delete g from its cluster c, label g as NO_CLASS
            if (c becomes unconnected) split c into two clusters
        else if g is a dense grid
            among all neighboring grids of g, find out the grid h whoe cluster c_h has the largest size
            if h is a dense grid
                if (g is labelled as NO_CLASS) label g as in c_h
                else if (g is in cluster c and |c| > |c_h|)
                    label all grids in c_h as in c
                else if (g is in cluster c and |c| <= |c_h|)
                    label all grids in c as in c_h
            else if h is a transitional grid
                if ((g is NO_CLASS) and (h is an outside grid if g is added to c_h)) label g as in c_h
                else if (g is in cluster c and |c| >= |c_h|)
                    move h from cluster c_h to c
        else if (g is transitional grid)
            among neighboring clusters of g, find the largest one c'
            satisfying that g is an outside grid if added to it and
            label g as in c'
    */

    Ok(())
}<|endoftext|>


<commit_before>use cliargsparser::CliArgsParser;
use dirs;
use gettextrs::gettext;
use libc;
use logger::{self, Level};
use std::fs::{self, DirBuilder};
use std::io;
use std::os::unix::fs::DirBuilderExt;
use std::path::{Path, PathBuf};
use xdg;

pub const NEWSBOAT_SUBDIR_XDG: &str = "newsboat";
pub const NEWSBOAT_CONFIG_SUBDIR: &str = ".newsboat";
pub const NEWSBEUTER_SUBDIR_XDG: &str = "newsbeuter";
pub const NEWSBEUTER_CONFIG_SUBDIR: &str = ".newsbeuter";
pub const LOCK_SUFFIX: &str = ".lock";

#[derive(Debug)]
pub struct ConfigPaths {
    env_home: PathBuf,
    error_message: String,

    data_dir: PathBuf,
    config_dir: PathBuf,

    url_file: String,
    cache_file: String,
    config_file: String,
    lock_file: String,
    queue_file: String,
    search_file: String,
    cmdline_file: String,

    silent: bool,
    using_nonstandard_configs: bool,
}

impl ConfigPaths {
    pub fn new() -> ConfigPaths {
        let mut config_paths = ConfigPaths {
            env_home: PathBuf::new(),
            error_message: String::new(),

            data_dir: PathBuf::new(),
            config_dir: PathBuf::new(),

            url_file: String::from("urls"),
            cache_file: String::from("cache.db"),
            config_file: String::from("config"),
            lock_file: String::new(),
            queue_file: String::from("queue"),
            search_file: String::new(),
            cmdline_file: String::new(),

            silent: false,
            using_nonstandard_configs: false,
        };

        let env_home = dirs::home_dir();
        if env_home.is_none() {
            let uid = unsafe { libc::getuid() };

            config_paths.error_message = fmt!(
                &gettext(
                    "Fatal error: couldn't determine home directory!\n\
                     Please set the HOME environment variable or add \
                     a valid user for UID %u!"
                ),
                uid
            );

            return config_paths;
        }

        // hitting this branch means we found a home directory
        // we can now safely call unwrap on all other functions in the dirs crate

        config_paths.env_home = env_home.unwrap();
        config_paths.find_dirs();
        config_paths
    }

    fn migrate_data_from_newsbeuter_xdg(&mut self) -> bool {
        // This can't panic because we've tested we can find the home directory in ConfigPaths::new
        // This should be replaced with proper error handling after this is not used by c++ anymore
        let xdg_dirs = xdg::BaseDirectories::new().unwrap();
        let xdg_config_dir = xdg_dirs.get_config_home();
        let xdg_data_dir = xdg_dirs.get_data_home();

        let newsbeuter_config_dir = xdg_config_dir.join(NEWSBEUTER_SUBDIR_XDG);
        let newsbeuter_data_dir = xdg_data_dir.join(NEWSBEUTER_SUBDIR_XDG);

        let newsboat_config_dir = xdg_config_dir.join(NEWSBOAT_SUBDIR_XDG);
        let newsboat_data_dir = xdg_data_dir.join(NEWSBOAT_SUBDIR_XDG);

        if !newsbeuter_config_dir.is_dir() {
            return false;
        }

        fn exists(path: &Path) -> bool {
            let exists = path.exists();
            if exists {
                log!(
                    Level::Debug,
                    "{:?} already exists, aborting XDG migration.",
                    path
                );
            }
            return exists;
        }

        if exists(&newsboat_config_dir) {
            return false;
        }

        if exists(&newsboat_data_dir) {
            return false;
        }

        self.config_dir = newsboat_config_dir;
        self.data_dir = newsboat_data_dir;

        if !self.silent {
            eprintln!("Migrating configs and data from Newsbeuter's XDG dirs...");
        }

        if !try_mkdir(&self.config_dir) {
            return false;
        }

        if !try_mkdir(&self.data_dir) {
            return false;
        }

        // We ignore the return codes because it's okay if some files are missing.

        // in config
        let _ = migrate_file(&newsbeuter_config_dir, &self.config_dir, "urls");
        let _ = migrate_file(&newsbeuter_config_dir, &self.config_dir, "config");

        // in data
        let _ = migrate_file(&newsbeuter_data_dir, &self.data_dir, "cache.db");
        let _ = migrate_file(&newsbeuter_data_dir, &self.data_dir, "queue");
        let _ = migrate_file(&newsbeuter_data_dir, &self.data_dir, "history.search");
        let _ = migrate_file(&newsbeuter_data_dir, &self.data_dir, "history.cmdline");

        return true;
    }

    fn migrate_data_from_newsbeuter_simple(&self) -> bool {
        let newsbeuter_dir = self.env_home.join(NEWSBEUTER_CONFIG_SUBDIR);

        if !newsbeuter_dir.is_dir() {
            return false;
        }

        let newsboat_dir = self.env_home.join(NEWSBOAT_CONFIG_SUBDIR);

        if newsboat_dir.exists() {
            log!(
                Level::Debug,
                "{:?} already exists, aborting migration.",
                newsboat_dir
            );
            return false;
        }

        if !self.silent {
            eprintln!("Migrating configs and data from Newsbeuter's dotdir...");
        }

        match mkdir(&newsboat_dir, 0o700) {
            Ok(_) => (),
            Err(ref e) if e.kind() == io::ErrorKind::AlreadyExists => (),
            Err(err) => {
                if !self.silent {
                    eprintln!(
                        "Aborting migration because mkdir on {:?} failed: {}",
                        newsboat_dir, err
                    );
                }
                return false;
            }
        };

        // We ignore the return codes because it's okay if some files are missing.
        let _ = migrate_file(&newsbeuter_dir, &newsboat_dir, "urls");
        let _ = migrate_file(&newsbeuter_dir, &newsboat_dir, "cache.db");
        let _ = migrate_file(&newsbeuter_dir, &newsboat_dir, "config");
        let _ = migrate_file(&newsbeuter_dir, &newsboat_dir, "queue");
        let _ = migrate_file(&newsbeuter_dir, &newsboat_dir, "history.search");
        let _ = migrate_file(&newsbeuter_dir, &newsboat_dir, "history.cmdline");

        return true;
    }

    fn migrate_data_from_newsbeuter(&mut self) -> bool {
        let mut migrated = self.migrate_data_from_newsbeuter_xdg();

        if migrated {
            // Re-running to pick up XDG dirs
            self.url_file = "urls".into();
            self.cache_file = "cache.db".into();
            self.config_file = "config".into();
            self.queue_file = "queue".into();
            self.find_dirs();
        } else {
            migrated = self.migrate_data_from_newsbeuter_simple();
        }

        migrated
    }

    pub fn create_dirs(&self) -> bool {
        return try_mkdir(&self.config_dir) && try_mkdir(&self.data_dir);
    }

    fn find_dirs(&mut self) {
        self.config_dir = self.env_home.join(NEWSBOAT_CONFIG_SUBDIR);

        self.data_dir = self.config_dir.clone();

        // Will change config_dir and data_dir to point to XDG if XDG
        // directories are available.
        self.find_dirs_xdg();

        // in config
        self.url_file = self
            .config_dir
            .join(&self.url_file)
            .to_string_lossy()
            .into();
        self.config_file = self
            .config_dir
            .join(&self.config_file)
            .to_string_lossy()
            .into();

        // in data
        self.cache_file = self
            .data_dir
            .join(&self.cache_file)
            .to_string_lossy()
            .into();
        self.lock_file = self.cache_file.clone() + LOCK_SUFFIX;
        self.queue_file = self
            .data_dir
            .join(&self.queue_file)
            .to_string_lossy()
            .into();
        self.search_file = self
            .data_dir
            .join("history.search")
            .to_string_lossy()
            .into();
        self.cmdline_file = self
            .data_dir
            .join("history.cmdline")
            .to_string_lossy()
            .into();
    }

    fn find_dirs_xdg(&mut self) {
        // This can't panic because we've tested we can find the home directory in ConfigPaths::new
        // This should be replaced with proper error handling after this is not used by c++ anymore
        let xdg_dirs = xdg::BaseDirectories::new().unwrap();
        let config_dir = xdg_dirs.get_config_home().join(NEWSBOAT_SUBDIR_XDG);
        let data_dir = xdg_dirs.get_data_home().join(NEWSBOAT_SUBDIR_XDG);

        if !config_dir.is_dir() {
            return;
        }

        /* Invariant: config dir exists.
         *
         * At this point, we're confident we'll be using XDG. We don't check if
         * data dir exists, because if it doesn't we'll create it. */

        self.config_dir = config_dir;
        self.data_dir = data_dir;
    }

    /// Indicates if the object can be used.
    ///
    /// If this method returned `false`, the cause for initialization failure can be found using
    /// `error_message()`.
    pub fn initialized(&self) -> bool {
        !self.env_home.as_os_str().is_empty()
    }

    /// Returns explanation why initialization failed.
    ///
    /// \note You shouldn't call this unless `initialized()` returns `false`.
    pub fn error_message(&self) -> &str {
        &self.error_message
    }

    /// Initializes paths to config, cache etc. from CLI arguments.
    pub fn process_args(&mut self, args: &CliArgsParser) {
        if let Some(ref url_file) = args.url_file {
            self.url_file = url_file.to_string();
        }

        if let Some(ref cache_file) = args.cache_file {
            self.cache_file = cache_file.to_string();
        }

        if let Some(ref lock_file) = args.lock_file {
            self.lock_file = lock_file.to_string();
        }

        if let Some(ref config_file) = args.config_file {
            self.config_file = config_file.to_string();
        }

        self.silent = args.silent;
        self.using_nonstandard_configs = args.using_nonstandard_configs();
    }

    /// Migrate configs and data from Newsbeuter if they exist. Return `true` if migrated
    /// something, `false` otherwise.
    pub fn try_migrate_from_newsbeuter(&mut self) -> bool {
        if !self.using_nonstandard_configs && !Path::new(&self.url_file).exists() {
            return self.migrate_data_from_newsbeuter();
        }

        // No migration occurred.
        false
    }

    /// Path to the URLs file.
    pub fn url_file(&self) -> String {
        self.url_file.clone()
    }

    /// Path to the cache file.
    pub fn cache_file(&self) -> String {
        self.cache_file.clone()
    }

    /// Sets path to the cache file.
    // FIXME: this is actually a kludge that lets Controller change the path
    // midway. That logic should be moved into ConfigPaths, and this method
    // removed.
    pub fn set_cache_file(&mut self, path: String) {
        self.cache_file = path.clone();
        self.lock_file = path + LOCK_SUFFIX;
    }

    /// Path to the config file.
    pub fn config_file(&self) -> String {
        self.config_file.clone()
    }

    /// Path to the lock file.
    ///
    /// \note This changes when path to config file changes.
    pub fn lock_file(&self) -> String {
        self.lock_file.clone()
    }

    /// \brief Path to the queue file.
    ///
    /// Queue file stores enqueued podcasts. It's written by Newsboat, and read by Podboat.
    pub fn queue_file(&self) -> String {
        self.queue_file.clone()
    }

    /// Path to the file with previous search queries.
    pub fn search_file(&self) -> String {
        self.search_file.clone()
    }

    /// Path to the file with command-line history.
    pub fn cmdline_file(&self) -> String {
        self.cmdline_file.clone()
    }
}

fn try_mkdir<R: AsRef<Path>>(path: R) -> bool {
    DirBuilder::new()
        .recursive(true)
        .mode(0o700)
        .create(path.as_ref())
        .is_ok()
}

fn mkdir<R: AsRef<Path>>(path: R, mode: u32) -> io::Result<()> {
    DirBuilder::new().mode(mode).create(path.as_ref())
}

fn migrate_file<R: AsRef<Path>>(newsbeuter_dir: R, newsboat_dir: R, file: &str) -> io::Result<()> {
    let input_filepath = newsbeuter_dir.as_ref().join(file);
    let output_filepath = newsboat_dir.as_ref().join(file);
    eprintln!("{:?} -> {:?}", input_filepath, output_filepath);
    fs::copy(input_filepath, output_filepath).map(|_| ())
}
<commit_msg>ConfigPaths: stop repeating string constants<commit_after>use cliargsparser::CliArgsParser;
use dirs;
use gettextrs::gettext;
use libc;
use logger::{self, Level};
use std::fs::{self, DirBuilder};
use std::io;
use std::os::unix::fs::DirBuilderExt;
use std::path::{Path, PathBuf};
use xdg;

pub const NEWSBOAT_SUBDIR_XDG: &str = "newsboat";
pub const NEWSBOAT_CONFIG_SUBDIR: &str = ".newsboat";
pub const NEWSBEUTER_SUBDIR_XDG: &str = "newsbeuter";
pub const NEWSBEUTER_CONFIG_SUBDIR: &str = ".newsbeuter";
pub const LOCK_SUFFIX: &str = ".lock";

const URLS_FILENAME: &str = "urls";
const CACHE_FILENAME: &str = "cache.db";
const CONFIG_FILENAME: &str = "config";
const QUEUE_FILENAME: &str = "queue";
const SEARCH_HISTORY_FILENAME: &str = "history.search";
const CMDLINE_HISTORY_FILENAME: &str = "history.cmdline";

#[derive(Debug)]
pub struct ConfigPaths {
    env_home: PathBuf,
    error_message: String,

    data_dir: PathBuf,
    config_dir: PathBuf,

    url_file: String,
    cache_file: String,
    config_file: String,
    lock_file: String,
    queue_file: String,
    search_file: String,
    cmdline_file: String,

    silent: bool,
    using_nonstandard_configs: bool,
}

impl ConfigPaths {
    pub fn new() -> ConfigPaths {
        let mut config_paths = ConfigPaths {
            env_home: PathBuf::new(),
            error_message: String::new(),

            data_dir: PathBuf::new(),
            config_dir: PathBuf::new(),

            url_file: URLS_FILENAME.to_owned(),
            cache_file: CACHE_FILENAME.to_owned(),
            config_file: CONFIG_FILENAME.to_owned(),
            lock_file: String::new(),
            queue_file: QUEUE_FILENAME.to_owned(),
            search_file: String::new(),
            cmdline_file: String::new(),

            silent: false,
            using_nonstandard_configs: false,
        };

        let env_home = dirs::home_dir();
        if env_home.is_none() {
            let uid = unsafe { libc::getuid() };

            config_paths.error_message = fmt!(
                &gettext(
                    "Fatal error: couldn't determine home directory!\n\
                     Please set the HOME environment variable or add \
                     a valid user for UID %u!"
                ),
                uid
            );

            return config_paths;
        }

        // hitting this branch means we found a home directory
        // we can now safely call unwrap on all other functions in the dirs crate

        config_paths.env_home = env_home.unwrap();
        config_paths.find_dirs();
        config_paths
    }

    fn migrate_data_from_newsbeuter_xdg(&mut self) -> bool {
        // This can't panic because we've tested we can find the home directory in ConfigPaths::new
        // This should be replaced with proper error handling after this is not used by c++ anymore
        let xdg_dirs = xdg::BaseDirectories::new().unwrap();
        let xdg_config_dir = xdg_dirs.get_config_home();
        let xdg_data_dir = xdg_dirs.get_data_home();

        let newsbeuter_config_dir = xdg_config_dir.join(NEWSBEUTER_SUBDIR_XDG);
        let newsbeuter_data_dir = xdg_data_dir.join(NEWSBEUTER_SUBDIR_XDG);

        let newsboat_config_dir = xdg_config_dir.join(NEWSBOAT_SUBDIR_XDG);
        let newsboat_data_dir = xdg_data_dir.join(NEWSBOAT_SUBDIR_XDG);

        if !newsbeuter_config_dir.is_dir() {
            return false;
        }

        fn exists(path: &Path) -> bool {
            let exists = path.exists();
            if exists {
                log!(
                    Level::Debug,
                    "{:?} already exists, aborting XDG migration.",
                    path
                );
            }
            return exists;
        }

        if exists(&newsboat_config_dir) {
            return false;
        }

        if exists(&newsboat_data_dir) {
            return false;
        }

        self.config_dir = newsboat_config_dir;
        self.data_dir = newsboat_data_dir;

        if !self.silent {
            eprintln!("Migrating configs and data from Newsbeuter's XDG dirs...");
        }

        if !try_mkdir(&self.config_dir) {
            return false;
        }

        if !try_mkdir(&self.data_dir) {
            return false;
        }

        // We ignore the return codes because it's okay if some files are missing.

        // in config
        let _ = migrate_file(&newsbeuter_config_dir, &self.config_dir, URLS_FILENAME);
        let _ = migrate_file(&newsbeuter_config_dir, &self.config_dir, CONFIG_FILENAME);

        // in data
        let _ = migrate_file(&newsbeuter_data_dir, &self.data_dir, CACHE_FILENAME);
        let _ = migrate_file(&newsbeuter_data_dir, &self.data_dir, QUEUE_FILENAME);
        let _ = migrate_file(
            &newsbeuter_data_dir,
            &self.data_dir,
            SEARCH_HISTORY_FILENAME,
        );
        let _ = migrate_file(
            &newsbeuter_data_dir,
            &self.data_dir,
            CMDLINE_HISTORY_FILENAME,
        );

        return true;
    }

    fn migrate_data_from_newsbeuter_simple(&self) -> bool {
        let newsbeuter_dir = self.env_home.join(NEWSBEUTER_CONFIG_SUBDIR);

        if !newsbeuter_dir.is_dir() {
            return false;
        }

        let newsboat_dir = self.env_home.join(NEWSBOAT_CONFIG_SUBDIR);

        if newsboat_dir.exists() {
            log!(
                Level::Debug,
                "{:?} already exists, aborting migration.",
                newsboat_dir
            );
            return false;
        }

        if !self.silent {
            eprintln!("Migrating configs and data from Newsbeuter's dotdir...");
        }

        match mkdir(&newsboat_dir, 0o700) {
            Ok(_) => (),
            Err(ref e) if e.kind() == io::ErrorKind::AlreadyExists => (),
            Err(err) => {
                if !self.silent {
                    eprintln!(
                        "Aborting migration because mkdir on {:?} failed: {}",
                        newsboat_dir, err
                    );
                }
                return false;
            }
        };

        // We ignore the return codes because it's okay if some files are missing.
        let _ = migrate_file(&newsbeuter_dir, &newsboat_dir, URLS_FILENAME);
        let _ = migrate_file(&newsbeuter_dir, &newsboat_dir, CACHE_FILENAME);
        let _ = migrate_file(&newsbeuter_dir, &newsboat_dir, CONFIG_FILENAME);
        let _ = migrate_file(&newsbeuter_dir, &newsboat_dir, QUEUE_FILENAME);
        let _ = migrate_file(&newsbeuter_dir, &newsboat_dir, SEARCH_HISTORY_FILENAME);
        let _ = migrate_file(&newsbeuter_dir, &newsboat_dir, CMDLINE_HISTORY_FILENAME);

        return true;
    }

    fn migrate_data_from_newsbeuter(&mut self) -> bool {
        let mut migrated = self.migrate_data_from_newsbeuter_xdg();

        if migrated {
            // Re-running to pick up XDG dirs
            self.url_file = URLS_FILENAME.into();
            self.cache_file = CACHE_FILENAME.into();
            self.config_file = CONFIG_FILENAME.into();
            self.queue_file = QUEUE_FILENAME.into();
            self.find_dirs();
        } else {
            migrated = self.migrate_data_from_newsbeuter_simple();
        }

        migrated
    }

    pub fn create_dirs(&self) -> bool {
        return try_mkdir(&self.config_dir) && try_mkdir(&self.data_dir);
    }

    fn find_dirs(&mut self) {
        self.config_dir = self.env_home.join(NEWSBOAT_CONFIG_SUBDIR);

        self.data_dir = self.config_dir.clone();

        // Will change config_dir and data_dir to point to XDG if XDG
        // directories are available.
        self.find_dirs_xdg();

        // in config
        self.url_file = self
            .config_dir
            .join(&self.url_file)
            .to_string_lossy()
            .into();
        self.config_file = self
            .config_dir
            .join(&self.config_file)
            .to_string_lossy()
            .into();

        // in data
        self.cache_file = self
            .data_dir
            .join(&self.cache_file)
            .to_string_lossy()
            .into();
        self.lock_file = self.cache_file.clone() + LOCK_SUFFIX;
        self.queue_file = self
            .data_dir
            .join(&self.queue_file)
            .to_string_lossy()
            .into();
        self.search_file = self
            .data_dir
            .join(SEARCH_HISTORY_FILENAME)
            .to_string_lossy()
            .into();
        self.cmdline_file = self
            .data_dir
            .join(CMDLINE_HISTORY_FILENAME)
            .to_string_lossy()
            .into();
    }

    fn find_dirs_xdg(&mut self) {
        // This can't panic because we've tested we can find the home directory in ConfigPaths::new
        // This should be replaced with proper error handling after this is not used by c++ anymore
        let xdg_dirs = xdg::BaseDirectories::new().unwrap();
        let config_dir = xdg_dirs.get_config_home().join(NEWSBOAT_SUBDIR_XDG);
        let data_dir = xdg_dirs.get_data_home().join(NEWSBOAT_SUBDIR_XDG);

        if !config_dir.is_dir() {
            return;
        }

        /* Invariant: config dir exists.
         *
         * At this point, we're confident we'll be using XDG. We don't check if
         * data dir exists, because if it doesn't we'll create it. */

        self.config_dir = config_dir;
        self.data_dir = data_dir;
    }

    /// Indicates if the object can be used.
    ///
    /// If this method returned `false`, the cause for initialization failure can be found using
    /// `error_message()`.
    pub fn initialized(&self) -> bool {
        !self.env_home.as_os_str().is_empty()
    }

    /// Returns explanation why initialization failed.
    ///
    /// \note You shouldn't call this unless `initialized()` returns `false`.
    pub fn error_message(&self) -> &str {
        &self.error_message
    }

    /// Initializes paths to config, cache etc. from CLI arguments.
    pub fn process_args(&mut self, args: &CliArgsParser) {
        if let Some(ref url_file) = args.url_file {
            self.url_file = url_file.to_string();
        }

        if let Some(ref cache_file) = args.cache_file {
            self.cache_file = cache_file.to_string();
        }

        if let Some(ref lock_file) = args.lock_file {
            self.lock_file = lock_file.to_string();
        }

        if let Some(ref config_file) = args.config_file {
            self.config_file = config_file.to_string();
        }

        self.silent = args.silent;
        self.using_nonstandard_configs = args.using_nonstandard_configs();
    }

    /// Migrate configs and data from Newsbeuter if they exist. Return `true` if migrated
    /// something, `false` otherwise.
    pub fn try_migrate_from_newsbeuter(&mut self) -> bool {
        if !self.using_nonstandard_configs && !Path::new(&self.url_file).exists() {
            return self.migrate_data_from_newsbeuter();
        }

        // No migration occurred.
        false
    }

    /// Path to the URLs file.
    pub fn url_file(&self) -> String {
        self.url_file.clone()
    }

    /// Path to the cache file.
    pub fn cache_file(&self) -> String {
        self.cache_file.clone()
    }

    /// Sets path to the cache file.
    // FIXME: this is actually a kludge that lets Controller change the path
    // midway. That logic should be moved into ConfigPaths, and this method
    // removed.
    pub fn set_cache_file(&mut self, path: String) {
        self.cache_file = path.clone();
        self.lock_file = path + LOCK_SUFFIX;
    }

    /// Path to the config file.
    pub fn config_file(&self) -> String {
        self.config_file.clone()
    }

    /// Path to the lock file.
    ///
    /// \note This changes when path to config file changes.
    pub fn lock_file(&self) -> String {
        self.lock_file.clone()
    }

    /// \brief Path to the queue file.
    ///
    /// Queue file stores enqueued podcasts. It's written by Newsboat, and read by Podboat.
    pub fn queue_file(&self) -> String {
        self.queue_file.clone()
    }

    /// Path to the file with previous search queries.
    pub fn search_file(&self) -> String {
        self.search_file.clone()
    }

    /// Path to the file with command-line history.
    pub fn cmdline_file(&self) -> String {
        self.cmdline_file.clone()
    }
}

fn try_mkdir<R: AsRef<Path>>(path: R) -> bool {
    DirBuilder::new()
        .recursive(true)
        .mode(0o700)
        .create(path.as_ref())
        .is_ok()
}

fn mkdir<R: AsRef<Path>>(path: R, mode: u32) -> io::Result<()> {
    DirBuilder::new().mode(mode).create(path.as_ref())
}

fn migrate_file<R: AsRef<Path>>(newsbeuter_dir: R, newsboat_dir: R, file: &str) -> io::Result<()> {
    let input_filepath = newsbeuter_dir.as_ref().join(file);
    let output_filepath = newsboat_dir.as_ref().join(file);
    eprintln!("{:?} -> {:?}", input_filepath, output_filepath);
    fs::copy(input_filepath, output_filepath).map(|_| ())
}
<|endoftext|>


<commit_before>use seed::prelude::*;
use crate::Msg;

use num_traits::{ToPrimitive};

const PERFECTS_COUNT: usize = 27;

mod perfects_utils {
	use num_bigint::{BigUint,ToBigUint};
    use seed::prelude::*;
	use crate::Model;
    use crate::Msg;

	pub struct Perfect<'a> {
		pub n: u64,
		pub p: u64,
		pub digits: u64,
		pub discovery: &'a str,
	}

	pub fn perfects<'a>() -> Vec<Perfect<'a>> {
        vec![
			/*Perfect {n: 51, p: 82589934, digits: 49724095, discovery: "2018 Laroche, Woltman, Kurowski, Blosser, et al."},
			Perfect {n: 50, p: 77232917, digits: 46498850, discovery: "2017 Jonathan Pace, George Woltman, Scott Kurowski, Aaron Blosser, et al.." },
			Perfect {n: 49, p: 74207281, digits: 44677235, discovery: "2016 Cooper, Woltman, Kurowski, Blosser et al." },
			Perfect {n: 48, p: 57885161, digits: 34850340, discovery: "2013 Cooper, Woltman, Kurowski, et al." },
			Perfect {n: 47, p: 43112609, digits: 25956377, discovery: "2008 Smith, Woltman, Kurowski, et al." },
			Perfect {n: 46, p: 42643801, digits: 42643801, discovery: "2009 Strindmo, Woltman, Kurowski, et al." },
			Perfect {n: 45, p: 37156667, digits: 22370543, discovery: "2008 Elvenich, Woltman, Kurowski, et al." },
			Perfect {n: 44, p: 32582657, digits: 19616714, discovery: "2006 Cooper, Boone, Woltman, Kurowski, et al." },
			Perfect {n: 43, p: 30402457, digits: 18304103, discovery: "2005 Cooper, Boone, Woltman, Kurowski, et al." },
			Perfect {n: 42, p: 25964951, digits: 15632458, discovery: "2005 Nowak, Woltman, Kurowski, et. al." },
			Perfect {n: 41, p: 24036583, digits: 14471465, discovery: "2004 Findley, Woltman, Kurowski, et. al." },
			Perfect {n: 40, p: 20996011, digits: 12640858, discovery: "2003 Shafer, Woltman, Kurowski, et. al." },
			Perfect {n: 39, p: 13466917, digits: 8107892, discovery: "2001 Cameron, Woltman, Kurowski, et. al." },
			Perfect {n: 38, p: 6972593, digits: 4197919, discovery: "1999 Hajratwala, Woltman, Kurowski, et. al." },
			Perfect {n: 37, p: 3021377, digits: 1819050, discovery: "1998 Clarkson, Woltman, Kurowski, et. al." },
			Perfect {n: 36, p: 2976221, digits: 1791864, discovery: "1997 Spence, Woltman, et. al." },
			Perfect {n: 35, p: 1398269, digits: 841842, discovery: "1996 Armengaud, Woltman, et. al." },
			Perfect {n: 34, p: 1257787, digits: 757263, discovery: "1996 Slowinski&Gage" },
			Perfect {n: 33, p: 859433, digits: 517430, discovery: "1994 Slowinski&Gage" },
			Perfect {n: 32, p: 756839, digits: 455663, discovery: "1992 Slowinski&Gage" },
			Perfect {n: 31, p: 216091, digits: 130100, discovery: "1985 Slowinski" },
			Perfect {n: 30, p: 132049, digits: 79502, discovery: "1983 Slowinski" },
			Perfect {n: 29, p: 110503, digits: 66530, discovery: "1988 Colquitt&Welsh" },
			Perfect {n: 28, p: 86243, digits: 51924, discovery: "1982 Slowinski" },*/
			Perfect {n: 27, p: 44497, digits: 26790, discovery: "1979 Nelson&Slowinski" },
			Perfect {n: 26, p: 23209, digits: 13973, discovery: "1979 Noll" },
			Perfect {n: 25, p: 21701, digits: 13066, discovery: "1978 Noll&Nickel" },
			Perfect {n: 24, p: 19937, digits: 12003, discovery: "1971 Tuckerman" },
			Perfect {n: 23, p: 11213, digits: 6751, discovery: "1963 Gillies" },
			Perfect {n: 22, p: 9941, digits: 5985, discovery: "1963 Gillies" },
			Perfect {n: 21, p: 9689, digits: 5834, discovery: "1963 Gillies" },
			Perfect {n: 20, p: 4423, digits: 2663, discovery: "1961 Hurwitz" },
			Perfect {n: 19, p: 4253, digits: 2561, discovery: "1961 Hurwitz" },
			Perfect {n: 18, p: 3217, digits: 1937, discovery: "1957 Riesel" },
			Perfect {n: 17, p: 2281, digits: 1373, discovery: "1952 Robinson" },
			Perfect {n: 16, p: 2203, digits: 1327, discovery: "1952 Robinson" },
			Perfect {n: 15, p: 1279, digits: 770, discovery: "1952 Robinson" },
			Perfect {n: 14, p: 607, digits: 366, discovery: "1952 Robinson" },
			Perfect {n: 13, p: 521, digits: 314, discovery: "1952 Robinson" },
			Perfect {n: 12, p: 127, digits: 77, discovery: "1876 Lucas" },
			Perfect {n: 11, p: 107, digits: 65, discovery: "1914 Powers" },
			Perfect {n: 10, p: 89, digits: 54, discovery: "1911 Powers" },
			Perfect {n: 9, p: 61, digits: 37, discovery: "1883 Pervushin" },
			Perfect {n: 8, p: 31, digits: 19, discovery: "1772 Euler" },
			Perfect {n: 7, p: 19, digits: 12, discovery: "1588 Cataldi" },
			Perfect {n: 6, p: 17, digits: 10, discovery: "1588 Cataldi" },
			Perfect {n: 5, p: 13, digits: 8, discovery: "1456 ?" },
			Perfect {n: 4, p: 7, digits: 4, discovery: "?" },
			Perfect {n: 3, p: 5, digits: 3, discovery: "?" },
			Perfect {n: 2, p: 3, digits: 2, discovery: "?" },
			Perfect {n: 1, p: 2, digits: 1, discovery: "?" },
		]
	}

	pub fn save_as_file(filename:String, filecontent:String) -> seed::dom_types::Node<Msg> {
        let href:String = vec!["data:text/plain,",&filecontent].into_iter().collect();
        a![attrs!{At::Download => &filename, At::Href => &href}, "TXT"]
    }

	pub fn generate_file(n:usize) -> seed::dom_types::Node<Msg> {
		let download_filename:String = format!("P{}.txt",&n.to_string());
        a![attrs!{At::Download => ""}, "TXT"]
    }
}

pub fn render(model: &crate::Model) -> seed::dom_types::Node<Msg> {
    let mut html = vec![];
	let two:BigUint = 2.to_biguint().unwrap();

    let mut perfects = perfects_utils::perfects();

    for n in 0..PERFECTS_COUNT {
        let download_txt:String = format!("https://static.bigprimes.net/archive/perfect/{}.txt",&perfects[n].n.to_string());

		let equation:String = format!("2{} × (2{}-1)",&(perfects[n].p-1).to_string(),&(perfects[n].p).to_string());

		let p:usize = perfects[n].p.to_usize().unwrap();
		let power:BigUint = two.clone() << (p-1-1);
        let perfect_value:BigUint = power.clone() * ((power.clone()*two.clone()) -1.to_biguint().unwrap());

        html.push(
            tr![
                td![perfects[n].n.to_string()],//rank
				td![El::from_html(&equation)],//perfect number as a formula

                td![perfects[n].digits.to_string()],//digits in length
                td![perfects[n].discovery],//disocvery
				td![a![attrs!{At::OnClick => "",}, "Generate"]],
            ]
        );
    }

    div![
        h1!["The Perfect Numbers"],
        br![],
        br![],
        br![],
        table![
            attrs!{At::Class => "perfecttable text"},
            tbody![
                tr![
                    td![
                        b!["No."]
                    ],
                    td![
                        b!["Prime"]
                    ],
                    td![
                        b!["Digits"]
                    ],
                    td![
                        b!["Discovered"]
                    ],
                    td![
                        b!["Download"]
                    ]
                ],
                html
            ]
        ]
    ]
}

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

    #[test]
    fn perfect_test<'a>() {
        let mut perfects:Vec<perfects_utils::Perfect<'a>> = perfects_utils::perfects();
		perfects.reverse();
        assert_eq!(perfects[49].digits, 46498850);
        assert_eq!(perfects[39].digits, 12640858);
    }
}<commit_msg>Moved logic into generate_file()<commit_after>use seed::prelude::*;
use crate::Msg;

use num_traits::{ToPrimitive};

const PERFECTS_COUNT: usize = 27;

mod perfects_utils {
	use num_bigint::{BigUint,ToBigUint};
    use seed::prelude::*;
	use crate::Model;
    use crate::Msg;

	pub struct Perfect<'a> {
		pub n: u64,
		pub p: u64,
		pub digits: u64,
		pub discovery: &'a str,
	}

	pub fn perfects<'a>() -> Vec<Perfect<'a>> {
        vec![
			/*Perfect {n: 51, p: 82589934, digits: 49724095, discovery: "2018 Laroche, Woltman, Kurowski, Blosser, et al."},
			Perfect {n: 50, p: 77232917, digits: 46498850, discovery: "2017 Jonathan Pace, George Woltman, Scott Kurowski, Aaron Blosser, et al.." },
			Perfect {n: 49, p: 74207281, digits: 44677235, discovery: "2016 Cooper, Woltman, Kurowski, Blosser et al." },
			Perfect {n: 48, p: 57885161, digits: 34850340, discovery: "2013 Cooper, Woltman, Kurowski, et al." },
			Perfect {n: 47, p: 43112609, digits: 25956377, discovery: "2008 Smith, Woltman, Kurowski, et al." },
			Perfect {n: 46, p: 42643801, digits: 42643801, discovery: "2009 Strindmo, Woltman, Kurowski, et al." },
			Perfect {n: 45, p: 37156667, digits: 22370543, discovery: "2008 Elvenich, Woltman, Kurowski, et al." },
			Perfect {n: 44, p: 32582657, digits: 19616714, discovery: "2006 Cooper, Boone, Woltman, Kurowski, et al." },
			Perfect {n: 43, p: 30402457, digits: 18304103, discovery: "2005 Cooper, Boone, Woltman, Kurowski, et al." },
			Perfect {n: 42, p: 25964951, digits: 15632458, discovery: "2005 Nowak, Woltman, Kurowski, et. al." },
			Perfect {n: 41, p: 24036583, digits: 14471465, discovery: "2004 Findley, Woltman, Kurowski, et. al." },
			Perfect {n: 40, p: 20996011, digits: 12640858, discovery: "2003 Shafer, Woltman, Kurowski, et. al." },
			Perfect {n: 39, p: 13466917, digits: 8107892, discovery: "2001 Cameron, Woltman, Kurowski, et. al." },
			Perfect {n: 38, p: 6972593, digits: 4197919, discovery: "1999 Hajratwala, Woltman, Kurowski, et. al." },
			Perfect {n: 37, p: 3021377, digits: 1819050, discovery: "1998 Clarkson, Woltman, Kurowski, et. al." },
			Perfect {n: 36, p: 2976221, digits: 1791864, discovery: "1997 Spence, Woltman, et. al." },
			Perfect {n: 35, p: 1398269, digits: 841842, discovery: "1996 Armengaud, Woltman, et. al." },
			Perfect {n: 34, p: 1257787, digits: 757263, discovery: "1996 Slowinski&Gage" },
			Perfect {n: 33, p: 859433, digits: 517430, discovery: "1994 Slowinski&Gage" },
			Perfect {n: 32, p: 756839, digits: 455663, discovery: "1992 Slowinski&Gage" },
			Perfect {n: 31, p: 216091, digits: 130100, discovery: "1985 Slowinski" },
			Perfect {n: 30, p: 132049, digits: 79502, discovery: "1983 Slowinski" },
			Perfect {n: 29, p: 110503, digits: 66530, discovery: "1988 Colquitt&Welsh" },
			Perfect {n: 28, p: 86243, digits: 51924, discovery: "1982 Slowinski" },*/
			Perfect {n: 27, p: 44497, digits: 26790, discovery: "1979 Nelson&Slowinski" },
			Perfect {n: 26, p: 23209, digits: 13973, discovery: "1979 Noll" },
			Perfect {n: 25, p: 21701, digits: 13066, discovery: "1978 Noll&Nickel" },
			Perfect {n: 24, p: 19937, digits: 12003, discovery: "1971 Tuckerman" },
			Perfect {n: 23, p: 11213, digits: 6751, discovery: "1963 Gillies" },
			Perfect {n: 22, p: 9941, digits: 5985, discovery: "1963 Gillies" },
			Perfect {n: 21, p: 9689, digits: 5834, discovery: "1963 Gillies" },
			Perfect {n: 20, p: 4423, digits: 2663, discovery: "1961 Hurwitz" },
			Perfect {n: 19, p: 4253, digits: 2561, discovery: "1961 Hurwitz" },
			Perfect {n: 18, p: 3217, digits: 1937, discovery: "1957 Riesel" },
			Perfect {n: 17, p: 2281, digits: 1373, discovery: "1952 Robinson" },
			Perfect {n: 16, p: 2203, digits: 1327, discovery: "1952 Robinson" },
			Perfect {n: 15, p: 1279, digits: 770, discovery: "1952 Robinson" },
			Perfect {n: 14, p: 607, digits: 366, discovery: "1952 Robinson" },
			Perfect {n: 13, p: 521, digits: 314, discovery: "1952 Robinson" },
			Perfect {n: 12, p: 127, digits: 77, discovery: "1876 Lucas" },
			Perfect {n: 11, p: 107, digits: 65, discovery: "1914 Powers" },
			Perfect {n: 10, p: 89, digits: 54, discovery: "1911 Powers" },
			Perfect {n: 9, p: 61, digits: 37, discovery: "1883 Pervushin" },
			Perfect {n: 8, p: 31, digits: 19, discovery: "1772 Euler" },
			Perfect {n: 7, p: 19, digits: 12, discovery: "1588 Cataldi" },
			Perfect {n: 6, p: 17, digits: 10, discovery: "1588 Cataldi" },
			Perfect {n: 5, p: 13, digits: 8, discovery: "1456 ?" },
			Perfect {n: 4, p: 7, digits: 4, discovery: "?" },
			Perfect {n: 3, p: 5, digits: 3, discovery: "?" },
			Perfect {n: 2, p: 3, digits: 2, discovery: "?" },
			Perfect {n: 1, p: 2, digits: 1, discovery: "?" },
		]
	}

	pub fn save_as_file(filename:String, filecontent:String) -> seed::dom_types::Node<Msg> {
        let href:String = vec!["data:text/plain,",&filecontent].into_iter().collect();
        a![attrs!{At::Download => &filename, At::Href => &href}, "TXT"]
    }

	pub fn generate_file(n:usize, p:usize) -> seed::dom_types::Node<Msg> {
		let download_filename:String = format!("P{}.txt",&n.to_string());
		let two:BigUint = 2.to_biguint().unwrap();
		let power:BigUint = two.clone() << (p-1-1);
        let perfect_value:BigUint = power.clone() * ((power.clone()*two.clone()) -1.to_biguint().unwrap());
        a![attrs!{At::Download => ""}, "TXT"]
    }
}

pub fn render(model: &crate::Model) -> seed::dom_types::Node<Msg> {
    let mut html = vec![];
    let mut perfects = perfects_utils::perfects();

    for n in 0..PERFECTS_COUNT {
		let equation:String = format!("2{} × (2{}-1)",&(perfects[n].p-1).to_string(),&(perfects[n].p).to_string());

		let p:usize = perfects[n].p.to_usize().unwrap();

        html.push(
            tr![
                td![perfects[n].n.to_string()],//rank
				td![El::from_html(&equation)],//perfect number as a formula

                td![perfects[n].digits.to_string()],//digits in length
                td![perfects[n].discovery],//disocvery
				td![a![attrs!{At::OnClick => "",}, "Generate"]],
            ]
        );
    }

    div![
        h1!["The Perfect Numbers"],
        br![],
        br![],
        br![],
        table![
            attrs!{At::Class => "perfecttable text"},
            tbody![
                tr![
                    td![
                        b!["No."]
                    ],
                    td![
                        b!["Prime"]
                    ],
                    td![
                        b!["Digits"]
                    ],
                    td![
                        b!["Discovered"]
                    ],
                    td![
                        b!["Download"]
                    ]
                ],
                html
            ]
        ]
    ]
}

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

    #[test]
    fn perfect_test<'a>() {
        let mut perfects:Vec<perfects_utils::Perfect<'a>> = perfects_utils::perfects();
		perfects.reverse();
        assert_eq!(perfects[49].digits, 46498850);
        assert_eq!(perfects[39].digits, 12640858);
    }
}<|endoftext|>


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

fn header(input: (&[u8], usize)) -> IResult<(&[u8], usize), (u8, bool)> {
  let result = chain!(input,
    bit_padding: take_bits!(u8, 1) ~
    subframe_type: take_bits!(u8, 6) ~
    wasted_bit_flag: take_bits!(u8, 1),
    || {
      let is_valid        = bit_padding == 0;
      let has_wasted_bits = wasted_bit_flag == 1;

      (is_valid, subframe_type, has_wasted_bits)
    }
  );

  match result {
    IResult::Done(i, data)    => {
      let (is_valid, subframe_type, has_wasted_bits) = data;

      if is_valid {
        IResult::Done(i, (subframe_type, has_wasted_bits))
      } else {
        IResult::Error(Err::Position(ErrorCode::Digit as u32, input.0))
      }
    }
    IResult::Error(error)     => IResult::Error(error),
    IResult::Incomplete(need) => IResult::Incomplete(need),
  }
}
<commit_msg>Add parser for leading zeros<commit_after>use nom::{
  IResult,
  ErrorCode, Err,
  Needed,
};

fn leading_zeros(input: (&[u8], usize)) -> IResult<(&[u8], usize), u32> {
  let (bytes, mut offset) = input;

  let mut index     = 0;
  let mut count     = 0;
  let mut is_parsed = false;
  let bytes_len     = bytes.len();

  for i in 0..bytes_len {
    // Clear the number of offset bits
    let byte  = bytes[i] << offset;
    let zeros = byte.leading_zeros() as usize;

    if byte > 0 {
      index     = i;
      is_parsed = true;
      count    += zeros;
      offset   += zeros + 1;

      if offset >= 8 {
        index  += 1;
        offset -= 8;
      }

      break;
    } else {
      count += zeros - offset;
      offset = 0;
    }
  }

  if is_parsed {
    IResult::Done((&bytes[index..], offset), count as u32)
  } else if index + 1 > bytes_len {
    IResult::Incomplete(Needed::Size(index + 1))
  } else {
    IResult::Error(Err::Position(ErrorCode::TakeUntil as u32, bytes))
  }
}

fn header(input: (&[u8], usize)) -> IResult<(&[u8], usize), (u8, bool)> {
  let result = chain!(input,
    bit_padding: take_bits!(u8, 1) ~
    subframe_type: take_bits!(u8, 6) ~
    wasted_bit_flag: take_bits!(u8, 1),
    || {
      let is_valid        = bit_padding == 0;
      let has_wasted_bits = wasted_bit_flag == 1;

      (is_valid, subframe_type, has_wasted_bits)
    }
  );

  match result {
    IResult::Done(i, data)    => {
      let (is_valid, subframe_type, has_wasted_bits) = data;

      if is_valid {
        IResult::Done(i, (subframe_type, has_wasted_bits))
      } else {
        IResult::Error(Err::Position(ErrorCode::Digit as u32, input.0))
      }
    }
    IResult::Error(error)     => IResult::Error(error),
    IResult::Incomplete(need) => IResult::Incomplete(need),
  }
}
<|endoftext|>


<commit_before>use socket::Socket;

pub enum Source {
    OUT1,
    OUT2,
}

impl ::std::fmt::Display for Source {
    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
        let display = match self {
            &Source::OUT1 => "SOUR1",
            &Source::OUT2 => "SOUR2",
        };

        write!(f, "{}", display)
    }
}

pub struct Burst {
    socket: Socket,
}

impl Burst {
    pub fn new(socket: Socket) -> Self {
        Burst {
            socket: socket,
        }
    }

    pub fn enable(&mut self, source: Source) {
        self.socket.send(format!("{}:BURS:STAT ON", source));
    }

    pub fn disable(&mut self, source: Source) {
        self.socket.send(format!("{}:BURS:STAT OFF", source));
    }

    pub fn set_count(&mut self, source: Source, count: u32) {
        self.socket.send(format!("{}:BURS:NCYC {}", source, count));
    }

    pub fn set_repetitions(&mut self, source: Source, repetitions: u32) {
        self.socket.send(format!("{}:BURS:NOR {}", source, repetitions));
    }

    pub fn set_period(&mut self, source: Source, period: u32) {
        self.socket.send(format!("{}:BURS:INT:PER {}", source, period));
    }
}

#[cfg(test)]
mod test {
    #[test]
    fn test_enable() {
        let (rx, mut burst) = create_burst();

        burst.enable(::burst::Source::OUT1);
        assert_eq!("SOUR1:BURS:STAT ON\r\n", rx.recv().unwrap());
    }

    #[test]
    fn test_disable() {
        let (rx, mut burst) = create_burst();

        burst.disable(::burst::Source::OUT1);
        assert_eq!("SOUR1:BURS:STAT OFF\r\n", rx.recv().unwrap());
    }

    #[test]
    fn test_set_count() {
        let (rx, mut burst) = create_burst();

        burst.set_count(::burst::Source::OUT1, 3);
        assert_eq!("SOUR1:BURS:NCYC 3\r\n", rx.recv().unwrap());
    }

    #[test]
    fn test_set_repetitions() {
        let (rx, mut burst) = create_burst();

        burst.set_repetitions(::burst::Source::OUT1, 5);
        assert_eq!("SOUR1:BURS:NOR 5\r\n", rx.recv().unwrap());
    }

    #[test]
    fn test_set_period() {
        let (rx, mut burst) = create_burst();

        burst.set_period(::burst::Source::OUT2, 1_000_000);
        assert_eq!("SOUR2:BURS:INT:PER 1000000\r\n", rx.recv().unwrap());
    }

    fn create_burst() -> (::std::sync::mpsc::Receiver<String>, ::burst::Burst) {
        let (addr, rx) = ::test::launch_server();
        let socket = ::socket::Socket::new(
            format!("{}", addr.ip()).as_str(),
            addr.port()
        );

        (rx, ::burst::Burst::new(socket))
    }
}
<commit_msg>[burst] Add burst::State enum<commit_after>use socket::Socket;

pub enum Source {
    OUT1,
    OUT2,
}

impl ::std::fmt::Display for Source {
    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
        let display = match self {
            &Source::OUT1 => "SOUR1",
            &Source::OUT2 => "SOUR2",
        };

        write!(f, "{}", display)
    }
}

enum State {
    ON,
    OFF,
}

impl ::std::fmt::Display for State {
    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
        let display = match self {
            &State::ON => "ON",
            &State::OFF => "OFF",
        };

        write!(f, "{}", display)
    }
}

pub struct Burst {
    socket: Socket,
}

impl Burst {
    pub fn new(socket: Socket) -> Self {
        Burst {
            socket: socket,
        }
    }

    pub fn enable(&mut self, source: Source) {
        self.socket.send(format!("{}:BURS:STAT {}", source, State::ON));
    }

    pub fn disable(&mut self, source: Source) {
        self.socket.send(format!("{}:BURS:STAT {}", source, State::OFF));
    }

    pub fn set_count(&mut self, source: Source, count: u32) {
        self.socket.send(format!("{}:BURS:NCYC {}", source, count));
    }

    pub fn set_repetitions(&mut self, source: Source, repetitions: u32) {
        self.socket.send(format!("{}:BURS:NOR {}", source, repetitions));
    }

    pub fn set_period(&mut self, source: Source, period: u32) {
        self.socket.send(format!("{}:BURS:INT:PER {}", source, period));
    }
}

#[cfg(test)]
mod test {
    #[test]
    fn test_enable() {
        let (rx, mut burst) = create_burst();

        burst.enable(::burst::Source::OUT1);
        assert_eq!("SOUR1:BURS:STAT ON\r\n", rx.recv().unwrap());
    }

    #[test]
    fn test_disable() {
        let (rx, mut burst) = create_burst();

        burst.disable(::burst::Source::OUT1);
        assert_eq!("SOUR1:BURS:STAT OFF\r\n", rx.recv().unwrap());
    }

    #[test]
    fn test_set_count() {
        let (rx, mut burst) = create_burst();

        burst.set_count(::burst::Source::OUT1, 3);
        assert_eq!("SOUR1:BURS:NCYC 3\r\n", rx.recv().unwrap());
    }

    #[test]
    fn test_set_repetitions() {
        let (rx, mut burst) = create_burst();

        burst.set_repetitions(::burst::Source::OUT1, 5);
        assert_eq!("SOUR1:BURS:NOR 5\r\n", rx.recv().unwrap());
    }

    #[test]
    fn test_set_period() {
        let (rx, mut burst) = create_burst();

        burst.set_period(::burst::Source::OUT2, 1_000_000);
        assert_eq!("SOUR2:BURS:INT:PER 1000000\r\n", rx.recv().unwrap());
    }

    fn create_burst() -> (::std::sync::mpsc::Receiver<String>, ::burst::Burst) {
        let (addr, rx) = ::test::launch_server();
        let socket = ::socket::Socket::new(
            format!("{}", addr.ip()).as_str(),
            addr.port()
        );

        (rx, ::burst::Burst::new(socket))
    }
}
<|endoftext|>


<commit_before>use std::thread;
use std::time;

use chrono;
use float_duration::{FloatDuration, TimePoint};

use framerate::{FrameCounter, FrameRateSampler};

#[derive(Debug, Clone, PartialEq, Eq)]
pub enum TimeProgression {
    FixedStep,
    VariableStep,
}

#[derive(Debug, Clone)]
pub struct GameTime {
    frame_wall_time: chrono::DateTime<chrono::Local>,
    frame_game_time: time::Duration,
    elapsed_game_time: FloatDuration,
    elapsed_wall_time: FloatDuration,
    frame_number: u64,
}

#[derive(Debug, Clone)]
pub struct GameClock {
    start_wall_time: chrono::DateTime<chrono::Local>,
    frame_wall_time: chrono::DateTime<chrono::Local>,
    total_game_time: time::Duration,
    elapsed_game_time: FloatDuration,
    elapsed_wall_time: FloatDuration,
    current_frame: u64,
    clock_multiplier: f64,
    time_progression: TimeProgression,
}

impl GameClock {
    pub fn new() -> GameClock {
        let now = chrono::Local::now();

        GameClock {
            start_wall_time: now,
            frame_wall_time: now,
            total_game_time: time::Duration::new(0, 0),
            elapsed_game_time: FloatDuration::zero(),
            elapsed_wall_time: FloatDuration::zero(),
            current_frame: 0,
            clock_multiplier: 1.0,
            time_progression: TimeProgression::VariableStep,
        }
    }

    pub fn current_frame_index(&self) -> u64 {
        self.current_frame
    }
    pub fn start_wall_time(&self) -> chrono::DateTime<chrono::Local> {
        self.start_wall_time
    }
    pub fn frame_wall_time(&self) -> chrono::DateTime<chrono::Local> {
        self.frame_wall_time
    }
    pub fn frame_elapsed_time(&self) -> FloatDuration {
        chrono::Local::now()
            .float_duration_since(self.frame_wall_time)
            .unwrap()
    }

    pub fn clock_multiplier(&self) -> f64 {
        self.clock_multiplier
    }
    pub fn with_clock_multiplier(&mut self, val: f64) -> &mut GameClock {
        self.clock_multiplier = val;
        self
    }

    pub fn do_frame<F, S>(&mut self, counter: &mut FrameCounter<S>, f: &mut F)
        where F: FnMut(&GameTime),
              S: FrameRateSampler
    {
        let game_time = self.tick(counter);
        f(&game_time);
        self.sleep_remaining(counter);
    }

    pub fn tick<S: FrameRateSampler>(&mut self, counter: &mut FrameCounter<S>) -> GameTime {
        let frame_start = chrono::Local::now();

        self.current_frame += 1;

        let elapsed_wall_time = frame_start
            .float_duration_since(self.frame_wall_time)
            .unwrap();

        let elapsed_game_time = match self.time_progression {
            TimeProgression::FixedStep => counter.target_time_per_frame() * self.clock_multiplier,
            TimeProgression::VariableStep => elapsed_wall_time * self.clock_multiplier,
        };

        let total_game_time = self.total_game_time + elapsed_game_time.to_std().unwrap();

        self.frame_wall_time = frame_start;
        self.total_game_time = total_game_time;
        self.elapsed_game_time = elapsed_game_time;
        self.elapsed_wall_time = elapsed_wall_time;

        let time = GameTime {
            frame_wall_time: frame_start,
            frame_game_time: total_game_time,
            elapsed_game_time,
            elapsed_wall_time,
            frame_number: self.current_frame,
        };

        counter.tick(&time);

        time
    }

    pub fn sleep_remaining_via<S, F>(&mut self, counter: &FrameCounter<S>, f: F)
        where S: FrameRateSampler,
              F: FnOnce(FloatDuration)
    {
        let remaining_time = counter.target_time_per_frame() -
                             chrono::Local::now()
                                 .float_duration_since(self.frame_wall_time)
                                 .unwrap();
        f(remaining_time)
    }

    pub fn sleep_remaining<S: FrameRateSampler>(&mut self, counter: &FrameCounter<S>) {
        self.sleep_remaining_via(counter, |rem| thread::sleep(rem.to_std().unwrap()))
    }
}

impl Default for GameClock {
    fn default() -> GameClock {
        GameClock::new()
    }
}

impl GameTime {
    pub fn frame_game_time(&self) -> time::Duration {
        self.frame_game_time
    }
    pub fn frame_wall_time(&self) -> chrono::DateTime<chrono::Local> {
        self.frame_wall_time
    }
    pub fn elapsed_game_time(&self) -> FloatDuration {
        self.elapsed_game_time
    }
    pub fn elapsed_wall_time(&self) -> FloatDuration {
        self.elapsed_wall_time
    }
    pub fn elapsed_time_since_frame_start(&self) -> FloatDuration {
        chrono::Local::now()
            .float_duration_since(self.frame_wall_time)
            .unwrap()
    }
    pub fn frame_number(&self) -> u64 {
        self.frame_number
    }
}
<commit_msg>Factor out elapsed game time computation to a function.<commit_after>use std::thread;
use std::time;

use chrono;
use float_duration::{FloatDuration, TimePoint};

use framerate::{FrameCounter, FrameRateSampler};

#[derive(Debug, Clone, PartialEq, Eq)]
pub enum TimeProgression {
    FixedStep,
    VariableStep,
}

#[derive(Debug, Clone)]
pub struct GameTime {
    frame_wall_time: chrono::DateTime<chrono::Local>,
    frame_game_time: time::Duration,
    elapsed_game_time: FloatDuration,
    elapsed_wall_time: FloatDuration,
    frame_number: u64,
}

#[derive(Debug, Clone)]
pub struct GameClock {
    start_wall_time: chrono::DateTime<chrono::Local>,
    frame_wall_time: chrono::DateTime<chrono::Local>,
    total_game_time: time::Duration,
    elapsed_game_time: FloatDuration,
    elapsed_wall_time: FloatDuration,
    current_frame: u64,
    clock_multiplier: f64,
    time_progression: TimeProgression,
}

impl GameClock {
    pub fn new() -> GameClock {
        let now = chrono::Local::now();

        GameClock {
            start_wall_time: now,
            frame_wall_time: now,
            total_game_time: time::Duration::new(0, 0),
            elapsed_game_time: FloatDuration::zero(),
            elapsed_wall_time: FloatDuration::zero(),
            current_frame: 0,
            clock_multiplier: 1.0,
            time_progression: TimeProgression::VariableStep,
        }
    }

    pub fn current_frame_index(&self) -> u64 {
        self.current_frame
    }
    pub fn start_wall_time(&self) -> chrono::DateTime<chrono::Local> {
        self.start_wall_time
    }
    pub fn frame_wall_time(&self) -> chrono::DateTime<chrono::Local> {
        self.frame_wall_time
    }
    pub fn frame_elapsed_time(&self) -> FloatDuration {
        chrono::Local::now()
            .float_duration_since(self.frame_wall_time)
            .unwrap()
    }

    pub fn clock_multiplier(&self) -> f64 {
        self.clock_multiplier
    }
    pub fn with_clock_multiplier(&mut self, val: f64) -> &mut GameClock {
        self.clock_multiplier = val;
        self
    }

    pub fn do_frame<F, S>(&mut self, counter: &mut FrameCounter<S>, f: &mut F)
        where F: FnMut(&GameTime),
              S: FrameRateSampler
    {
        let game_time = self.tick(counter);
        f(&game_time);
        self.sleep_remaining(counter);
    }

    pub fn tick<S: FrameRateSampler>(&mut self, counter: &mut FrameCounter<S>) -> GameTime {
        let frame_start = chrono::Local::now();

        self.current_frame += 1;

        let elapsed_wall_time = frame_start
            .float_duration_since(self.frame_wall_time)
            .unwrap();

        let elapsed_game_time = self.elapsed_game_time_from_wall_time(counter, elapsed_wall_time);
        let total_game_time = self.total_game_time + elapsed_game_time.to_std().unwrap();

        self.frame_wall_time = frame_start;
        self.total_game_time = total_game_time;
        self.elapsed_game_time = elapsed_game_time;
        self.elapsed_wall_time = elapsed_wall_time;

        let time = GameTime {
            frame_wall_time: frame_start,
            frame_game_time: total_game_time,
            elapsed_game_time,
            elapsed_wall_time,
            frame_number: self.current_frame,
        };

        counter.tick(&time);

        time
    }

    fn elapsed_game_time_from_wall_time<S: FrameRateSampler>(&self,
                                                             counter: &mut FrameCounter<S>,
                                                             elapsed_wall_time: FloatDuration)
                                                             -> FloatDuration {
        match self.time_progression {
            TimeProgression::FixedStep => counter.target_time_per_frame() * self.clock_multiplier,
            TimeProgression::VariableStep => elapsed_wall_time * self.clock_multiplier,
        }
    }

    pub fn sleep_remaining_via<S, F>(&mut self, counter: &FrameCounter<S>, f: F)
        where S: FrameRateSampler,
              F: FnOnce(FloatDuration)
    {
        let remaining_time = counter.target_time_per_frame() -
                             chrono::Local::now()
                                 .float_duration_since(self.frame_wall_time)
                                 .unwrap();
        f(remaining_time)
    }

    pub fn sleep_remaining<S: FrameRateSampler>(&mut self, counter: &FrameCounter<S>) {
        self.sleep_remaining_via(counter, |rem| thread::sleep(rem.to_std().unwrap()))
    }
}

impl Default for GameClock {
    fn default() -> GameClock {
        GameClock::new()
    }
}

impl GameTime {
    pub fn frame_game_time(&self) -> time::Duration {
        self.frame_game_time
    }
    pub fn frame_wall_time(&self) -> chrono::DateTime<chrono::Local> {
        self.frame_wall_time
    }
    pub fn elapsed_game_time(&self) -> FloatDuration {
        self.elapsed_game_time
    }
    pub fn elapsed_wall_time(&self) -> FloatDuration {
        self.elapsed_wall_time
    }
    pub fn elapsed_time_since_frame_start(&self) -> FloatDuration {
        chrono::Local::now()
            .float_duration_since(self.frame_wall_time)
            .unwrap()
    }
    pub fn frame_number(&self) -> u64 {
        self.frame_number
    }
}
<|endoftext|>


<commit_before>// http://rosettacode.org/wiki/Define_a_primitive_data_type
// Implements a custom type named CustomInt.
// This type only implements a subset of all traits within std::ops.
use std::ops;

#[derive(Eq, PartialEq, Ord, PartialOrd, Debug, Copy, Clone)]
struct CustomInt {
    value: u8,
}

// constructor function
impl CustomInt {
    fn custom_int(v: u8) -> CustomInt {
        let rval = CustomInt { value: v };
        rval.in_bounds();
        rval
    }
}
// custom trait to specify bounds
trait Bounded {
    fn in_bounds(&self);
}

impl Bounded for CustomInt {
    fn in_bounds(&self) {
        if self.value < 1 || self.value > 10 {
            panic(self.value);
        }
        #[cold]
        #[inline(never)]
        fn panic(v: u8) -> ! {
            panic!("CustomInt is out of bounds! {} was value", v);
        }
    }
}

impl ops::Add for CustomInt {
    type Output = CustomInt;
    fn add(self, rhs: CustomInt) -> CustomInt {
        let rval = CustomInt { value: (self.value + rhs.value) };
        rval.in_bounds();
        rval
    }
}

impl ops::Sub for CustomInt {
    type Output = CustomInt;
    fn sub(self, rhs: CustomInt) -> CustomInt {
        let rval = CustomInt { value: (self.value - rhs.value) };
        rval.in_bounds();
        rval
    }
}

impl ops::Mul for CustomInt {
    type Output = CustomInt;
    fn mul(self, rhs: CustomInt) -> CustomInt {
        let rval = CustomInt { value: (self.value * rhs.value) };
        rval.in_bounds();
        rval
    }
}

impl ops::Div for CustomInt {
    type Output = CustomInt;
    fn div(self, rhs: CustomInt) -> CustomInt {
        let rval = CustomInt { value: (self.value / rhs.value) };
        rval.in_bounds();
        rval
    }
}

impl ops::BitAnd for CustomInt {
    type Output = CustomInt;
    fn bitand(self, rhs: CustomInt) -> CustomInt {
        let rval = CustomInt { value: (self.value & rhs.value) };
        rval.in_bounds();
        rval
    }
}

impl ops::BitOr for CustomInt {
    type Output = CustomInt;
    fn bitor(self, rhs: CustomInt) -> CustomInt {
        let rval = CustomInt { value: (self.value | rhs.value) };
        rval.in_bounds();
        rval
    }
}

impl ops::BitXor for CustomInt {
    type Output = CustomInt;
    fn bitxor(self, rhs: CustomInt) -> CustomInt {
        let rval = CustomInt { value: (self.value ^ rhs.value) };
        rval.in_bounds();
        rval
    }
}

fn main() {
    let cint_2: CustomInt = CustomInt::custom_int(2);
    let cint_3: CustomInt = CustomInt::custom_int(3);
    let cint_4: CustomInt = CustomInt::custom_int(4);
    cint_2 + cint_4; // CustomInt { value: 6 }
    cint_4 - cint_2; // CustomInt { value: 2 }
    cint_4 * cint_2; // CustomInt { value: 8 }
    cint_4 / cint_2; // CustomInt { value: 2 }
    cint_3 & cint_2; // CustomInt { value: 2 }
    cint_3 | cint_2; // CustomInt { value: 3 }
    cint_3 ^ cint_2; // CustomInt { value: 1 }
}

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

    #[test]
    fn add_test() {
        let cint_2: CustomInt = CustomInt::custom_int(2);
        let cint_4: CustomInt = CustomInt::custom_int(4);
        assert_eq!(CustomInt::custom_int(6), cint_2 + cint_4);
    }

    #[test]
    fn sub_test() {
        let cint_2: CustomInt = CustomInt::custom_int(2);
        let cint_4: CustomInt = CustomInt::custom_int(4);
        assert_eq!(CustomInt::custom_int(2), cint_4 - cint_2);
    }

    #[test]
    fn mul_test() {
        let cint_2: CustomInt = CustomInt::custom_int(2);
        let cint_4: CustomInt = CustomInt::custom_int(4);
        assert_eq!(CustomInt::custom_int(8), cint_4 * cint_2);
    }

    #[test]
    fn div_test() {
        let cint_2: CustomInt = CustomInt::custom_int(2);
        let cint_4: CustomInt = CustomInt::custom_int(4);
        assert_eq!(CustomInt::custom_int(2), cint_4 / cint_2);
    }

    #[test]
    fn and_test() {
        let cint_2: CustomInt = CustomInt::custom_int(2);
        let cint_3: CustomInt = CustomInt::custom_int(3);
        assert_eq!(CustomInt::custom_int(2), cint_3 & cint_2);
    }

    #[test]
    fn or_test() {
        let cint_2: CustomInt = CustomInt::custom_int(2);
        let cint_3: CustomInt = CustomInt::custom_int(3);
        assert_eq!(CustomInt::custom_int(3), cint_3 | cint_2);
    }

    #[test]
    fn xor_test() {
        let cint_2: CustomInt = CustomInt::custom_int(2);
        let cint_3: CustomInt = CustomInt::custom_int(3);
        assert_eq!(CustomInt::custom_int(1), cint_3 ^ cint_2);
    }

    #[test]
    #[should_panic(expected = "CustomInt is out of bounds! 11 was value")]
    fn above_out_of_bounds_test() {
        let cint_10: CustomInt = CustomInt::custom_int(10);
        let cint_1: CustomInt = CustomInt::custom_int(1);
        cint_10 + cint_1; // should panic here
    }

    #[test]
    #[should_panic(expected = "CustomInt is out of bounds! 0 was value")]
    fn below_out_of_bounds_test() {
        let cint_1: CustomInt = CustomInt::custom_int(10);
        cint_1 - cint_1; // should panic here
    }
}
<commit_msg>make custom_int return Result<commit_after>// http://rosettacode.org/wiki/Define_a_primitive_data_type
// Implements a custom type named CustomInt.
// This type only implements a subset of all traits within std::ops.
use std::ops;

#[derive(Eq, PartialEq, Ord, PartialOrd, Debug, Copy, Clone)]
struct CustomInt {
    value: u8,
}

enum CustomIntError {
    OutOfBoundsAssn,
}

impl CustomInt {
    fn custom_int(v: u8) -> Result<CustomInt, CustomIntError> {
        if v < 1 || v > 10 {
            Err(CustomIntError::OutOfBoundsAssn)
        } else {
            Ok(CustomInt { value: v })
        }
    }
}
// custom trait to specify bounds
trait Bounded {
    fn in_bounds(&self);
}

impl Bounded for CustomInt {
    fn in_bounds(&self) {
        if self.value < 1 || self.value > 10 {
            panic(self.value);
        }
        #[cold]
        #[inline(never)]
        fn panic(v: u8) -> ! {
            panic!("CustomInt is out of bounds! {} was value", v);
        }
    }
}

impl ops::Add for CustomInt {
    type Output = CustomInt;
    fn add(self, rhs: CustomInt) -> CustomInt {
        let rval = CustomInt { value: (self.value + rhs.value) };
        rval.in_bounds();
        rval
    }
}

impl ops::Sub for CustomInt {
    type Output = CustomInt;
    fn sub(self, rhs: CustomInt) -> CustomInt {
        let rval = CustomInt { value: (self.value - rhs.value) };
        rval.in_bounds();
        rval
    }
}

impl ops::Mul for CustomInt {
    type Output = CustomInt;
    fn mul(self, rhs: CustomInt) -> CustomInt {
        let rval = CustomInt { value: (self.value * rhs.value) };
        rval.in_bounds();
        rval
    }
}

impl ops::Div for CustomInt {
    type Output = CustomInt;
    fn div(self, rhs: CustomInt) -> CustomInt {
        let rval = CustomInt { value: (self.value / rhs.value) };
        rval.in_bounds();
        rval
    }
}

impl ops::BitAnd for CustomInt {
    type Output = CustomInt;
    fn bitand(self, rhs: CustomInt) -> CustomInt {
        let rval = CustomInt { value: (self.value & rhs.value) };
        rval.in_bounds();
        rval
    }
}

impl ops::BitOr for CustomInt {
    type Output = CustomInt;
    fn bitor(self, rhs: CustomInt) -> CustomInt {
        let rval = CustomInt { value: (self.value | rhs.value) };
        rval.in_bounds();
        rval
    }
}

impl ops::BitXor for CustomInt {
    type Output = CustomInt;
    fn bitxor(self, rhs: CustomInt) -> CustomInt {
        let rval = CustomInt { value: (self.value ^ rhs.value) };
        rval.in_bounds();
        rval
    }
}

fn main() {
    let cint_2: CustomInt = CustomInt::custom_int(2).ok().unwrap();
    let cint_3: CustomInt = CustomInt::custom_int(3).ok().unwrap();
    let cint_4: CustomInt = CustomInt::custom_int(4).ok().unwrap();
    cint_2 + cint_4; // CustomInt { value: 6 }
    cint_4 - cint_2; // CustomInt { value: 2 }
    cint_4 * cint_2; // CustomInt { value: 8 }
    cint_4 / cint_2; // CustomInt { value: 2 }
    cint_3 & cint_2; // CustomInt { value: 2 }
    cint_3 | cint_2; // CustomInt { value: 3 }
    cint_3 ^ cint_2; // CustomInt { value: 1 }
}

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

    #[test]
    fn add_test() {
        let cint_2: CustomInt = CustomInt::custom_int(2).ok().unwrap();
        let cint_4: CustomInt = CustomInt::custom_int(4).ok().unwrap();
        assert_eq!(CustomInt::custom_int(6).ok().unwrap(), cint_2 + cint_4);
    }

    #[test]
    fn sub_test() {
        let cint_2: CustomInt = CustomInt::custom_int(2).ok().unwrap();
        let cint_4: CustomInt = CustomInt::custom_int(4).ok().unwrap();
        assert_eq!(CustomInt::custom_int(2).ok().unwrap(), cint_4 - cint_2);
    }

    #[test]
    fn mul_test() {
        let cint_2: CustomInt = CustomInt::custom_int(2).ok().unwrap();
        let cint_4: CustomInt = CustomInt::custom_int(4).ok().unwrap();
        assert_eq!(CustomInt::custom_int(8).ok().unwrap(), cint_4 * cint_2);
    }

    #[test]
    fn div_test() {
        let cint_2: CustomInt = CustomInt::custom_int(2).ok().unwrap();
        let cint_4: CustomInt = CustomInt::custom_int(4).ok().unwrap();
        assert_eq!(CustomInt::custom_int(2).ok().unwrap(), cint_4 / cint_2);
    }

    #[test]
    fn and_test() {
        let cint_2: CustomInt = CustomInt::custom_int(2).ok().unwrap();
        let cint_3: CustomInt = CustomInt::custom_int(3).ok().unwrap();
        assert_eq!(CustomInt::custom_int(2).ok().unwrap(), cint_3 & cint_2);
    }

    #[test]
    fn or_test() {
        let cint_2: CustomInt = CustomInt::custom_int(2).ok().unwrap();
        let cint_3: CustomInt = CustomInt::custom_int(3).ok().unwrap();
        assert_eq!(CustomInt::custom_int(3).ok().unwrap(), cint_3 | cint_2);
    }

    #[test]
    fn xor_test() {
        let cint_2: CustomInt = CustomInt::custom_int(2).ok().unwrap();
        let cint_3: CustomInt = CustomInt::custom_int(3).ok().unwrap();
        assert_eq!(CustomInt::custom_int(1).ok().unwrap(), cint_3 ^ cint_2);
    }

    #[test]
    fn assn_out_of_bounds_test() {
        let cint_error = CustomInt::custom_int(0);
        assert!(cint_error.is_err());
    }

    #[test]
    #[should_panic(expected = "CustomInt is out of bounds! 11 was value")]
    fn above_out_of_bounds_test() {
        let cint_10: CustomInt = CustomInt::custom_int(10).ok().unwrap();
        let cint_1: CustomInt = CustomInt::custom_int(1).ok().unwrap();
        cint_10 + cint_1; // should panic here
    }

    #[test]
    #[should_panic(expected = "CustomInt is out of bounds! 0 was value")]
    fn below_out_of_bounds_test() {
        let cint_1: CustomInt = CustomInt::custom_int(1).ok().unwrap();
        cint_1 - cint_1; // should panic here
    }
}
<|endoftext|>


<commit_before>use error::StatsError;

/// Implements the [Fisher-Snedecor](https://en.wikipedia.org/wiki/F-distribution) distribution
/// also commonly known as the F-distribution
///
/// # Examples
///
/// ```
/// use statrs::distribution::{FisherSnedecor, Continuous};
/// use statrs::statistics::Mean;
/// ```
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct FisherSnedecor {
    freedom_1: f64,
    freedom_2: f64,
}

impl FisherSnedecor {
    /// Constructs a new fisher-snedecor distribution with
    /// degrees of freedom `freedom_1` and `freedom_2`
    ///
    /// # Errors
    ///
    /// Returns an error if `freedom_1` or `freedom_2` are `NaN`.
    /// Also returns an error if `freedom_1 <= 0.0` or `freedom_2 <= 0.0`
    ///
    /// # Examples
    ///
    /// ```
    /// use statrs::distribution::FisherSnedecor;
    ///
    /// let mut result = FisherSnedecor::new(1.0, 1.0);
    /// assert!(result.is_ok());
    ///
    /// result = FisherSnedecor::new(0.0, 0.0);
    /// assert!(result.is_err());
    /// ```
    pub fn new(freedom_1: f64, freedom_2: f64) -> Result<FisherSnedecor> {
        if shape_a.is_nan() || shape_b.is_nan() {
            Err(StatsError::BadParams)
        } else if freedom_1 <= 0.0 || freedom_2 <= 0.0 {
            Err(StatsError::BadParams)
        } else {
            OK(FisherSnedecor {
                freedom_1: freedom_1,
                freedom_2: freedom_2,
            })
        }
    }

    /// Returns the first degree of freedom for the
    /// fisher-snedecor distribution
    ///
    /// # Examples
    ///
    /// ```
    /// use statrs::distribution::FisherSnedecor;
    ///
    /// let n = FisherSnedecor::new(2.0, 3.0).unwrap();
    /// assert_eq!(n.freedom_1(), 2.0);
    /// ```
    pub fn freedom_1(&self) -> f64 {
        self.freedom_1
    }

    /// Returns the second degree of freedom for the
    /// fisher-snedecor distribution
    ///
    /// # Examples
    ///
    /// ```
    /// use statrs::distribution::FisherSnedecor;
    ///
    /// let n = FisherSnedecor::new(2.0, 3.0).unwrap();
    /// assert_eq!(n.freedom_2(), 3.0);
    /// ```
    pub fn freedom_2(&self) -> f64 {
        self.freedom_2
    }
}<commit_msg>wip: continued implementation of f distribution<commit_after>use rand::Rng;
use rand::distributions::{Sample, IndependentSample};
use distribution::Distribution;
use result::Result;
use error::StatsError;

/// Implements the [Fisher-Snedecor](https://en.wikipedia.org/wiki/F-distribution) distribution
/// also commonly known as the F-distribution
///
/// # Examples
///
/// ```
/// use statrs::distribution::{FisherSnedecor, Continuous};
/// use statrs::statistics::Mean;
/// ```
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct FisherSnedecor {
    freedom_1: f64,
    freedom_2: f64,
}

impl FisherSnedecor {
    /// Constructs a new fisher-snedecor distribution with
    /// degrees of freedom `freedom_1` and `freedom_2`
    ///
    /// # Errors
    ///
    /// Returns an error if `freedom_1` or `freedom_2` are `NaN`.
    /// Also returns an error if `freedom_1 <= 0.0` or `freedom_2 <= 0.0`
    ///
    /// # Examples
    ///
    /// ```
    /// use statrs::distribution::FisherSnedecor;
    ///
    /// let mut result = FisherSnedecor::new(1.0, 1.0);
    /// assert!(result.is_ok());
    ///
    /// result = FisherSnedecor::new(0.0, 0.0);
    /// assert!(result.is_err());
    /// ```
    pub fn new(freedom_1: f64, freedom_2: f64) -> Result<FisherSnedecor> {
        if freedom_1.is_nan() || freedom_2.is_nan() {
            Err(StatsError::BadParams)
        } else if freedom_1 <= 0.0 || freedom_2 <= 0.0 {
            Err(StatsError::BadParams)
        } else {
            Ok(FisherSnedecor {
                freedom_1: freedom_1,
                freedom_2: freedom_2,
            })
        }
    }

    /// Returns the first degree of freedom for the
    /// fisher-snedecor distribution
    ///
    /// # Examples
    ///
    /// ```
    /// use statrs::distribution::FisherSnedecor;
    ///
    /// let n = FisherSnedecor::new(2.0, 3.0).unwrap();
    /// assert_eq!(n.freedom_1(), 2.0);
    /// ```
    pub fn freedom_1(&self) -> f64 {
        self.freedom_1
    }

    /// Returns the second degree of freedom for the
    /// fisher-snedecor distribution
    ///
    /// # Examples
    ///
    /// ```
    /// use statrs::distribution::FisherSnedecor;
    ///
    /// let n = FisherSnedecor::new(2.0, 3.0).unwrap();
    /// assert_eq!(n.freedom_2(), 3.0);
    /// ```
    pub fn freedom_2(&self) -> f64 {
        self.freedom_2
    }
}

impl Sample<f64> for FisherSnedecor {
    /// Generate a random sample from a fisher-snedecor distribution
    /// using `r` as the source of randomness.
    /// Refer [here](#method.sample-1) for implementation details.
    fn sample<R: Rng>(&mut self, r: &mut R) -> f64 {
        super::Distribution::sample(self, r)
    }
}

impl IndependentSample<f64> for FisherSnedecor {
    /// Generate a random independent sample from a fisher-snedecor distribution
    /// using `r` as the source of randomness.
    /// Refer [here](#method.sample-1) for implementation details.
    fn ind_sample<R: Rng>(&self, r: &mut R) -> f64 {
        super::Distribution::sample(self, r)
    }
}

impl Distribution<f64> for FisherSnedecor {
    /// Generate a random sample from a fisher-snedecor distribution using
    /// `r` as the source of randomness.
    ///
    /// # Examples
    ///
    /// ```
    /// # extern crate rand;
    /// # extern crate statrs;
    /// use rand::StdRng;
    /// use statrs::distribution::{FisherSnedecor, Distribution};
    ///
    /// # fn main() {
    /// let mut r = rand::StdRng::new().unwrap();
    /// let n = FisherSnedecor::new(2.0, 2.0).unwrap();
    /// print!("{}", n.sample::<StdRng>(&mut r));
    /// # }
    /// ```
    fn sample<R: Rng>(&self, r: &mut R) -> f64 {
        (super::gamma::sample_unchecked(r, self.freedom_1 / 2.0, 0.5) * self.freedom_2) /
        (super::gamma::sample_unchecked(r, self.freedom_2 / 2.0, 0.5) * self.freedom_1)
    }
}
 <|endoftext|>