<commit_before>/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2015 Andres Vahter (andres.vahter@gmail.com)
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

use ffipredict;
use tle;

use std::default::Default;
use time;

#[derive(Debug, Copy, Clone, PartialEq)]
pub struct Location {
    pub lat_deg: f64,
    pub lon_deg: f64,
    pub alt_m: i32,
}

#[derive(Default, Debug)]
pub struct Sat {
    /// next AOS
    pub aos:                Option<time::Tm>,

    /// next LOS
    pub los:                Option<time::Tm>,

    /// azimuth [deg]
    pub az_deg:             f64,

    /// elevation [deg]
    pub el_deg:             f64,

    /// range [km]
    pub range_km:           f64,

    /// range rate [km/sec]
    pub range_rate_km_sec:  f64,

    /// SSP latitude [deg]
    pub lat_deg:            f64,

    /// SSP longitude [deg]
    pub lon_deg:            f64,

    /// altitude [km]
    pub alt_km:             f64,

    /// velocity [km/s]
    pub vel_km_s:           f64,

    /// orbit number
    pub orbit_nr:           u64,
}

#[derive(Debug)]
pub struct Predict {
    pub sat: Sat,

    p_sat: ffipredict::sat_t,
    p_qth: ffipredict::qth_t,
}

fn fraction_of_day(h: i32, m: i32, s: i32) -> f64{
    (h as f64 + (m as f64 + s as f64 / 60.0) / 60.0) / 24.0
}

/// Astronomical Formulae for Calculators, Jean Meeus, pages 23-25.
/// Calculate Julian Date of 0.0 Jan year
fn julian_date_of_year(yr: i32) -> f64 {
    let mut year: u64;
    let mut a: f64;
    let mut b: f64;
    let mut i: f64;

    let mut jdoy: f64;

    year = yr as u64 -1;
    i = (year as f64 / 100.).trunc();
    a = i;
    i = (a / 4.).trunc();
    b = (2. - a + i).trunc();
    i = (365.25 * year as f64).trunc();
    i += (30.6001_f64 * 14.0_f64).trunc();
    jdoy = i + 1720994.5 + b;

    jdoy
}

/// Calculates the day of the year for the specified date.
fn day_of_the_year(yr: i32, mo: i32, dy: i32) -> i32 {
    let days: [u8; 12] = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
    let mut day: i32 = 0;

    for d in &days[0 .. mo as usize - 1] {
        day += *d as i32;
    }

    day += dy as i32;
    if (yr % 4 == 0) && ((yr % 100 != 0) || (yr % 400 == 0)) && (mo > 2) {
        day += 1;
    }

    day
}

// Calculates Julian Day Number
fn julian_timestamp(t: time::Tm) -> f64 {
    let year = t.tm_year + 1900;
    let month = t.tm_mon + 1;

    julian_date_of_year(year) +
        day_of_the_year(year, month, t.tm_mday) as f64 +
        fraction_of_day(t.tm_hour, t.tm_min, t.tm_sec) +
        t.tm_nsec as f64 / 1000_f64 / 8.64e+10
}

pub fn julian_to_unix(julian: f64) -> time::Tm {
    let unix = (julian - 2440587.5) * 86400.;
    let t = time::Timespec::new(unix.trunc() as i64, unix.fract() as i32);
    time::at(t)
}

impl Predict {

    pub fn new(tle: &tle::Tle, location: &Location) -> Predict {
        let tle_t = tle::create_tle_t(tle).unwrap();

        let sgps: ffipredict::sgpsdp_static_t = Default::default();
        let dps: ffipredict::deep_static_t = Default::default();
        let deep_arg: ffipredict::deep_arg_t = Default::default();
        let pos: ffipredict::vector_t = Default::default();
        let vel: ffipredict::vector_t = Default::default();

        let mut sat_t = ffipredict::sat_t{
            name: b"placeholder\0".as_ptr() as *const i8,
            nickname: b"placeholder\0".as_ptr() as *const i8,
            website: b"placeholder\0".as_ptr() as *const i8,
            tle: tle_t,
            flags: 0,
            sgps: sgps,
            dps: dps,
            deep_arg: deep_arg,
            pos: pos,
            vel: vel,

            jul_epoch: 0.0,
            jul_utc: 0.0,
            tsince: 0.0,
            aos: 0.0,
            los: 0.0,
            az: 0.0,
            el: 0.0,
            range: 0.0,
            range_rate: 0.0,
            ra: 0.0,
            dec: 0.0,
            ssplat: 0.0,
            ssplon: 0.0,
            alt: 0.0,
            velo: 0.0,
            ma: 0.0,
            footprint: 0.0,
            phase: 0.0,
            meanmo: 0.0,
            orbit: 0,
            otype: ffipredict::orbit_type_t::ORBIT_TYPE_UNKNOWN,
        };

        let sat: Sat = Default::default();
        let mut qth = ffipredict::qth_t {
            name: b"placeholder\0".as_ptr() as *const i8,
            loc: b"placeholder\0".as_ptr() as *const i8,
            desc: b"placeholder\0".as_ptr() as *const i8,
            lat: location.lat_deg,
            lon: location.lon_deg,
            alt: location.alt_m,
            qra: b"placeholder\0".as_ptr() as *const i8,
            wx: b"placeholder\0".as_ptr() as *const i8,
        };

        unsafe {ffipredict::select_ephemeris(&mut sat_t)};
        unsafe {ffipredict::gtk_sat_data_init_sat(&mut sat_t, &mut qth)};

        Predict{sat: sat, p_sat: sat_t, p_qth: qth}
    }

    pub fn update(&mut self, timeoption: Option<time::Tm>) {
        let juliantime = match timeoption {
            Some(t) => julian_timestamp(t),
            None => unsafe {ffipredict::get_current_daynum()}
        };

        // we do not have AOS with some satellites, therefore option is used
        let aos = match unsafe {ffipredict::find_aos(&mut self.p_sat, &mut self.p_qth, juliantime, 1.0)} {
            0.0 => None,
            aos => Some(julian_to_unix(aos)),
        };
        let los = match unsafe {ffipredict::find_los(&mut self.p_sat, &mut self.p_qth, juliantime, 1.0)} {
            0.0 => None,
            los => Some(julian_to_unix(los)),
        };

        unsafe {ffipredict::predict_calc(&mut self.p_sat, &mut self.p_qth, juliantime)};

        self.sat.aos                = aos;
        self.sat.los                = los;
        self.sat.az_deg             = self.p_sat.az;
        self.sat.el_deg             = self.p_sat.el;
        self.sat.range_km           = self.p_sat.range;
        self.sat.range_rate_km_sec  = self.p_sat.range_rate;
        self.sat.lat_deg            = self.p_sat.ssplat;
        self.sat.lon_deg            = self.p_sat.ssplon;
        self.sat.alt_km             = self.p_sat.alt;
        self.sat.vel_km_s           = self.p_sat.velo;
        self.sat.orbit_nr           = self.p_sat.orbit;
    }
}

#[test]
fn test_julian_timestamp() {
    // http://en.wikipedia.org/wiki/Julian_day#Converting_Julian_or_Gregorian_calendar_date_to_Julian_Day_Number
    let t = time::strptime("2000-1-1 12:00:00", "%Y-%m-%d %H:%M:%S").unwrap();
    assert_eq!(julian_timestamp(t), 2451545.0);

    let t = time::strptime("1970-1-1 00:00:00", "%Y-%m-%d %H:%M:%S").unwrap();
    assert_eq!(julian_timestamp(t), 2440587.5);
}
<commit_msg>fix build for 32 bit machines<commit_after>/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2015 Andres Vahter (andres.vahter@gmail.com)
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

use ffipredict;
use tle;

use std::default::Default;
use time;

#[derive(Debug, Copy, Clone, PartialEq)]
pub struct Location {
    pub lat_deg: f64,
    pub lon_deg: f64,
    pub alt_m: i32,
}

#[derive(Default, Debug)]
pub struct Sat {
    /// next AOS
    pub aos:                Option<time::Tm>,

    /// next LOS
    pub los:                Option<time::Tm>,

    /// azimuth [deg]
    pub az_deg:             f64,

    /// elevation [deg]
    pub el_deg:             f64,

    /// range [km]
    pub range_km:           f64,

    /// range rate [km/sec]
    pub range_rate_km_sec:  f64,

    /// SSP latitude [deg]
    pub lat_deg:            f64,

    /// SSP longitude [deg]
    pub lon_deg:            f64,

    /// altitude [km]
    pub alt_km:             f64,

    /// velocity [km/s]
    pub vel_km_s:           f64,

    /// orbit number
    pub orbit_nr:           u64,
}

#[derive(Debug)]
pub struct Predict {
    pub sat: Sat,

    p_sat: ffipredict::sat_t,
    p_qth: ffipredict::qth_t,
}

fn fraction_of_day(h: i32, m: i32, s: i32) -> f64{
    (h as f64 + (m as f64 + s as f64 / 60.0) / 60.0) / 24.0
}

/// Astronomical Formulae for Calculators, Jean Meeus, pages 23-25.
/// Calculate Julian Date of 0.0 Jan year
fn julian_date_of_year(yr: i32) -> f64 {
    let mut year: u64;
    let mut a: f64;
    let mut b: f64;
    let mut i: f64;

    let mut jdoy: f64;

    year = yr as u64 -1;
    i = (year as f64 / 100.).trunc();
    a = i;
    i = (a / 4.).trunc();
    b = (2. - a + i).trunc();
    i = (365.25 * year as f64).trunc();
    i += (30.6001_f64 * 14.0_f64).trunc();
    jdoy = i + 1720994.5 + b;

    jdoy
}

