<commit_before>// mod shifts;
// use shifts::get_shifts_hashmap;
use super::PI;
use super::AIRY_1830_SEMI_MAJOR;
use super::AIRY_1830_SEMI_MINOR;
use super::GRS80_SEMI_MAJOR;
use super::GRS80_SEMI_MINOR;

use super::RAD;
use super::MIN_LONGITUDE;
use super::MAX_LONGITUDE;
use super::MIN_LATITUDE;
use super::MAX_LATITUDE;

const WGS84_A: f64 = GRS80_SEMI_MAJOR;
const WGS84_B: f64 = GRS80_SEMI_MINOR;

// lon and lat of true origin
const LAM0: f64 = RAD * -2.0;
const PHI0: f64 = RAD * 49.0;

// Easting and Northing of origin
const E0: f64 = 400000.;
const N0: f64 = -100000.;
// convergence factor
const F0: f64 = 0.9996012717;

const MIN_X_SHIFT: f64 = 86.275;
const MIN_Y_SHIFT: f64 = -81.603;
const MIN_Z_SHIFT: f64 = 43.982;

use std::collections::HashMap;
use ostn02_phf::ostn02_lookup;
use super::check;

// Herbie's going to have a field day with this
pub fn round_to_nearest_mm(x: f64, y: f64, z: f64) -> (f64, f64, f64) {
    let new_x = (x * 1000.).round() as f64 / 1000.;
    let new_y = (y * 1000.).round() as f64 / 1000.;
    let new_z = (z * 1000.).round() as f64 / 1000.;
    (new_x, new_y, new_z)
}

pub fn get_ostn_ref(x: &i32, y: &i32) -> (f64, f64, f64) {
    let key = format!("{:03x}{:03x}", y, x);
    // some or None, so try! this
    let result = ostn02_lookup(&*key).unwrap();
    // if we get a hit
    let data2 = (result.0 as f64 / 1000. + MIN_X_SHIFT,
                 result.1 as f64 / 1000. + MIN_Y_SHIFT,
                 result.2 as f64 / 1000. + MIN_Z_SHIFT);
    data2
}

// Input values must be valid ETRS89 grid references
// See p20 of the transformation user guide at
// https://www.ordnancesurvey.co.uk/business-and-government/help-and-support/navigation-technology/os-net/formats-for-developers.html
pub fn ostn02_shifts(x: &f64, y: &f64) -> (f64, f64, f64) {
    let e_index = (*x / 1000.) as i32;
    let n_index = (*y / 1000.) as i32;

    // eastings and northings of the south-west corner of the cell
    let x0 = e_index * 1000;
    let y0 = n_index * 1000;

    // The easting, northing and geoid shifts for the four corners of the cell
    // any of these could be Err, so use try!
    let s0_ref: (f64, f64, f64) = get_ostn_ref(&(e_index + 0), &(n_index + 0));
    let s1_ref: (f64, f64, f64) = get_ostn_ref(&(e_index + 1), &(n_index + 0));
    let s2_ref: (f64, f64, f64) = get_ostn_ref(&(e_index + 0), &(n_index + 1));
    let s3_ref: (f64, f64, f64) = get_ostn_ref(&(e_index + 1), &(n_index + 1));
    // only continue if we get Results for the above

    // offset within square
    let dx = *x - (x0 as f64);
    let dy = *y - (y0 as f64);

    // the python script divides by an int here, which = 0 (e.g. 300 / 1000)
    let t = dx / 1000.;
    let u = dy / 1000.;

    let f0 = (1. - t as f64) * (1. - u as f64);
    let f1 = t as f64 * (1. - u as f64);
    let f2 = (1. - t as f64) * u as f64;
    let f3 = t as f64 * u as f64;

    // bilinear interpolation, to obtain the actual shifts
    let se = f0 * s0_ref.0 + f1 * s1_ref.0 + f2 * s2_ref.0 + f3 * s3_ref.0;
    let sn = f0 * s0_ref.1 + f1 * s1_ref.1 + f2 * s2_ref.1 + f3 * s3_ref.1;
    let sg = f0 * s0_ref.2 + f1 * s1_ref.2 + f2 * s2_ref.2 + f3 * s3_ref.2;

    let (r_se, r_sn, r_sg) = round_to_nearest_mm(se, sn, sg);
    (r_se, r_sn, r_sg)

}

// See Annexe B (p23) of the transformation user guide for instructions
pub fn convert_etrs89(longitude: &f64, latitude: &f64) -> Result<(f64, f64), f64> {
    // input is restricted to the UK bounding box
    // Convert bounds-checked input to degrees, or return an Err
    let lon_1: f64 = try!(check(*longitude as f32, (MIN_LONGITUDE, MAX_LONGITUDE)).map_err(|e| e)) as f64 * RAD;
    let lat_1: f64 = try!(check(*latitude as f32, (MIN_LATITUDE, MAX_LATITUDE)).map_err(|e| e)) as f64 * RAD;
    let alt = 0.0;
    // ellipsoid squared eccentricity constant
    let e2 = (WGS84_A.powf(2.) - WGS84_B.powf(2.)) / WGS84_A.powf(2.);
    let n = (WGS84_A - WGS84_B) / (WGS84_A + WGS84_B);
    let phi = RAD * *latitude;
    let lambda = RAD * *longitude;

    let sp2 = phi.sin().powf(2.);
    let nu = WGS84_A * F0 * (1. - e2 * sp2).powf(-0.5); // v
    let rho = WGS84_A * F0 * (1. - e2) * (1. - e2 * sp2).powf(-1.5);
    let eta2 = nu / rho - 1.;

    let m = compute_m(&phi, &WGS84_B, &n);

    let cp = phi.cos();
    let sp = phi.sin();
    let tp = phi.tan();
    let tp2 = tp.powf(2.);
    let tp4 = tp.powf(4.);

    let I = m + N0;
    let II = nu / 2. * sp * cp;
    let III = nu / 24. * sp * cp.powf(3.) * (5. - tp2 + 9. * eta2);
    let IIIA = nu / 720. * sp * cp.powf(5.) * (61. - 58. * tp2 + tp4);

    let IV = nu * cp;
    let V = nu / 6. * cp.powf(3.) * (nu / rho - tp2);
    let VI = nu / 120. * cp.powf(5.) * (5. - 18. * tp2 + tp4 + 14. * eta2 - 58. * tp2 * eta2);

    let l = lambda - LAM0;
    let north = I + II * l.powf(2.) + III * l.powf(4.) + IIIA * l.powf(6.);
    let east = E0 + IV * l + V * l.powf(3.) + VI * l.powf(5.);
    let (rounded_eastings, rounded_northings, _) = round_to_nearest_mm(east, north, 1.00);
    Ok((rounded_eastings, rounded_northings))
}

fn compute_m(phi: &f64, b: &f64, n: &f64) -> f64 {
    let p_plus = *phi + PHI0;
    let p_minus = *phi - PHI0;

    let result = *b * F0 *
                 ((1. + *n * (1. + 5. / 4. * *n * (1. + *n))) * p_minus -
                  3. * *n * (1. + *n * (1. + 7. / 8. * *n)) * p_minus.sin() * p_plus.cos() +
                  (15. / 8. * *n * (*n * (1. + *n))) * (2. * p_minus).sin() * (2. * p_plus).cos() -
                  35. / 24. * n.powf(3.) * (3. * p_minus).sin() * (3. * p_plus).cos());
    result
}
// Convert OSGB36 coordinates to ETRS89 using OSTN02 shifts
// pub fn shift_osgb36_to_etrs89(E: &f64, N: &f64) -> (f64, f64) {
//     let z0 = 0.000;
//     let epsilon = 0.00001;
//     let (dx, dy, dz) = ostn02_shifts(&E, &N);
//     let (x, y, z) = (E - dx, N - dy, dz);
//     let (last_dx, last_dy) = (dx.clone(), dy.clone());
//     while (dx - last_dx).abs() < epsilon && (dy - last_dy).abs() < epsilon {
//         let (dx, dy, dz) = ostn02_shifts(&x, &y);
//         let (x, y) = (E - dx, N - dy);
//         let (last_dx, last_dy) = (dx, dy);
//     }
//     let (x, y, z) = round_to_nearest_mm(E - dx, N - dy, z0 + dz);
//     (x, y)
// }
<commit_msg>Add documentation for ll -> ETRS89 conversion<commit_after>// mod shifts;
// use shifts::get_shifts_hashmap;
use super::PI;
use super::AIRY_1830_SEMI_MAJOR;
use super::AIRY_1830_SEMI_MINOR;
use super::GRS80_SEMI_MAJOR;
use super::GRS80_SEMI_MINOR;

use super::RAD;
use super::MIN_LONGITUDE;
use super::MAX_LONGITUDE;
use super::MIN_LATITUDE;
use super::MAX_LATITUDE;

const WGS84_A: f64 = GRS80_SEMI_MAJOR;
const WGS84_B: f64 = GRS80_SEMI_MINOR;

// lon and lat of true origin
const LAM0: f64 = RAD * -2.0;
const PHI0: f64 = RAD * 49.0;

// Easting and Northing of origin
const E0: f64 = 400000.;
const N0: f64 = -100000.;
// convergence factor
const F0: f64 = 0.9996012717;

const MIN_X_SHIFT: f64 = 86.275;
const MIN_Y_SHIFT: f64 = -81.603;
const MIN_Z_SHIFT: f64 = 43.982;

use std::collections::HashMap;
use ostn02_phf::ostn02_lookup;
use super::check;

// Herbie's going to have a field day with this
pub fn round_to_nearest_mm(x: f64, y: f64, z: f64) -> (f64, f64, f64) {
    let new_x = (x * 1000.).round() as f64 / 1000.;
    let new_y = (y * 1000.).round() as f64 / 1000.;
    let new_z = (z * 1000.).round() as f64 / 1000.;
    (new_x, new_y, new_z)
}

pub fn get_ostn_ref(x: &i32, y: &i32) -> (f64, f64, f64) {
    let key = format!("{:03x}{:03x}", y, x);
    // some or None, so try! this
    let result = ostn02_lookup(&*key).unwrap();
    // if we get a hit
    let data2 = (result.0 as f64 / 1000. + MIN_X_SHIFT,
                 result.1 as f64 / 1000. + MIN_Y_SHIFT,
                 result.2 as f64 / 1000. + MIN_Z_SHIFT);
    data2
}

// Input values must be valid ETRS89 grid references
// See p20 of the transformation user guide at
// https://www.ordnancesurvey.co.uk/business-and-government/help-and-support/navigation-technology/os-net/formats-for-developers.html
pub fn ostn02_shifts(x: &f64, y: &f64) -> (f64, f64, f64) {
    let e_index = (*x / 1000.) as i32;
    let n_index = (*y / 1000.) as i32;

    // eastings and northings of the south-west corner of the cell
    let x0 = e_index * 1000;
    let y0 = n_index * 1000;

    // The easting, northing and geoid shifts for the four corners of the cell
    // any of these could be Err, so use try!
    let s0_ref: (f64, f64, f64) = get_ostn_ref(&(e_index + 0), &(n_index + 0));
    let s1_ref: (f64, f64, f64) = get_ostn_ref(&(e_index + 1), &(n_index + 0));
    let s2_ref: (f64, f64, f64) = get_ostn_ref(&(e_index + 0), &(n_index + 1));
    let s3_ref: (f64, f64, f64) = get_ostn_ref(&(e_index + 1), &(n_index + 1));
    // only continue if we get Results for the above

    // offset within square
    let dx = *x - (x0 as f64);
    let dy = *y - (y0 as f64);

    // the python script divides by an int here, which = 0 (e.g. 300 / 1000)
    let t = dx / 1000.;
    let u = dy / 1000.;

    let f0 = (1. - t as f64) * (1. - u as f64);
    let f1 = t as f64 * (1. - u as f64);
    let f2 = (1. - t as f64) * u as f64;
    let f3 = t as f64 * u as f64;

    // bilinear interpolation, to obtain the actual shifts
    let se = f0 * s0_ref.0 + f1 * s1_ref.0 + f2 * s2_ref.0 + f3 * s3_ref.0;
    let sn = f0 * s0_ref.1 + f1 * s1_ref.1 + f2 * s2_ref.1 + f3 * s3_ref.1;
    let sg = f0 * s0_ref.2 + f1 * s1_ref.2 + f2 * s2_ref.2 + f3 * s3_ref.2;

    let (r_se, r_sn, r_sg) = round_to_nearest_mm(se, sn, sg);
    (r_se, r_sn, r_sg)

}

/// Perform Longitude, Latitude to ETRS89 conversion
///
/// # Examples
///
/// ```
/// use lonlat_bng::ostn02::convert_etrs89
/// assert_eq!((651307.003, 313255.686), convert_etrs89(&1.716073973, &52.658007833).unwrap());
#[allow(non_snake_case)]
// See Annexe B (p23) of the transformation user guide for instructions
pub fn convert_etrs89(longitude: &f64, latitude: &f64) -> Result<(f64, f64), f64> {
    // input is restricted to the UK bounding box
    // Convert bounds-checked input to degrees, or return an Err
    let lon_1: f64 = try!(check(*longitude as f32, (MIN_LONGITUDE, MAX_LONGITUDE)).map_err(|e| e)) as f64 * RAD;
    let lat_1: f64 = try!(check(*latitude as f32, (MIN_LATITUDE, MAX_LATITUDE)).map_err(|e| e)) as f64 * RAD;
    let alt = 0.0;
    // ellipsoid squared eccentricity constant
    let e2 = (WGS84_A.powf(2.) - WGS84_B.powf(2.)) / WGS84_A.powf(2.);
    let n = (WGS84_A - WGS84_B) / (WGS84_A + WGS84_B);
    let phi = RAD * *latitude;
    let lambda = RAD * *longitude;

    let sp2 = phi.sin().powf(2.);
    let nu = WGS84_A * F0 * (1. - e2 * sp2).powf(-0.5); // v
    let rho = WGS84_A * F0 * (1. - e2) * (1. - e2 * sp2).powf(-1.5);
    let eta2 = nu / rho - 1.;

    let m = compute_m(&phi, &WGS84_B, &n);

    let cp = phi.cos();
    let sp = phi.sin();
    let tp = phi.tan();
    let tp2 = tp.powf(2.);
    let tp4 = tp.powf(4.);

    let I = m + N0;
    let II = nu / 2. * sp * cp;
    let III = nu / 24. * sp * cp.powf(3.) * (5. - tp2 + 9. * eta2);
    let IIIA = nu / 720. * sp * cp.powf(5.) * (61. - 58. * tp2 + tp4);

    let IV = nu * cp;
    let V = nu / 6. * cp.powf(3.) * (nu / rho - tp2);
    let VI = nu / 120. * cp.powf(5.) * (5. - 18. * tp2 + tp4 + 14. * eta2 - 58. * tp2 * eta2);

    let l = lambda - LAM0;
    let north = I + II * l.powf(2.) + III * l.powf(4.) + IIIA * l.powf(6.);
    let east = E0 + IV * l + V * l.powf(3.) + VI * l.powf(5.);
    let (rounded_eastings, rounded_northings, _) = round_to_nearest_mm(east, north, 1.00);
    Ok((rounded_eastings, rounded_northings))
}

fn compute_m(phi: &f64, b: &f64, n: &f64) -> f64 {
    let p_plus = *phi + PHI0;
    let p_minus = *phi - PHI0;

    let result = *b * F0 *
                 ((1. + *n * (1. + 5. / 4. * *n * (1. + *n))) * p_minus -
                  3. * *n * (1. + *n * (1. + 7. / 8. * *n)) * p_minus.sin() * p_plus.cos() +
                  (15. / 8. * *n * (*n * (1. + *n))) * (2. * p_minus).sin() * (2. * p_plus).cos() -
                  35. / 24. * n.powf(3.) * (3. * p_minus).sin() * (3. * p_plus).cos());
    result
}
// Convert OSGB36 coordinates to ETRS89 using OSTN02 shifts
// pub fn shift_osgb36_to_etrs89(E: &f64, N: &f64) -> (f64, f64) {
//     let z0 = 0.000;
//     let epsilon = 0.00001;
//     let (dx, dy, dz) = ostn02_shifts(&E, &N);
//     let (x, y, z) = (E - dx, N - dy, dz);
//     let (last_dx, last_dy) = (dx.clone(), dy.clone());
//     while (dx - last_dx).abs() < epsilon && (dy - last_dy).abs() < epsilon {
//         let (dx, dy, dz) = ostn02_shifts(&x, &y);
//         let (x, y) = (E - dx, N - dy);
//         let (last_dx, last_dy) = (dx, dy);
//     }
//     let (x, y, z) = round_to_nearest_mm(E - dx, N - dy, z0 + dz);
//     (x, y)
// }
<|endoftext|>


<commit_before>// mod shifts;
// use shifts::get_shifts_hashmap;
use super::GRS80_SEMI_MAJOR;
use super::GRS80_SEMI_MINOR;

use super::RAD;
use super::MIN_LONGITUDE;
use super::MAX_LONGITUDE;
use super::MIN_LATITUDE;
use super::MAX_LATITUDE;

use super::TRUE_ORIGIN_EASTING;
use super::TRUE_ORIGIN_NORTHING;

const WGS84_A: f64 = GRS80_SEMI_MAJOR;
const WGS84_B: f64 = GRS80_SEMI_MINOR;

// lon and lat of true origin
const LAM0: f64 = RAD * -2.0;
const PHI0: f64 = RAD * 49.0;

// Easting and Northing of origin
const E0: f64 = TRUE_ORIGIN_EASTING;
const N0: f64 = TRUE_ORIGIN_NORTHING;
// convergence factor
const F0: f64 = 0.9996012717;

const MIN_X_SHIFT: f64 = 86.275;
const MIN_Y_SHIFT: f64 = -81.603;
const MIN_Z_SHIFT: f64 = 43.982;

use ostn02_phf::ostn02_lookup;
use super::check;

// Herbie's going to have a field day with this
pub fn round_to_nearest_mm(x: f64, y: f64, z: f64) -> (f64, f64, f64) {
    let new_x = (x * 1000.).round() as f64 / 1000.;
    let new_y = (y * 1000.).round() as f64 / 1000.;
    let new_z = (z * 1000.).round() as f64 / 1000.;
    (new_x, new_y, new_z)
}

pub fn get_ostn_ref(x: &i32, y: &i32) -> (f64, f64, f64) {
    let key = format!("{:03x}{:03x}", y, x);
    // some or None, so try! this
    let result = ostn02_lookup(&*key).unwrap();
    // if we get a hit
    let data2 = (result.0 as f64 / 1000. + MIN_X_SHIFT,
                 result.1 as f64 / 1000. + MIN_Y_SHIFT,
                 result.2 as f64 / 1000. + MIN_Z_SHIFT);
    data2
}

// Input values must be valid ETRS89 grid references
// See p20 of the transformation user guide at
// https://www.ordnancesurvey.co.uk/business-and-government/help-and-support/navigation-technology/os-net/formats-for-developers.html
pub fn ostn02_shifts(x: &f64, y: &f64) -> (f64, f64, f64) {
    let e_index = (*x / 1000.) as i32;
    let n_index = (*y / 1000.) as i32;

    // eastings and northings of the south-west corner of the cell
    let x0 = e_index * 1000;
    let y0 = n_index * 1000;

    // The easting, northing and geoid shifts for the four corners of the cell
    // any of these could be Err, so use try!
    let s0_ref: (f64, f64, f64) = get_ostn_ref(&(e_index + 0), &(n_index + 0));
    let s1_ref: (f64, f64, f64) = get_ostn_ref(&(e_index + 1), &(n_index + 0));
    let s2_ref: (f64, f64, f64) = get_ostn_ref(&(e_index + 0), &(n_index + 1));
    let s3_ref: (f64, f64, f64) = get_ostn_ref(&(e_index + 1), &(n_index + 1));
    // only continue if we get Results for the above

    // offset within square
    let dx = *x - (x0 as f64);
    let dy = *y - (y0 as f64);

    // the python script divides by an int here, which = 0 (e.g. 300 / 1000)
    let t = dx / 1000.;
    let u = dy / 1000.;

    let f0 = (1. - t as f64) * (1. - u as f64);
    let f1 = t as f64 * (1. - u as f64);
    let f2 = (1. - t as f64) * u as f64;
    let f3 = t as f64 * u as f64;

    // bilinear interpolation, to obtain the actual shifts
    let se = f0 * s0_ref.0 + f1 * s1_ref.0 + f2 * s2_ref.0 + f3 * s3_ref.0;
    let sn = f0 * s0_ref.1 + f1 * s1_ref.1 + f2 * s2_ref.1 + f3 * s3_ref.1;
    let sg = f0 * s0_ref.2 + f1 * s1_ref.2 + f2 * s2_ref.2 + f3 * s3_ref.2;

    let (r_se, r_sn, r_sg) = round_to_nearest_mm(se, sn, sg);
    (r_se, r_sn, r_sg)

}

/// Perform Longitude, Latitude to ETRS89 conversion
///
/// # Examples
///
/// ```
/// use lonlat_bng::ostn02::convert_etrs89
/// assert_eq!((651307.003, 313255.686), convert_etrs89(&1.716073973, &52.658007833).unwrap());
#[allow(non_snake_case)]
// See Annexe B (p23) of the transformation user guide for instructions
pub fn convert_etrs89(longitude: &f64, latitude: &f64) -> Result<(f64, f64), f64> {
    // input is restricted to the UK bounding box
    // Convert bounds-checked input to degrees, or return an Err
    let lon_1: f64 = try!(check(*longitude as f32, (MIN_LONGITUDE, MAX_LONGITUDE)).map_err(|e| e)) as f64 * RAD;
    let lat_1: f64 = try!(check(*latitude as f32, (MIN_LATITUDE, MAX_LATITUDE)).map_err(|e| e)) as f64 * RAD;
    let alt = 0.0;
    // ellipsoid squared eccentricity constant
    let e2 = (WGS84_A.powf(2.) - WGS84_B.powf(2.)) / WGS84_A.powf(2.);
    let n = (WGS84_A - WGS84_B) / (WGS84_A + WGS84_B);
    let phi = RAD * *latitude;
    let lambda = RAD * *longitude;

    let sp2 = phi.sin().powf(2.);
    let nu = WGS84_A * F0 * (1. - e2 * sp2).powf(-0.5); // v
    let rho = WGS84_A * F0 * (1. - e2) * (1. - e2 * sp2).powf(-1.5);
    let eta2 = nu / rho - 1.;

    let m = compute_m(&phi, &WGS84_B, &n);

    let cp = phi.cos();
    let sp = phi.sin();
    let tp = phi.tan();
    let tp2 = tp.powf(2.);
    let tp4 = tp.powf(4.);

    let I = m + N0;
    let II = nu / 2. * sp * cp;
    let III = nu / 24. * sp * cp.powf(3.) * (5. - tp2 + 9. * eta2);
    let IIIA = nu / 720. * sp * cp.powf(5.) * (61. - 58. * tp2 + tp4);

    let IV = nu * cp;
    let V = nu / 6. * cp.powf(3.) * (nu / rho - tp2);
    let VI = nu / 120. * cp.powf(5.) * (5. - 18. * tp2 + tp4 + 14. * eta2 - 58. * tp2 * eta2);

    let l = lambda - LAM0;
    let north = I + II * l.powf(2.) + III * l.powf(4.) + IIIA * l.powf(6.);
    let east = E0 + IV * l + V * l.powf(3.) + VI * l.powf(5.);
    let (rounded_eastings, rounded_northings, _) = round_to_nearest_mm(east, north, 1.00);
    Ok((rounded_eastings, rounded_northings))
}

/// Perform Longitude, Latitude to OSGB36 conversion
///
/// # Examples
///
/// ```
/// use lonlat_bng::ostn02::convert_osgb36
/// assert_eq!((651409.792, 313177.448), convert_etrs89(&1.716073973, &52.658007833).unwrap());
#[allow(non_snake_case)]
pub fn convert_osgb36(longitude: &f64, latitude: &f64) -> Result<(f64, f64), f64> {
    // convert input to ETRS89
    let (eastings, northings) = try!(convert_etrs89(longitude, latitude).map_err(|e| e));
    let alt = 0.0;
    // obtain OSTN02 corrections, and incorporate
    let (e_shift, n_shift, _) = ostn02_shifts(&eastings, &northings);
    let (shifted_e, shifted_n) = (eastings + e_shift, northings + n_shift);
    Ok((shifted_e, shifted_n))
}