/// Calculates the day of the year for the specified date.
fn day_of_the_year(yr: i32, mo: i32, dy: i32) -> i32 {
    let days: [u8; 12] = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
    let mut day: i32 = 0;

    for d in &days[0 .. mo as usize - 1] {
        day += *d as i32;
    }

    day += dy as i32;
    if (yr % 4 == 0) && ((yr % 100 != 0) || (yr % 400 == 0)) && (mo > 2) {
        day += 1;
    }

    day
}

// Calculates Julian Day Number
fn julian_timestamp(t: time::Tm) -> f64 {
    let year = t.tm_year + 1900;
    let month = t.tm_mon + 1;

    julian_date_of_year(year) +
        day_of_the_year(year, month, t.tm_mday) as f64 +
        fraction_of_day(t.tm_hour, t.tm_min, t.tm_sec) +
        t.tm_nsec as f64 / 1000_f64 / 8.64e+10
}

pub fn julian_to_unix(julian: f64) -> time::Tm {
    let unix = (julian - 2440587.5) * 86400.;
    let t = time::Timespec::new(unix.trunc() as i64, unix.fract() as i32);
    time::at(t)
}

impl Predict {

    pub fn new(tle: &tle::Tle, location: &Location) -> Predict {
        let tle_t = tle::create_tle_t(tle).unwrap();

        let sgps: ffipredict::sgpsdp_static_t = Default::default();
        let dps: ffipredict::deep_static_t = Default::default();
        let deep_arg: ffipredict::deep_arg_t = Default::default();
        let pos: ffipredict::vector_t = Default::default();
        let vel: ffipredict::vector_t = Default::default();

        let mut sat_t = ffipredict::sat_t{
            name: b"placeholder\0".as_ptr() as *const i8,
            nickname: b"placeholder\0".as_ptr() as *const i8,
            website: b"placeholder\0".as_ptr() as *const i8,
            tle: tle_t,
            flags: 0,
            sgps: sgps,
            dps: dps,
            deep_arg: deep_arg,
            pos: pos,
            vel: vel,

            jul_epoch: 0.0,
            jul_utc: 0.0,
            tsince: 0.0,
            aos: 0.0,
            los: 0.0,
            az: 0.0,
            el: 0.0,
            range: 0.0,
            range_rate: 0.0,
            ra: 0.0,
            dec: 0.0,
            ssplat: 0.0,
            ssplon: 0.0,
            alt: 0.0,
            velo: 0.0,
            ma: 0.0,
            footprint: 0.0,
            phase: 0.0,
            meanmo: 0.0,
            orbit: 0,
            otype: ffipredict::orbit_type_t::ORBIT_TYPE_UNKNOWN,
        };

        let sat: Sat = Default::default();
        let mut qth = ffipredict::qth_t {
            name: b"placeholder\0".as_ptr() as *const i8,
            loc: b"placeholder\0".as_ptr() as *const i8,
            desc: b"placeholder\0".as_ptr() as *const i8,
            lat: location.lat_deg,
            lon: location.lon_deg,
            alt: location.alt_m,
            qra: b"placeholder\0".as_ptr() as *const i8,
            wx: b"placeholder\0".as_ptr() as *const i8,
        };

        unsafe {ffipredict::select_ephemeris(&mut sat_t)};
        unsafe {ffipredict::gtk_sat_data_init_sat(&mut sat_t, &mut qth)};

        Predict{sat: sat, p_sat: sat_t, p_qth: qth}
    }

    pub fn update(&mut self, timeoption: Option<time::Tm>) {
        let juliantime = match timeoption {
            Some(t) => julian_timestamp(t),
            None => unsafe {ffipredict::get_current_daynum()}
        };

        // we do not have AOS with some satellites, therefore option is used
        let aos = match unsafe {ffipredict::find_aos(&mut self.p_sat, &mut self.p_qth, juliantime, 1.0)} {
            0.0 => None,
            aos => Some(julian_to_unix(aos)),
        };
        let los = match unsafe {ffipredict::find_los(&mut self.p_sat, &mut self.p_qth, juliantime, 1.0)} {
            0.0 => None,
            los => Some(julian_to_unix(los)),
        };

        unsafe {ffipredict::predict_calc(&mut self.p_sat, &mut self.p_qth, juliantime)};

        self.sat.aos                = aos;
        self.sat.los                = los;
        self.sat.az_deg             = self.p_sat.az;
        self.sat.el_deg             = self.p_sat.el;
        self.sat.range_km           = self.p_sat.range;
        self.sat.range_rate_km_sec  = self.p_sat.range_rate;
        self.sat.lat_deg            = self.p_sat.ssplat;
        self.sat.lon_deg            = self.p_sat.ssplon;
        self.sat.alt_km             = self.p_sat.alt;
        self.sat.vel_km_s           = self.p_sat.velo;
        self.sat.orbit_nr           = self.p_sat.orbit as u64;
    }
}

#[test]
fn test_julian_timestamp() {
    // http://en.wikipedia.org/wiki/Julian_day#Converting_Julian_or_Gregorian_calendar_date_to_Julian_Day_Number
    let t = time::strptime("2000-1-1 12:00:00", "%Y-%m-%d %H:%M:%S").unwrap();
    assert_eq!(julian_timestamp(t), 2451545.0);

    let t = time::strptime("1970-1-1 00:00:00", "%Y-%m-%d %H:%M:%S").unwrap();
    assert_eq!(julian_timestamp(t), 2440587.5);
}
<|endoftext|>


<commit_before>use command::Command;
use vm::VM;

pub struct Program {
    instructions: Vec<Command>,
    instruction_pointer: Option<usize>,
    current_depth: u64,
    pub status: ProgramStatus,
}

#[derive(Clone, Copy, PartialEq, Debug)]
pub enum ProgramStatus {
    Normal,
    Seeking(u64),
}

impl Program {
    pub fn new() -> Program {
        Program {
            instructions: Vec::new(),
            instruction_pointer: None,
            current_depth: 0,
            status: ProgramStatus::Normal,
        }
    }

    pub fn append(&mut self, instructions: &[Command]) {
        self.instructions.extend(instructions.iter().cloned());
        if self.instruction_pointer.is_none() {
            self.instruction_pointer = Some(0);
        }
    }

    pub fn execute(&mut self, vm: &mut VM) {
        match (self.instruction_pointer, self.status) {
            (Some(mut index), ProgramStatus::Seeking(_)) => {
                self.handle_jump_forward(vm, &mut index);
                self.execute(vm);
            }

            (Some(mut index), ProgramStatus::Normal) => {
                while index < self.instructions.len() {
                    match self.instructions[index] {
                        Command::JumpForward => self.handle_jump_forward(vm, &mut index),
                        Command::JumpBackward => self.handle_jump_backward(vm, &mut index),
                        command => {
                            vm.apply(command);
                            index += 1;
                        }
                    }
                }

                self.instruction_pointer = Some(index);
            }

            _ => {}
        }
    }

    fn handle_jump_backward(&mut self, vm: &VM, index_ref: &mut usize) {
        match vm.cells[vm.data_pointer] {
            0 => {
                self.current_depth -= 1;
                *index_ref += 1;
            }

            _ => {
                let goal_depth = self.current_depth;
                for index in (0..*index_ref).rev() {
                    match self.instructions[index] {
                        Command::JumpBackward => self.current_depth += 1,
                        Command::JumpForward => {
                            if self.current_depth == goal_depth {
                                *index_ref = index + 1;
                                return;
                            }
                            self.current_depth -= 1;
                        }
                        _ => {}
                    }
                }
                panic!("No starting brace found!");
            }
        }
    }

    fn seek_forward(&mut self, index_ref: &mut usize) {
        if let ProgramStatus::Seeking(goal_depth) = self.status {
            for index in (*index_ref)..self.instructions.len() {
                match self.instructions[index] {
                    Command::JumpForward => self.current_depth += 1,
                    Command::JumpBackward => self.current_depth -= 1,
                    _ => {}
                }
                if self.current_depth == goal_depth {
                    *index_ref = index + 1;
                    self.status = ProgramStatus::Normal;
                    return;
                }
            }

            *index_ref = self.instructions.len();
            self.status = ProgramStatus::Seeking(goal_depth);
        }
    }