fn compute_m(phi: &f64, b: &f64, n: &f64) -> f64 {
    let p_plus = *phi + PHI0;
    let p_minus = *phi - PHI0;

    let result = *b * F0 *
                 ((1. + *n * (1. + 5. / 4. * *n * (1. + *n))) * p_minus -
                  3. * *n * (1. + *n * (1. + 7. / 8. * *n)) * p_minus.sin() * p_plus.cos() +
                  (15. / 8. * *n * (*n * (1. + *n))) * (2. * p_minus).sin() * (2. * p_plus).cos() -
                  35. / 24. * n.powf(3.) * (3. * p_minus).sin() * (3. * p_plus).cos());
    result
}
// Convert OSGB36 coordinates to ETRS89 using OSTN02 shifts
// pub fn shift_osgb36_to_etrs89(E: &f64, N: &f64) -> (f64, f64) {
//     let z0 = 0.000;
//     let epsilon = 0.00001;
//     let (dx, dy, dz) = ostn02_shifts(&E, &N);
//     let (x, y, z) = (E - dx, N - dy, dz);
//     let (last_dx, last_dy) = (dx.clone(), dy.clone());
//     while (dx - last_dx).abs() < epsilon && (dy - last_dy).abs() < epsilon {
//         let (dx, dy, dz) = ostn02_shifts(&x, &y);
//         let (x, y) = (E - dx, N - dy);
//         let (last_dx, last_dy) = (dx, dy);
//     }
//     let (x, y, z) = round_to_nearest_mm(E - dx, N - dy, z0 + dz);
//     (x, y)
// }
<commit_msg>Always return a value from the correction lookup, even if it's 0.0 x3<commit_after>// mod shifts;
// use shifts::get_shifts_hashmap;
use super::GRS80_SEMI_MAJOR;
use super::GRS80_SEMI_MINOR;

use super::RAD;
use super::MIN_LONGITUDE;
use super::MAX_LONGITUDE;
use super::MIN_LATITUDE;
use super::MAX_LATITUDE;

use super::TRUE_ORIGIN_EASTING;
use super::TRUE_ORIGIN_NORTHING;

const WGS84_A: f64 = GRS80_SEMI_MAJOR;
const WGS84_B: f64 = GRS80_SEMI_MINOR;

// lon and lat of true origin
const LAM0: f64 = RAD * -2.0;
const PHI0: f64 = RAD * 49.0;

// Easting and Northing of origin
const E0: f64 = TRUE_ORIGIN_EASTING;
const N0: f64 = TRUE_ORIGIN_NORTHING;
// convergence factor
const F0: f64 = 0.9996012717;

const MIN_X_SHIFT: f64 = 86.275;
const MIN_Y_SHIFT: f64 = -81.603;
const MIN_Z_SHIFT: f64 = 43.982;

use ostn02_phf::ostn02_lookup;
use super::check;

// Herbie's going to have a field day with this
pub fn round_to_nearest_mm(x: f64, y: f64, z: f64) -> (f64, f64, f64) {
    let new_x = (x * 1000.).round() as f64 / 1000.;
    let new_y = (y * 1000.).round() as f64 / 1000.;
    let new_z = (z * 1000.).round() as f64 / 1000.;
    (new_x, new_y, new_z)
}

pub fn get_ostn_ref(x: &i32, y: &i32) -> (f64, f64, f64) {
    let key = format!("{:03x}{:03x}", y, x);
    // some or None, so try! this
    let result = ostn02_lookup(&*key);
    // The implication here is that all valid kilometer-grid references return corrections
    // and that a transformation is valid even if we apply (0.0, 0.0, 0.0)
    let data2 = match result {
        Some(result) => {
            (result.0 as f64 / 1000. + MIN_X_SHIFT,
             result.1 as f64 / 1000. + MIN_Y_SHIFT,
             result.2 as f64 / 1000. + MIN_Z_SHIFT)
        }
        _ => (0.0, 0.0, 0.0),
    };
    data2
}

// Input values must be valid ETRS89 grid references
// See p20 of the transformation user guide at
// https://www.ordnancesurvey.co.uk/business-and-government/help-and-support/navigation-technology/os-net/formats-for-developers.html
pub fn ostn02_shifts(x: &f64, y: &f64) -> (f64, f64, f64) {
    let e_index = (*x / 1000.) as i32;
    let n_index = (*y / 1000.) as i32;

    // eastings and northings of the south-west corner of the cell
    let x0 = e_index * 1000;
    let y0 = n_index * 1000;

    // The easting, northing and geoid shifts for the four corners of the cell
    // any of these could be Err, so use try!
    let s0_ref: (f64, f64, f64) = get_ostn_ref(&(e_index + 0), &(n_index + 0));
    let s1_ref: (f64, f64, f64) = get_ostn_ref(&(e_index + 1), &(n_index + 0));
    let s2_ref: (f64, f64, f64) = get_ostn_ref(&(e_index + 0), &(n_index + 1));
    let s3_ref: (f64, f64, f64) = get_ostn_ref(&(e_index + 1), &(n_index + 1));
    // only continue if we get Results for the above

    // offset within square
    let dx = *x - (x0 as f64);
    let dy = *y - (y0 as f64);

    // the python script divides by an int here, which = 0 (e.g. 300 / 1000)
    let t = dx / 1000.;
    let u = dy / 1000.;

    let f0 = (1. - t as f64) * (1. - u as f64);
    let f1 = t as f64 * (1. - u as f64);
    let f2 = (1. - t as f64) * u as f64;
    let f3 = t as f64 * u as f64;

    // bilinear interpolation, to obtain the actual shifts
    let se = f0 * s0_ref.0 + f1 * s1_ref.0 + f2 * s2_ref.0 + f3 * s3_ref.0;
    let sn = f0 * s0_ref.1 + f1 * s1_ref.1 + f2 * s2_ref.1 + f3 * s3_ref.1;
    let sg = f0 * s0_ref.2 + f1 * s1_ref.2 + f2 * s2_ref.2 + f3 * s3_ref.2;

    let (r_se, r_sn, r_sg) = round_to_nearest_mm(se, sn, sg);
    (r_se, r_sn, r_sg)

}

/// Perform Longitude, Latitude to ETRS89 conversion
///
/// # Examples
///
/// ```
/// use lonlat_bng::ostn02::convert_etrs89
/// assert_eq!((651307.003, 313255.686), convert_etrs89(&1.716073973, &52.658007833).unwrap());
#[allow(non_snake_case)]
// See Annexe B (p23) of the transformation user guide for instructions
pub fn convert_etrs89(longitude: &f64, latitude: &f64) -> Result<(f64, f64), f64> {
    // input is restricted to the UK bounding box
    // Convert bounds-checked input to degrees, or return an Err
    let lon_1: f64 = try!(check(*longitude as f32, (MIN_LONGITUDE, MAX_LONGITUDE))
                              .map_err(|e| e)) as f64 * RAD;
    let lat_1: f64 = try!(check(*latitude as f32, (MIN_LATITUDE, MAX_LATITUDE))
                              .map_err(|e| e)) as f64 * RAD;
    let alt = 0.0;
    // ellipsoid squared eccentricity constant
    let e2 = (WGS84_A.powf(2.) - WGS84_B.powf(2.)) / WGS84_A.powf(2.);
    let n = (WGS84_A - WGS84_B) / (WGS84_A + WGS84_B);
    let phi = RAD * *latitude;
    let lambda = RAD * *longitude;

    let sp2 = phi.sin().powf(2.);
    let nu = WGS84_A * F0 * (1. - e2 * sp2).powf(-0.5); // v
    let rho = WGS84_A * F0 * (1. - e2) * (1. - e2 * sp2).powf(-1.5);
    let eta2 = nu / rho - 1.;

    let m = compute_m(&phi, &WGS84_B, &n);

    let cp = phi.cos();
    let sp = phi.sin();
    let tp = phi.tan();
    let tp2 = tp.powf(2.);
    let tp4 = tp.powf(4.);

    let I = m + N0;
    let II = nu / 2. * sp * cp;
    let III = nu / 24. * sp * cp.powf(3.) * (5. - tp2 + 9. * eta2);
    let IIIA = nu / 720. * sp * cp.powf(5.) * (61. - 58. * tp2 + tp4);

    let IV = nu * cp;
    let V = nu / 6. * cp.powf(3.) * (nu / rho - tp2);
    let VI = nu / 120. * cp.powf(5.) * (5. - 18. * tp2 + tp4 + 14. * eta2 - 58. * tp2 * eta2);

    let l = lambda - LAM0;
    let north = I + II * l.powf(2.) + III * l.powf(4.) + IIIA * l.powf(6.);
    let east = E0 + IV * l + V * l.powf(3.) + VI * l.powf(5.);
    let (rounded_eastings, rounded_northings, _) = round_to_nearest_mm(east, north, 1.00);
    Ok((rounded_eastings, rounded_northings))
}

/// Perform Longitude, Latitude to OSGB36 conversion
///
/// # Examples
///
/// ```
/// use lonlat_bng::ostn02::convert_osgb36
/// assert_eq!((651409.792, 313177.448), convert_etrs89(&1.716073973, &52.658007833).unwrap());
#[allow(non_snake_case)]
pub fn convert_osgb36(longitude: &f64, latitude: &f64) -> Result<(f64, f64), f64> {
    // convert input to ETRS89
    let (eastings, northings) = try!(convert_etrs89(longitude, latitude).map_err(|e| e));
    let alt = 0.0;
    // obtain OSTN02 corrections, and incorporate
    let (e_shift, n_shift, _) = ostn02_shifts(&eastings, &northings);
    let (shifted_e, shifted_n) = (eastings + e_shift, northings + n_shift);
    Ok((shifted_e, shifted_n))
}

fn compute_m(phi: &f64, b: &f64, n: &f64) -> f64 {
    let p_plus = *phi + PHI0;
    let p_minus = *phi - PHI0;

    let result = *b * F0 *
                 ((1. + *n * (1. + 5. / 4. * *n * (1. + *n))) * p_minus -
                  3. * *n * (1. + *n * (1. + 7. / 8. * *n)) * p_minus.sin() * p_plus.cos() +
                  (15. / 8. * *n * (*n * (1. + *n))) * (2. * p_minus).sin() * (2. * p_plus).cos() -
                  35. / 24. * n.powf(3.) * (3. * p_minus).sin() * (3. * p_plus).cos());
    result
}
// Convert OSGB36 coordinates to ETRS89 using OSTN02 shifts
// pub fn shift_osgb36_to_etrs89(E: &f64, N: &f64) -> (f64, f64) {
//     let z0 = 0.000;
//     let epsilon = 0.00001;
//     let (dx, dy, dz) = ostn02_shifts(&E, &N);
//     let (x, y, z) = (E - dx, N - dy, dz);
//     let (last_dx, last_dy) = (dx.clone(), dy.clone());
//     while (dx - last_dx).abs() < epsilon && (dy - last_dy).abs() < epsilon {
//         let (dx, dy, dz) = ostn02_shifts(&x, &y);
//         let (x, y) = (E - dx, N - dy);
//         let (last_dx, last_dy) = (dx, dy);
//     }
//     let (x, y, z) = round_to_nearest_mm(E - dx, N - dy, z0 + dz);
//     (x, y)
// }
<|endoftext|>


<commit_before>use crate::util::color::ColorChoice;

use std::{
    fmt::{self, Display, Formatter},
    io::{self, Write},
};

#[derive(Clone, Debug)]
pub(crate) struct Colorizer {
    use_stderr: bool,
    color_when: ColorChoice,
    pieces: Vec<(String, Style)>,
}

impl Colorizer {
    #[inline]
    pub(crate) fn new(use_stderr: bool, color_when: ColorChoice) -> Self {
        Colorizer {
            use_stderr,
            color_when,
            pieces: vec![],
        }
    }

    #[inline]
    pub(crate) fn good(&mut self, msg: impl Into<String>) {
        self.pieces.push((msg.into(), Style::Good));
    }

    #[inline]
    pub(crate) fn warning(&mut self, msg: impl Into<String>) {
        self.pieces.push((msg.into(), Style::Warning));
    }

    #[inline]
    pub(crate) fn error(&mut self, msg: impl Into<String>) {
        self.pieces.push((msg.into(), Style::Error));
    }

    #[inline]
    #[allow(dead_code)]
    pub(crate) fn hint(&mut self, msg: impl Into<String>) {
        self.pieces.push((msg.into(), Style::Hint));
    }

    #[inline]
    pub(crate) fn none(&mut self, msg: impl Into<String>) {
        self.pieces.push((msg.into(), Style::Default));
    }
}

/// Printing methods.
impl Colorizer {
    #[cfg(feature = "color")]
    pub(crate) fn print(&self) -> io::Result<()> {
        use termcolor::{BufferWriter, ColorChoice as DepColorChoice, ColorSpec, WriteColor};

        let color_when = match self.color_when {
            ColorChoice::Always => DepColorChoice::Always,
            ColorChoice::Auto if is_a_tty(self.use_stderr) => DepColorChoice::Auto,
            _ => DepColorChoice::Never,
        };

        let writer = if self.use_stderr {
            BufferWriter::stderr(color_when)
        } else {
            BufferWriter::stdout(color_when)
        };

        let mut buffer = writer.buffer();

        for piece in &self.pieces {
            let mut color = ColorSpec::new();
            match piece.1 {
                Style::Good => {
                    color.set_fg(Some(termcolor::Color::Green));
                }
                Style::Warning => {
                    color.set_fg(Some(termcolor::Color::Yellow));
                }
                Style::Error => {
                    color.set_fg(Some(termcolor::Color::Red));
                    color.set_bold(true);
                }
                Style::Hint => {
                    color.set_dimmed(true);
                }
                Style::Default => {}
            }

            buffer.set_color(&color)?;
            buffer.write_all(piece.0.as_bytes())?;
            buffer.reset()?;
        }

        writer.print(&buffer)
    }

    #[cfg(not(feature = "color"))]
    pub(crate) fn print(&self) -> io::Result<()> {
        // [e]println can't be used here because it panics
        // if something went wrong. We don't want that.
        if self.use_stderr {
            let stderr = std::io::stderr();
            let mut stderr = stderr.lock();
            write!(stderr, "{}", self)
        } else {
            let stdout = std::io::stdout();
            let mut stdout = stdout.lock();
            write!(stdout, "{}", self)
        }
    }
}

/// Color-unaware printing. Never uses coloring.
impl Display for Colorizer {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        for piece in &self.pieces {
            Display::fmt(&piece.0, f)?;
        }

        Ok(())
    }
}

#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum Style {
    Good,
    Warning,
    Error,
    Hint,
    Default,
}

impl Default for Style {
    fn default() -> Self {
        Self::Default
    }
}

#[cfg(feature = "color")]
fn is_a_tty(stderr: bool) -> bool {
    let stream = if stderr {
        atty::Stream::Stderr
    } else {
        atty::Stream::Stdout
    };

    atty::is(stream)
}
<commit_msg>style: allow unused field<commit_after>use crate::util::color::ColorChoice;

use std::{
    fmt::{self, Display, Formatter},
    io::{self, Write},
};

#[derive(Clone, Debug)]
pub(crate) struct Colorizer {
    use_stderr: bool,
    #[allow(unused)]
    color_when: ColorChoice,
    pieces: Vec<(String, Style)>,
}

impl Colorizer {
    #[inline]
    pub(crate) fn new(use_stderr: bool, color_when: ColorChoice) -> Self {
        Colorizer {
            use_stderr,
            color_when,
            pieces: vec![],
        }
    }

    #[inline]
    pub(crate) fn good(&mut self, msg: impl Into<String>) {
        self.pieces.push((msg.into(), Style::Good));
    }

    #[inline]
    pub(crate) fn warning(&mut self, msg: impl Into<String>) {
        self.pieces.push((msg.into(), Style::Warning));
    }

    #[inline]
    pub(crate) fn error(&mut self, msg: impl Into<String>) {
        self.pieces.push((msg.into(), Style::Error));
    }

    #[inline]
    #[allow(dead_code)]
    pub(crate) fn hint(&mut self, msg: impl Into<String>) {
        self.pieces.push((msg.into(), Style::Hint));
    }

    #[inline]
    pub(crate) fn none(&mut self, msg: impl Into<String>) {
        self.pieces.push((msg.into(), Style::Default));
    }
}

/// Printing methods.
impl Colorizer {
    #[cfg(feature = "color")]
    pub(crate) fn print(&self) -> io::Result<()> {
        use termcolor::{BufferWriter, ColorChoice as DepColorChoice, ColorSpec, WriteColor};

        let color_when = match self.color_when {
            ColorChoice::Always => DepColorChoice::Always,
            ColorChoice::Auto if is_a_tty(self.use_stderr) => DepColorChoice::Auto,
            _ => DepColorChoice::Never,
        };

        let writer = if self.use_stderr {
            BufferWriter::stderr(color_when)
        } else {
            BufferWriter::stdout(color_when)
        };

        let mut buffer = writer.buffer();

        for piece in &self.pieces {
            let mut color = ColorSpec::new();
            match piece.1 {
                Style::Good => {
                    color.set_fg(Some(termcolor::Color::Green));
                }
                Style::Warning => {
                    color.set_fg(Some(termcolor::Color::Yellow));
                }
                Style::Error => {
                    color.set_fg(Some(termcolor::Color::Red));
                    color.set_bold(true);
                }
                Style::Hint => {
                    color.set_dimmed(true);
                }
                Style::Default => {}
            }

            buffer.set_color(&color)?;
            buffer.write_all(piece.0.as_bytes())?;
            buffer.reset()?;
        }

        writer.print(&buffer)
    }

    #[cfg(not(feature = "color"))]
    pub(crate) fn print(&self) -> io::Result<()> {
        // [e]println can't be used here because it panics
        // if something went wrong. We don't want that.
        if self.use_stderr {
            let stderr = std::io::stderr();
            let mut stderr = stderr.lock();
            write!(stderr, "{}", self)
        } else {
            let stdout = std::io::stdout();
            let mut stdout = stdout.lock();
            write!(stdout, "{}", self)
        }
    }
}

/// Color-unaware printing. Never uses coloring.
impl Display for Colorizer {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        for piece in &self.pieces {
            Display::fmt(&piece.0, f)?;
        }

        Ok(())
    }
}

#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum Style {
    Good,
    Warning,
    Error,
    Hint,
    Default,
}

impl Default for Style {
    fn default() -> Self {
        Self::Default
    }
}

#[cfg(feature = "color")]
fn is_a_tty(stderr: bool) -> bool {
    let stream = if stderr {
        atty::Stream::Stderr
    } else {
        atty::Stream::Stdout
    };

    atty::is(stream)
}
<|endoftext|>


<commit_before>// Copyright (c) 2015 David Stainton <dstainton415@gmail.com>
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! TCP packet abstraction

use packet::Packet;
use packet::HasPseudoheader;
use packet::checksum::rfc1071_checksum;
use pnet_macros::types::*;

/// Represents a TCP Packet
#[packet]
pub struct Tcp {
    source: u16be,
    destination: u16be,
    sequence: u32be,
    acknowledgement: u32be,
    data_offset_and_reserved: u8,
    control_bits: u8,
    window: u16be,
    checksum: u16be,
    urgent_pointer: u16be,
    #[length_fn = "tcp_options_length"]
    options: Vec<TcpOptions>,
    #[length_fn = "tcp_padding_length"]
    padding: Vec<TcpPadding>,
    #[payload]
    payload: Vec<u8>
}

fn tcp_options_length<'a>(tcp: &TcpPacket<'a>) -> usize {
    /* The data offset field specifies the total size of the TCP header
       in 32-bit words. The minimum size of a TCP header is 20 bytes and thus
       TCP headers must have data offset set to 5 or more.
     */
    let size = tcp.get_data_offset_and_reserved() as usize;
    return (size / 4) - 5 // XXX the "reserved" 4-bit word is zeros and is ignored when we divide by 4
}

/// Represents the TCP Option fields
#[packet]
pub struct TcpOptions {
    kind: u8,
    #[payload]
    data: Vec<u8>
}

fn tcp_padding_length<'a>(tcp: &TcpPacket<'a>) -> usize {
    /* The TCP header padding is used to ensure that the entire header
       ends on a 32 bit boundary.
     */
    return tcp.get_data_offset_and_reserved() as usize % 4;
}

/// Represents the TCP header padding
#[packet]
pub struct TcpPadding {
    #[payload]
    data: Vec<u8>
}

/// Calculates the checksum of a TCP packet
/// The passed in TcpPacket must have it's initial checksum value set to zero.
pub fn checksum<'a, T: HasPseudoheader>(packet: &TcpPacket<'a>, encapsulating_packet: T) -> u16be {
    let mut sum = encapsulating_packet.pseudoheader_checksum();
    let length = packet.packet().len() as u32;
    sum = sum + length & 0xffff;
    sum = sum + length >> 16;
    return rfc1071_checksum(packet.packet(), sum);
}

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

    const TCP_MIN_HEADER_LEN: usize = 20;
    const TCP_OPTIONS_LEN: usize = 12;
    const PAYLOAD_LEN: usize = 5;

    #[test]
    fn tcp_header_ipv4_test() {
        use pnet::packet::ip::IpNextHeaderProtocols;
        use pnet::packet::ipv4::{Ipv4Packet,MutableIpv4Packet};
        use std::net::{Ipv4Addr};

        const IPV4_HEADER_LEN: usize = 20;

        let mut packet = [0u8; IPV4_HEADER_LEN + TCP_MIN_HEADER_LEN + TCP_OPTIONS_LEN + PAYLOAD_LEN];
        let ipv4_source = Ipv4Addr::new(127, 0, 0, 1);
        let ipv4_destination = Ipv4Addr::new(127, 0, 0, 1);
        let next_level_protocol = IpNextHeaderProtocols::Tcp;

        {
            let mut mut_ip_header = MutableIpv4Packet::new(&mut packet[..]).unwrap();
            mut_ip_header.set_next_level_protocol(next_level_protocol);
            mut_ip_header.set_source(ipv4_source);
            mut_ip_header.set_destination(ipv4_destination);
        }

        {
            let ip_header = Ipv4Packet::new(&packet[..]).unwrap();
            let tcp_header = TcpPacket::new(&packet[IPV4_HEADER_LEN..]).unwrap();
            let csum = checksum(tcp_header, ip_header);
        }

        {
            generate_simple_tcp_header(&mut packet[IPV4_HEADER_LEN..]);
        }

        // Set payload data
        packet[IPV4_HEADER_LEN + TCP_MIN_HEADER_LEN + TCP_OPTIONS_LEN + 0] = 'm' as u8;
        packet[IPV4_HEADER_LEN + TCP_MIN_HEADER_LEN + TCP_OPTIONS_LEN + 1] = 'e' as u8;
        packet[IPV4_HEADER_LEN + TCP_MIN_HEADER_LEN + TCP_OPTIONS_LEN + 2] = 'o' as u8;
        packet[IPV4_HEADER_LEN + TCP_MIN_HEADER_LEN + TCP_OPTIONS_LEN + 3] = 'w' as u8;
        packet[IPV4_HEADER_LEN + TCP_MIN_HEADER_LEN + TCP_OPTIONS_LEN + 4] = '\n' as u8;

        let ref_tcp_packet = [0xe0, 0x0f, // source port
                              0x25, 0xc2, // dest port
                              0xdf, 0x06, // sequence
                              0xe6, 0xe6,
                              0xc9, 0x2d, // acknowledgement
                              0x98, 0x71,
                              0x80,       // header length + reserved
                              0x18,       // control bits
                              0x02, 0xab, // window
                              0xfe, 0x2d, // checksum
                              0x00, 0x00, // urgent pointer
                              0x01, 0x01, // tcp option no-op
                              0x08, 0x0a, // tcp option timestamp, options length == 10 bytes
                              0x1d, 0xfc, // 4-byte send timestamp
                              0xcb, 0x76,
                              0x1d, 0xfc, // 4-byte latest replied timestamp
                              0xbe, 0x62,
                              0x6d, 0x65, // payload
                              0x6f, 0x77, 0x0a];
        assert_eq!(&ref_tcp_packet[..], &packet[IPV4_HEADER_LEN..]);

        //tcp/ipv4 == "45, 00 00 39 58 89 40 00 40 06 e4 33 7f 00 00 01 7f 00 00 01 e0 0f 25 c2 df 06 e6 e6 c9 2d 98 71 80 18 02 ab fe 2d 00 00 01 01 08 0a 1d fc cb 76 1d fc be 62 6d 65 6f 77 0a";

    }

    fn generate_simple_tcp_header<'p>(packet: &'p mut [u8]) {
        let mut tcp_header = MutableTcpPacket::new(&mut packet[..]).unwrap();
        tcp_header.set_source(57359);
        assert_eq!(tcp_header.get_source(), 57359);

        tcp_header.set_destination(9666);
        assert_eq!(tcp_header.get_destination(), 9666);

        tcp_header.set_sequence(3741771494);
        assert_eq!(tcp_header.get_sequence(), 3741771494);

        tcp_header.set_acknowledgement(3375208561);
        assert_eq!(tcp_header.get_acknowledgement(), 3375208561);

        tcp_header.set_data_offset_and_reserved(0x80);
        assert_eq!(tcp_header.get_data_offset_and_reserved(), 0x80);

        tcp_header.set_control_bits(0x18);
        assert_eq!(tcp_header.get_control_bits(), 0x18);

        tcp_header.set_window(0x02ab);
        assert_eq!(tcp_header.get_window(), 0x02ab);

        tcp_header.set_checksum(0xfe2d);
        assert_eq!(tcp_header.get_checksum(), 0xfe2d);

        tcp_header.set_urgent_pointer(0x0000);
        assert_eq!(tcp_header.get_urgent_pointer(), 0x0000);

        let mut opts: Vec<TcpOptions> = Vec::new();
        let tcp_option = TcpOptions{
            kind: 0x1,
            data: vec![0x01,0x08,0x0a,0x1d,0xfc,0xcb,0x76,0x1d,0xfc,0xbe,0x62],
        };
        opts.push(tcp_option);
        tcp_header.set_options(opts);
    }
}
<commit_msg>fix tcp checksum unit test<commit_after>// Copyright (c) 2015 David Stainton <dstainton415@gmail.com>
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! TCP packet abstraction