    fn handle_jump_forward(&mut self, vm: &VM, index: &mut usize) {
        match (vm.cells[vm.data_pointer], self.status) {
            (0, ProgramStatus::Normal) => {
                self.status = ProgramStatus::Seeking(self.current_depth);
                self.seek_forward(index);
            }

            (_, ProgramStatus::Normal) => {
                *index += 1;
                self.current_depth += 1;
                self.status = ProgramStatus::Normal;
            }

            (_, ProgramStatus::Seeking(_)) => self.seek_forward(index),

        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    #[test]
    pub fn test_seek_forward_normal() {
        let mut program = Program {
            instruction_pointer: None,
            current_depth: 0,
            status: ProgramStatus::Seeking(0),
            instructions: vec![
                Command::JumpForward,
                Command::JumpForward,
                Command::JumpBackward,
                Command::JumpBackward,
            ],
        };
        let mut index = 0;
        program.seek_forward(&mut index);
        assert_eq!(index, 4);
        assert_eq!(program.status, ProgramStatus::Normal);
    }

    #[test]
    pub fn test_seek_forward_seeking() {
        let mut program = Program {
            instruction_pointer: None,
            current_depth: 0,
            status: ProgramStatus::Seeking(0),
            instructions: vec![
                Command::JumpForward,
                Command::JumpForward,
                Command::JumpBackward,
            ],
        };
        let mut index = 0;
        program.seek_forward(&mut index);
        assert_eq!(index, 3);
        assert_eq!(program.status, ProgramStatus::Seeking(0));
    }
}
<commit_msg>Add missing set to instruction_pointer after advance<commit_after>use command::Command;
use vm::VM;

pub struct Program {
    instructions: Vec<Command>,
    instruction_pointer: Option<usize>,
    current_depth: u64,
    pub status: ProgramStatus,
}

#[derive(Clone, Copy, PartialEq, Debug)]
pub enum ProgramStatus {
    Normal,
    Seeking(u64),
}

impl Program {
    pub fn new() -> Program {
        Program {
            instructions: Vec::new(),
            instruction_pointer: None,
            current_depth: 0,
            status: ProgramStatus::Normal,
        }
    }

    pub fn append(&mut self, instructions: &[Command]) {
        self.instructions.extend(instructions.iter().cloned());
        if self.instruction_pointer.is_none() {
            self.instruction_pointer = Some(0);
        }
    }

    pub fn execute(&mut self, vm: &mut VM) {
        match (self.instruction_pointer, self.status) {
            (Some(mut index), ProgramStatus::Seeking(_)) => {
                self.handle_jump_forward(vm, &mut index);
                self.instruction_pointer = Some(index);
                self.execute(vm);
            }

            (Some(mut index), ProgramStatus::Normal) => {
                while index < self.instructions.len() {
                    match self.instructions[index] {
                        Command::JumpForward => self.handle_jump_forward(vm, &mut index),
                        Command::JumpBackward => self.handle_jump_backward(vm, &mut index),
                        command => {
                            vm.apply(command);
                            index += 1;
                        }
                    }
                }

                self.instruction_pointer = Some(index);
            }

            _ => {}
        }
    }

    fn handle_jump_backward(&mut self, vm: &VM, index_ref: &mut usize) {
        match vm.cells[vm.data_pointer] {
            0 => {
                self.current_depth -= 1;
                *index_ref += 1;
            }

            _ => {
                let goal_depth = self.current_depth;
                for index in (0..*index_ref).rev() {
                    match self.instructions[index] {
                        Command::JumpBackward => self.current_depth += 1,
                        Command::JumpForward => {
                            if self.current_depth == goal_depth {
                                *index_ref = index + 1;
                                return;
                            }
                            self.current_depth -= 1;
                        }
                        _ => {}
                    }
                }
                panic!("No starting brace found!");
            }
        }
    }

    fn seek_forward(&mut self, index_ref: &mut usize) {
        if let ProgramStatus::Seeking(goal_depth) = self.status {
            for index in (*index_ref)..self.instructions.len() {
                match self.instructions[index] {
                    Command::JumpForward => self.current_depth += 1,
                    Command::JumpBackward => self.current_depth -= 1,
                    _ => {}
                }
                if self.current_depth == goal_depth {
                    *index_ref = index + 1;
                    self.status = ProgramStatus::Normal;
                    return;
                }
            }

            *index_ref = self.instructions.len();
            self.status = ProgramStatus::Seeking(goal_depth);
        }
    }

    fn handle_jump_forward(&mut self, vm: &VM, index: &mut usize) {
        match (vm.cells[vm.data_pointer], self.status) {
            (0, ProgramStatus::Normal) => {
                self.status = ProgramStatus::Seeking(self.current_depth);
                self.seek_forward(index);
            }

            (_, ProgramStatus::Normal) => {
                *index += 1;
                self.current_depth += 1;
                self.status = ProgramStatus::Normal;
            }

            (_, ProgramStatus::Seeking(_)) => self.seek_forward(index),

        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    #[test]
    pub fn test_seek_forward_normal() {
        let mut program = Program {
            instruction_pointer: None,
            current_depth: 0,
            status: ProgramStatus::Seeking(0),
            instructions: vec![
                Command::JumpForward,
                Command::JumpForward,
                Command::JumpBackward,
                Command::JumpBackward,
            ],
        };
        let mut index = 0;
        program.seek_forward(&mut index);
        assert_eq!(index, 4);
        assert_eq!(program.status, ProgramStatus::Normal);
    }

    #[test]
    pub fn test_seek_forward_seeking() {
        let mut program = Program {
            instruction_pointer: None,
            current_depth: 0,
            status: ProgramStatus::Seeking(0),
            instructions: vec![
                Command::JumpForward,
                Command::JumpForward,
                Command::JumpBackward,
            ],
        };
        let mut index = 0;
        program.seek_forward(&mut index);
        assert_eq!(index, 3);
        assert_eq!(program.status, ProgramStatus::Seeking(0));
    }
}
<|endoftext|>


<commit_before>#![warn(clippy::similar_names)]
#![allow(unused, clippy::println_empty_string)]

struct Foo {
    apple: i32,
    bpple: i32,
}

fn main() {
    let specter: i32;
    let spectre: i32;

    let apple: i32;

    let bpple: i32;

    let cpple: i32;

    let a_bar: i32;
    let b_bar: i32;
    let c_bar: i32;

    let items = [5];
    for item in &items {
        loop {}
    }

    let foo_x: i32;
    let foo_y: i32;

    let rhs: i32;
    let lhs: i32;

    let bla_rhs: i32;
    let bla_lhs: i32;

    let blubrhs: i32;
    let blublhs: i32;

    let blubx: i32;
    let bluby: i32;

    let cake: i32;
    let cakes: i32;
    let coke: i32;

    match 5 {
        cheese @ 1 => {},
        rabbit => panic!(),
    }
    let cheese: i32;
    match (42, 43) {
        (cheese1, 1) => {},
        (cheese2, 2) => panic!(),
        _ => println!(""),
    }
    let ipv4: i32;
    let ipv6: i32;
    let abcd1: i32;
    let abdc2: i32;
    let xyz1abc: i32;
    let xyz2abc: i32;
    let xyzeabc: i32;

    let parser: i32;
    let parsed: i32;
    let parsee: i32;

    let setter: i32;
    let getter: i32;
    let tx1: i32;
    let rx1: i32;
    let tx_cake: i32;
    let rx_cake: i32;

    // names often used in win32 code (for example WindowProc)
    let wparam: i32;
    let lparam: i32;

    let iter: i32;
    let item: i32;
}

fn foo() {
    let Foo { apple, bpple } = unimplemented!();
    let Foo {
        apple: spring,
        bpple: sprang,
    } = unimplemented!();
}

// false positive similar_names (#3057, #2651)
// clippy claimed total_reg_src_size and total_size and
// numb_reg_src_checkouts and total_bin_size were similar
#[derive(Debug, Clone)]
pub(crate) struct DirSizes {
    pub(crate) total_size: u64,
    pub(crate) numb_bins: u64,
    pub(crate) total_bin_size: u64,
    pub(crate) total_reg_size: u64,
    pub(crate) total_git_db_size: u64,
    pub(crate) total_git_repos_bare_size: u64,
    pub(crate) numb_git_repos_bare_repos: u64,
    pub(crate) numb_git_checkouts: u64,
    pub(crate) total_git_chk_size: u64,
    pub(crate) total_reg_cache_size: u64,
    pub(crate) total_reg_src_size: u64,
    pub(crate) numb_reg_cache_entries: u64,
    pub(crate) numb_reg_src_checkouts: u64,
}

fn ignore_underscore_prefix() {
    let hello: ();
    let _hello: ();
}
<commit_msg>rustfmt<commit_after>#![warn(clippy::similar_names)]
#![allow(unused, clippy::println_empty_string)]

struct Foo {
    apple: i32,
    bpple: i32,
}

fn main() {
    let specter: i32;
    let spectre: i32;

    let apple: i32;

    let bpple: i32;

    let cpple: i32;

    let a_bar: i32;
    let b_bar: i32;
    let c_bar: i32;

    let items = [5];
    for item in &items {
        loop {}
    }

    let foo_x: i32;
    let foo_y: i32;

    let rhs: i32;
    let lhs: i32;

    let bla_rhs: i32;
    let bla_lhs: i32;

    let blubrhs: i32;
    let blublhs: i32;

    let blubx: i32;
    let bluby: i32;

    let cake: i32;
    let cakes: i32;
    let coke: i32;

    match 5 {
        cheese @ 1 => {},
        rabbit => panic!(),
    }
    let cheese: i32;
    match (42, 43) {
        (cheese1, 1) => {},
        (cheese2, 2) => panic!(),
        _ => println!(""),
    }
    let ipv4: i32;
    let ipv6: i32;
    let abcd1: i32;
    let abdc2: i32;
    let xyz1abc: i32;
    let xyz2abc: i32;
    let xyzeabc: i32;

    let parser: i32;
    let parsed: i32;
    let parsee: i32;

    let setter: i32;
    let getter: i32;
    let tx1: i32;
    let rx1: i32;
    let tx_cake: i32;
    let rx_cake: i32;

    // names often used in win32 code (for example WindowProc)
    let wparam: i32;
    let lparam: i32;

    let iter: i32;
    let item: i32;
}

fn foo() {
    let Foo { apple, bpple } = unimplemented!();
    let Foo {
        apple: spring,
        bpple: sprang,
    } = unimplemented!();
}

// false positive similar_names (#3057, #2651)
// clippy claimed total_reg_src_size and total_size and
// numb_reg_src_checkouts and total_bin_size were similar
#[derive(Debug, Clone)]
pub(crate) struct DirSizes {
    pub(crate) total_size: u64,
    pub(crate) numb_bins: u64,
    pub(crate) total_bin_size: u64,
    pub(crate) total_reg_size: u64,
    pub(crate) total_git_db_size: u64,
    pub(crate) total_git_repos_bare_size: u64,
    pub(crate) numb_git_repos_bare_repos: u64,
    pub(crate) numb_git_checkouts: u64,
    pub(crate) total_git_chk_size: u64,
    pub(crate) total_reg_cache_size: u64,
    pub(crate) total_reg_src_size: u64,
    pub(crate) numb_reg_cache_entries: u64,
    pub(crate) numb_reg_src_checkouts: u64,
}

fn ignore_underscore_prefix() {
    let hello: ();
    let _hello: ();
}
<|endoftext|>


<commit_before>use buffer::{Position, Range, range};

/// A more concise expression for ranges spanning complete lines.
pub struct LineRange {
    start: usize,
    end:   usize,
}

impl LineRange {
    pub fn start(&self) -> usize {
        self.start
    }

    pub fn end(&self) -> usize {
        self.end
    }

    /// Converts the line range to a regular, zero-offset range.
    ///
    /// # Examples
    ///
    /// ```
    /// use scribe::buffer::{line_range, Position, range};
    ///
    /// // Builder a line range.
    /// let line_range = line_range::new(10, 14);
    ///
    /// // Ensure that the resulting range is a zero-based equivalent.
    /// assert_eq!(line_range.to_range(), range::new(
    ///     Position{ line: 10, offset: 0 },
    ///     Position{ line: 14, offset:0 }
    /// ));
    /// ```
    pub fn to_range(&self) -> Range {
        range::new(
            Position{ line: self.start, offset: 0 },
            Position{ line: self.end, offset:0 }
        )
    }

    /// Whether or not the line range includes the specified line.
    /// The range is exclusive, such that its ending line is not included.
    ///
    /// # Examples
    ///
    /// ```
    /// use scribe::buffer::line_range;
    ///
    /// // Builder a line range.
    /// let line_range = line_range::new(10, 14);
    ///
    /// assert!(line_range.includes(11));
    /// assert!(!line_range.includes(14));
    /// ```
    pub fn includes(&self, line: usize) -> bool {
        line >= self.start() && line < self.end()
    }
}

pub fn new(start: usize, end: usize) -> LineRange {
    if start < end {
        LineRange{ start: start, end: end }
    } else {
        LineRange{ start: end, end: start }
    }
}

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

    #[test]
    fn new_does_not_swap_values_if_end_does_not_precede_start() {
        let range = new(0, 1);

        assert_eq!(range.start(), 0);
        assert_eq!(range.end(), 1);
    }

    #[test]
    fn new_swaps_start_and_end_when_end_precedes_start() {
        let range = new(1, 0);

        assert_eq!(range.start(), 0);
        assert_eq!(range.end(), 1);
    }
}
<commit_msg>Add equality and debug traits to line range type.<commit_after>use buffer::{Position, Range, range};

/// A more concise expression for ranges spanning complete lines.
#[derive(PartialEq, Debug)]
pub struct LineRange {
    start: usize,
    end:   usize,
}

impl LineRange {
    pub fn start(&self) -> usize {
        self.start
    }

    pub fn end(&self) -> usize {
        self.end
    }

    /// Converts the line range to a regular, zero-offset range.
    ///
    /// # Examples
    ///
    /// ```
    /// use scribe::buffer::{line_range, Position, range};
    ///
    /// // Builder a line range.
    /// let line_range = line_range::new(10, 14);
    ///
    /// // Ensure that the resulting range is a zero-based equivalent.
    /// assert_eq!(line_range.to_range(), range::new(
    ///     Position{ line: 10, offset: 0 },
    ///     Position{ line: 14, offset:0 }
    /// ));
    /// ```
    pub fn to_range(&self) -> Range {
        range::new(
            Position{ line: self.start, offset: 0 },
            Position{ line: self.end, offset:0 }
        )
    }

    /// Whether or not the line range includes the specified line.
    /// The range is exclusive, such that its ending line is not included.
    ///
    /// # Examples
    ///
    /// ```
    /// use scribe::buffer::line_range;
    ///
    /// // Builder a line range.
    /// let line_range = line_range::new(10, 14);
    ///
    /// assert!(line_range.includes(11));
    /// assert!(!line_range.includes(14));
    /// ```
    pub fn includes(&self, line: usize) -> bool {
        line >= self.start() && line < self.end()
    }
}

pub fn new(start: usize, end: usize) -> LineRange {
    if start < end {
        LineRange{ start: start, end: end }
    } else {
        LineRange{ start: end, end: start }
    }
}

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

    #[test]
    fn new_does_not_swap_values_if_end_does_not_precede_start() {
        let range = new(0, 1);

        assert_eq!(range.start(), 0);
        assert_eq!(range.end(), 1);
    }

    #[test]
    fn new_swaps_start_and_end_when_end_precedes_start() {
        let range = new(1, 0);

        assert_eq!(range.start(), 0);
        assert_eq!(range.end(), 1);
    }
}
<|endoftext|>


<commit_before>/// A TOML [1] configuration file parser
///
/// [1]: https://github.com/mojombo/toml

use std::io::mem::MemReader;
use std::io::File;
use std::hashmap::HashMap;

#[deriving(ToStr)]
enum Value {
    True,
    False,
    Unsigned(u64),
    Integer(i64),
    Float(f64),
    String(~str),
    Array(~[Value]),
    Datetime, // XXX
    Map(HashMap<~str, Value>) // XXX: This is no value
}

trait Visitor {
    fn section(&mut self, name: ~str, is_array: bool) -> bool;
    fn pair(&mut self, key: ~str, val: Value) -> bool;
}

struct TOMLVisitor {
    root: HashMap<~str, Value>,
    current_section: ~str,
    section_is_array: bool
}

impl TOMLVisitor {
    fn new() -> TOMLVisitor {
        TOMLVisitor { root: HashMap::new(), current_section: ~"", section_is_array: false }
    }
    fn get_root<'a>(&'a self) -> &'a HashMap<~str, Value> {
        return &self.root;
    }
}

impl Visitor for TOMLVisitor {
    fn section(&mut self, name: ~str, is_array: bool) -> bool {
        debug!("Section: {} (is_array={})", name, is_array);
        self.section_is_array = is_array;
        self.current_section = name;
        return true
    }
    fn pair(&mut self, key: ~str, val: Value) -> bool {
        debug!("Pair: {} {:s}", key, val.to_str());
        let m = self.root.find_or_insert(self.current_section.clone(), Map(HashMap::new())); // XXX: remove clone
        match *m {
            Map(ref mut map) => {
                let ok = map.insert(key, val);
                return ok
            }
            _ => { return false }
        }
    }
}

struct Parser<'a> {
    rd: &'a mut MemReader,
    current_char: Option<char>
}

impl<'a> Parser<'a> {
    fn read_char(rd: &mut MemReader) -> Option<char> {
        match rd.read_byte() {
            Some(b) => Some(b as char),
            None => None
        }
    }

    fn new(rd: &'a mut MemReader) -> Parser<'a> {
        let ch = Parser::read_char(rd);
        Parser { rd: rd, current_char: ch }
    }

    fn advance(&mut self) {
        self.current_char = Parser::read_char(self.rd)
    }

    fn ch(&self) -> Option<char> {
        return self.current_char;
    }

    fn eos(&self) -> bool {
        return self.current_char.is_none();
    }

    fn advance_if(&mut self, c: char) -> bool {
        match self.ch() {
            Some(ch) if ch == c => {
               self.advance();
               true
            }
            _ => {
                false
            }
        }
    }

    fn read_digit(&mut self) -> Option<u8> {
        let res = match self.ch() {
            Some('0') => Some(0),
            Some('1') => Some(1),
            Some('2') => Some(2),
            Some('3') => Some(3),
            Some('4') => Some(4),
            Some('5') => Some(5),
            Some('6') => Some(6),
            Some('7') => Some(7),
            Some('8') => Some(8),
            Some('9') => Some(9),
            _ => None
        };
        if res.is_some() { self.advance() }
        return res
    }

    fn read_digits(&mut self) -> Option<u64> {
        let mut num: u64;
        match self.read_digit() {
            Some(n) => { num = n as u64; }
            None => { return None }
        }
        loop {
            match self.read_digit() {
                Some(n) => {
                    // XXX: check range
                    num = num * 10 + (n as u64);
                }
                None => {
                    return Some(num)
                }
            }
        }
    }

    // allows a single "."
    fn read_float_mantissa(&mut self) -> f64 {
        let mut num: f64 = 0.0;
        let mut div: f64 = 10.0;

        loop {
            match self.read_digit() {
                Some(n) => {
                    num = num + (n as f64)/div;
                    div = div * 10.0;
                }
                None => {
                    return num;
                }
            }
        }
    }

    fn parse_value(&mut self) -> Option<Value> {
        self.skip_whitespaces();

        if self.eos() { return None }
        match self.ch().unwrap() {
            '-' => {
                self.advance();
                match self.read_digits() {
                    Some(n) => {
                        if self.ch() == Some('.') {
                            // floating point
                            self.advance();
                            let num = self.read_float_mantissa();
                            let num = (n as f64) + num;
                            return Some(Float(-num));
                        }
                        else {
                            match n.to_i64() {
                                Some(i) => Some(Integer(-i)),
                                None => None // XXX: Use Result
                            }
                        }
                    }
                    None => {
                        return None
                    }
                }
            }
            '0' .. '9' => {
                match self.read_digits() {
                    Some(n) => {
                        match self.ch() {
                            Some('.') => {
                                // floating point
                                self.advance();
                                let num = self.read_float_mantissa();
                                let num = (n as f64) + num;
                                return Some(Float(num));
                            }
                            Some('-') => {
                                // XXX
                                fail!("Datetime not yet supported");
                            }
                            _ => {
                                return Some(Unsigned(n))
                            }
                        }
                    }
                    None => {
                        assert!(false);
                        return None
                    }
                }
            }
            't' => {
                self.advance();
                if self.advance_if('r') &&
                   self.advance_if('u') &&
                   self.advance_if('e') {
                    return Some(True)
                } else {
                    return None
                }
            }
            'f' => {
                self.advance();
                if self.advance_if('a') &&
                   self.advance_if('l') &&
                   self.advance_if('s') &&
                   self.advance_if('e') {
                    return Some(True)
                } else {
                    return None
                }
            }
            '[' => {
                self.advance();
                let mut arr = ~[];
                loop {
                    match self.parse_value() {
                        Some(val) => {
                            arr.push(val);
                        }
                        None => {
                            break;
                        }
                    }

                    self.skip_whitespaces_and_comments();
                    if !self.advance_if(',') { break }
                }
                self.skip_whitespaces_and_comments();
                if self.advance_if(']') {
                    return Some(Array(arr));
                } else {
                    return None;
                }
            }
            '"' => {
                self.advance();
                let str = self.read_token(|ch| {
                    match ch {
                        '"' => false,
                        _ => true
                    }
                });
                if self.advance_if('"') {
                    return Some(String(str))
                } else {
                    return None
                }
            }
            _ => { return None }
        }
    }

    fn read_token(&mut self, f: |char| -> bool) -> ~str {
        let mut token = ~"";
        loop {
            match self.ch() {
                Some(ch) => {
                    if f(ch) { token.push_char(ch) }
                    else { break }
                }
                None => { break }
            }
            self.advance();
        }

        return token;
    }

    fn parse_section_identifier(&mut self) -> ~str {
        self.read_token(|ch| {
            match ch {
                'a' .. 'z' | 'A' .. 'Z' | '0' .. '9' | '.' | '_' => true,
                _ => false
            }
        })
    }

    fn skip_whitespaces(&mut self) {
        loop {
            match self.ch() {
                Some(' ') | Some('\t') | Some('\r') | Some('\n') => {
                    self.advance();
                }
                _ => { break }
            }
        }
    }

    fn skip_whitespaces_and_comments(&mut self) {
        loop {
            match self.ch() {
                Some(' ') | Some('\t') | Some('\r') | Some('\n') => {
                    self.advance();
                }
                Some('#') => {
                    self.skip_comment();
                }
                _ => { break }
            }
        }
    }

    fn skip_comment(&mut self) {
        assert!(self.ch() == Some('#'));
        // skip to end of line
        loop {
            self.advance();
            match self.ch() {
                Some('\n') => { break }
                None => { return }
                _ => { /* skip */ }
            }
        }
        self.advance();
    }

    fn parse<V: Visitor>(&mut self, visitor: &mut V) -> bool {
        loop {
            if self.eos() { return true }
            match self.ch().unwrap() {
                // ignore whitespace
                '\r' | '\n' | ' ' | '\t' => {
                    self.advance();
                }

                // comment
                '#' => {
                    self.skip_comment();
                }

                // section
                '[' => {
                    self.advance();
                    let mut double_section = false;
                    match self.ch() {
                        Some('[') => {
                            double_section = true;
                            self.advance();
                        }
                        _ => {}
                    }

                    let section_name = self.parse_section_identifier();

                    if !self.advance_if(']') { return false }
                    if double_section {
                        if !self.advance_if(']') { return false }
                    }

                    visitor.section(section_name, double_section);
                }

                // identifier
                'a' .. 'z' | 'A' .. 'Z' | '_' => {

                    let ident = self.read_token(|ch| {
                        match ch {
                            'a' .. 'z' | 'A' .. 'Z' | '0' .. '9' | '_' => true,
                            _ => false
                        }
                    });

                    self.skip_whitespaces();

                    if !self.advance_if('=') { return false } // assign wanted

                    match self.parse_value() {
                        Some(val) => { visitor.pair(ident, val); }
                        None => { return false; }
                    }
                    // do not advance!
                }

                _ => { return false }
            } /* end match */
        }

        assert!(false);
    }
}

fn main() {
  let contents = File::open(&Path::new(std::os::args()[1])).read_to_end();
  let mut visitor = TOMLVisitor::new();
  let mut rd = MemReader::new(contents);
  let mut parser = Parser::new(&mut rd);
  parser.parse(&mut visitor);
  println!("{:s}", visitor.get_root().to_str());
}
<commit_msg>Implement string parsing<commit_after>/// A TOML [1] configuration file parser
///
/// [1]: https://github.com/mojombo/toml

use std::io::mem::MemReader;
use std::io::File;
use std::hashmap::HashMap;

#[deriving(ToStr)]
enum Value {
    True,
    False,
    Unsigned(u64),
    Integer(i64),
    Float(f64),
    String(~str),
    Array(~[Value]),
    Datetime, // XXX
    Map(HashMap<~str, Value>) // XXX: This is no value
}

trait Visitor {
    fn section(&mut self, name: ~str, is_array: bool) -> bool;
    fn pair(&mut self, key: ~str, val: Value) -> bool;
}

struct TOMLVisitor {
    root: HashMap<~str, Value>,
    current_section: ~str,
    section_is_array: bool
}

impl TOMLVisitor {
    fn new() -> TOMLVisitor {
        TOMLVisitor { root: HashMap::new(), current_section: ~"", section_is_array: false }
    }
    fn get_root<'a>(&'a self) -> &'a HashMap<~str, Value> {
        return &self.root;
    }
}