use packet::Packet;
use packet::HasPseudoheader;
use packet::checksum::rfc1071_checksum;
use pnet_macros::types::*;

/// Represents a TCP Packet
#[packet]
pub struct Tcp {
    source: u16be,
    destination: u16be,
    sequence: u32be,
    acknowledgement: u32be,
    data_offset_and_reserved: u8,
    control_bits: u8,
    window: u16be,
    checksum: u16be,
    urgent_pointer: u16be,
    #[length_fn = "tcp_options_length"]
    options: Vec<TcpOptions>,
    #[length_fn = "tcp_padding_length"]
    padding: Vec<TcpPadding>,
    #[payload]
    payload: Vec<u8>
}

fn tcp_options_length<'a>(tcp: &TcpPacket<'a>) -> usize {
    /* The data offset field specifies the total size of the TCP header
       in 32-bit words. The minimum size of a TCP header is 20 bytes and thus
       TCP headers must have data offset set to 5 or more.
     */
    let size = tcp.get_data_offset_and_reserved() as usize;
    return (size / 4) - 5 // XXX the "reserved" 4-bit word is zeros and is ignored when we divide by 4
}

/// Represents the TCP Option fields
#[packet]
pub struct TcpOptions {
    kind: u8,
    #[payload]
    data: Vec<u8>
}

fn tcp_padding_length<'a>(tcp: &TcpPacket<'a>) -> usize {
    /* The TCP header padding is used to ensure that the entire header
       ends on a 32 bit boundary.
     */
    return tcp.get_data_offset_and_reserved() as usize % 4;
}

/// Represents the TCP header padding
#[packet]
pub struct TcpPadding {
    #[payload]
    data: Vec<u8>
}

/// Calculates the checksum of a TCP packet
/// The passed in TcpPacket must have it's initial checksum value set to zero.
pub fn checksum<'a, T: HasPseudoheader>(packet: &TcpPacket<'a>, encapsulating_packet: T) -> u16be {
    let mut sum = encapsulating_packet.pseudoheader_checksum();
    let length = packet.packet().len() as u32;
    sum = sum + length & 0xffff;
    sum = sum + length >> 16;
    return rfc1071_checksum(packet.packet(), sum);
}

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

    const TCP_MIN_HEADER_LEN: usize = 20;
    const TCP_OPTIONS_LEN: usize = 12;
    const PAYLOAD_LEN: usize = 5;

    #[test]
    fn tcp_header_ipv4_test() {
        use pnet::packet::ip::IpNextHeaderProtocols;
        use pnet::packet::ipv4::{Ipv4Packet,MutableIpv4Packet};
        use std::net::{Ipv4Addr};

        const IPV4_HEADER_LEN: usize = 20;

        let mut packet = [0u8; IPV4_HEADER_LEN + TCP_MIN_HEADER_LEN + TCP_OPTIONS_LEN + PAYLOAD_LEN];
        let ipv4_source = Ipv4Addr::new(127, 0, 0, 1);
        let ipv4_destination = Ipv4Addr::new(127, 0, 0, 1);
        let next_level_protocol = IpNextHeaderProtocols::Tcp;

        {
            let mut mut_ip_header = MutableIpv4Packet::new(&mut packet[..]).unwrap();
            mut_ip_header.set_next_level_protocol(next_level_protocol);
            mut_ip_header.set_source(ipv4_source);
            mut_ip_header.set_destination(ipv4_destination);
        }

        {
            let mut mutable_tcp_header = MutableTcpPacket::new(&mut packet[IPV4_HEADER_LEN..]).unwrap();
            mutable_tcp_header.set_checksum(0);
        }

        {
            let ip_header = Ipv4Packet::new(&packet[..IPV4_HEADER_LEN]).unwrap();
            let tcp_header = TcpPacket::new(&packet[IPV4_HEADER_LEN..]).unwrap();
            let csum = checksum(&tcp_header, ip_header);
        }

        {
            generate_simple_tcp_header(&mut packet[IPV4_HEADER_LEN..]);
        }

        // Set payload data
        packet[IPV4_HEADER_LEN + TCP_MIN_HEADER_LEN + TCP_OPTIONS_LEN + 0] = 'm' as u8;
        packet[IPV4_HEADER_LEN + TCP_MIN_HEADER_LEN + TCP_OPTIONS_LEN + 1] = 'e' as u8;
        packet[IPV4_HEADER_LEN + TCP_MIN_HEADER_LEN + TCP_OPTIONS_LEN + 2] = 'o' as u8;
        packet[IPV4_HEADER_LEN + TCP_MIN_HEADER_LEN + TCP_OPTIONS_LEN + 3] = 'w' as u8;
        packet[IPV4_HEADER_LEN + TCP_MIN_HEADER_LEN + TCP_OPTIONS_LEN + 4] = '\n' as u8;

        let ref_tcp_packet = [0xe0, 0x0f, // source port
                              0x25, 0xc2, // dest port
                              0xdf, 0x06, // sequence
                              0xe6, 0xe6,
                              0xc9, 0x2d, // acknowledgement
                              0x98, 0x71,
                              0x80,       // header length + reserved
                              0x18,       // control bits
                              0x02, 0xab, // window
                              0xfe, 0x2d, // checksum
                              0x00, 0x00, // urgent pointer
                              0x01, 0x01, // tcp option no-op
                              0x08, 0x0a, // tcp option timestamp, options length == 10 bytes
                              0x1d, 0xfc, // 4-byte send timestamp
                              0xcb, 0x76,
                              0x1d, 0xfc, // 4-byte latest replied timestamp
                              0xbe, 0x62,
                              0x6d, 0x65, // payload
                              0x6f, 0x77, 0x0a];
        assert_eq!(&ref_tcp_packet[..], &packet[IPV4_HEADER_LEN..]);

        //tcp/ipv4 == "45, 00 00 39 58 89 40 00 40 06 e4 33 7f 00 00 01 7f 00 00 01 e0 0f 25 c2 df 06 e6 e6 c9 2d 98 71 80 18 02 ab fe 2d 00 00 01 01 08 0a 1d fc cb 76 1d fc be 62 6d 65 6f 77 0a";

    }

    fn generate_simple_tcp_header<'p>(packet: &'p mut [u8]) {
        let mut tcp_header = MutableTcpPacket::new(&mut packet[..]).unwrap();
        tcp_header.set_source(57359);
        assert_eq!(tcp_header.get_source(), 57359);

        tcp_header.set_destination(9666);
        assert_eq!(tcp_header.get_destination(), 9666);

        tcp_header.set_sequence(3741771494);
        assert_eq!(tcp_header.get_sequence(), 3741771494);

        tcp_header.set_acknowledgement(3375208561);
        assert_eq!(tcp_header.get_acknowledgement(), 3375208561);

        tcp_header.set_data_offset_and_reserved(0x80);
        assert_eq!(tcp_header.get_data_offset_and_reserved(), 0x80);

        tcp_header.set_control_bits(0x18);
        assert_eq!(tcp_header.get_control_bits(), 0x18);

        tcp_header.set_window(0x02ab);
        assert_eq!(tcp_header.get_window(), 0x02ab);

        tcp_header.set_checksum(0xfe2d);
        assert_eq!(tcp_header.get_checksum(), 0xfe2d);

        tcp_header.set_urgent_pointer(0x0000);
        assert_eq!(tcp_header.get_urgent_pointer(), 0x0000);

        let mut opts: Vec<TcpOptions> = Vec::new();
        let tcp_option = TcpOptions{
            kind: 0x1,
            data: vec![0x01,0x08,0x0a,0x1d,0xfc,0xcb,0x76,0x1d,0xfc,0xbe,0x62],
        };
        opts.push(tcp_option);
        tcp_header.set_options(opts);
    }
}
<|endoftext|>


<commit_before>mod document_spec;

use futures::future::{Future, ok, err, result};
use futures::Stream;
use hyper;
use hyper::{Get, Post, Head, StatusCode};
use hyper::header::ContentType;
use hyper::mime::{Mime, TopLevel, SubLevel};
use hyper::server::{Request, Response};
use serde_json;
use slog;
use tokio_service::{NewService, Service};
use tokio_core::reactor::Remote;

use error::{Error, ErrorKind};
pub use self::document_spec::DocumentSpec;
use workspace::Workspace;

pub struct Papers {
    remote: Remote,
    logger: slog::Logger,
}

impl Papers {
    pub fn new(remote: Remote, logger: slog::Logger) -> Papers {
        Papers {
            remote: remote,
            logger: logger,
        }
    }

    fn submit(&self, req: Request) -> Box<Future<Item=Response, Error=Error>> {
        let content_type = req.headers().get::<ContentType>().cloned();

        // Return an error if the content type is not application/json
        match content_type {
            Some(ContentType(Mime(TopLevel::Application, SubLevel::Json, _))) => (),
            _ => return Box::new(err(ErrorKind::UnprocessableEntity.into())),
        };

        let remote = self.remote.clone();
        let handle = self.remote.handle().unwrap().clone();

        let response = req.body()
            // Ignore hyper errors (i.e. io error, invalid utf-8, etc.) for now
            .map_err(|_| ErrorKind::UnprocessableEntity.into())
            .fold(Vec::new(), |mut acc, chunk| {
            // Receive all the body chunks into a vector
            acc.extend_from_slice(&chunk);
            ok::<_, Error>(acc)
        })

        // Parse the body into a DocumentSpec
        .and_then(|body| {
            result(
                serde_json::from_slice::<DocumentSpec>(body.as_slice())
                    .map_err(|err| Error::with_chain(err, ErrorKind::UnprocessableEntity))
            )
        })

        // Handle the parsed request
        .map_err(|_| ErrorKind::InternalServerError.into())
        .and_then(|document_spec| {
            result(Workspace::new(remote, document_spec))
        }).and_then(move |workspace| {
            handle.spawn(workspace.execute().map(|_| ()).map_err(|err| panic!("{}", err)));
            ok(Response::new().with_status(StatusCode::Ok))
        }).map_err(|_| ErrorKind::InternalServerError.into());

        Box::new(response)
    }