impl Visitor for TOMLVisitor {
    fn section(&mut self, name: ~str, is_array: bool) -> bool {
        debug!("Section: {} (is_array={})", name, is_array);
        self.section_is_array = is_array;
        self.current_section = name;
        return true
    }
    fn pair(&mut self, key: ~str, val: Value) -> bool {
        debug!("Pair: {} {:s}", key, val.to_str());
        let m = self.root.find_or_insert(self.current_section.clone(), Map(HashMap::new())); // XXX: remove clone
        match *m {
            Map(ref mut map) => {
                let ok = map.insert(key, val);
                return ok
            }
            _ => { return false }
        }
    }
}

struct Parser<'a> {
    rd: &'a mut MemReader,
    current_char: Option<char>
}

impl<'a> Parser<'a> {
    fn read_char(rd: &mut MemReader) -> Option<char> {
        match rd.read_byte() {
            Some(b) => Some(b as char),
            None => None
        }
    }

    fn new(rd: &'a mut MemReader) -> Parser<'a> {
        let ch = Parser::read_char(rd);
        Parser { rd: rd, current_char: ch }
    }

    fn advance(&mut self) {
        self.current_char = Parser::read_char(self.rd)
    }

    fn ch(&self) -> Option<char> {
        return self.current_char;
    }

    fn eos(&self) -> bool {
        return self.current_char.is_none();
    }

    fn advance_if(&mut self, c: char) -> bool {
        match self.ch() {
            Some(ch) if ch == c => {
               self.advance();
               true
            }
            _ => {
                false
            }
        }
    }

    fn read_digit(&mut self, radix: uint) -> Option<u8> {
        if self.eos() { return None }
        match std::char::to_digit(self.ch().unwrap(), radix) {
            Some(n) => {
                self.advance();
                Some(n as u8)
            }
            None => { None }
        }
    }

    fn read_digits(&mut self) -> Option<u64> {
        let mut num: u64;
        match self.read_digit(10) {
            Some(n) => { num = n as u64; }
            None => { return None }
        }
        loop {
            match self.read_digit(10) {
                Some(n) => {
                    // XXX: check range
                    num = num * 10 + (n as u64);
                }
                None => {
                    return Some(num)
                }
            }
        }
    }

    // allows a single "."
    fn read_float_mantissa(&mut self) -> f64 {
        let mut num: f64 = 0.0;
        let mut div: f64 = 10.0;

        loop {
            match self.read_digit(10) {
                Some(n) => {
                    num = num + (n as f64)/div;
                    div = div * 10.0;
                }
                None => {
                    return num;
                }
            }
        }
    }

    fn parse_value(&mut self) -> Option<Value> {
        self.skip_whitespaces();

        if self.eos() { return None }
        match self.ch().unwrap() {
            '-' => {
                self.advance();
                match self.read_digits() {
                    Some(n) => {
                        if self.ch() == Some('.') {
                            // floating point
                            self.advance();
                            let num = self.read_float_mantissa();
                            let num = (n as f64) + num;
                            return Some(Float(-num));
                        }
                        else {
                            match n.to_i64() {
                                Some(i) => Some(Integer(-i)),
                                None => None // XXX: Use Result
                            }
                        }
                    }
                    None => {
                        return None
                    }
                }
            }
            '0' .. '9' => {
                match self.read_digits() {
                    Some(n) => {
                        match self.ch() {
                            Some('.') => {
                                // floating point
                                self.advance();
                                let num = self.read_float_mantissa();
                                let num = (n as f64) + num;
                                return Some(Float(num));
                            }
                            Some('-') => {
                                // XXX
                                fail!("Datetime not yet supported");
                            }
                            _ => {
                                return Some(Unsigned(n))
                            }
                        }
                    }
                    None => {
                        assert!(false);
                        return None
                    }
                }
            }
            't' => {
                self.advance();
                if self.advance_if('r') &&
                   self.advance_if('u') &&
                   self.advance_if('e') {
                    return Some(True)
                } else {
                    return None
                }
            }
            'f' => {
                self.advance();
                if self.advance_if('a') &&
                   self.advance_if('l') &&
                   self.advance_if('s') &&
                   self.advance_if('e') {
                    return Some(True)
                } else {
                    return None
                }
            }
            '[' => {
                self.advance();
                let mut arr = ~[];
                loop {
                    match self.parse_value() {
                        Some(val) => {
                            arr.push(val);
                        }
                        None => {
                            break;
                        }
                    }

                    self.skip_whitespaces_and_comments();
                    if !self.advance_if(',') { break }
                }
                self.skip_whitespaces_and_comments();
                if self.advance_if(']') {
                    return Some(Array(arr));
                } else {
                    return None;
                }
            }
            '"' => {
                match self.parse_string() {
                    Some(str) => { return Some(String(str)) }
                    None => { return None }
                }
            }
            _ => { return None }
        }
    }

    fn parse_string(&mut self) -> Option<~str> {
        if !self.advance_if('"') { return None }

        let mut str = ~"";
        loop {
            if self.ch().is_none() { return None }
            match self.ch().unwrap() {
                '\r' | '\n' | '\u000C' | '\u0008' => { return None }
                '\\' => {
                    self.advance();
                    if self.ch().is_none() { return None }
                    match self.ch().unwrap() {
                        'b' => { str.push_char('\u0008'); self.advance() },
                        't' => { str.push_char('\t'); self.advance() },
                        'n' => { str.push_char('\n'); self.advance() },
                        'f' => { str.push_char('\u000C'); self.advance() },
                        'r' => { str.push_char('\r'); self.advance() },
                        '"' => { str.push_char('"'); self.advance() },
                        '/' => { str.push_char('/'); self.advance() },
                        '\\' => { str.push_char('\\'); self.advance() },
                        'u' => {
                            self.advance();
                            let d1 = self.read_digit(16);
                            let d2 = self.read_digit(16);
                            let d3 = self.read_digit(16);
                            let d4 = self.read_digit(16);
                            match (d1, d2, d3, d4) {
                                (Some(d1), Some(d2), Some(d3), Some(d4)) => {
                                    // XXX: how to construct an UTF character
                                    let ch = (((((d1 as u32 << 8) | d2 as u32) << 8) | d3 as u32) << 8) | d4 as u32;
                                    match std::char::from_u32(ch) {
                                        Some(ch) => {
                                            str.push_char(ch);
                                        }
                                        None => {
                                            return None;
                                        }
                                    }
                                }
                                _ => return None
                            }
                        }
                        _ => { return None }
                    }
                }
                '"' => {
                    self.advance();
                    return Some(str);
                }
                c => {
                    let len = std::char::len_utf8_bytes(c);
                    //assert!(len >= 1 && len <= 4);
                    assert!(len == 1);
                    str.push_char(c);
                    self.advance();
                }
            }
        }
    }

    fn read_token(&mut self, f: |char| -> bool) -> ~str {
        let mut token = ~"";
        loop {
            match self.ch() {
                Some(ch) => {
                    if f(ch) { token.push_char(ch) }
                    else { break }
                }
                None => { break }
            }
            self.advance();
        }

        return token;
    }

    fn parse_section_identifier(&mut self) -> ~str {
        self.read_token(|ch| {
            match ch {
                'a' .. 'z' | 'A' .. 'Z' | '0' .. '9' | '.' | '_' => true,
                _ => false
            }
        })
    }

    fn skip_whitespaces(&mut self) {
        loop {
            match self.ch() {
                Some(' ') | Some('\t') | Some('\r') | Some('\n') => {
                    self.advance();
                }
                _ => { break }
            }
        }
    }

    fn skip_whitespaces_and_comments(&mut self) {
        loop {
            match self.ch() {
                Some(' ') | Some('\t') | Some('\r') | Some('\n') => {
                    self.advance();
                }
                Some('#') => {
                    self.skip_comment();
                }
                _ => { break }
            }
        }
    }

    fn skip_comment(&mut self) {
        assert!(self.ch() == Some('#'));
        // skip to end of line
        loop {
            self.advance();
            match self.ch() {
                Some('\n') => { break }
                None => { return }
                _ => { /* skip */ }
            }
        }
        self.advance();
    }

    fn parse<V: Visitor>(&mut self, visitor: &mut V) -> bool {
        loop {
            if self.eos() { return true }
            match self.ch().unwrap() {
                // ignore whitespace
                '\r' | '\n' | ' ' | '\t' => {
                    self.advance();
                }

                // comment
                '#' => {
                    self.skip_comment();
                }

                // section
                '[' => {
                    self.advance();
                    let mut double_section = false;
                    match self.ch() {
                        Some('[') => {
                            double_section = true;
                            self.advance();
                        }
                        _ => {}
                    }

                    let section_name = self.parse_section_identifier();

                    if !self.advance_if(']') { return false }
                    if double_section {
                        if !self.advance_if(']') { return false }
                    }

                    visitor.section(section_name, double_section);
                }

                // identifier
                'a' .. 'z' | 'A' .. 'Z' | '_' => {

                    let ident = self.read_token(|ch| {
                        match ch {
                            'a' .. 'z' | 'A' .. 'Z' | '0' .. '9' | '_' => true,
                            _ => false
                        }
                    });

                    self.skip_whitespaces();

                    if !self.advance_if('=') { return false } // assign wanted

                    match self.parse_value() {
                        Some(val) => { visitor.pair(ident, val); }
                        None => { return false; }
                    }
                    // do not advance!
                }

                _ => { return false }
            } /* end match */
        }

        assert!(false);
    }
}

fn main() {
  let contents = File::open(&Path::new(std::os::args()[1])).read_to_end();
  let mut visitor = TOMLVisitor::new();
  let mut rd = MemReader::new(contents);
  let mut parser = Parser::new(&mut rd);
  parser.parse(&mut visitor);
  println!("{:s}", visitor.get_root().to_str());
}
<|endoftext|>


<commit_before>use story_builder::story_builder::*;
use story_builder::article_provider::*;
use std::collections::HashMap;
use std::rc::Rc;

static EXPECTED_SUGGESTION: &'static str = "Cannot find wikipedia article for <not-found>, try one of the following suggestions:\r\n\
- Suggestion 1\r\n\
- Suggestion 2\r\n\
- Suggestion 3\r\n";

#[test]
/// For: build_suggestions_msg
fn build_suggestions_msg_is_working() {
    struct TestProvider {}
    impl ArticleProvider for TestProvider {
        #[allow(unused_variables)]
        fn get(&self, topic: &str) -> Option<Box<Article>> {
            panic!("get() should never be called in this test.");
        }
        #[allow(unused_variables)]
        fn search(&self, topic: &str) -> Vec<String> {
            vec!["Suggestion 1".to_owned(),
            "Suggestion 2".to_owned(),
            "Suggestion 3".to_owned()]
        }
    }
    let provider = TestProvider {};
    let story_builder = StoryBuilder::new(&provider);

    assert_eq!(story_builder.build_suggestions_msg("not-found"), EXPECTED_SUGGESTION);
}

#[test]
/// For: build_story
fn build_story_cannot_find_first_article_suggest() {
    struct TestArticle {
        topics: Vec<Paragraph>
    }
    impl Article for TestArticle {
        fn get_paragraphs(&self) -> &Vec<Paragraph> {&self.topics}
    }
    struct TestProvider {}
    impl ArticleProvider for TestProvider {
        fn get(&self, topic: &str) -> Option<Box<Article>> {
            if topic == "found" {
                Some(Box::new(TestArticle {topics: vec![]}))
            }
            else {
                None
            }
        }
        #[allow(unused_variables)]
        fn search(&self, topic: &str) -> Vec<String> {
            vec!["Suggestion 1".to_owned(),
            "Suggestion 2".to_owned(),
            "Suggestion 3".to_owned()]
        }
    }

    let provider = TestProvider {};
    let story_builder = StoryBuilder::new(&provider);
    assert_eq!(story_builder.build_story("not-found", "found"), Err(EXPECTED_SUGGESTION.to_owned()));
}

#[test]
/// For: build_story
fn build_story_cannot_find_second_article_suggest() {
    struct TestArticle {
        topics: Vec<Paragraph>
    }
    impl Article for TestArticle {
        fn get_paragraphs(&self) -> &Vec<Paragraph> {&self.topics}
    }
    struct TestProvider {}
    impl ArticleProvider for TestProvider {
        fn get(&self, topic: &str) -> Option<Box<Article>> {
            if topic == "found"
                {Some(Box::new(TestArticle {topics: vec![]}))}
            else
                {None}
        }
        #[allow(unused_variables)]
        fn search(&self, topic: &str) -> Vec<String> {
            vec!["Suggestion 1".to_owned(),
            "Suggestion 2".to_owned(),
            "Suggestion 3".to_owned()]
        }
    }

    let provider = TestProvider {};
    let story_builder = StoryBuilder::new(&provider);
    assert_eq!(story_builder.build_story("found", "not-found"), Err(EXPECTED_SUGGESTION.to_owned()));
}

#[test]
/// For: build_story
fn build_story_from_same_start_and_end_should_err() {
    struct TestProvider {}
    impl ArticleProvider for TestProvider {
        #[allow(unused_variables)]
        fn get(&self, topic: &str) -> Option<Box<Article>> {panic!("get() should not get called in this test.")}
        #[allow(unused_variables)]
        fn search(&self, topic: &str) -> Vec<String> {panic!("get() should not get called in this test.")}
    }
    let provider = TestProvider {};
    let story_builder = StoryBuilder::new(&provider);
    assert_eq!(story_builder.build_story("similar topic", "similar topic"),
               Err("No story to build; same start and end topics.".to_owned()));
}

#[test]
/// For: build_story
fn build_story_empty_start_topic_should_err() {
    struct TestProvider {}
    impl ArticleProvider for TestProvider {
        #[allow(unused_variables)]
        fn get(&self, topic: &str) -> Option<Box<Article>> {panic!("get() should not get called in this test.")}
        #[allow(unused_variables)]
        fn search(&self, topic: &str) -> Vec<String> {panic!("get() should not get called in this test.")}
    }
    let provider = TestProvider {};
    let story_builder = StoryBuilder::new(&provider);
    assert_eq!(story_builder.build_story("", "Other topic"),
               Err("Missing start topic.".to_owned()));
}

#[test]
/// For: build_story
fn build_story_empty_end_topic_should_err() {
    struct TestProvider {}
    impl ArticleProvider for TestProvider {
        #[allow(unused_variables)]
        fn get(&self, topic: &str) -> Option<Box<Article>> {panic!("get() should not get called in this test.")}
        #[allow(unused_variables)]
        fn search(&self, topic: &str) -> Vec<String> {panic!("get() should not get called in this test.")}
    }
    let provider = TestProvider {};
    let story_builder = StoryBuilder::new(&provider);
    assert_eq!(story_builder.build_story("First topic", ""),
               Err("Missing end topic.".to_owned()));
}

#[test]
/// For: build_story
fn build_story_end_topic_found_in_start_article() {
    let mut prebuilt_rels = Rc::new(HashMap::new());
    Rc::get_mut(&mut prebuilt_rels).unwrap().insert("start", vec![Paragraph {text: "Paragraph 1".to_owned(), topics: vec!["topic 1".to_owned(), "topic 2".to_owned(), "topic 3".to_owned()]},
                                                                  Paragraph {text: "Paragraph 2".to_owned(), topics: vec!["topic 3".to_owned(), "end".to_owned(), "topic 5".to_owned()]},
                                                                  Paragraph {text: "Paragraph 3".to_owned(), topics: vec!["topic 3".to_owned(), "topic 1".to_owned(), "topic 5".to_owned()]}]);
    struct TestArticle {
        topic: String,
        prebuilt_rels: Rc<HashMap<&'static str, Vec<Paragraph>>>,
    }

    impl TestArticle {
        fn new(topic: String, prebuilt_rels: Rc<HashMap<&'static str, Vec<Paragraph>>>) -> TestArticle {
            TestArticle {topic, prebuilt_rels}
        }
    }

    impl Article for TestArticle {
            fn get_paragraphs(&self) -> &Vec<Paragraph> {
            self.prebuilt_rels.get::<str>(&self.topic).expect("Tried to access a node that doesn't exist!")
        }
    }
    struct TestProvider {
        prebuilt_rels: Rc<HashMap<&'static str, Vec<Paragraph>>>
    }
    impl TestProvider {
        fn new(prebuilt_rels: Rc<HashMap<&'static str, Vec<Paragraph>>>) -> TestProvider {
            TestProvider {prebuilt_rels}
        }
    }
    impl ArticleProvider for TestProvider {
        fn get(&self, topic: &str) -> Option<Box<Article>> {
                let new_rels: Rc<HashMap<&'static str, Vec<Paragraph>>> = self.prebuilt_rels.clone();
                Some(Box::new(TestArticle::new(topic.to_owned(), new_rels)))
        }
        fn search(&self, topic: &str) -> Vec<String> {panic!("search() should not be called in this test.");}
    }
    let provider = TestProvider::new(prebuilt_rels.clone());
    let story_builder = StoryBuilder::new(&provider);
    assert_eq!(story_builder.build_story("start", "end"), Ok("Paragraph for end.\r\n".to_owned()));
}
<commit_msg>Fixed expected test result<commit_after>use story_builder::story_builder::*;
use story_builder::article_provider::*;
use std::collections::HashMap;
use std::rc::Rc;

static EXPECTED_SUGGESTION: &'static str = "Cannot find wikipedia article for <not-found>, try one of the following suggestions:\r\n\
- Suggestion 1\r\n\
- Suggestion 2\r\n\
- Suggestion 3\r\n";

#[test]
/// For: build_suggestions_msg
fn build_suggestions_msg_is_working() {
    struct TestProvider {}
    impl ArticleProvider for TestProvider {
        #[allow(unused_variables)]
        fn get(&self, topic: &str) -> Option<Box<Article>> {
            panic!("get() should never be called in this test.");
        }
        #[allow(unused_variables)]
        fn search(&self, topic: &str) -> Vec<String> {
            vec!["Suggestion 1".to_owned(),
            "Suggestion 2".to_owned(),
            "Suggestion 3".to_owned()]
        }
    }
    let provider = TestProvider {};
    let story_builder = StoryBuilder::new(&provider);

    assert_eq!(story_builder.build_suggestions_msg("not-found"), EXPECTED_SUGGESTION);
}

#[test]
/// For: build_story
fn build_story_cannot_find_first_article_suggest() {
    struct TestArticle {
        topics: Vec<Paragraph>
    }
    impl Article for TestArticle {
        fn get_paragraphs(&self) -> &Vec<Paragraph> {&self.topics}
    }
    struct TestProvider {}
    impl ArticleProvider for TestProvider {
        fn get(&self, topic: &str) -> Option<Box<Article>> {
            if topic == "found" {
                Some(Box::new(TestArticle {topics: vec![]}))
            }
            else {
                None
            }
        }
        #[allow(unused_variables)]
        fn search(&self, topic: &str) -> Vec<String> {
            vec!["Suggestion 1".to_owned(),
            "Suggestion 2".to_owned(),
            "Suggestion 3".to_owned()]
        }
    }

    let provider = TestProvider {};
    let story_builder = StoryBuilder::new(&provider);
    assert_eq!(story_builder.build_story("not-found", "found"), Err(EXPECTED_SUGGESTION.to_owned()));
}

#[test]
/// For: build_story
fn build_story_cannot_find_second_article_suggest() {
    struct TestArticle {
        topics: Vec<Paragraph>
    }
    impl Article for TestArticle {
        fn get_paragraphs(&self) -> &Vec<Paragraph> {&self.topics}
    }
    struct TestProvider {}
    impl ArticleProvider for TestProvider {
        fn get(&self, topic: &str) -> Option<Box<Article>> {
            if topic == "found"
                {Some(Box::new(TestArticle {topics: vec![]}))}
            else
                {None}
        }
        #[allow(unused_variables)]
        fn search(&self, topic: &str) -> Vec<String> {
            vec!["Suggestion 1".to_owned(),
            "Suggestion 2".to_owned(),
            "Suggestion 3".to_owned()]
        }
    }

    let provider = TestProvider {};
    let story_builder = StoryBuilder::new(&provider);
    assert_eq!(story_builder.build_story("found", "not-found"), Err(EXPECTED_SUGGESTION.to_owned()));
}

#[test]
/// For: build_story
fn build_story_from_same_start_and_end_should_err() {
    struct TestProvider {}
    impl ArticleProvider for TestProvider {
        #[allow(unused_variables)]
        fn get(&self, topic: &str) -> Option<Box<Article>> {panic!("get() should not get called in this test.")}
        #[allow(unused_variables)]
        fn search(&self, topic: &str) -> Vec<String> {panic!("get() should not get called in this test.")}
    }
    let provider = TestProvider {};
    let story_builder = StoryBuilder::new(&provider);
    assert_eq!(story_builder.build_story("similar topic", "similar topic"),
               Err("No story to build; same start and end topics.".to_owned()));
}

#[test]
/// For: build_story
fn build_story_empty_start_topic_should_err() {
    struct TestProvider {}
    impl ArticleProvider for TestProvider {
        #[allow(unused_variables)]
        fn get(&self, topic: &str) -> Option<Box<Article>> {panic!("get() should not get called in this test.")}
        #[allow(unused_variables)]
        fn search(&self, topic: &str) -> Vec<String> {panic!("get() should not get called in this test.")}
    }
    let provider = TestProvider {};
    let story_builder = StoryBuilder::new(&provider);
    assert_eq!(story_builder.build_story("", "Other topic"),
               Err("Missing start topic.".to_owned()));
}

#[test]
/// For: build_story
fn build_story_empty_end_topic_should_err() {
    struct TestProvider {}
    impl ArticleProvider for TestProvider {
        #[allow(unused_variables)]
        fn get(&self, topic: &str) -> Option<Box<Article>> {panic!("get() should not get called in this test.")}
        #[allow(unused_variables)]
        fn search(&self, topic: &str) -> Vec<String> {panic!("get() should not get called in this test.")}
    }
    let provider = TestProvider {};
    let story_builder = StoryBuilder::new(&provider);
    assert_eq!(story_builder.build_story("First topic", ""),
               Err("Missing end topic.".to_owned()));
}

#[test]
/// For: build_story
fn build_story_end_topic_found_in_start_article() {
    let mut prebuilt_rels = Rc::new(HashMap::new());
    Rc::get_mut(&mut prebuilt_rels).unwrap().insert("start", vec![Paragraph {text: "Paragraph 1".to_owned(), topics: vec!["topic 1".to_owned(), "topic 2".to_owned(), "topic 3".to_owned()]},
                                                                  Paragraph {text: "Paragraph 2".to_owned(), topics: vec!["topic 3".to_owned(), "end".to_owned(), "topic 5".to_owned()]},
                                                                  Paragraph {text: "Paragraph 3".to_owned(), topics: vec!["topic 3".to_owned(), "topic 1".to_owned(), "topic 5".to_owned()]}]);
    struct TestArticle {
        topic: String,
        prebuilt_rels: Rc<HashMap<&'static str, Vec<Paragraph>>>,
    }

    impl TestArticle {
        fn new(topic: String, prebuilt_rels: Rc<HashMap<&'static str, Vec<Paragraph>>>) -> TestArticle {
            TestArticle {topic, prebuilt_rels}
        }
    }

    impl Article for TestArticle {
            fn get_paragraphs(&self) -> &Vec<Paragraph> {
            self.prebuilt_rels.get::<str>(&self.topic).expect("Tried to access a node that doesn't exist!")
        }
    }
    struct TestProvider {
        prebuilt_rels: Rc<HashMap<&'static str, Vec<Paragraph>>>
    }
    impl TestProvider {
        fn new(prebuilt_rels: Rc<HashMap<&'static str, Vec<Paragraph>>>) -> TestProvider {
            TestProvider {prebuilt_rels}
        }
    }
    impl ArticleProvider for TestProvider {
        fn get(&self, topic: &str) -> Option<Box<Article>> {
                let new_rels: Rc<HashMap<&'static str, Vec<Paragraph>>> = self.prebuilt_rels.clone();
                Some(Box::new(TestArticle::new(topic.to_owned(), new_rels)))
        }
        fn search(&self, topic: &str) -> Vec<String> {panic!("search() should not be called in this test.");}
    }
    let provider = TestProvider::new(prebuilt_rels.clone());
    let story_builder = StoryBuilder::new(&provider);
    assert_eq!(story_builder.build_story("start", "end"), Ok("Paragraph 2.\r\n".to_owned()));
}
<|endoftext|>


<commit_before>use crate::io::util::{BufReader, BufWriter};
use crate::io::{AsyncBufRead, AsyncRead, AsyncWrite};

use pin_project_lite::pin_project;
use std::io;
use std::mem::MaybeUninit;
use std::pin::Pin;
use std::task::{Context, Poll};

pin_project! {
    /// Wraps a type that is [`AsyncWrite`] and [`AsyncRead`], and buffers its input and output.
    ///
    /// It can be excessively inefficient to work directly with something that implements [`AsyncWrite`]
    /// and [`AsyncRead`]. For example, every `write`, however small, has to traverse the syscall
    /// interface, and similarly, every read has to do the same. The [`BufWriter`] and [`BufReader`]
    /// types aid with these problems respectively, but do so in only one direction. `BufStream` wraps
    /// one in the other so that both directions are buffered. See their documentation for details.
    #[derive(Debug)]
    #[cfg_attr(docsrs, doc(cfg(feature = "io-util")))]
    pub struct BufStream<RW> {
        #[pin]
        inner: BufReader<BufWriter<RW>>,
    }
}

impl<RW: AsyncRead + AsyncWrite> BufStream<RW> {
    /// Wrap a type in both [`BufWriter`] and [`BufReader`].
    ///
    /// See the documentation for those types and [`BufStream`] for details.
    pub fn new(stream: RW) -> BufStream<RW> {
        BufStream {
            inner: BufReader::new(BufWriter::new(stream)),
        }
    }