    fn preview(&self, req: Request) -> Box<Future<Item=Response, Error=Error>> {
        let content_type = {
            req.headers().get::<ContentType>().cloned()
        };

        // Return an error if the content type is not application/json
        match content_type {
            Some(ContentType(Mime(TopLevel::Application, SubLevel::Json, _))) => (),
            _ => return Box::new(err(ErrorKind::UnprocessableEntity.into())),
        };

        let remote = self.remote.clone();

        let response = req.body()
            // Ignore hyper errors (i.e. io error, invalid utf-8, etc.) for now
            .map_err(|err| Error::with_chain(err, ErrorKind::UnprocessableEntity))
            .fold(Vec::new(), |mut acc, chunk| {
            // Receive all the body chunks into a vector
            acc.extend_from_slice(&chunk);
            ok::<_, Error>(acc)
        })

        // Parse the body into a DocumentSpec
        .and_then(|body| {
            result(
                serde_json::from_slice::<DocumentSpec>(body.as_slice())
                    .map_err(|_| ErrorKind::UnprocessableEntity.into())
            )
        })

        // Handle the parsed request
        .and_then(|document_spec| {
            result(Workspace::new(remote, document_spec))
                .map_err(|err| Error::with_chain(err, ErrorKind::InternalServerError))
        })
        .and_then(|workspace| {
            workspace.preview()
        }).and_then(|populated_template| {
            ok(Response::new()
                .with_status(StatusCode::Ok)
                .with_body(populated_template))
        });

        Box::new(response)

    }

    fn health_check(&self, _: Request) -> Box<Future<Item=Response, Error=Error>> {
        ok(Response::new().with_status(StatusCode::Ok)).boxed()
    }
}

impl Service for Papers {
    type Request = Request;
    type Response = Response;
    type Error = hyper::Error;
    type Future = Box<Future<Item=Response, Error=hyper::Error>>;

    fn call(&self, req: Self::Request) -> Self::Future {
        // debug!("called with uri {:?}, and method {:?}", req.path(), req.method());
        let response = match (req.method(), req.path()) {
            (&Get, "/healthz") | (&Head, "/healthz") => self.health_check(req),
            (&Post, "/preview") => self.preview(req),
            (&Post, "/submit") => self.submit(req),
            _ => ok(Response::new().with_status(StatusCode::NotFound)).boxed(),
        }.then(|handler_result| {
            match handler_result {
                Ok(response) => ok(response),
                Err(err) => ok(err.into_response()),
            }
        });

        Box::new(response)
    }
}

impl NewService for Papers {
    type Request = Request;
    type Response = Response;
    type Error = hyper::Error;
    type Instance = Papers;

    fn new_service(&self) -> Result<Self::Instance, ::std::io::Error> {
        Ok(Papers {
            remote: self.remote.clone(),
            logger: self.logger.clone(),
        })
    }
}
<commit_msg>:sparkles: Add logging to endpoint calls<commit_after>mod document_spec;

use futures::future::{Future, ok, err, result};
use futures::Stream;
use hyper;
use hyper::{Get, Post, Head, StatusCode};
use hyper::header::ContentType;
use hyper::mime::{Mime, TopLevel, SubLevel};
use hyper::server::{Request, Response};
use serde_json;
use slog;
use tokio_service::{NewService, Service};
use tokio_core::reactor::Remote;

use error::{Error, ErrorKind};
pub use self::document_spec::DocumentSpec;
use workspace::Workspace;

pub struct Papers {
    remote: Remote,
    logger: slog::Logger,
}

impl Papers {
    pub fn new(remote: Remote, logger: slog::Logger) -> Papers {
        Papers {
            remote: remote,
            logger: logger,
        }
    }

    fn submit(&self, req: Request) -> Box<Future<Item=Response, Error=Error>> {
        info!(
            self.logger,
            "Received a submit request ({}) from {:?}",
            req.method(),
            req.remote_addr().unwrap(),
        );
        debug!(self.logger, "Full request: {:#?}", req);

        let content_type = req.headers().get::<ContentType>().cloned();

        // Return an error if the content type is not application/json
        match content_type {
            Some(ContentType(Mime(TopLevel::Application, SubLevel::Json, _))) => (),
            _ => return Box::new(err(ErrorKind::UnprocessableEntity.into())),
        };

        let remote = self.remote.clone();
        let handle = self.remote.handle().unwrap().clone();

        let response = req.body()
            // Ignore hyper errors (i.e. io error, invalid utf-8, etc.) for now
            .map_err(|_| ErrorKind::UnprocessableEntity.into())
            .fold(Vec::new(), |mut acc, chunk| {
            // Receive all the body chunks into a vector
            acc.extend_from_slice(&chunk);
            ok::<_, Error>(acc)
        })

        // Parse the body into a DocumentSpec
        .and_then(|body| {
            result(
                serde_json::from_slice::<DocumentSpec>(body.as_slice())
                    .map_err(|err| Error::with_chain(err, ErrorKind::UnprocessableEntity))
            )
        })

        // Handle the parsed request
        .map_err(|_| ErrorKind::InternalServerError.into())
        .and_then(|document_spec| {
            result(Workspace::new(remote, document_spec))
        }).and_then(move |workspace| {
            handle.spawn(workspace.execute().map(|_| ()).map_err(|err| panic!("{}", err)));
            ok(Response::new().with_status(StatusCode::Ok))
        }).map_err(|_| ErrorKind::InternalServerError.into());

        Box::new(response)
    }

    fn preview(&self, req: Request) -> Box<Future<Item=Response, Error=Error>> {
        info!(
            self.logger,
            "Received a preview request ({}) from: {:?}",
            req.method(),
            req.remote_addr().unwrap(),
        );
        debug!(self.logger, "Full request: {:#?}", req);
        let content_type = {
            req.headers().get::<ContentType>().cloned()
        };

        // Return an error if the content type is not application/json
        match content_type {
            Some(ContentType(Mime(TopLevel::Application, SubLevel::Json, _))) => (),
            _ => return Box::new(err(ErrorKind::UnprocessableEntity.into())),
        };

        let remote = self.remote.clone();

        let response = req.body()
            // Ignore hyper errors (i.e. io error, invalid utf-8, etc.) for now
            .map_err(|err| Error::with_chain(err, ErrorKind::UnprocessableEntity))
            .fold(Vec::new(), |mut acc, chunk| {
            // Receive all the body chunks into a vector
            acc.extend_from_slice(&chunk);
            ok::<_, Error>(acc)
        })

        // Parse the body into a DocumentSpec
        .and_then(|body| {
            result(
                serde_json::from_slice::<DocumentSpec>(body.as_slice())
                    .map_err(|_| ErrorKind::UnprocessableEntity.into())
            )
        })

        // Handle the parsed request
        .and_then(|document_spec| {
            result(Workspace::new(remote, document_spec))
                .map_err(|err| Error::with_chain(err, ErrorKind::InternalServerError))
        })
        .and_then(|workspace| {
            workspace.preview()
        }).and_then(|populated_template| {
            ok(Response::new()
                .with_status(StatusCode::Ok)
                .with_body(populated_template))
        });

        Box::new(response)

    }

    fn health_check(&self, req: Request) -> Box<Future<Item=Response, Error=Error>> {
        info!(
            self.logger,
            "Received a health request check ({}) from {:?}",
            req.method(),
            req.remote_addr().unwrap(),
        );
        ok(Response::new().with_status(StatusCode::Ok)).boxed()
    }
}

impl Service for Papers {
    type Request = Request;
    type Response = Response;
    type Error = hyper::Error;
    type Future = Box<Future<Item=Response, Error=hyper::Error>>;

    fn call(&self, req: Self::Request) -> Self::Future {
        // debug!("called with uri {:?}, and method {:?}", req.path(), req.method());
        let response = match (req.method(), req.path()) {
            (&Get, "/healthz") | (&Head, "/healthz") => self.health_check(req),
            (&Post, "/preview") => self.preview(req),
            (&Post, "/submit") => self.submit(req),
            _ => {
                info!(
                    self.logger,
                    "Received a request to a non-existing endpoint \"{}\" from {:?}",
                    req.path(),
                    req.remote_addr().unwrap(),
                );
                ok(Response::new().with_status(StatusCode::NotFound)).boxed()
            }
        }.then(|handler_result| {
            match handler_result {
                Ok(response) => ok(response),
                Err(err) => ok(err.into_response()),
            }
        });

        Box::new(response)
    }
}

impl NewService for Papers {
    type Request = Request;
    type Response = Response;
    type Error = hyper::Error;
    type Instance = Papers;

    fn new_service(&self) -> Result<Self::Instance, ::std::io::Error> {
        Ok(Papers {
            remote: self.remote.clone(),
            logger: self.logger.clone(),
        })
    }
}
<|endoftext|>


<commit_before>use std::io::Read;
use std::result::Result as StdResult;
use serde_json::de::from_reader;
use serde_json::Error as JsonError;
use time_span::ParseError as TimeSpanError;
use {Run, TimeSpan, Time, Segment};

quick_error! {
    #[derive(Debug)]
    pub enum Error {
        Time(err: TimeSpanError) {
            from()
        }
        Json(err: JsonError) {
            from()
        }
    }
}

pub type Result<T> = StdResult<T, Error>;

#[derive(Deserialize)]
struct Splits {
    title: String,
    attempt_count: u32,
    start_delay: String,
    splits: Vec<Split>,
}

#[derive(Deserialize)]
struct Split {
    title: String,
    time: String,
    best_time: String,
    best_segment: String,
}

fn parse_time(time: &str) -> Result<Time> {
    let real_time = time.parse::<TimeSpan>()?;

    // Empty Time is stored as zero
    let real_time = if real_time != TimeSpan::zero() {
        Some(real_time)
    } else {
        None
    };

    Ok(Time::new().with_real_time(real_time))
}

pub fn parse<R: Read>(source: R) -> Result<Run> {
    let mut run = Run::new();

    let splits: Splits = from_reader(source)?;

    run.set_category_name(splits.title);
    run.set_attempt_count(splits.attempt_count);
    run.set_offset(splits.start_delay.parse()?);

    // Best Split Times can be used for the Segment History
    // Every single best split time should be included as its own run,
    // since the best split times could be apart from each other less
    // than the best segments, so we have to assume they are from different runs.
    let mut attempt_history_index = 1;

    for split in splits.splits {
        let mut segment = Segment::new(split.title);
        segment.set_personal_best_split_time(parse_time(&split.time)?);
        segment.set_best_segment_time(parse_time(&split.best_segment)?);

        let best_split_time = parse_time(&split.best_time)?;
        if best_split_time.real_time.is_some() {
            run.add_attempt_with_index(Time::default(), attempt_history_index, None, None, None);

            // Insert a new run that skips to the current split
            for already_inserted_segment in run.segments_mut() {
                already_inserted_segment
                    .segment_history_mut()
                    .insert(attempt_history_index, Time::default());
            }

            segment
                .segment_history_mut()
                .insert(attempt_history_index, best_split_time);

            attempt_history_index += 1;
        }

        run.push_segment(segment);
    }

    Ok(run)
}
<commit_msg>Properly parse Urn's offset<commit_after>use std::io::Read;
use std::result::Result as StdResult;
use serde_json::de::from_reader;
use serde_json::Error as JsonError;
use time_span::ParseError as TimeSpanError;
use {Run, TimeSpan, Time, Segment};

quick_error! {
    #[derive(Debug)]
    pub enum Error {
        Time(err: TimeSpanError) {
            from()
        }
        Json(err: JsonError) {
            from()
        }
    }
}

pub type Result<T> = StdResult<T, Error>;

#[derive(Deserialize)]
struct Splits {
    title: String,
    attempt_count: u32,
    start_delay: String,
    splits: Vec<Split>,
}

#[derive(Deserialize)]
struct Split {
    title: String,
    time: String,
    best_time: String,
    best_segment: String,
}

fn parse_time(time: &str) -> Result<Time> {
    let real_time = time.parse::<TimeSpan>()?;

    // Empty Time is stored as zero
    let real_time = if real_time != TimeSpan::zero() {
        Some(real_time)
    } else {
        None
    };

    Ok(Time::new().with_real_time(real_time))
}

pub fn parse<R: Read>(source: R) -> Result<Run> {
    let mut run = Run::new();

    let splits: Splits = from_reader(source)?;

    run.set_category_name(splits.title);
    run.set_attempt_count(splits.attempt_count);
    run.set_offset(-splits.start_delay.parse()?);

    // Best Split Times can be used for the Segment History
    // Every single best split time should be included as its own run,
    // since the best split times could be apart from each other less
    // than the best segments, so we have to assume they are from different runs.
    let mut attempt_history_index = 1;

    for split in splits.splits {
        let mut segment = Segment::new(split.title);
        segment.set_personal_best_split_time(parse_time(&split.time)?);
        segment.set_best_segment_time(parse_time(&split.best_segment)?);

        let best_split_time = parse_time(&split.best_time)?;
        if best_split_time.real_time.is_some() {
            run.add_attempt_with_index(Time::default(), attempt_history_index, None, None, None);

            // Insert a new run that skips to the current split
            for already_inserted_segment in run.segments_mut() {
                already_inserted_segment
                    .segment_history_mut()
                    .insert(attempt_history_index, Time::default());
            }

            segment
                .segment_history_mut()
                .insert(attempt_history_index, best_split_time);

            attempt_history_index += 1;
        }

        run.push_segment(segment);
    }

    Ok(run)
}
<|endoftext|>


<commit_before>use rustc::lint::*;
use syntax::codemap::Spanned;
use syntax::ast::*;
use utils::span_lint;

declare_lint!(pub PRECEDENCE, Warn,
              "catches operations where precedence may be unclear. See the wiki for a \
               list of cases caught");

#[derive(Copy,Clone)]
pub struct Precedence;

impl LintPass for Precedence {
    fn get_lints(&self) -> LintArray {
        lint_array!(PRECEDENCE)
    }
}

impl EarlyLintPass for Precedence {
    fn check_expr(&mut self, cx: &EarlyContext, expr: &Expr) {
        if let ExprBinary(Spanned { node: op, ..}, ref left, ref right) = expr.node {
            if is_bit_op(op) && (is_arith_expr(left) || is_arith_expr(right)) {
                span_lint(cx, PRECEDENCE, expr.span,
                    "operator precedence can trip the unwary. Consider adding parentheses \
                     to the subexpression");
            }
        }

        if let ExprUnary(UnNeg, ref rhs) = expr.node {
            if let ExprMethodCall(_, _, ref args) = rhs.node {
                if let Some(slf) = args.first() {
                    if let ExprLit(ref lit) = slf.node {
                        match lit.node {
                            LitInt(..) | LitFloat(..) | LitFloatUnsuffixed(..) =>
                                span_lint(cx, PRECEDENCE, expr.span,
                                    "unary minus has lower precedence than method call. Consider \
                                     adding parentheses to clarify your intent"),
                                _ => ()
                        }
                    }
                }
            }
        }
    }
}

fn is_arith_expr(expr : &Expr) -> bool {
    match expr.node {
        ExprBinary(Spanned { node: op, ..}, _, _) => is_arith_op(op),
        _ => false
    }
}

fn is_bit_op(op : BinOp_) -> bool {
    match op {
        BiBitXor | BiBitAnd | BiBitOr | BiShl | BiShr => true,
        _ => false
    }
}

fn is_arith_op(op : BinOp_) -> bool {
    match op {
        BiAdd | BiSub | BiMul | BiDiv | BiRem => true,
        _ => false
    }
}
<commit_msg>improved precedence messages (fixes #389)<commit_after>use rustc::lint::*;
use syntax::codemap::Spanned;
use syntax::ast::*;
use syntax::ast_util::binop_to_string;

use utils::{span_lint, snippet};

declare_lint!(pub PRECEDENCE, Warn,
              "catches operations where precedence may be unclear. See the wiki for a \
               list of cases caught");

#[derive(Copy,Clone)]
pub struct Precedence;

impl LintPass for Precedence {
    fn get_lints(&self) -> LintArray {
        lint_array!(PRECEDENCE)
    }
}

impl EarlyLintPass for Precedence {
    fn check_expr(&mut self, cx: &EarlyContext, expr: &Expr) {
        if let ExprBinary(Spanned { node: op, ..}, ref left, ref right) = expr.node {
            if !is_bit_op(op) { return; }
            match (is_arith_expr(left), is_arith_expr(right)) {
                (true, true) =>  span_lint(cx, PRECEDENCE, expr.span,
                    &format!("operator precedence can trip the unwary. \
                         Consider parenthesizing your expression:\
                         `({}) {} ({})`", snippet(cx, left.span, ".."),
                         binop_to_string(op), snippet(cx, right.span, ".."))),
                (true, false) => span_lint(cx, PRECEDENCE, expr.span,
                    &format!("operator precedence can trip the unwary. \
                         Consider parenthesizing your expression:\
                         `({}) {} {}`", snippet(cx, left.span, ".."),
                         binop_to_string(op), snippet(cx, right.span, ".."))),
                (false, true) => span_lint(cx, PRECEDENCE, expr.span,
                    &format!("operator precedence can trip the unwary. \
                         Consider parenthesizing your expression:\
                         `{} {} ({})`", snippet(cx, left.span, ".."),
                         binop_to_string(op), snippet(cx, right.span, ".."))),
                _ => (),
            }
        }

        if let ExprUnary(UnNeg, ref rhs) = expr.node {
            if let ExprMethodCall(_, _, ref args) = rhs.node {
                if let Some(slf) = args.first() {
                    if let ExprLit(ref lit) = slf.node {
                        match lit.node {
                            LitInt(..) | LitFloat(..) | LitFloatUnsuffixed(..) =>
                                span_lint(cx, PRECEDENCE, expr.span, &format!(
                                    "unary minus has lower precedence than \
                                     method call. Consider adding parentheses \
                                     to clarify your intent: -({})",
                                     snippet(cx, rhs.span, ".."))),
                                _ => ()
                        }
                    }
                }
            }
        }
    }
}

fn is_arith_expr(expr : &Expr) -> bool {
    match expr.node {
        ExprBinary(Spanned { node: op, ..}, _, _) => is_arith_op(op),
        _ => false
    }
}

fn is_bit_op(op : BinOp_) -> bool {
    match op {
        BiBitXor | BiBitAnd | BiBitOr | BiShl | BiShr => true,
        _ => false
    }
}

fn is_arith_op(op : BinOp_) -> bool {
    match op {
        BiAdd | BiSub | BiMul | BiDiv | BiRem => true,
        _ => false
    }
}
<|endoftext|>


<commit_before>use std::sync::mpsc::{channel, Sender, SendError, Receiver};
use std::error::Error;

pub struct Publisher<T> {
    senders: Vec<Sender<T>>
}

pub type Subscriber<T> = Receiver<T>;

impl<T: Clone> Publisher<T> {
    pub fn new() -> Publisher<T> {
        Publisher {
            senders: Vec::new(),
        }
    }

    pub fn subscribe(&mut self, sub: Sender<T>) {
        self.senders.push(sub);
    }

    pub fn publish(&mut self, sub: T) -> Result<(), SendError<T>> {
        for s in self.senders.iter() {
            let res = s.send(sub.clone());
            if res.is_err() {
                return res
            }
        }
        Ok(())
    }
}

pub fn pubsub_channel<T: Clone>(num_subs: usize) -> (Publisher<T>, Vec<Subscriber<T>>) {
        let mut p = Publisher::new();
        let mut vec = Vec::new();

        for _a in 0..num_subs {
            let (sender, sub) = channel();
            p.subscribe(sender);
            vec.push(sub);
        }
        (p, vec)
}

#[cfg(test)]
mod test {
    use super::{Publisher, Subscriber, pubsub_channel};
    use std::sync::mpsc::{channel};

    #[test]
    fn test_pubsub() {
        let (sn1, s1) = channel::<usize>();
        let (sn2, s2) = channel::<usize>();
        let mut p = Publisher::new();
        p.subscribe(sn1);
        p.subscribe(sn2);

        let res = p.publish(9);
        assert!(res.is_ok());

        let res = s1.recv();
        assert!(res.ok().unwrap() == 9);
        let res = s2.recv();
        assert!(res.ok().unwrap() == 9);
    }

    #[test]
    fn test_pubsub_channel() {
        let (mut p, subs) = pubsub_channel::<usize>(3);

        let res = p.publish(9);
        assert!(res.is_ok());
        assert!(subs.len() == 3);

        for s in subs.iter() {
            let res = s.recv();
            assert!(res.ok().unwrap() == 9);
        }
    }
}
<commit_msg>Cloning a subscriber now creates a subscriber that is still subscribed.<commit_after>use std::sync::mpsc::{channel, Sender, SendError, Receiver, RecvError};
use std::error::Error;
use std::sync::{Arc, RwLock};
use std::fmt;
use std::any::Any;
use std::convert::From;

pub struct Subscriber<T> {
    receiver: Receiver<T>,
    self_sender: Sender<T>,
    publishers: Vec<Arc<Publisher<T>>>,
}

impl<T: Clone> Subscriber<T> {
    pub fn new() -> Subscriber<T>  {
        let (sn, rc) = channel();
        Subscriber {
            receiver: rc,
            self_sender: sn,
            publishers: Vec::new(),
        }
    }

    pub fn subscribe(&mut self, p: &Arc<Publisher<T>>) {
        self.publishers.push(p.clone());
        p.subscribe(self.self_sender.clone());
    }

    pub fn recv(&self) -> Result<T, PubSubError<T>> {
        let data = try!(self.receiver.recv());
        Ok(data)
    }
}

impl<T: Clone> Clone for Subscriber<T> {
    fn clone(&self) -> Subscriber<T> {
        let sub = Subscriber::new();
        for p in self.publishers.iter() {
            p.subscribe(sub.self_sender.clone());
        }
        sub
    }
}

pub struct Publisher<T> {
    senders: RwLock<Vec<Sender<T>>>
}

impl<T: Clone> Publisher<T> {
    pub fn new() -> Arc<Publisher<T>> {
        Arc::new(Publisher {
            senders: RwLock::new(Vec::new()),
        })
    }

    fn subscribe(&self, sub: Sender<T>) {
        let mut vec = self.senders.write().unwrap();
        vec.push(sub);
    }

    pub fn publish(&self, sub: T) -> Result<(), PubSubError<T>> {
        let vec = self.senders.read().unwrap();
        for s in vec.iter() {
            try!(s.send(sub.clone()));
        }
        Ok(())
    }
}

#[derive(PartialEq, Eq, Clone, Copy, Debug)]
pub struct PubSubError<T> {
    kind: ErrorKind<T>,
}

#[derive(PartialEq, Eq, Clone, Copy, Debug)]
enum ErrorKind<T> {
    SendError(SendError<T>),
    RecvError(RecvError),
}

impl<T> From<RecvError> for PubSubError<T> {
    fn from(err: RecvError) -> PubSubError<T> {
        PubSubError {
            kind: ErrorKind::RecvError(err),
        }
    }
}

impl<T> From<SendError<T>> for PubSubError<T> {
    fn from(err: SendError<T>) -> PubSubError<T> {
        PubSubError {
            kind: ErrorKind::SendError(err),
        }
    }
}

impl<T> fmt::Display for PubSubError<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self.kind {
            ErrorKind::SendError(ref se) => se.fmt(f),
            ErrorKind::RecvError(ref re) => re.fmt(f),
        }
    }
}

impl<T: Any + fmt::Debug + Send> Error for PubSubError<T> {
    fn description(&self) -> &str {
        match self.kind {
            ErrorKind::SendError(ref se) => se.description(),
            ErrorKind::RecvError(ref re) => re.description(),
        }
    }

    fn cause(&self) -> Option<&Error> {
        match self.kind {
            ErrorKind::SendError(ref se) => se.cause(),
            ErrorKind::RecvError(ref re) => re.cause(),
        }
    }
}

pub fn pubsub_channel<T: Clone>() -> (Arc<Publisher<T>>, Subscriber<T>) {
        let p = Publisher::new();
        let mut s = Subscriber::new();
        s.subscribe(&p);
        (p, s)
}

#[cfg(test)]
mod test {
    use super::{Publisher, Subscriber, pubsub_channel};
    use std::sync::mpsc::{channel};