    /// Gets a reference to the underlying I/O object.
    ///
    /// It is inadvisable to directly read from the underlying I/O object.
    pub fn get_ref(&self) -> &RW {
        self.inner.get_ref().get_ref()
    }

    /// Gets a mutable reference to the underlying I/O object.
    ///
    /// It is inadvisable to directly read from the underlying I/O object.
    pub fn get_mut(&mut self) -> &mut RW {
        self.inner.get_mut().get_mut()
    }

    /// Gets a pinned mutable reference to the underlying I/O object.
    ///
    /// It is inadvisable to directly read from the underlying I/O object.
    pub fn get_pin_mut(self: Pin<&mut Self>) -> Pin<&mut RW> {
        self.project().inner.get_pin_mut().get_pin_mut()
    }

    /// Consumes this `BufStream`, returning the underlying I/O object.
    ///
    /// Note that any leftover data in the internal buffer is lost.
    pub fn into_inner(self) -> RW {
        self.inner.into_inner().into_inner()
    }
}

impl<RW> From<BufReader<BufWriter<RW>>> for BufStream<RW> {
    fn from(b: BufReader<BufWriter<RW>>) -> Self {
        BufStream { inner: b }
    }
}

impl<RW> From<BufWriter<BufReader<RW>>> for BufStream<RW> {
    fn from(b: BufWriter<BufReader<RW>>) -> Self {
        // we need to "invert" the reader and writer
        let BufWriter {
            inner:
                BufReader {
                    inner,
                    buf: rbuf,
                    pos,
                    cap,
                },
            buf: wbuf,
            written,
        } = b;

        BufStream {
            inner: BufReader {
                inner: BufWriter {
                    inner,
                    buf: wbuf,
                    written,
                },
                buf: rbuf,
                pos,
                cap,
            },
        }
    }
}

impl<RW: AsyncRead + AsyncWrite> AsyncWrite for BufStream<RW> {
    fn poll_write(
        self: Pin<&mut Self>,
        cx: &mut Context<'_>,
        buf: &[u8],
    ) -> Poll<io::Result<usize>> {
        self.project().inner.poll_write(cx, buf)
    }

    fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
        self.project().inner.poll_flush(cx)
    }

    fn poll_shutdown(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
        self.project().inner.poll_shutdown(cx)
    }
}

impl<RW: AsyncRead + AsyncWrite> AsyncRead for BufStream<RW> {
    fn poll_read(
        self: Pin<&mut Self>,
        cx: &mut Context<'_>,
        buf: &mut [u8],
    ) -> Poll<io::Result<usize>> {
        self.project().inner.poll_read(cx, buf)
    }

    // we can't skip unconditionally because of the large buffer case in read.
    unsafe fn prepare_uninitialized_buffer(&self, buf: &mut [MaybeUninit<u8>]) -> bool {
        self.inner.prepare_uninitialized_buffer(buf)
    }
}

impl<RW: AsyncRead + AsyncWrite> AsyncBufRead for BufStream<RW> {
    fn poll_fill_buf(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<&[u8]>> {
        self.project().inner.poll_fill_buf(cx)
    }

    fn consume(self: Pin<&mut Self>, amt: usize) {
        self.project().inner.consume(amt)
    }
}

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

    #[test]
    fn assert_unpin() {
        crate::is_unpin::<BufStream<()>>();
    }
}
<commit_msg>io: add `BufStream::with_capacity` (#2125)<commit_after>use crate::io::util::{BufReader, BufWriter};
use crate::io::{AsyncBufRead, AsyncRead, AsyncWrite};

use pin_project_lite::pin_project;
use std::io;
use std::mem::MaybeUninit;
use std::pin::Pin;
use std::task::{Context, Poll};

pin_project! {
    /// Wraps a type that is [`AsyncWrite`] and [`AsyncRead`], and buffers its input and output.
    ///
    /// It can be excessively inefficient to work directly with something that implements [`AsyncWrite`]
    /// and [`AsyncRead`]. For example, every `write`, however small, has to traverse the syscall
    /// interface, and similarly, every read has to do the same. The [`BufWriter`] and [`BufReader`]
    /// types aid with these problems respectively, but do so in only one direction. `BufStream` wraps
    /// one in the other so that both directions are buffered. See their documentation for details.
    #[derive(Debug)]
    #[cfg_attr(docsrs, doc(cfg(feature = "io-util")))]
    pub struct BufStream<RW> {
        #[pin]
        inner: BufReader<BufWriter<RW>>,
    }
}

impl<RW: AsyncRead + AsyncWrite> BufStream<RW> {
    /// Wrap a type in both [`BufWriter`] and [`BufReader`].
    ///
    /// See the documentation for those types and [`BufStream`] for details.
    pub fn new(stream: RW) -> BufStream<RW> {
        BufStream {
            inner: BufReader::new(BufWriter::new(stream)),
        }
    }

    /// Creates a `BufStream` with the specified [`BufReader`] capacity and [`BufWriter`]
    /// capacity.
    ///
    /// See the documentation for those types and [`BufStream`] for details.
    pub fn with_capacity(
        reader_capacity: usize,
        writer_capacity: usize,
        stream: RW,
    ) -> BufStream<RW> {
        BufStream {
            inner: BufReader::with_capacity(
                reader_capacity,
                BufWriter::with_capacity(writer_capacity, stream),
            ),
        }
    }

    /// Gets a reference to the underlying I/O object.
    ///
    /// It is inadvisable to directly read from the underlying I/O object.
    pub fn get_ref(&self) -> &RW {
        self.inner.get_ref().get_ref()
    }

    /// Gets a mutable reference to the underlying I/O object.
    ///
    /// It is inadvisable to directly read from the underlying I/O object.
    pub fn get_mut(&mut self) -> &mut RW {
        self.inner.get_mut().get_mut()
    }

    /// Gets a pinned mutable reference to the underlying I/O object.
    ///
    /// It is inadvisable to directly read from the underlying I/O object.
    pub fn get_pin_mut(self: Pin<&mut Self>) -> Pin<&mut RW> {
        self.project().inner.get_pin_mut().get_pin_mut()
    }

    /// Consumes this `BufStream`, returning the underlying I/O object.
    ///
    /// Note that any leftover data in the internal buffer is lost.
    pub fn into_inner(self) -> RW {
        self.inner.into_inner().into_inner()
    }
}

impl<RW> From<BufReader<BufWriter<RW>>> for BufStream<RW> {
    fn from(b: BufReader<BufWriter<RW>>) -> Self {
        BufStream { inner: b }
    }
}

impl<RW> From<BufWriter<BufReader<RW>>> for BufStream<RW> {
    fn from(b: BufWriter<BufReader<RW>>) -> Self {
        // we need to "invert" the reader and writer
        let BufWriter {
            inner:
                BufReader {
                    inner,
                    buf: rbuf,
                    pos,
                    cap,
                },
            buf: wbuf,
            written,
        } = b;

        BufStream {
            inner: BufReader {
                inner: BufWriter {
                    inner,
                    buf: wbuf,
                    written,
                },
                buf: rbuf,
                pos,
                cap,
            },
        }
    }
}

impl<RW: AsyncRead + AsyncWrite> AsyncWrite for BufStream<RW> {
    fn poll_write(
        self: Pin<&mut Self>,
        cx: &mut Context<'_>,
        buf: &[u8],
    ) -> Poll<io::Result<usize>> {
        self.project().inner.poll_write(cx, buf)
    }

    fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
        self.project().inner.poll_flush(cx)
    }

    fn poll_shutdown(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
        self.project().inner.poll_shutdown(cx)
    }
}

impl<RW: AsyncRead + AsyncWrite> AsyncRead for BufStream<RW> {
    fn poll_read(
        self: Pin<&mut Self>,
        cx: &mut Context<'_>,
        buf: &mut [u8],
    ) -> Poll<io::Result<usize>> {
        self.project().inner.poll_read(cx, buf)
    }

    // we can't skip unconditionally because of the large buffer case in read.
    unsafe fn prepare_uninitialized_buffer(&self, buf: &mut [MaybeUninit<u8>]) -> bool {
        self.inner.prepare_uninitialized_buffer(buf)
    }
}

impl<RW: AsyncRead + AsyncWrite> AsyncBufRead for BufStream<RW> {
    fn poll_fill_buf(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<&[u8]>> {
        self.project().inner.poll_fill_buf(cx)
    }

    fn consume(self: Pin<&mut Self>, amt: usize) {
        self.project().inner.consume(amt)
    }
}

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

    #[test]
    fn assert_unpin() {
        crate::is_unpin::<BufStream<()>>();
    }
}
<|endoftext|>