    #[test]
    fn test_pubsub() {
        let mut s1 = Subscriber::new();
        let mut s2 = Subscriber::new();
        let p = Publisher::new();
        s1.subscribe(&p);
        s2.subscribe(&p);

        let res = p.publish(9);
        assert!(res.is_ok());

        let res = s1.recv();
        assert!(res.ok().unwrap() == 9);
        let res = s2.recv();
        assert!(res.ok().unwrap() == 9);
    }

    #[test]
    fn test_sub_clone() {
        let p = Publisher::new();

        let mut sub1 = Subscriber::new();
        sub1.subscribe(&p);
        let mut sub2 = sub1.clone();

        let res = p.publish(9);
        assert!(res.is_ok());

        let res = sub2.recv();
        assert!(res.ok().unwrap() == 9);
        let res = sub1.recv();
        assert!(res.ok().unwrap() == 9);
    }

    #[test]
    fn test_sub_clone_multi_publish() {
        let p = Publisher::new();
        let p2 = Publisher::new();

        let mut sub1 = Subscriber::new();
        sub1.subscribe(&p);
        sub1.subscribe(&p2);
        let mut sub2 = sub1.clone();

        let res = p.publish(9);
        assert!(res.is_ok());
        let res = p2.publish(3);
        assert!(res.is_ok());

        let res = sub2.recv();
        assert!(res.ok().unwrap() == 9);
        let res = sub1.recv();
        assert!(res.ok().unwrap() == 9);
        let res = sub1.recv();
        assert!(res.ok().unwrap() == 3);
        let res = sub2.recv();
        assert!(res.ok().unwrap() == 3);
    }

    #[test]
    fn test_pubsub_channel() {
        let (p, sub) = pubsub_channel::<usize>();

        let res = p.publish(9);
        assert!(res.is_ok());

        let res = sub.recv();
        assert!(res.ok().unwrap() == 9);
    }
}
<|endoftext|>


<commit_before>use std::io;
use std::io::IoResult;
use libc::{c_void, c_int, size_t};
use get_error;
use SdlResult;

#[allow(non_camel_case_types)]
pub mod ll {
    use libc::{c_uchar, uint32_t, c_char, FILE, c_void};
    use libc::{c_int, int64_t, size_t};

    struct SDL_RWops_Anon {
        data: [c_uchar, ..24],
    }

    pub type SDL_bool = c_int;

    pub static RW_SEEK_SET: c_int = 0;
    pub static RW_SEEK_CUR: c_int = 1;
    pub static RW_SEEK_END: c_int = 2;

    pub struct SDL_RWops {
        pub size:  extern "C" fn(context: *SDL_RWops) -> int64_t,
        pub seek:  extern "C" fn(context: *SDL_RWops, offset: int64_t, whence: c_int) -> int64_t,
        pub read:  extern "C" fn(context: *SDL_RWops, ptr: *c_void,
                                 size: size_t, maxnum: size_t) -> size_t,
        pub write: extern "C" fn(context: *SDL_RWops, ptr: *c_void,
                                 size: size_t, maxnum: size_t) -> size_t,
        pub close: extern "C" fn(context: *SDL_RWops) -> c_int,
        pub _type: uint32_t,
        hidden: SDL_RWops_Anon
    }

    extern "C" {
        pub fn SDL_RWFromFile(file: *c_char, mode: *c_char) -> *SDL_RWops;
        pub fn SDL_RWFromFP(fp: *FILE, autoclose: SDL_bool) -> *SDL_RWops;
        pub fn SDL_RWFromMem(mem: *c_void, size: c_int) -> *SDL_RWops;
        pub fn SDL_RWFromConstMem(mem: *c_void, size: c_int) -> *SDL_RWops;

        pub fn SDL_AllocRW() -> *SDL_RWops;
        pub fn SDL_FreeRW(area: *SDL_RWops);
    }
}

#[deriving(PartialEq)] #[allow(raw_pointer_deriving)]
pub struct RWops {
    raw: *ll::SDL_RWops,
    close_on_drop: bool
}

impl_raw_accessors!(RWops, *ll::SDL_RWops)
impl_owned_accessors!(RWops, close_on_drop)

/// A structure that provides an abstract interface to stream I/O.
impl RWops {
    pub fn from_file(path: &Path, mode: &str) -> SdlResult<RWops> {
        let raw = unsafe {
            ll::SDL_RWFromFile(path.to_c_str().unwrap(), mode.to_c_str().unwrap())
        };
        if raw.is_null() { Err(get_error()) }
        else { Ok(RWops{raw: raw, close_on_drop: true}) }
    }

    pub fn from_bytes(buf: &[u8]) -> SdlResult<RWops> {
        let raw = unsafe {
            ll::SDL_RWFromConstMem(buf.as_ptr() as *c_void, buf.len() as c_int)
        };
        if raw.is_null() { Err(get_error()) }
        else { Ok(RWops{raw: raw, close_on_drop: false}) }
    }
}

impl Drop for RWops {
    fn drop(&mut self) {
        // TODO: handle close error
        if self.close_on_drop {
            let ret = unsafe { ((*self.raw).close)(self.raw) };
            if ret != 0 {
                println!("error {} when closing RWopt {:?}", get_error(), self);
            }
        }
    }
}

impl Reader for RWops {
    fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
        let out_len = buf.len() as size_t;
        // FIXME: it's better to use as_mut_ptr().
        // number of objects read, or 0 at error or end of file.
        let ret = unsafe {
            ((*self.raw).read)(self.raw, buf.as_ptr() as *c_void, 1, out_len)
        };
        if ret == 0 {
            Err(io::standard_error(io::EndOfFile))
        } else {
            Ok(ret as uint)
        }
    }
}

impl Writer for RWops {
    fn write(&mut self, buf: &[u8]) -> IoResult<()> {
        let in_len = buf.len() as size_t;
        let ret = unsafe {
            ((*self.raw).write)(self.raw, buf.as_ptr() as *c_void, 1, in_len)
        };
        if ret == 0 {
            Err(io::standard_error(io::EndOfFile))
        } else if ret != in_len {
            // FIXME: what error should we return here?
            Err(io::standard_error(io::EndOfFile))
        } else {
            Ok(())
        }
    }
}

impl Seek for RWops {
    fn tell(&self) -> IoResult<u64> {
        let ret = unsafe {
            ((*self.raw).seek)(self.raw, 0, ll::RW_SEEK_CUR)
        };
        if ret == -1 {
            Err(io::IoError::last_error())
        } else {
            Ok(ret as u64)
        }
    }

    fn seek(&mut self, pos: i64, style: io::SeekStyle) -> IoResult<()> {
        // whence code is different from SeekStyle
        let whence = match style {
            io::SeekSet => ll::RW_SEEK_SET,
            io::SeekEnd => ll::RW_SEEK_END,
            io::SeekCur => ll::RW_SEEK_CUR
        };
        let ret = unsafe {
            ((*self.raw).seek)(self.raw, pos, whence)
        };
        if ret == -1 {
            Err(io::IoError::last_error())
        } else {
            Ok(())
        }
    }
}

impl Container for RWops {
    fn len(&self) -> uint {
        unsafe {
            ((*self.raw).size)(self.raw) as uint
        }
    }
}
<commit_msg>Update to latest Rust<commit_after>use std::io;
use std::io::IoResult;
use libc::{c_void, c_int, size_t};
use get_error;
use SdlResult;

#[allow(non_camel_case_types)]
pub mod ll {
    use libc::{c_uchar, uint32_t, c_char, FILE, c_void};
    use libc::{c_int, int64_t, size_t};

    struct SDL_RWops_Anon {
        data: [c_uchar, ..24],
    }

    pub type SDL_bool = c_int;

    pub static RW_SEEK_SET: c_int = 0;
    pub static RW_SEEK_CUR: c_int = 1;
    pub static RW_SEEK_END: c_int = 2;

    pub struct SDL_RWops {
        pub size:  extern "C" fn(context: *SDL_RWops) -> int64_t,
        pub seek:  extern "C" fn(context: *SDL_RWops, offset: int64_t, whence: c_int) -> int64_t,
        pub read:  extern "C" fn(context: *SDL_RWops, ptr: *c_void,
                                 size: size_t, maxnum: size_t) -> size_t,
        pub write: extern "C" fn(context: *SDL_RWops, ptr: *c_void,
                                 size: size_t, maxnum: size_t) -> size_t,
        pub close: extern "C" fn(context: *SDL_RWops) -> c_int,
        pub _type: uint32_t,
        hidden: SDL_RWops_Anon
    }

    extern "C" {
        pub fn SDL_RWFromFile(file: *c_char, mode: *c_char) -> *SDL_RWops;
        pub fn SDL_RWFromFP(fp: *FILE, autoclose: SDL_bool) -> *SDL_RWops;
        pub fn SDL_RWFromMem(mem: *c_void, size: c_int) -> *SDL_RWops;
        pub fn SDL_RWFromConstMem(mem: *c_void, size: c_int) -> *SDL_RWops;

        pub fn SDL_AllocRW() -> *SDL_RWops;
        pub fn SDL_FreeRW(area: *SDL_RWops);
    }
}

#[deriving(PartialEq)] #[allow(raw_pointer_deriving)]
pub struct RWops {
    raw: *ll::SDL_RWops,
    close_on_drop: bool
}

impl_raw_accessors!(RWops, *ll::SDL_RWops)
impl_owned_accessors!(RWops, close_on_drop)

/// A structure that provides an abstract interface to stream I/O.
impl RWops {
    pub fn from_file(path: &Path, mode: &str) -> SdlResult<RWops> {
        let raw = unsafe {
            ll::SDL_RWFromFile(path.to_c_str().unwrap(), mode.to_c_str().unwrap())
        };
        if raw.is_null() { Err(get_error()) }
        else { Ok(RWops{raw: raw, close_on_drop: true}) }
    }

    pub fn from_bytes(buf: &[u8]) -> SdlResult<RWops> {
        let raw = unsafe {
            ll::SDL_RWFromConstMem(buf.as_ptr() as *c_void, buf.len() as c_int)
        };
        if raw.is_null() { Err(get_error()) }
        else { Ok(RWops{raw: raw, close_on_drop: false}) }
    }
}

impl Drop for RWops {
    fn drop(&mut self) {
        // TODO: handle close error
        if self.close_on_drop {
            let ret = unsafe { ((*self.raw).close)(self.raw) };
            if ret != 0 {
                println!("error {} when closing RWopt {:?}", get_error(), self);
            }
        }
    }
}

impl Reader for RWops {
    fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
        let out_len = buf.len() as size_t;
        // FIXME: it's better to use as_mut_ptr().
        // number of objects read, or 0 at error or end of file.
        let ret = unsafe {
            ((*self.raw).read)(self.raw, buf.as_ptr() as *c_void, 1, out_len)
        };
        if ret == 0 {
            Err(io::standard_error(io::EndOfFile))
        } else {
            Ok(ret as uint)
        }
    }
}

impl Writer for RWops {
    fn write(&mut self, buf: &[u8]) -> IoResult<()> {
        let in_len = buf.len() as size_t;
        let ret = unsafe {
            ((*self.raw).write)(self.raw, buf.as_ptr() as *c_void, 1, in_len)
        };
        if ret == 0 {
            Err(io::standard_error(io::EndOfFile))
        } else if ret != in_len {
            // FIXME: what error should we return here?
            Err(io::standard_error(io::EndOfFile))
        } else {
            Ok(())
        }
    }
}

impl Seek for RWops {
    fn tell(&self) -> IoResult<u64> {
        let ret = unsafe {
            ((*self.raw).seek)(self.raw, 0, ll::RW_SEEK_CUR)
        };
        if ret == -1 {
            Err(io::IoError::last_error())
        } else {
            Ok(ret as u64)
        }
    }

    fn seek(&mut self, pos: i64, style: io::SeekStyle) -> IoResult<()> {
        // whence code is different from SeekStyle
        let whence = match style {
            io::SeekSet => ll::RW_SEEK_SET,
            io::SeekEnd => ll::RW_SEEK_END,
            io::SeekCur => ll::RW_SEEK_CUR
        };
        let ret = unsafe {
            ((*self.raw).seek)(self.raw, pos, whence)
        };
        if ret == -1 {
            Err(io::IoError::last_error())
        } else {
            Ok(())
        }
    }
}

impl Collection for RWops {
    fn len(&self) -> uint {
        unsafe {
            ((*self.raw).size)(self.raw) as uint
        }
    }
}
<|endoftext|>