<commit_before>use std::io::{Cursor, BufRead};
use std::net::UdpSocket;
use std::net::Ipv4Addr;
use std::net::IpAddr;
use std::net::SocketAddr;
use byteorder::{BigEndian, WriteBytesExt, ReadBytesExt};
use rand::random;

use DnsError;

/// Dns resolver: send dns request
pub struct DnsResolv {
    id: u16,
}

impl DnsResolv {
    pub fn new() -> DnsResolv {
        DnsResolv { id: random() }
    }

    /// resolve a dns query using a PTR request.
    ///
    /// This assume all informations are available using only one PTR request.
    /// It is true while testing with avahi, other implementation might require
    /// multiple dns requests.
    pub fn resolv_ptr(self, query: &str) -> Result<Vec<DnsAnswer>, DnsError> {
        let query_buffer = self.create_query_buffer(query)?;
        let addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), 0);
        let socket = UdpSocket::bind(addr)?;
        socket
            .join_multicast_v4(&Ipv4Addr::new(224, 0, 0, 251), &Ipv4Addr::new(0, 0, 0, 0))?;

        socket
            .send_to(query_buffer.into_inner().as_slice(), "224.0.0.251:5353")?;

        let mut answer_buffer: [u8; 512] = [0; 512];
        //TODO: multiple reply / timeout
        socket.recv(&mut answer_buffer)?;
        self.parse_answers(Cursor::new(answer_buffer.to_vec()))
    }

    fn create_query_buffer(&self, host: &str) -> Result<Cursor<Vec<u8>>, DnsError> {
        let mut buffer = Cursor::new(Vec::new());

        buffer.write_u16::<BigEndian>(self.id)?;
        buffer.write_u16::<BigEndian>(1 << 8)?;  // option: recursive
        buffer.write_u16::<BigEndian>(1)?; // qcount
        buffer.write_u16::<BigEndian>(0)?; // ancount
        buffer.write_u16::<BigEndian>(0)?; // nscount
        buffer.write_u16::<BigEndian>(0)?; // arcount

        for label in host.split(".") {
            buffer.write_u8(label.len() as u8)?;
            for b in label.bytes() {
                buffer.write_u8(b)?;
            }
        }

        buffer.write_u8(0)?;

        buffer.write_u16::<BigEndian>(12)?; // PTR
        buffer.write_u16::<BigEndian>(1)?; // IN

        Ok(buffer)
    }

    fn parse_answers<T: BufRead>(&self, mut answer_buffer: T) -> Result<Vec<DnsAnswer>, DnsError> {
        // TODO check header (tc bit, ...)
        let id = answer_buffer.read_u16::<BigEndian>()?;
        if id != self.id {
            return Err(DnsError::InvalidFormat(String::from("wrong id")));
        }
        answer_buffer.read_u16::<BigEndian>()?; //skip FLAGS
        answer_buffer.read_u16::<BigEndian>()?; //skip QDCOUNT

        let ancount = answer_buffer.read_u16::<BigEndian>()?;

        let mut answers: Vec<DnsAnswer> = Vec::with_capacity(ancount as usize);

        answer_buffer.read_u16::<BigEndian>()?; //skip NSCOUNT
        answer_buffer.read_u16::<BigEndian>()?; //skip ARCOUNT

        answer_buffer.read_until(0, &mut Vec::new())?; // skip QNAME
        answer_buffer.read_u16::<BigEndian>()?; //skip QTYPE
        answer_buffer.read_u16::<BigEndian>()?; //skip QCLASS

        for _ in 0..ancount {
            let dns_answer = match create_dnsanswer(&mut answer_buffer) {
                Ok(a) => a,
                Err(e) => return Err(e),
            };
            answers.push(dns_answer);
        }
        Ok(answers)
    }
}

fn create_dnsanswer<T: BufRead>(answer_buffer: &mut T) -> Result<DnsAnswer, DnsError> {
    let name = answer_buffer.read_u8()?;
    if name != 0xc0 {
        return Err(DnsError::InvalidFormat(
            String::from("parser doesn't support non pointer value")));
    }

    answer_buffer.read_u8()?; // skip name last byte
    let dnstype = answer_buffer.read_u16::<BigEndian>()?;

    answer_buffer.read_u16::<BigEndian>()?; // skip CLASS
    answer_buffer.read_u32::<BigEndian>()?; // skip TTL

    let rdlength = answer_buffer.read_u16::<BigEndian>()?;
    let mut dnsdata: Vec<u8> = Vec::with_capacity(rdlength as usize);
    for _ in 0..rdlength {
        let v = answer_buffer.read_u8()?;
        dnsdata.push(v);
    }

    Ok(DnsAnswer::new(dnstype, dnsdata))
}

/// dns result. data can be parsed acording to dns_type.
#[derive(Debug)]
#[derive(PartialEq)]
pub enum DnsAnswer {
    UNKNOWN(Vec<u8>),
    PTR(Vec<u8>),
    TXT(Vec<u8>),
    A(Vec<u8>),
    SRV(Vec<u8>),
}

impl DnsAnswer {
    fn new(idns_type: u16, data: Vec<u8>) -> DnsAnswer {
        match idns_type {
            1 => DnsAnswer::A(data),
            12 => DnsAnswer::PTR(data),
            16 => DnsAnswer::TXT(data),
            33 => DnsAnswer::SRV(data),
            _ => DnsAnswer::UNKNOWN(data),
        }
    }
}

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

    #[test]
    fn tst_parseanswer() {
        let resolv = DnsResolv { id: 42 };
        let v: Vec<u8> = vec![
            0x00,
            0x2a,
            0x84,
            0x00,
            0x00,
            0x01,
            0x00,
            0x05,
            0x00,
            0x00,
            0x00,
            0x00,
            0x05,
            0x5f,
            0x68,
            0x74,
            0x74,
            0x70,
            0x04,
            0x5f,
            0x74,
            0x63,
            0x70,
            0x05,
            0x6c,
            0x6f,
            0x63,
            0x61,
            0x6c,
            0x00,
            0x00,
            0x0c,
            0x00,
            0x01,
            0xc0,
            0x0c,
            0x00,
            0x0c,
            0x00,
            0x01,
            0x00,
            0x00,
            0x00,
            0x0a,
            0x00,
            0x0a,
            0x07,
            0x6d,
            0x69,
            0x61,
            0x6f,
            0x77,
            0x5f,
            0x31,
            0xc0,
            0x0c,
            0xc0,
            0x2e,
            0x00,
            0x10,
            0x00,
            0x01,
            0x00,
            0x00,
            0x00,
            0x0a,
            0x00,
            0x1b,
            0x11,
            0x66,
            0x69,
            0x6c,
            0x65,
            0x3d,
            0x70,
            0x61,
            0x74,
            0x68,
            0x2f,
            0x74,
            0x6f,
            0x2f,
            0x66,
            0x69,
            0x6c,
            0x65,
            0x08,
            0x75,
            0x73,
            0x65,
            0x72,
            0x3d,
            0x63,
            0x65,
            0x64,
            0xc0,
            0x2e,
            0x00,
            0x21,
            0x00,
            0x01,
            0x00,
            0x00,
            0x00,
            0x0a,
            0x00,
            0x0e,
            0x00,
            0x00,
            0x00,
            0x00,
            0x1f,
            0x90,
            0x05,
            0x6c,
            0x69,
            0x6e,
            0x75,
            0x78,
            0xc0,
            0x17,
            0xc0,
            0x71,
            0x00,
            0x1c,
            0x00,
            0x01,
            0x00,
            0x00,
            0x00,
            0x0a,
            0x00,
            0x10,
            0xfe,
            0x80,
            0x00,
            0x00,
            0x00,
            0x00,
            0x00,
            0x00,
            0x47,
            0x4d,
            0xd7,
            0x46,
            0x54,
            0x16,
            0xee,
            0xbb,
            0xc0,
            0x71,
            0x00,
            0x01,
            0x00,
            0x01,
            0x00,
            0x00,
            0x00,
            0x0a,
            0x00,
            0x04,
            0x0a,
            0x74,
            0x00,
            0x19,
        ];
        let answers = resolv.parse_answers(Cursor::new(v)).unwrap();
        assert_eq!(5, answers.len());
        assert_eq!(
            1,
            answers
                .iter()
                .filter(|x| match **x {
                    DnsAnswer::A(_) => true,
                    _ => false,
                })
                .count()
        );
        assert_eq!(
            1,
            answers
                .iter()
                .filter(|x| match **x {
                    DnsAnswer::UNKNOWN(_) => true,
                    _ => false,
                })
                .count()
        ); //AAAA
        assert_eq!(
            1,
            answers
                .iter()
                .filter(|x| match **x {
                    DnsAnswer::SRV(_) => true,
                    _ => false,
                })
                .count()
        );
        assert_eq!(
            1,
            answers
                .iter()
                .filter(|x| match **x {
                    DnsAnswer::TXT(_) => true,
                    _ => false,
                })
                .count()
        );
        assert_eq!(
            1,
            answers
                .iter()
                .filter(|x| match **x {
                    DnsAnswer::PTR(_) => true,
                    _ => false,
                })
                .count()
        );
    }
}
<commit_msg>update comment according to RFC<commit_after>use std::io::{Cursor, BufRead};
use std::net::UdpSocket;
use std::net::Ipv4Addr;
use std::net::IpAddr;
use std::net::SocketAddr;
use byteorder::{BigEndian, WriteBytesExt, ReadBytesExt};
use rand::random;

use DnsError;

/// Dns resolver: send dns request
pub struct DnsResolv {
    id: u16,
}

impl DnsResolv {
    pub fn new() -> DnsResolv {
        DnsResolv { id: random() }
    }

    /// resolve a dns query using a PTR request.
    ///
    /// This assume all informations are available using only one PTR request.
    /// RFC6763 12.1: the server should include the SRV / TXT / A data.
    pub fn resolv_ptr(self, query: &str) -> Result<Vec<DnsAnswer>, DnsError> {
        let query_buffer = self.create_query_buffer(query)?;
        let addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), 0);
        let socket = UdpSocket::bind(addr)?;
        socket
            .join_multicast_v4(&Ipv4Addr::new(224, 0, 0, 251), &Ipv4Addr::new(0, 0, 0, 0))?;

        socket
            .send_to(query_buffer.into_inner().as_slice(), "224.0.0.251:5353")?;

        let mut answer_buffer: [u8; 512] = [0; 512];
        //TODO: multiple reply / timeout
        socket.recv(&mut answer_buffer)?;
        self.parse_answers(Cursor::new(answer_buffer.to_vec()))
    }

    fn create_query_buffer(&self, host: &str) -> Result<Cursor<Vec<u8>>, DnsError> {
        let mut buffer = Cursor::new(Vec::new());

        buffer.write_u16::<BigEndian>(self.id)?;
        buffer.write_u16::<BigEndian>(1 << 8)?;  // option: recursive
        buffer.write_u16::<BigEndian>(1)?; // qcount
        buffer.write_u16::<BigEndian>(0)?; // ancount
        buffer.write_u16::<BigEndian>(0)?; // nscount
        buffer.write_u16::<BigEndian>(0)?; // arcount

        for label in host.split(".") {
            buffer.write_u8(label.len() as u8)?;
            for b in label.bytes() {
                buffer.write_u8(b)?;
            }
        }

        buffer.write_u8(0)?;

        buffer.write_u16::<BigEndian>(12)?; // PTR
        buffer.write_u16::<BigEndian>(1)?; // IN

        Ok(buffer)
    }

    fn parse_answers<T: BufRead>(&self, mut answer_buffer: T) -> Result<Vec<DnsAnswer>, DnsError> {
        // TODO check header (tc bit, ...)
        let id = answer_buffer.read_u16::<BigEndian>()?;
        if id != self.id {
            return Err(DnsError::InvalidFormat(String::from("wrong id")));
        }
        answer_buffer.read_u16::<BigEndian>()?; //skip FLAGS
        answer_buffer.read_u16::<BigEndian>()?; //skip QDCOUNT

        let ancount = answer_buffer.read_u16::<BigEndian>()?;

        let mut answers: Vec<DnsAnswer> = Vec::with_capacity(ancount as usize);

        answer_buffer.read_u16::<BigEndian>()?; //skip NSCOUNT
        answer_buffer.read_u16::<BigEndian>()?; //skip ARCOUNT

        answer_buffer.read_until(0, &mut Vec::new())?; // skip QNAME
        answer_buffer.read_u16::<BigEndian>()?; //skip QTYPE
        answer_buffer.read_u16::<BigEndian>()?; //skip QCLASS

        for _ in 0..ancount {
            let dns_answer = match create_dnsanswer(&mut answer_buffer) {
                Ok(a) => a,
                Err(e) => return Err(e),
            };
            answers.push(dns_answer);
        }
        Ok(answers)
    }
}

fn create_dnsanswer<T: BufRead>(answer_buffer: &mut T) -> Result<DnsAnswer, DnsError> {
    let name = answer_buffer.read_u8()?;
    if name != 0xc0 {
        return Err(DnsError::InvalidFormat(
            String::from("parser doesn't support non pointer value")));
    }

    answer_buffer.read_u8()?; // skip name last byte
    let dnstype = answer_buffer.read_u16::<BigEndian>()?;

    answer_buffer.read_u16::<BigEndian>()?; // skip CLASS
    answer_buffer.read_u32::<BigEndian>()?; // skip TTL

    let rdlength = answer_buffer.read_u16::<BigEndian>()?;
    let mut dnsdata: Vec<u8> = Vec::with_capacity(rdlength as usize);
    for _ in 0..rdlength {
        let v = answer_buffer.read_u8()?;
        dnsdata.push(v);
    }

    Ok(DnsAnswer::new(dnstype, dnsdata))
}

/// dns result. data can be parsed acording to dns_type.
#[derive(Debug)]
#[derive(PartialEq)]
pub enum DnsAnswer {
    UNKNOWN(Vec<u8>),
    PTR(Vec<u8>),
    TXT(Vec<u8>),
    A(Vec<u8>),
    SRV(Vec<u8>),
}

impl DnsAnswer {
    fn new(idns_type: u16, data: Vec<u8>) -> DnsAnswer {
        match idns_type {
            1 => DnsAnswer::A(data),
            12 => DnsAnswer::PTR(data),
            16 => DnsAnswer::TXT(data),
            33 => DnsAnswer::SRV(data),
            _ => DnsAnswer::UNKNOWN(data),
        }
    }
}

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

    #[test]
    fn tst_parseanswer() {
        let resolv = DnsResolv { id: 42 };
        let v: Vec<u8> = vec![
            0x00,
            0x2a,
            0x84,
            0x00,
            0x00,
            0x01,
            0x00,
            0x05,
            0x00,
            0x00,
            0x00,
            0x00,
            0x05,
            0x5f,
            0x68,
            0x74,
            0x74,
            0x70,
            0x04,
            0x5f,
            0x74,
            0x63,
            0x70,
            0x05,
            0x6c,
            0x6f,
            0x63,
            0x61,
            0x6c,
            0x00,
            0x00,
            0x0c,
            0x00,
            0x01,
            0xc0,
            0x0c,
            0x00,
            0x0c,
            0x00,
            0x01,
            0x00,
            0x00,
            0x00,
            0x0a,
            0x00,
            0x0a,
            0x07,
            0x6d,
            0x69,
            0x61,
            0x6f,
            0x77,
            0x5f,
            0x31,
            0xc0,
            0x0c,
            0xc0,
            0x2e,
            0x00,
            0x10,
            0x00,
            0x01,
            0x00,
            0x00,
            0x00,
            0x0a,
            0x00,
            0x1b,
            0x11,
            0x66,
            0x69,
            0x6c,
            0x65,
            0x3d,
            0x70,
            0x61,
            0x74,
            0x68,
            0x2f,
            0x74,
            0x6f,
            0x2f,
            0x66,
            0x69,
            0x6c,
            0x65,
            0x08,
            0x75,
            0x73,
            0x65,
            0x72,
            0x3d,
            0x63,
            0x65,
            0x64,
            0xc0,
            0x2e,
            0x00,
            0x21,
            0x00,
            0x01,
            0x00,
            0x00,
            0x00,
            0x0a,
            0x00,
            0x0e,
            0x00,
            0x00,
            0x00,
            0x00,
            0x1f,
            0x90,
            0x05,
            0x6c,
            0x69,
            0x6e,
            0x75,
            0x78,
            0xc0,
            0x17,
            0xc0,
            0x71,
            0x00,
            0x1c,
            0x00,
            0x01,
            0x00,
            0x00,
            0x00,
            0x0a,
            0x00,
            0x10,
            0xfe,
            0x80,
            0x00,
            0x00,
            0x00,
            0x00,
            0x00,
            0x00,
            0x47,
            0x4d,
            0xd7,
            0x46,
            0x54,
            0x16,
            0xee,
            0xbb,
            0xc0,
            0x71,
            0x00,
            0x01,
            0x00,
            0x01,
            0x00,
            0x00,
            0x00,
            0x0a,
            0x00,
            0x04,
            0x0a,
            0x74,
            0x00,
            0x19,
        ];
        let answers = resolv.parse_answers(Cursor::new(v)).unwrap();
        assert_eq!(5, answers.len());
        assert_eq!(
            1,
            answers
                .iter()
                .filter(|x| match **x {
                    DnsAnswer::A(_) => true,
                    _ => false,
                })
                .count()
        );
        assert_eq!(
            1,
            answers
                .iter()
                .filter(|x| match **x {
                    DnsAnswer::UNKNOWN(_) => true,
                    _ => false,
                })
                .count()
        ); //AAAA
        assert_eq!(
            1,
            answers
                .iter()
                .filter(|x| match **x {
                    DnsAnswer::SRV(_) => true,
                    _ => false,
                })
                .count()
        );
        assert_eq!(
            1,
            answers
                .iter()
                .filter(|x| match **x {
                    DnsAnswer::TXT(_) => true,
                    _ => false,
                })
                .count()
        );
        assert_eq!(
            1,
            answers
                .iter()
                .filter(|x| match **x {
                    DnsAnswer::PTR(_) => true,
                    _ => false,
                })
                .count()
        );
    }
}
<|endoftext|>


<commit_before>use common::GeneralError;
use ctrl::GameController;
use ctrl::Gesture;
use gfx::ShaderLoader;
use gfx::Window;
use level::Level;
use player::Player;
use sdl2::keyboard::Scancode;
use sdl2::{self, Sdl};
use std::default::Default;
use std::error::Error;
use std::path::PathBuf;
use super::SHADER_ROOT;
use time;
use wad::{Archive, TextureDirectory};

pub struct GameConfig {
    pub wad_file: PathBuf,
    pub metadata_file: PathBuf,
    pub level_index: usize,
    pub fov: f32,
    pub width: u32,
    pub height: u32,
}

pub struct Game {
    window: Window,
    player: Player,
    level: Level,
    sdl: Sdl,
}

impl Game {
    pub fn new(config: GameConfig) -> Result<Game, Box<Error>> {
        let sdl = try!(sdl2::init().video().build().map_err(GeneralError));
        let window = try!(Window::new(&sdl, config.width, config.height));

        let shader_loader = ShaderLoader::new(PathBuf::from(SHADER_ROOT));

        let mut wad = try!(Archive::open(&config.wad_file, &config.metadata_file));
        let textures = try!(TextureDirectory::from_archive(&mut wad));
        let level = try!(Level::new(&shader_loader, &mut wad, &textures, config.level_index));

        let mut player = Player::new(config.fov,
                                     window.aspect_ratio(),
                                     Default::default());
        player.set_position(level.start_pos());

        Ok(Game {
            window: window,
            player: player,
            level: level,
            sdl: sdl,
        })
    }

    pub fn run(&mut self) {
        let quit_gesture = Gesture::AnyOf(
            vec![Gesture::QuitTrigger,
                 Gesture::KeyTrigger(Scancode::Escape)]);
        let grab_toggle_gesture = Gesture::KeyTrigger(Scancode::Grave);

        let mut cum_time = 0.0;
        let mut cum_updates_time = 0.0;
        let mut num_frames = 0.0;
        let mut t0 = time::precise_time_s();
        let mut control = GameController::new(self.sdl.event_pump());
        let mut mouse_grabbed = true;
        loop {
            self.window.clear();
            let t1 = time::precise_time_s();
            let mut delta = (t1 - t0) as f32;
            if delta < 1e-10 { delta = 1.0 / 60.0; }
            let delta = delta;
            t0 = t1;

            let updates_t0 = time::precise_time_s();

            control.update();
            if control.poll_gesture(&quit_gesture) {
                break;
            } else if control.poll_gesture(&grab_toggle_gesture) {
                mouse_grabbed = !mouse_grabbed;
                control.set_mouse_enabled(mouse_grabbed);
                control.set_cursor_grabbed(mouse_grabbed);
            }

            self.player.update(delta, &control, &self.level);
            self.level.render(delta,
                              self.player.camera().projection(), self.player.camera().modelview());

            let updates_t1 = time::precise_time_s();
            cum_updates_time += updates_t1 - updates_t0;

            cum_time += delta as f64;
            num_frames += 1.0;
            if cum_time > 2.0 {
                let fps = num_frames / cum_time;
                let cpums = 1000.0 * cum_updates_time / num_frames;
                info!("Frame time: {:.2}ms ({:.2}ms cpu, FPS: {:.2})",
                      1000.0 / fps, cpums, fps);
                cum_time = 0.0;
                cum_updates_time = 0.0;
                num_frames = 0.0;
            }

            self.window.swap_buffers();
        }
    }
}
<commit_msg>Actually introduce aspect ratio correction.<commit_after>use common::GeneralError;
use ctrl::GameController;
use ctrl::Gesture;
use gfx::ShaderLoader;
use gfx::Window;
use level::Level;
use player::Player;
use sdl2::keyboard::Scancode;
use sdl2::{self, Sdl};
use std::default::Default;
use std::error::Error;
use std::path::PathBuf;
use super::SHADER_ROOT;
use time;
use wad::{Archive, TextureDirectory};

pub struct GameConfig {
    pub wad_file: PathBuf,
    pub metadata_file: PathBuf,
    pub level_index: usize,
    pub fov: f32,
    pub width: u32,
    pub height: u32,
}

pub struct Game {
    window: Window,
    player: Player,
    level: Level,
    sdl: Sdl,
}

impl Game {
    pub fn new(config: GameConfig) -> Result<Game, Box<Error>> {
        let sdl = try!(sdl2::init().video().build().map_err(GeneralError));
        let window = try!(Window::new(&sdl, config.width, config.height));

        let shader_loader = ShaderLoader::new(PathBuf::from(SHADER_ROOT));

        let mut wad = try!(Archive::open(&config.wad_file, &config.metadata_file));
        let textures = try!(TextureDirectory::from_archive(&mut wad));
        let level = try!(Level::new(&shader_loader, &mut wad, &textures, config.level_index));

        let mut player = Player::new(config.fov,
                                     window.aspect_ratio() * 1.2,
                                     Default::default());
        player.set_position(level.start_pos());

        Ok(Game {
            window: window,
            player: player,
            level: level,
            sdl: sdl,
        })
    }

    pub fn run(&mut self) {
        let quit_gesture = Gesture::AnyOf(
            vec![Gesture::QuitTrigger,
                 Gesture::KeyTrigger(Scancode::Escape)]);
        let grab_toggle_gesture = Gesture::KeyTrigger(Scancode::Grave);

        let mut cum_time = 0.0;
        let mut cum_updates_time = 0.0;
        let mut num_frames = 0.0;
        let mut t0 = time::precise_time_s();
        let mut control = GameController::new(self.sdl.event_pump());
        let mut mouse_grabbed = true;
        loop {
            self.window.clear();
            let t1 = time::precise_time_s();
            let mut delta = (t1 - t0) as f32;
            if delta < 1e-10 { delta = 1.0 / 60.0; }
            let delta = delta;
            t0 = t1;

            let updates_t0 = time::precise_time_s();

            control.update();
            if control.poll_gesture(&quit_gesture) {
                break;
            } else if control.poll_gesture(&grab_toggle_gesture) {
                mouse_grabbed = !mouse_grabbed;
                control.set_mouse_enabled(mouse_grabbed);
                control.set_cursor_grabbed(mouse_grabbed);
            }

            self.player.update(delta, &control, &self.level);
            self.level.render(delta,
                              self.player.camera().projection(), self.player.camera().modelview());

            let updates_t1 = time::precise_time_s();
            cum_updates_time += updates_t1 - updates_t0;

            cum_time += delta as f64;
            num_frames += 1.0;
            if cum_time > 2.0 {
                let fps = num_frames / cum_time;
                let cpums = 1000.0 * cum_updates_time / num_frames;
                info!("Frame time: {:.2}ms ({:.2}ms cpu, FPS: {:.2})",
                      1000.0 / fps, cpums, fps);
                cum_time = 0.0;
                cum_updates_time = 0.0;
                num_frames = 0.0;
            }

            self.window.swap_buffers();
        }
    }
}
<|endoftext|>


<commit_before>
#![crate_name = "geoip"]
#![crate_type = "rlib"]

#![warn(non_camel_case_types,
        non_upper_case_globals,
        unused_qualifications)]
#![feature(libc, path, std_misc, io)]

extern crate libc;
extern crate "rustc-serialize" as rustc_serialize;
extern crate "geoip-sys" as geoip_sys;

use libc::{c_char, c_int, c_ulong};
use std::ffi;
use std::fmt;
use std::old_io::net::ip::{IpAddr,Ipv4Addr,Ipv6Addr};

#[cfg(test)]
use std::str::FromStr;

enum Charset {
    UTF8 = 1
}

pub enum Options {
    Standard = 0,
    MemoryCache = 1,
    CheckCache = 2,
    IndexCache = 4,
    MmapCache = 8
}

impl Copy for Options { }

pub enum DBType {
    CountryEdition = 1,
    RegionEditionRev0 = 7,
    CityEditionRev0 = 6,
    ORGEdition = 5,
    ISPEdition = 4,
    CityEditionRev1 = 2,
    RegionEditionRev1 = 3,
    ProxyEdition = 8,
    ASNUMEdition = 9,
    NetSpeedEdition = 10,
    DomainEdition = 11,
    CountryEditionV6 = 12,
    LocationAEdition = 13,
    AccuracyRadiusEdition = 14,
    LargeCountryEdition = 17,
    LargeCountryEditionV6 = 18,
    ASNumEditionV6 = 21,
    ISPEditionV6 = 22,
    ORGEditionV6 = 23,
    DomainEditionV6 = 24,
    LoctionAEditionV6 = 25,
    RegistrarEdition = 26,
    RegistrarEditionV6 = 27,
    UserTypeEdition = 28,
    UserTypeEditionV6 = 29,
    CityEditionRev1V6 = 30,
    CityEditionRev0V6 = 31,
    NetSpeedEditionRev1 = 32,
    NetSpeedEditionRev1V6 = 33,
    CountryConfEdition = 34,
    CityConfEdition = 35,
    RegionConfEdition = 36,
    PostalConfEdition = 37,
    AccuracyRadiusEditionV6 = 38
}

impl Copy for DBType { }

pub struct GeoIp {
    db: geoip_sys::RawGeoIp
}

#[derive(RustcDecodable, RustcEncodable)]
pub struct ASInfo {
    pub asn: u32,
    pub name: String,
    pub netmask: u32
}

#[derive(RustcDecodable, RustcEncodable)]
pub struct CityInfo {
    pub country_code: Option<String>,
    pub country_code3: Option<String>,
    pub country_name: Option<String>,
    pub region: Option<String>,
    pub city: Option<String>,
    pub postal_code: Option<String>,
    pub latitude: f32,
    pub longitude: f32,
    pub dma_code: u32,
    pub area_code: u32,
    pub charset: u32,
    pub continent_code: Option<String>,
    pub netmask: u32
}

fn maybe_string(c_str: *const c_char) -> Option<String> {
    if c_str.is_null() {
        None
    } else {
        String::from_utf8(unsafe { ffi::c_str_to_bytes(&c_str) }.to_vec()).ok()
    }
}

impl CityInfo {
    unsafe fn from_geoiprecord(res: &geoip_sys::GeoIpRecord) -> CityInfo {
        CityInfo {
            country_code: maybe_string(res.country_code),
            country_code3: maybe_string(res.country_code3),
            country_name: maybe_string(res.country_name),
            region: maybe_string(res.region),
            city: maybe_string(res.city),
            postal_code: maybe_string(res.postal_code),
            latitude: res.latitude as f32,
            longitude: res.longitude as f32,
            dma_code: res.dma_code as u32,
            area_code: res.area_code as u32,
            charset: res.charset as u32,
            continent_code: maybe_string(res.continent_code),
            netmask: res.netmask as u32
        }
    }
}

impl fmt::Debug for ASInfo {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}\t{}", self.asn, self.name)
    }
}

enum CNetworkIp {
    V4(c_ulong),
    V6(geoip_sys::In6Addr)
}

impl CNetworkIp {
    fn new(ip: IpAddr) -> CNetworkIp {
        match ip {
            Ipv4Addr(a, b, c, d) => {
                CNetworkIp::V4(((a as c_ulong) << 24) | ((b as c_ulong) << 16) |
                               ((c as c_ulong) << 8)  | ((d as c_ulong)))
            },
            Ipv6Addr(a, b, c, d, e, f, g, h) => {
                CNetworkIp::V6([(a >> 8) as u8, a as u8,
                                (b >> 8) as u8, b as u8,
                                (c >> 8) as u8, c as u8,
                                (d >> 8) as u8, d as u8,
                                (e >> 8) as u8, e as u8,
                                (f >> 8) as u8, f as u8,
                                (g >> 8) as u8, g as u8,
                                (h >> 8) as u8, h as u8])
            }
        }
    }
}

impl GeoIp {
    pub fn open(path: &Path, options: Options) -> Result<GeoIp, String> {
        let file = match path.as_str() {
            None => return Err(format!("Invalid path {}", path.display())),
            Some(file) => file
        };
        let db = unsafe {
            geoip_sys::GeoIP_open(ffi::CString::from_slice(file.as_bytes()).as_ptr(),
                                  options as c_int)
        };
        if db.is_null() {
            return Err(format!("Can't open {}", file));
        }
        if unsafe { geoip_sys::GeoIP_set_charset(db, Charset::UTF8 as c_int)
        } != 0 {
            return Err("Can't set charset to UTF8".to_string());
        }
        Ok(GeoIp { db: db })
    }

    pub fn city_info_by_ip(&self, ip: IpAddr) -> Option<CityInfo> {
        let cres = match CNetworkIp::new(ip) {
            CNetworkIp::V4(ip) => unsafe {
                geoip_sys::GeoIP_record_by_ipnum(self.db, ip) },
            CNetworkIp::V6(ip) => unsafe {
                geoip_sys::GeoIP_record_by_ipnum_v6(self.db, ip) }
        };

        if cres.is_null() { return None; }

        unsafe {
            let city_info = CityInfo::from_geoiprecord(&*cres);
            geoip_sys::GeoIPRecord_delete(cres);
            std::mem::forget(cres);
            Some(city_info)
        }
    }

    pub fn as_info_by_ip(&self, ip: IpAddr) -> Option<ASInfo> {
        let mut gl = geoip_sys::GeoIpLookup::new();
        let cres = match CNetworkIp::new(ip) {
            CNetworkIp::V4(ip) => unsafe {
                geoip_sys::GeoIP_name_by_ipnum_gl(self.db, ip, &mut gl) },
            CNetworkIp::V6(ip) => unsafe {
                geoip_sys::GeoIP_name_by_ipnum_v6_gl(self.db, ip, &mut gl) }
        };

        if cres.is_null() {
            return None;
        }
        let description = match maybe_string(cres) {
            None => return None,
            Some(description) => description
        };
        let mut di = description.splitn(1, ' ');
        let asn = match di.next() {
            None => return None,
            Some(asn) => {
                if ! asn.starts_with("AS") {
                    return None
                } else {
                    asn[2..].parse::<u32>().unwrap()
                }
            }
        };
        let name = di.next().unwrap_or("(none)");
        let as_info = ASInfo {
            asn: asn,
            name: name.to_string(),
            netmask: gl.netmask as u32
        };
        Some(as_info)
    }
}

impl Drop for GeoIp {
    fn drop(&mut self) {
        unsafe {
            geoip_sys::GeoIP_delete(self.db);
        }
    }
}

#[test]
fn geoip_test_basic() {
    let geoip = match GeoIp::open(&Path::new("/opt/geoip/GeoIPASNum.dat"), Options::MemoryCache) {
        Err(err) => panic!(err),
        Ok(geoip) => geoip
    };
    let ip = FromStr::from_str("91.203.184.192").unwrap();
    let res = geoip.as_info_by_ip(ip).unwrap();
    assert!(res.asn == 41064);
    assert!(res.name.as_slice().contains("Telefun"));
    assert!(res.netmask == 22);
}

#[test]
fn geoip_test_city() {
    let geoip = match GeoIp::open(&Path::new("/opt/geoip/GeoLiteCity.dat"), Options::MemoryCache) {
        Err(err) => panic!(err),
        Ok(geoip) => geoip
    };
    let ip = FromStr::from_str("8.8.8.8").unwrap();
    let res = geoip.city_info_by_ip(ip).unwrap();
    assert!(res.city.unwrap().as_slice() == "Mountain View");
}
<commit_msg>Remove useless .as_slice()<commit_after>
#![crate_name = "geoip"]
#![crate_type = "rlib"]

#![warn(non_camel_case_types,
        non_upper_case_globals,
        unused_qualifications)]
#![feature(libc, path, std_misc, io)]

extern crate libc;
extern crate "rustc-serialize" as rustc_serialize;
extern crate "geoip-sys" as geoip_sys;

use libc::{c_char, c_int, c_ulong};
use std::ffi;
use std::fmt;
use std::old_io::net::ip::{IpAddr,Ipv4Addr,Ipv6Addr};

#[cfg(test)]
use std::str::FromStr;

enum Charset {
    UTF8 = 1
}

pub enum Options {
    Standard = 0,
    MemoryCache = 1,
    CheckCache = 2,
    IndexCache = 4,
    MmapCache = 8
}

impl Copy for Options { }

pub enum DBType {
    CountryEdition = 1,
    RegionEditionRev0 = 7,
    CityEditionRev0 = 6,
    ORGEdition = 5,
    ISPEdition = 4,
    CityEditionRev1 = 2,
    RegionEditionRev1 = 3,
    ProxyEdition = 8,
    ASNUMEdition = 9,
    NetSpeedEdition = 10,
    DomainEdition = 11,
    CountryEditionV6 = 12,
    LocationAEdition = 13,
    AccuracyRadiusEdition = 14,
    LargeCountryEdition = 17,
    LargeCountryEditionV6 = 18,
    ASNumEditionV6 = 21,
    ISPEditionV6 = 22,
    ORGEditionV6 = 23,
    DomainEditionV6 = 24,
    LoctionAEditionV6 = 25,
    RegistrarEdition = 26,
    RegistrarEditionV6 = 27,
    UserTypeEdition = 28,
    UserTypeEditionV6 = 29,
    CityEditionRev1V6 = 30,
    CityEditionRev0V6 = 31,
    NetSpeedEditionRev1 = 32,
    NetSpeedEditionRev1V6 = 33,
    CountryConfEdition = 34,
    CityConfEdition = 35,
    RegionConfEdition = 36,
    PostalConfEdition = 37,
    AccuracyRadiusEditionV6 = 38
}

impl Copy for DBType { }

pub struct GeoIp {
    db: geoip_sys::RawGeoIp
}

#[derive(RustcDecodable, RustcEncodable)]
pub struct ASInfo {
    pub asn: u32,
    pub name: String,
    pub netmask: u32
}

#[derive(RustcDecodable, RustcEncodable)]
pub struct CityInfo {
    pub country_code: Option<String>,
    pub country_code3: Option<String>,
    pub country_name: Option<String>,
    pub region: Option<String>,
    pub city: Option<String>,
    pub postal_code: Option<String>,
    pub latitude: f32,
    pub longitude: f32,
    pub dma_code: u32,
    pub area_code: u32,
    pub charset: u32,
    pub continent_code: Option<String>,
    pub netmask: u32
}

fn maybe_string(c_str: *const c_char) -> Option<String> {
    if c_str.is_null() {
        None
    } else {
        String::from_utf8(unsafe { ffi::c_str_to_bytes(&c_str) }.to_vec()).ok()
    }
}

impl CityInfo {
    unsafe fn from_geoiprecord(res: &geoip_sys::GeoIpRecord) -> CityInfo {
        CityInfo {
            country_code: maybe_string(res.country_code),
            country_code3: maybe_string(res.country_code3),
            country_name: maybe_string(res.country_name),
            region: maybe_string(res.region),
            city: maybe_string(res.city),
            postal_code: maybe_string(res.postal_code),
            latitude: res.latitude as f32,
            longitude: res.longitude as f32,
            dma_code: res.dma_code as u32,
            area_code: res.area_code as u32,
            charset: res.charset as u32,
            continent_code: maybe_string(res.continent_code),
            netmask: res.netmask as u32
        }
    }
}

impl fmt::Debug for ASInfo {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}\t{}", self.asn, self.name)
    }
}

enum CNetworkIp {
    V4(c_ulong),
    V6(geoip_sys::In6Addr)
}

impl CNetworkIp {
    fn new(ip: IpAddr) -> CNetworkIp {
        match ip {
            Ipv4Addr(a, b, c, d) => {
                CNetworkIp::V4(((a as c_ulong) << 24) | ((b as c_ulong) << 16) |
                               ((c as c_ulong) << 8)  | ((d as c_ulong)))
            },
            Ipv6Addr(a, b, c, d, e, f, g, h) => {
                CNetworkIp::V6([(a >> 8) as u8, a as u8,
                                (b >> 8) as u8, b as u8,
                                (c >> 8) as u8, c as u8,
                                (d >> 8) as u8, d as u8,
                                (e >> 8) as u8, e as u8,
                                (f >> 8) as u8, f as u8,
                                (g >> 8) as u8, g as u8,
                                (h >> 8) as u8, h as u8])
            }
        }
    }
}

impl GeoIp {
    pub fn open(path: &Path, options: Options) -> Result<GeoIp, String> {
        let file = match path.as_str() {
            None => return Err(format!("Invalid path {}", path.display())),
            Some(file) => file
        };
        let db = unsafe {
            geoip_sys::GeoIP_open(ffi::CString::from_slice(file.as_bytes()).as_ptr(),
                                  options as c_int)
        };
        if db.is_null() {
            return Err(format!("Can't open {}", file));
        }
        if unsafe { geoip_sys::GeoIP_set_charset(db, Charset::UTF8 as c_int)
        } != 0 {
            return Err("Can't set charset to UTF8".to_string());
        }
        Ok(GeoIp { db: db })
    }

    pub fn city_info_by_ip(&self, ip: IpAddr) -> Option<CityInfo> {
        let cres = match CNetworkIp::new(ip) {
            CNetworkIp::V4(ip) => unsafe {
                geoip_sys::GeoIP_record_by_ipnum(self.db, ip) },
            CNetworkIp::V6(ip) => unsafe {
                geoip_sys::GeoIP_record_by_ipnum_v6(self.db, ip) }
        };

        if cres.is_null() { return None; }

        unsafe {
            let city_info = CityInfo::from_geoiprecord(&*cres);
            geoip_sys::GeoIPRecord_delete(cres);
            std::mem::forget(cres);
            Some(city_info)
        }
    }

    pub fn as_info_by_ip(&self, ip: IpAddr) -> Option<ASInfo> {
        let mut gl = geoip_sys::GeoIpLookup::new();
        let cres = match CNetworkIp::new(ip) {
            CNetworkIp::V4(ip) => unsafe {
                geoip_sys::GeoIP_name_by_ipnum_gl(self.db, ip, &mut gl) },
            CNetworkIp::V6(ip) => unsafe {
                geoip_sys::GeoIP_name_by_ipnum_v6_gl(self.db, ip, &mut gl) }
        };

        if cres.is_null() {
            return None;
        }
        let description = match maybe_string(cres) {
            None => return None,
            Some(description) => description
        };
        let mut di = description.splitn(1, ' ');
        let asn = match di.next() {
            None => return None,
            Some(asn) => {
                if ! asn.starts_with("AS") {
                    return None
                } else {
                    asn[2..].parse::<u32>().unwrap()
                }
            }
        };
        let name = di.next().unwrap_or("(none)");
        let as_info = ASInfo {
            asn: asn,
            name: name.to_string(),
            netmask: gl.netmask as u32
        };
        Some(as_info)
    }
}

impl Drop for GeoIp {
    fn drop(&mut self) {
        unsafe {
            geoip_sys::GeoIP_delete(self.db);
        }
    }
}

#[test]
fn geoip_test_basic() {
    let geoip = match GeoIp::open(&Path::new("/opt/geoip/GeoIPASNum.dat"), Options::MemoryCache) {
        Err(err) => panic!(err),
        Ok(geoip) => geoip
    };
    let ip = FromStr::from_str("91.203.184.192").unwrap();
    let res = geoip.as_info_by_ip(ip).unwrap();
    assert!(res.asn == 41064);
    assert!(res.name.contains("Telefun"));
    assert!(res.netmask == 22);
}

#[test]
fn geoip_test_city() {
    let geoip = match GeoIp::open(&Path::new("/opt/geoip/GeoLiteCity.dat"), Options::MemoryCache) {
        Err(err) => panic!(err),
        Ok(geoip) => geoip
    };
    let ip = FromStr::from_str("8.8.8.8").unwrap();
    let res = geoip.city_info_by_ip(ip).unwrap();
    assert!(res.city.unwrap() == "Mountain View");
}
<|endoftext|>


<commit_before>use std::num::NonZeroU8;
use std::{fmt, ops};

/// Interests used in registering.
///
/// Interests are used in [registering] [`event::Source`]s with [`Poll`], they
/// indicate what readiness should be monitored for. For example if a socket is
/// registered with [readable] interests and the socket becomes writable, no
/// event will be returned from a call to [`poll`].
///
/// The size of `Option<Interests>` should be identical to itself.
///
/// ```
/// use std::mem::size_of;
/// use mio::Interests;
///
/// assert_eq!(size_of::<Option<Interests>>(), size_of::<Interests>());
/// ```
///
/// [registering]: crate::Registry::register
/// [`event::Source`]: crate::event::Source
/// [`Poll`]: crate::Poll
/// [readable]: Interests::READABLE
/// [`poll`]: crate::Poll::poll
#[derive(Copy, PartialEq, Eq, Clone, PartialOrd, Ord)]
#[repr(transparent)]
pub struct Interests(NonZeroU8);

// These must be unique.
const READABLE: u8 = 0b0_001;
const WRITABLE: u8 = 0b0_010;
// The following are not available on all platforms.
#[cfg_attr(
    not(any(
        target_os = "dragonfly",
        target_os = "freebsd",
        target_os = "ios",
        target_os = "macos"
    )),
    allow(dead_code)
)]
const AIO: u8 = 0b0_100;
#[cfg_attr(not(target_os = "freebsd"), allow(dead_code))]
const LIO: u8 = 0b1_000;

impl Interests {
    /// Returns a `Interests` set representing readable interests.
    pub const READABLE: Interests = Interests(unsafe { NonZeroU8::new_unchecked(READABLE) });

    /// Returns a `Interests` set representing writable interests.
    pub const WRITABLE: Interests = Interests(unsafe { NonZeroU8::new_unchecked(WRITABLE) });

    /// Returns a `Interests` set representing AIO completion interests.
    #[cfg(any(
        target_os = "dragonfly",
        target_os = "freebsd",
        target_os = "ios",
        target_os = "macos"
    ))]
    pub const AIO: Interests = Interests(unsafe { NonZeroU8::new_unchecked(AIO) });

    /// Returns a `Interests` set representing LIO completion interests.
    #[cfg(target_os = "freebsd")]
    pub const LIO: Interests = Interests(unsafe { NonZeroU8::new_unchecked(LIO) });

    /// Add together two `Interests`.
    ///
    /// This does the same thing as the `BitOr` implementation, but is a
    /// constant function.
    ///
    /// ```
    /// use mio::Interests;
    ///
    /// const INTERESTS: Interests = Interests::READABLE.and(Interests::WRITABLE);
    /// # fn silent_dead_code_warning(_: Interests) { }
    /// # silent_dead_code_warning(INTERESTS)
    /// ```
    pub const fn and(self, other: Interests) -> Interests {
        Interests(unsafe { NonZeroU8::new_unchecked(self.0.get() | other.0.get()) })
    }

    /// Returns true if the value includes readable readiness.
    pub const fn is_readable(self) -> bool {
        (self.0.get() & READABLE) != 0
    }

    /// Returns true if the value includes writable readiness.
    pub const fn is_writable(self) -> bool {
        (self.0.get() & WRITABLE) != 0
    }

    /// Returns true if `Interests` contains AIO readiness
    pub const fn is_aio(self) -> bool {
        (self.0.get() & AIO) != 0
    }

    /// Returns true if `Interests` contains LIO readiness
    pub const fn is_lio(self) -> bool {
        (self.0.get() & LIO) != 0
    }
}

impl ops::BitOr for Interests {
    type Output = Self;

    #[inline]
    fn bitor(self, other: Self) -> Self {
        Interests(unsafe { NonZeroU8::new_unchecked(self.0.get() | other.0.get()) })
    }
}

impl ops::BitOrAssign for Interests {
    #[inline]
    fn bitor_assign(&mut self, other: Self) {
        self.0 = (*self | other).0;
    }
}

impl fmt::Debug for Interests {
    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
        let mut one = false;
        if self.is_readable() {
            if one {
                write!(fmt, " | ")?
            }
            write!(fmt, "READABLE")?;
            one = true
        }
        if self.is_writable() {
            if one {
                write!(fmt, " | ")?
            }
            write!(fmt, "WRITABLE")?;
            one = true
        }
        #[cfg(any(
            target_os = "dragonfly",
            target_os = "freebsd",
            target_os = "ios",
            target_os = "macos"
        ))]
        {
            if self.is_aio() {
                if one {
                    write!(fmt, " | ")?
                }
                write!(fmt, "AIO")?;
                one = true
            }
        }
        #[cfg(any(target_os = "freebsd"))]
        {
            if self.is_lio() {
                if one {
                    write!(fmt, " | ")?
                }
                write!(fmt, "LIO")?;
                one = true
            }
        }
        debug_assert!(one, "printing empty interests");
        Ok(())
    }
}
<commit_msg>Rename Interests::and to Interests::add<commit_after>use std::num::NonZeroU8;
use std::{fmt, ops};

/// Interests used in registering.
///
/// Interests are used in [registering] [`event::Source`]s with [`Poll`], they
/// indicate what readiness should be monitored for. For example if a socket is
/// registered with [readable] interests and the socket becomes writable, no
/// event will be returned from a call to [`poll`].
///
/// The size of `Option<Interests>` should be identical to itself.
///
/// ```
/// use std::mem::size_of;
/// use mio::Interests;
///
/// assert_eq!(size_of::<Option<Interests>>(), size_of::<Interests>());
/// ```
///
/// [registering]: crate::Registry::register
/// [`event::Source`]: crate::event::Source
/// [`Poll`]: crate::Poll
/// [readable]: Interests::READABLE
/// [`poll`]: crate::Poll::poll
#[derive(Copy, PartialEq, Eq, Clone, PartialOrd, Ord)]
#[repr(transparent)]
pub struct Interests(NonZeroU8);

// These must be unique.
const READABLE: u8 = 0b0_001;
const WRITABLE: u8 = 0b0_010;
// The following are not available on all platforms.
#[cfg_attr(
    not(any(
        target_os = "dragonfly",
        target_os = "freebsd",
        target_os = "ios",
        target_os = "macos"
    )),
    allow(dead_code)
)]
const AIO: u8 = 0b0_100;
#[cfg_attr(not(target_os = "freebsd"), allow(dead_code))]
const LIO: u8 = 0b1_000;

impl Interests {
    /// Returns a `Interests` set representing readable interests.
    pub const READABLE: Interests = Interests(unsafe { NonZeroU8::new_unchecked(READABLE) });

    /// Returns a `Interests` set representing writable interests.
    pub const WRITABLE: Interests = Interests(unsafe { NonZeroU8::new_unchecked(WRITABLE) });

    /// Returns a `Interests` set representing AIO completion interests.
    #[cfg(any(
        target_os = "dragonfly",
        target_os = "freebsd",
        target_os = "ios",
        target_os = "macos"
    ))]
    pub const AIO: Interests = Interests(unsafe { NonZeroU8::new_unchecked(AIO) });

    /// Returns a `Interests` set representing LIO completion interests.
    #[cfg(target_os = "freebsd")]
    pub const LIO: Interests = Interests(unsafe { NonZeroU8::new_unchecked(LIO) });

    /// Add together two `Interests`.
    ///
    /// This does the same thing as the `BitOr` implementation, but is a
    /// constant function.
    ///
    /// ```
    /// use mio::Interests;
    ///
    /// const INTERESTS: Interests = Interests::READABLE.add(Interests::WRITABLE);
    /// # fn silent_dead_code_warning(_: Interests) { }
    /// # silent_dead_code_warning(INTERESTS)
    /// ```
    #[allow(clippy::should_implement_trait)]
    pub const fn add(self, other: Interests) -> Interests {
        Interests(unsafe { NonZeroU8::new_unchecked(self.0.get() | other.0.get()) })
    }

    /// Returns true if the value includes readable readiness.
    pub const fn is_readable(self) -> bool {
        (self.0.get() & READABLE) != 0
    }

    /// Returns true if the value includes writable readiness.
    pub const fn is_writable(self) -> bool {
        (self.0.get() & WRITABLE) != 0
    }

    /// Returns true if `Interests` contains AIO readiness
    pub const fn is_aio(self) -> bool {
        (self.0.get() & AIO) != 0
    }

    /// Returns true if `Interests` contains LIO readiness
    pub const fn is_lio(self) -> bool {
        (self.0.get() & LIO) != 0
    }
}

impl ops::BitOr for Interests {
    type Output = Self;

    #[inline]
    fn bitor(self, other: Self) -> Self {
        Interests(unsafe { NonZeroU8::new_unchecked(self.0.get() | other.0.get()) })
    }
}

impl ops::BitOrAssign for Interests {
    #[inline]
    fn bitor_assign(&mut self, other: Self) {
        self.0 = (*self | other).0;
    }
}

impl fmt::Debug for Interests {
    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
        let mut one = false;
        if self.is_readable() {
            if one {
                write!(fmt, " | ")?
            }
            write!(fmt, "READABLE")?;
            one = true
        }
        if self.is_writable() {
            if one {
                write!(fmt, " | ")?
            }
            write!(fmt, "WRITABLE")?;
            one = true
        }
        #[cfg(any(
            target_os = "dragonfly",
            target_os = "freebsd",
            target_os = "ios",
            target_os = "macos"
        ))]
        {
            if self.is_aio() {
                if one {
                    write!(fmt, " | ")?
                }
                write!(fmt, "AIO")?;
                one = true
            }
        }
        #[cfg(any(target_os = "freebsd"))]
        {
            if self.is_lio() {
                if one {
                    write!(fmt, " | ")?
                }
                write!(fmt, "LIO")?;
                one = true
            }
        }
        debug_assert!(one, "printing empty interests");
        Ok(())
    }
}
<|endoftext|>


<commit_before>use std::result;
use std::num;

use instructions::*;

//Returns a string with comments removed, with everything in lowercase
pub fn sanitize_line(input: &mut String){
	println!("Input: {}", *input);
	if let Some(i) = input.find(',') { input.remove(i); }

	//TODO: remove comments from input
	input.trim_left();
	input.trim_right();
	*input = input.to_lowercase();
}

fn convert_number(input: &str) -> Result<u16, String> {
	let convert = input.to_string();
	let result: result::Result<u16, num::ParseIntError>;
	if convert.chars().count() >= 2 {
		if convert[..2].to_string() == "0x" {
			result = u16::from_str_radix(&convert[2..], 16);
		} else {
			result = convert.parse::<u16>();
		}
	}
	else {
		result = convert.parse::<u16>();
	}

	match result {
		Ok(num) => return Ok(num),
		Err(_)  => return Err("Not a number: ".to_string() + input),
	};
}

fn interpret_ld_instruction(data: &Vec<&str>) -> Result<(CPUInstruction, u16), String> {
	//LD Vx, Vy
	if data[1].chars().nth(0).unwrap() == 'v' {
		if data[1].chars().count() > 2 {
			return Err("Unknown register: ".to_string() + data[1]);
		}
		if data[2].chars().nth(0).unwrap() == 'v' {
			let convert = convert_number(&data[2][1..]);
			match convert {
				Ok(n) => {
					let x = convert_number(&data[1][1..]);
					match x {
						Ok(m)    => return Ok((CPUInstruction::LD_Vy, (m << 4) | (n << 8))),
						Err(msg) => return Err(msg),
					}
				}
				Err(msg) => return Err(msg),
			}
		}
		//LD Vx, *
		match data[2] {
			"dt"  => return Ok((CPUInstruction::LD_Vx_DT, 0)),
			"k"   => return Ok((CPUInstruction::LD_K, 0)),
			"[i]" => return Ok((CPUInstruction::LD_Vx_ADDR_I, 0)),
			_     => { //LD Vx, byte
				let x: u16;
				let byte: u16;

				let convert = convert_number(&data[1][1..]);
				match convert {
					Ok(n)    => {
						x = n;
					},
					Err(msg) => return Err(msg),
				}

				match convert_number(&data[2]) {
					Ok(n)    => byte = n & 0x00FF,
					Err(msg) => return Err(msg),
				}
				return Ok((CPUInstruction::LD, (x << 8) | byte));

			}
		}
	}

	//LD I, addr
	if data[1] == "i" {
		let addr = match convert_number(&data[2]) {
			Ok(n)    => n,
			Err(msg) => return Err(msg),
		};
		return Ok((CPUInstruction::LD_I, addr));
	}

	let v = match convert_number(&data[2]) {
		Ok(n)    => n << 8,
		Err(msg) => return Err(msg),
	};
	match data[1] {
		"dt"  => return Ok((CPUInstruction::LD_DT_Vx, v)),
		"st"  => return Ok((CPUInstruction::LD_ST_Vx, v)),
		"f"   => return Ok((CPUInstruction::LD_F, v)),
		"b"   => return Ok((CPUInstruction::LD_B, v)),
		"[i]" => return Ok((CPUInstruction::LD_ADDR_I_Vx, v)),
		_     => return Err("Not an ld variant".to_string()),
	}
}

//Returns two bytes to be written to the binary file
pub fn interpret_line(input: &mut String) -> Result<u16, String> {
	sanitize_line(input);
	let data: Vec<&str> = input.split(' ').collect();

	match data[0] {
		"ld" => match interpret_ld_instruction(&data) {
			Ok((ins, op)) => return Ok(convert_to_opcode(ins, op)),
			Err(s)        => return Err(s),
		},
		_    => return Err("Failed to parse line: {}".to_string()  + input),
	};

}
<commit_msg>remove all commas<commit_after>use std::result;
use std::num;

use instructions::*;

//Returns a string with comments removed, with everything in lowercase
pub fn sanitize_line(input: &mut String){
	println!("Input: {}", *input);
	while let Some(i) = input.find(',') { input.remove(i); }

	//TODO: remove comments from input
	input.trim_left();
	input.trim_right();
	*input = input.to_lowercase();
}

fn convert_number(input: &str) -> Result<u16, String> {
	let convert = input.to_string();
	let result: result::Result<u16, num::ParseIntError>;
	if convert.chars().count() >= 2 {
		if convert[..2].to_string() == "0x" {
			result = u16::from_str_radix(&convert[2..], 16);
		} else {
			result = convert.parse::<u16>();
		}
	}
	else {
		result = convert.parse::<u16>();
	}

	match result {
		Ok(num) => return Ok(num),
		Err(_)  => return Err("Not a number: ".to_string() + input),
	};
}

fn interpret_ld_instruction(data: &Vec<&str>) -> Result<(CPUInstruction, u16), String> {
	//LD Vx, Vy
	if data[1].chars().nth(0).unwrap() == 'v' {
		if data[1].chars().count() > 2 {
			return Err("Unknown register: ".to_string() + data[1]);
		}
		if data[2].chars().nth(0).unwrap() == 'v' {
			let convert = convert_number(&data[2][1..]);
			match convert {
				Ok(n) => {
					let x = convert_number(&data[1][1..]);
					match x {
						Ok(m)    => return Ok((CPUInstruction::LD_Vy, (m << 4) | (n << 8))),
						Err(msg) => return Err(msg),
					}
				}
				Err(msg) => return Err(msg),
			}
		}
		//LD Vx, *
		match data[2] {
			"dt"  => return Ok((CPUInstruction::LD_Vx_DT, 0)),
			"k"   => return Ok((CPUInstruction::LD_K, 0)),
			"[i]" => return Ok((CPUInstruction::LD_Vx_ADDR_I, 0)),
			_     => { //LD Vx, byte
				let x: u16;
				let byte: u16;

				let convert = convert_number(&data[1][1..]);
				match convert {
					Ok(n)    => {
						x = n;
					},
					Err(msg) => return Err(msg),
				}

				match convert_number(&data[2]) {
					Ok(n)    => byte = n & 0x00FF,
					Err(msg) => return Err(msg),
				}
				return Ok((CPUInstruction::LD, (x << 8) | byte));

			}
		}
	}

	//LD I, addr
	if data[1] == "i" {
		let addr = match convert_number(&data[2]) {
			Ok(n)    => n,
			Err(msg) => return Err(msg),
		};
		return Ok((CPUInstruction::LD_I, addr));
	}

	let v = match convert_number(&data[2]) {
		Ok(n)    => n << 8,
		Err(msg) => return Err(msg),
	};
	match data[1] {
		"dt"  => return Ok((CPUInstruction::LD_DT_Vx, v)),
		"st"  => return Ok((CPUInstruction::LD_ST_Vx, v)),
		"f"   => return Ok((CPUInstruction::LD_F, v)),
		"b"   => return Ok((CPUInstruction::LD_B, v)),
		"[i]" => return Ok((CPUInstruction::LD_ADDR_I_Vx, v)),
		_     => return Err("Not an ld variant".to_string()),
	}
}

//Returns two bytes to be written to the binary file
pub fn interpret_line(input: &mut String) -> Result<u16, String> {
	sanitize_line(input);
	let data: Vec<&str> = input.split(' ').collect();

	match data[0] {
		"ld" => match interpret_ld_instruction(&data) {
			Ok((ins, op)) => return Ok(convert_to_opcode(ins, op)),
			Err(s)        => return Err(s),
		},
		_    => return Err("Failed to parse line: {}".to_string()  + input),
	};

}
<|endoftext|>


<commit_before>/*
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

use clap::arg_enum;
use std::fmt::{self, Display};

arg_enum! {
    #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, serde::Deserialize)]
    #[serde(rename_all = "lowercase")]
    pub enum Platform {
        Mac,
        Linux,
        Windows
    }
}

#[derive(
    Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, serde::Deserialize, serde::Serialize,
)]
#[serde(rename_all = "lowercase")]
pub enum PackType {
    Frameworks,
    Core,
}

impl Display for PackType {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match *self {
            Self::Frameworks => write!(f, "frameworks"),
            Self::Core => write!(f, "core"),
        }
    }
}

#[derive(Eq, PartialEq, Debug, serde::Serialize)]
pub struct HashSum(pub String);
<commit_msg>Daily `arc lint --take RUSTFMT`<commit_after>/*
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

use clap::arg_enum;
use std::fmt::{self, Display};

arg_enum! {
    #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, serde::Deserialize)]
    #[serde(rename_all = "lowercase")]
    pub enum Platform {
        Mac,
        Linux,
        Windows
    }
}

#[derive(
    Debug,
    Clone,
    Copy,
    PartialEq,
    Eq,
    PartialOrd,
    Ord,
    serde::Deserialize,
    serde::Serialize
)]
#[serde(rename_all = "lowercase")]
pub enum PackType {
    Frameworks,
    Core,
}

impl Display for PackType {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match *self {
            Self::Frameworks => write!(f, "frameworks"),
            Self::Core => write!(f, "core"),
        }
    }
}

#[derive(Eq, PartialEq, Debug, serde::Serialize)]
pub struct HashSum(pub String);
<|endoftext|>


<commit_before>use convert::*;
use errors::*;

#[derive(Debug, PartialEq, Default, FromBytes)]
pub struct Member {
    pub port: u16,
    pub host: String,
}

#[derive(Debug, PartialEq, Default, FromBytes, BlockLength, Message)]
#[message(template_id = "0", schema_id = "4", version = "1")]
pub struct JoinRequest {
    pub partition_id: u16,
    pub term: u16,
    pub port: u16,
    pub topic_name: String,
    pub host: String,
}

#[derive(Debug, PartialEq, Default, FromBytes, BlockLength, Message)]
#[message(template_id = "1", schema_id = "4", version = "1")]
pub struct JoinResponse {
    pub term: u16,
    pub succeeded: bool,
    pub configuration_entry_position: u64,
    pub configuration_entry_term: i32,
    pub members: Vec<Member>,
}

#[derive(Debug, PartialEq, Default, FromBytes, BlockLength, Message)]
#[message(template_id = "2", schema_id = "4", version = "1")]
pub struct LeaveRequest {
    pub partition_id: u16,
    pub term: u16,
    pub port: u16,
    pub topic_name: String,
    pub host: String,
}

#[derive(Debug, PartialEq, Default, FromBytes, BlockLength, Message)]
#[message(template_id = "3", schema_id = "4", version = "1")]
pub struct LeaveResponse {
    pub term: u16,
    pub succeeded: bool,
    pub configuration_entry_position: u64,
    pub configuration_entry_term: i32,
    pub members: Vec<Member>,
}

#[derive(Debug, PartialEq, Default, FromBytes, BlockLength, Message)]
#[message(template_id = "4", schema_id = "4", version = "1")]
pub struct ConfigurationRequest {
    pub partition_id: u16,
    pub term: u16,
    pub configuration_entry_position: u64,
    pub configuration_entry_term: i32,
    pub members: Vec<Member>,
    pub topic_name: String,
}

#[derive(Debug, PartialEq, Default, FromBytes, BlockLength, Message)]
#[message(template_id = "5", schema_id = "4", version = "1")]
pub struct ConfigurationResponse {
    pub term: u16,
}

#[derive(Debug, PartialEq, Default, FromBytes, BlockLength, Message)]
#[message(template_id = "6", schema_id = "4", version = "1")]
pub struct PollRequest {
    pub partition_id: u16,
    pub term: u16,
    pub last_entry_position: u64,
    pub last_entry_term: i32,
    pub port: u16,
    pub topic_name: String,
    pub host: String,
}

#[derive(Debug, PartialEq, Default, FromBytes, BlockLength, Message)]
#[message(template_id = "7", schema_id = "4", version = "1")]
pub struct PollResponse {
    pub term: u16,
    pub granted: bool,
}

#[derive(Debug, PartialEq, Default, FromBytes, BlockLength, Message)]
#[message(template_id = "8", schema_id = "4", version = "1")]
pub struct VoteRequest {
    pub partition_id: u16,
    pub term: u16,
    pub last_entry_position: u64,
    pub last_entry_term: i32,
    pub port: u16,
    pub topic_name: String,
    pub host: String,
}

#[derive(Debug, PartialEq, Default, FromBytes, BlockLength, Message)]
#[message(template_id = "9", schema_id = "4", version = "1")]
pub struct VoteResponse {
    pub term: u16,
    pub granted: bool,
}

#[derive(Debug, PartialEq, Default, FromBytes, BlockLength, Message)]
#[message(template_id = "10", schema_id = "4", version = "1")]
pub struct AppendRequest {
    pub partition_id: u16,
    pub term: u16,
    pub previous_entry_position: u64,
    pub previous_entry_term: i32,
    pub commit_position: u64,
    pub port: u16,
    pub topic_name: String,
    pub host: String,
    pub data: Data,
}

#[derive(Debug, PartialEq, Default, FromBytes, BlockLength, Message)]
#[message(template_id = "10", schema_id = "4", version = "1")]
pub struct AppendResponse {
    pub partition_id: u16,
    pub term: u16,
    pub succeeded: bool,
    pub entry_position: u64,
    pub port: u16,
    pub topic_name: String,
    pub host: String,
}
<commit_msg>fix(raft): fix template id of AppendResponse<commit_after>use convert::*;
use errors::*;

#[derive(Debug, PartialEq, Default, FromBytes)]
pub struct Member {
    pub port: u16,
    pub host: String,
}

#[derive(Debug, PartialEq, Default, FromBytes, BlockLength, Message)]
#[message(template_id = "0", schema_id = "4", version = "1")]
pub struct JoinRequest {
    pub partition_id: u16,
    pub term: u16,
    pub port: u16,
    pub topic_name: String,
    pub host: String,
}

#[derive(Debug, PartialEq, Default, FromBytes, BlockLength, Message)]
#[message(template_id = "1", schema_id = "4", version = "1")]
pub struct JoinResponse {
    pub term: u16,
    pub succeeded: bool,
    pub configuration_entry_position: u64,
    pub configuration_entry_term: i32,
    pub members: Vec<Member>,
}

#[derive(Debug, PartialEq, Default, FromBytes, BlockLength, Message)]
#[message(template_id = "2", schema_id = "4", version = "1")]
pub struct LeaveRequest {
    pub partition_id: u16,
    pub term: u16,
    pub port: u16,
    pub topic_name: String,
    pub host: String,
}

#[derive(Debug, PartialEq, Default, FromBytes, BlockLength, Message)]
#[message(template_id = "3", schema_id = "4", version = "1")]
pub struct LeaveResponse {
    pub term: u16,
    pub succeeded: bool,
    pub configuration_entry_position: u64,
    pub configuration_entry_term: i32,
    pub members: Vec<Member>,
}

#[derive(Debug, PartialEq, Default, FromBytes, BlockLength, Message)]
#[message(template_id = "4", schema_id = "4", version = "1")]
pub struct ConfigurationRequest {
    pub partition_id: u16,
    pub term: u16,
    pub configuration_entry_position: u64,
    pub configuration_entry_term: i32,
    pub members: Vec<Member>,
    pub topic_name: String,
}

#[derive(Debug, PartialEq, Default, FromBytes, BlockLength, Message)]
#[message(template_id = "5", schema_id = "4", version = "1")]
pub struct ConfigurationResponse {
    pub term: u16,
}

#[derive(Debug, PartialEq, Default, FromBytes, BlockLength, Message)]
#[message(template_id = "6", schema_id = "4", version = "1")]
pub struct PollRequest {
    pub partition_id: u16,
    pub term: u16,
    pub last_entry_position: u64,
    pub last_entry_term: i32,
    pub port: u16,
    pub topic_name: String,
    pub host: String,
}

#[derive(Debug, PartialEq, Default, FromBytes, BlockLength, Message)]
#[message(template_id = "7", schema_id = "4", version = "1")]
pub struct PollResponse {
    pub term: u16,
    pub granted: bool,
}

#[derive(Debug, PartialEq, Default, FromBytes, BlockLength, Message)]
#[message(template_id = "8", schema_id = "4", version = "1")]
pub struct VoteRequest {
    pub partition_id: u16,
    pub term: u16,
    pub last_entry_position: u64,
    pub last_entry_term: i32,
    pub port: u16,
    pub topic_name: String,
    pub host: String,
}

#[derive(Debug, PartialEq, Default, FromBytes, BlockLength, Message)]
#[message(template_id = "9", schema_id = "4", version = "1")]
pub struct VoteResponse {
    pub term: u16,
    pub granted: bool,
}

#[derive(Debug, PartialEq, Default, FromBytes, BlockLength, Message)]
#[message(template_id = "10", schema_id = "4", version = "1")]
pub struct AppendRequest {
    pub partition_id: u16,
    pub term: u16,
    pub previous_entry_position: u64,
    pub previous_entry_term: i32,
    pub commit_position: u64,
    pub port: u16,
    pub topic_name: String,
    pub host: String,
    pub data: Data,
}

#[derive(Debug, PartialEq, Default, FromBytes, BlockLength, Message)]
#[message(template_id = "11", schema_id = "4", version = "1")]
pub struct AppendResponse {
    pub partition_id: u16,
    pub term: u16,
    pub succeeded: bool,
    pub entry_position: u64,
    pub port: u16,
    pub topic_name: String,
    pub host: String,
}
<|endoftext|>


<commit_before>#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Request(pub RequestId, pub Vec<u8>);

#[derive(Clone, Debug, Eq, PartialEq)]
pub enum AttrMacro {
    All,
    Fast,
    Full,
}

impl Copy for AttrMacro {}

#[derive(Debug, Eq, PartialEq)]
pub enum Response<'a> {
    Capabilities(Vec<Capability<'a>>),
    Continue {
        code: Option<ResponseCode<'a>>,
        information: Option<&'a str>,
    },
    Done {
        tag: RequestId,
        status: Status,
        code: Option<ResponseCode<'a>>,
        information: Option<&'a str>,
    },
    Data {
        status: Status,
        code: Option<ResponseCode<'a>>,
        information: Option<&'a str>,
    },
    Expunge(u32),
    Fetch(u32, Vec<AttributeValue<'a>>),
    MailboxData(MailboxDatum<'a>),
    IDs(Vec<u32>),
}

#[derive(Debug, Eq, PartialEq)]
pub enum Status {
    Ok,
    No,
    Bad,
    PreAuth,
    Bye,
}

#[derive(Debug, Eq, PartialEq)]
pub enum ResponseCode<'a> {
    Alert,
    BadCharset(Option<Vec<&'a str>>),
    Capabilities(Vec<Capability<'a>>),
    HighestModSeq(u64), // RFC 4551, section 3.1.1
    Parse,
    PermanentFlags(Vec<&'a str>),
    ReadOnly,
    ReadWrite,
    TryCreate,
    UidNext(u32),
    UidValidity(u32),
    Unseen(u32),
}

#[derive(Debug, Eq, PartialEq)]
pub enum StatusAttribute {
    HighestModSeq(u64), // RFC 4551
    Messages(u32),
    Recent(u32),
    UidNext(u32),
    UidValidity(u32),
    Unseen(u32),
}

#[derive(Debug, Eq, PartialEq, Clone)]
pub struct Metadata {
    pub entry: String,
    pub value: Option<String>,
}

#[derive(Debug, Eq, PartialEq)]
pub enum MailboxDatum<'a> {
    Exists(u32),
    Flags(Vec<&'a str>),
    List {
        flags: Vec<&'a str>,
        delimiter: Option<&'a str>,
        name: &'a str,
    },
    Status {
        mailbox: &'a str,
        status: Vec<StatusAttribute>,
    },
    Recent(u32),
    MetadataSolicited {
        mailbox: &'a str,
        values: Vec<Metadata>,
    },
    MetadataUnsolicited {
        mailbox: &'a str,
        values: Vec<&'a str>,
    },
}

#[derive(Debug, Eq, PartialEq, Hash)]
pub enum Capability<'a> {
    Imap4rev1,
    Auth(&'a str),
    Atom(&'a str),
}

#[derive(Debug, Eq, PartialEq)]
pub enum Attribute {
    Body,
    Envelope,
    Flags,
    InternalDate,
    ModSeq, // RFC 4551, section 3.3.2
    Rfc822,
    Rfc822Size,
    Rfc822Text,
    Uid,
}

#[derive(Debug, Eq, PartialEq)]
pub enum MessageSection {
    Header,
    Mime,
    Text,
}

#[derive(Debug, Eq, PartialEq)]
pub enum SectionPath {
    Full(MessageSection),
    Part(Vec<u32>, Option<MessageSection>),
}

#[allow(clippy::large_enum_variant)]
#[derive(Debug, Eq, PartialEq)]
pub enum AttributeValue<'a> {
    BodySection {
        section: Option<SectionPath>,
        index: Option<u32>,
        data: Option<&'a [u8]>,
    },
    BodyStructure(BodyStructure<'a>),
    Envelope(Box<Envelope<'a>>),
    Flags(Vec<&'a str>),
    InternalDate(&'a str),
    ModSeq(u64), // RFC 4551, section 3.3.2
    Rfc822(Option<&'a [u8]>),
    Rfc822Header(Option<&'a [u8]>),
    Rfc822Size(u32),
    Rfc822Text(Option<&'a [u8]>),
    Uid(u32),
}

#[allow(clippy::large_enum_variant)]
#[derive(Debug, Eq, PartialEq)]
pub enum BodyStructure<'a> {
    Basic {
        common: BodyContentCommon<'a>,
        other: BodyContentSinglePart<'a>,
        extension: Option<BodyExtension<'a>>,
    },
    Text {
        common: BodyContentCommon<'a>,
        other: BodyContentSinglePart<'a>,
        lines: u32,
        extension: Option<BodyExtension<'a>>,
    },
    Message {
        common: BodyContentCommon<'a>,
        other: BodyContentSinglePart<'a>,
        envelope: Envelope<'a>,
        body: Box<BodyStructure<'a>>,
        lines: u32,
        extension: Option<BodyExtension<'a>>,
    },
    Multipart {
        common: BodyContentCommon<'a>,
        bodies: Vec<BodyStructure<'a>>,
        extension: Option<BodyExtension<'a>>,
    },
}

#[derive(Debug, Eq, PartialEq)]
pub struct BodyContentCommon<'a> {
    pub ty: ContentType<'a>,
    pub disposition: Option<ContentDisposition<'a>>,
    pub language: Option<Vec<&'a str>>,
    pub location: Option<&'a str>,
}

#[derive(Debug, Eq, PartialEq)]
pub struct BodyContentSinglePart<'a> {
    pub id: Option<&'a str>,
    pub md5: Option<&'a str>,
    pub description: Option<&'a str>,
    pub transfer_encoding: ContentEncoding<'a>,
    pub octets: u32,
}

#[derive(Debug, Eq, PartialEq)]
pub struct ContentType<'a> {
    pub ty: &'a str,
    pub subtype: &'a str,
    pub params: BodyParams<'a>,
}

#[derive(Debug, Eq, PartialEq)]
pub struct ContentDisposition<'a> {
    pub ty: &'a str,
    pub params: BodyParams<'a>,
}

#[derive(Debug, Eq, PartialEq)]
pub enum ContentEncoding<'a> {
    SevenBit,
    EightBit,
    Binary,
    Base64,
    QuotedPrintable,
    Other(&'a str),
}

#[derive(Debug, Eq, PartialEq)]
pub enum BodyExtension<'a> {
    Num(u32),
    Str(Option<&'a str>),
    List(Vec<BodyExtension<'a>>),
}

pub type BodyParams<'a> = Option<Vec<(&'a str, &'a str)>>;

#[derive(Debug, Eq, PartialEq)]
pub struct Envelope<'a> {
    pub date: Option<&'a [u8]>,
    pub subject: Option<&'a [u8]>,
    pub from: Option<Vec<Address<'a>>>,
    pub sender: Option<Vec<Address<'a>>>,
    pub reply_to: Option<Vec<Address<'a>>>,
    pub to: Option<Vec<Address<'a>>>,
    pub cc: Option<Vec<Address<'a>>>,
    pub bcc: Option<Vec<Address<'a>>>,
    pub in_reply_to: Option<&'a [u8]>,
    pub message_id: Option<&'a [u8]>,
}

#[derive(Debug, Eq, PartialEq)]
pub struct Address<'a> {
    pub name: Option<&'a [u8]>,
    pub adl: Option<&'a [u8]>,
    pub mailbox: Option<&'a [u8]>,
    pub host: Option<&'a [u8]>,
}

#[derive(Clone, Debug, Eq, PartialEq)]
pub struct RequestId(pub String);

impl RequestId {
    pub fn as_bytes(&self) -> &[u8] {
        self.0.as_bytes()
    }
}

#[derive(Debug, Eq, PartialEq)]
pub enum State {
    NotAuthenticated,
    Authenticated,
    Selected,
    Logout,
}

// Body Structure

pub struct BodyFields<'a> {
    pub param: BodyParams<'a>,
    pub id: Option<&'a str>,
    pub description: Option<&'a str>,
    pub transfer_encoding: ContentEncoding<'a>,
    pub octets: u32,
}

pub struct BodyExt1Part<'a> {
    pub md5: Option<&'a str>,
    pub disposition: Option<ContentDisposition<'a>>,
    pub language: Option<Vec<&'a str>>,
    pub location: Option<&'a str>,
    pub extension: Option<BodyExtension<'a>>,
}

pub struct BodyExtMPart<'a> {
    pub param: BodyParams<'a>,
    pub disposition: Option<ContentDisposition<'a>>,
    pub language: Option<Vec<&'a str>>,
    pub location: Option<&'a str>,
    pub extension: Option<BodyExtension<'a>>,
}
<commit_msg>Use derive(Copy) in AttrMacro<commit_after>#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Request(pub RequestId, pub Vec<u8>);

#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum AttrMacro {
    All,
    Fast,
    Full,
}

#[derive(Debug, Eq, PartialEq)]
pub enum Response<'a> {
    Capabilities(Vec<Capability<'a>>),
    Continue {
        code: Option<ResponseCode<'a>>,
        information: Option<&'a str>,
    },
    Done {
        tag: RequestId,
        status: Status,
        code: Option<ResponseCode<'a>>,
        information: Option<&'a str>,
    },
    Data {
        status: Status,
        code: Option<ResponseCode<'a>>,
        information: Option<&'a str>,
    },
    Expunge(u32),
    Fetch(u32, Vec<AttributeValue<'a>>),
    MailboxData(MailboxDatum<'a>),
    IDs(Vec<u32>),
}

#[derive(Debug, Eq, PartialEq)]
pub enum Status {
    Ok,
    No,
    Bad,
    PreAuth,
    Bye,
}

#[derive(Debug, Eq, PartialEq)]
pub enum ResponseCode<'a> {
    Alert,
    BadCharset(Option<Vec<&'a str>>),
    Capabilities(Vec<Capability<'a>>),
    HighestModSeq(u64), // RFC 4551, section 3.1.1
    Parse,
    PermanentFlags(Vec<&'a str>),
    ReadOnly,
    ReadWrite,
    TryCreate,
    UidNext(u32),
    UidValidity(u32),
    Unseen(u32),
}

#[derive(Debug, Eq, PartialEq)]
pub enum StatusAttribute {
    HighestModSeq(u64), // RFC 4551
    Messages(u32),
    Recent(u32),
    UidNext(u32),
    UidValidity(u32),
    Unseen(u32),
}

#[derive(Debug, Eq, PartialEq, Clone)]
pub struct Metadata {
    pub entry: String,
    pub value: Option<String>,
}

#[derive(Debug, Eq, PartialEq)]
pub enum MailboxDatum<'a> {
    Exists(u32),
    Flags(Vec<&'a str>),
    List {
        flags: Vec<&'a str>,
        delimiter: Option<&'a str>,
        name: &'a str,
    },
    Status {
        mailbox: &'a str,
        status: Vec<StatusAttribute>,
    },
    Recent(u32),
    MetadataSolicited {
        mailbox: &'a str,
        values: Vec<Metadata>,
    },
    MetadataUnsolicited {
        mailbox: &'a str,
        values: Vec<&'a str>,
    },
}

#[derive(Debug, Eq, PartialEq, Hash)]
pub enum Capability<'a> {
    Imap4rev1,
    Auth(&'a str),
    Atom(&'a str),
}

#[derive(Debug, Eq, PartialEq)]
pub enum Attribute {
    Body,
    Envelope,
    Flags,
    InternalDate,
    ModSeq, // RFC 4551, section 3.3.2
    Rfc822,
    Rfc822Size,
    Rfc822Text,
    Uid,
}

#[derive(Debug, Eq, PartialEq)]
pub enum MessageSection {
    Header,
    Mime,
    Text,
}

#[derive(Debug, Eq, PartialEq)]
pub enum SectionPath {
    Full(MessageSection),
    Part(Vec<u32>, Option<MessageSection>),
}

#[allow(clippy::large_enum_variant)]
#[derive(Debug, Eq, PartialEq)]
pub enum AttributeValue<'a> {
    BodySection {
        section: Option<SectionPath>,
        index: Option<u32>,
        data: Option<&'a [u8]>,
    },
    BodyStructure(BodyStructure<'a>),
    Envelope(Box<Envelope<'a>>),
    Flags(Vec<&'a str>),
    InternalDate(&'a str),
    ModSeq(u64), // RFC 4551, section 3.3.2
    Rfc822(Option<&'a [u8]>),
    Rfc822Header(Option<&'a [u8]>),
    Rfc822Size(u32),
    Rfc822Text(Option<&'a [u8]>),
    Uid(u32),
}

#[allow(clippy::large_enum_variant)]
#[derive(Debug, Eq, PartialEq)]
pub enum BodyStructure<'a> {
    Basic {
        common: BodyContentCommon<'a>,
        other: BodyContentSinglePart<'a>,
        extension: Option<BodyExtension<'a>>,
    },
    Text {
        common: BodyContentCommon<'a>,
        other: BodyContentSinglePart<'a>,
        lines: u32,
        extension: Option<BodyExtension<'a>>,
    },
    Message {
        common: BodyContentCommon<'a>,
        other: BodyContentSinglePart<'a>,
        envelope: Envelope<'a>,
        body: Box<BodyStructure<'a>>,
        lines: u32,
        extension: Option<BodyExtension<'a>>,
    },
    Multipart {
        common: BodyContentCommon<'a>,
        bodies: Vec<BodyStructure<'a>>,
        extension: Option<BodyExtension<'a>>,
    },
}

#[derive(Debug, Eq, PartialEq)]
pub struct BodyContentCommon<'a> {
    pub ty: ContentType<'a>,
    pub disposition: Option<ContentDisposition<'a>>,
    pub language: Option<Vec<&'a str>>,
    pub location: Option<&'a str>,
}

#[derive(Debug, Eq, PartialEq)]
pub struct BodyContentSinglePart<'a> {
    pub id: Option<&'a str>,
    pub md5: Option<&'a str>,
    pub description: Option<&'a str>,
    pub transfer_encoding: ContentEncoding<'a>,
    pub octets: u32,
}

#[derive(Debug, Eq, PartialEq)]
pub struct ContentType<'a> {
    pub ty: &'a str,
    pub subtype: &'a str,
    pub params: BodyParams<'a>,
}

#[derive(Debug, Eq, PartialEq)]
pub struct ContentDisposition<'a> {
    pub ty: &'a str,
    pub params: BodyParams<'a>,
}

#[derive(Debug, Eq, PartialEq)]
pub enum ContentEncoding<'a> {
    SevenBit,
    EightBit,
    Binary,
    Base64,
    QuotedPrintable,
    Other(&'a str),
}

#[derive(Debug, Eq, PartialEq)]
pub enum BodyExtension<'a> {
    Num(u32),
    Str(Option<&'a str>),
    List(Vec<BodyExtension<'a>>),
}

pub type BodyParams<'a> = Option<Vec<(&'a str, &'a str)>>;

#[derive(Debug, Eq, PartialEq)]
pub struct Envelope<'a> {
    pub date: Option<&'a [u8]>,
    pub subject: Option<&'a [u8]>,
    pub from: Option<Vec<Address<'a>>>,
    pub sender: Option<Vec<Address<'a>>>,
    pub reply_to: Option<Vec<Address<'a>>>,
    pub to: Option<Vec<Address<'a>>>,
    pub cc: Option<Vec<Address<'a>>>,
    pub bcc: Option<Vec<Address<'a>>>,
    pub in_reply_to: Option<&'a [u8]>,
    pub message_id: Option<&'a [u8]>,
}

#[derive(Debug, Eq, PartialEq)]
pub struct Address<'a> {
    pub name: Option<&'a [u8]>,
    pub adl: Option<&'a [u8]>,
    pub mailbox: Option<&'a [u8]>,
    pub host: Option<&'a [u8]>,
}

#[derive(Clone, Debug, Eq, PartialEq)]
pub struct RequestId(pub String);

impl RequestId {
    pub fn as_bytes(&self) -> &[u8] {
        self.0.as_bytes()
    }
}

#[derive(Debug, Eq, PartialEq)]
pub enum State {
    NotAuthenticated,
    Authenticated,
    Selected,
    Logout,
}

// Body Structure

pub struct BodyFields<'a> {
    pub param: BodyParams<'a>,
    pub id: Option<&'a str>,
    pub description: Option<&'a str>,
    pub transfer_encoding: ContentEncoding<'a>,
    pub octets: u32,
}

pub struct BodyExt1Part<'a> {
    pub md5: Option<&'a str>,
    pub disposition: Option<ContentDisposition<'a>>,
    pub language: Option<Vec<&'a str>>,
    pub location: Option<&'a str>,
    pub extension: Option<BodyExtension<'a>>,
}

pub struct BodyExtMPart<'a> {
    pub param: BodyParams<'a>,
    pub disposition: Option<ContentDisposition<'a>>,
    pub language: Option<Vec<&'a str>>,
    pub location: Option<&'a str>,
    pub extension: Option<BodyExtension<'a>>,
}
<|endoftext|>


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

/// Create the `main` function which will initialize the rust runtime and call
/// users main function.
pub(crate) fn maybe_create_entry_wrapper(tcx: TyCtxt<'_>, module: &mut Module<impl Backend + 'static>) {
    use rustc_hir::lang_items::StartFnLangItem;
    use rustc_session::config::EntryFnType;

    let (main_def_id, use_start_lang_item) = match tcx.entry_fn(LOCAL_CRATE) {
        Some((def_id, entry_ty)) => (
            def_id,
            match entry_ty {
                EntryFnType::Main => true,
                EntryFnType::Start => false,
            },
        ),
        None => return,
    };

    let instance = Instance::mono(tcx, main_def_id);
    if module.get_name(&*tcx.symbol_name(instance).name.as_str()).is_none() {
        return;
    }

    create_entry_fn(tcx, module, main_def_id, use_start_lang_item);

    fn create_entry_fn(
        tcx: TyCtxt<'_>,
        m: &mut Module<impl Backend + 'static>,
        rust_main_def_id: DefId,
        use_start_lang_item: bool,
    ) {
        let main_ret_ty = tcx.fn_sig(rust_main_def_id).output();
        // Given that `main()` has no arguments,
        // then its return type cannot have
        // late-bound regions, since late-bound
        // regions must appear in the argument
        // listing.
        let main_ret_ty = tcx.erase_regions(&main_ret_ty.no_bound_vars().unwrap());

        let cmain_sig = Signature {
            params: vec![
                AbiParam::new(m.target_config().pointer_type()),
                AbiParam::new(m.target_config().pointer_type()),
            ],
            returns: vec![AbiParam::new(
                m.target_config().pointer_type(), /*isize*/
            )],
            call_conv: CallConv::triple_default(m.isa().triple()),
        };

        let cmain_func_id = m
            .declare_function("main", Linkage::Export, &cmain_sig)
            .unwrap();

        let instance = Instance::mono(tcx, rust_main_def_id);

        let (main_name, main_sig) =
            get_function_name_and_sig(tcx, m.isa().triple(), instance, false);
        let main_func_id = m
            .declare_function(&main_name, Linkage::Import, &main_sig)
            .unwrap();

        let mut ctx = Context::new();
        ctx.func = Function::with_name_signature(ExternalName::user(0, 0), cmain_sig.clone());
        {
            let mut func_ctx = FunctionBuilderContext::new();
            let mut bcx = FunctionBuilder::new(&mut ctx.func, &mut func_ctx);

            let block = bcx.create_block();
            bcx.switch_to_block(block);
            let arg_argc = bcx.append_block_param(block, m.target_config().pointer_type());
            let arg_argv = bcx.append_block_param(block, m.target_config().pointer_type());

            crate::atomic_shim::init_global_lock(m, &mut bcx);

            let main_func_ref = m.declare_func_in_func(main_func_id, &mut bcx.func);

            let call_inst = if use_start_lang_item {
                let start_def_id = tcx.require_lang_item(StartFnLangItem, None);
                let start_instance = Instance::resolve(
                    tcx,
                    ParamEnv::reveal_all(),
                    start_def_id,
                    tcx.intern_substs(&[main_ret_ty.into()]),
                )
                .unwrap()
                .unwrap();
                let start_func_id = import_function(tcx, m, start_instance);

                let main_val = bcx
                    .ins()
                    .func_addr(m.target_config().pointer_type(), main_func_ref);

                let func_ref = m.declare_func_in_func(start_func_id, &mut bcx.func);
                bcx.ins().call(func_ref, &[main_val, arg_argc, arg_argv])
            } else {
                // using user-defined start fn
                bcx.ins().call(main_func_ref, &[arg_argc, arg_argv])
            };

            let result = bcx.inst_results(call_inst)[0];
            bcx.ins().return_(&[result]);
            bcx.seal_all_blocks();
            bcx.finalize();
        }
        m.define_function(
            cmain_func_id,
            &mut ctx,
            &mut cranelift_codegen::binemit::NullTrapSink {},
        ).unwrap();
    }
}
<commit_msg>Commit missing change for rustup<commit_after>use crate::prelude::*;

/// Create the `main` function which will initialize the rust runtime and call
/// users main function.
pub(crate) fn maybe_create_entry_wrapper(tcx: TyCtxt<'_>, module: &mut Module<impl Backend + 'static>) {
    use rustc_hir::lang_items::StartFnLangItem;
    use rustc_session::config::EntryFnType;

    let (main_def_id, use_start_lang_item) = match tcx.entry_fn(LOCAL_CRATE) {
        Some((def_id, entry_ty)) => (
            def_id.to_def_id(),
            match entry_ty {
                EntryFnType::Main => true,
                EntryFnType::Start => false,
            },
        ),
        None => return,
    };

    let instance = Instance::mono(tcx, main_def_id);
    if module.get_name(&*tcx.symbol_name(instance).name.as_str()).is_none() {
        return;
    }

    create_entry_fn(tcx, module, main_def_id, use_start_lang_item);

    fn create_entry_fn(
        tcx: TyCtxt<'_>,
        m: &mut Module<impl Backend + 'static>,
        rust_main_def_id: DefId,
        use_start_lang_item: bool,
    ) {
        let main_ret_ty = tcx.fn_sig(rust_main_def_id).output();
        // Given that `main()` has no arguments,
        // then its return type cannot have
        // late-bound regions, since late-bound
        // regions must appear in the argument
        // listing.
        let main_ret_ty = tcx.erase_regions(&main_ret_ty.no_bound_vars().unwrap());

        let cmain_sig = Signature {
            params: vec![
                AbiParam::new(m.target_config().pointer_type()),
                AbiParam::new(m.target_config().pointer_type()),
            ],
            returns: vec![AbiParam::new(
                m.target_config().pointer_type(), /*isize*/
            )],
            call_conv: CallConv::triple_default(m.isa().triple()),
        };

        let cmain_func_id = m
            .declare_function("main", Linkage::Export, &cmain_sig)
            .unwrap();

        let instance = Instance::mono(tcx, rust_main_def_id);

        let (main_name, main_sig) =
            get_function_name_and_sig(tcx, m.isa().triple(), instance, false);
        let main_func_id = m
            .declare_function(&main_name, Linkage::Import, &main_sig)
            .unwrap();

        let mut ctx = Context::new();
        ctx.func = Function::with_name_signature(ExternalName::user(0, 0), cmain_sig.clone());
        {
            let mut func_ctx = FunctionBuilderContext::new();
            let mut bcx = FunctionBuilder::new(&mut ctx.func, &mut func_ctx);

            let block = bcx.create_block();
            bcx.switch_to_block(block);
            let arg_argc = bcx.append_block_param(block, m.target_config().pointer_type());
            let arg_argv = bcx.append_block_param(block, m.target_config().pointer_type());

            crate::atomic_shim::init_global_lock(m, &mut bcx);

            let main_func_ref = m.declare_func_in_func(main_func_id, &mut bcx.func);

            let call_inst = if use_start_lang_item {
                let start_def_id = tcx.require_lang_item(StartFnLangItem, None);
                let start_instance = Instance::resolve(
                    tcx,
                    ParamEnv::reveal_all(),
                    start_def_id,
                    tcx.intern_substs(&[main_ret_ty.into()]),
                )
                .unwrap()
                .unwrap();
                let start_func_id = import_function(tcx, m, start_instance);

                let main_val = bcx
                    .ins()
                    .func_addr(m.target_config().pointer_type(), main_func_ref);

                let func_ref = m.declare_func_in_func(start_func_id, &mut bcx.func);
                bcx.ins().call(func_ref, &[main_val, arg_argc, arg_argv])
            } else {
                // using user-defined start fn
                bcx.ins().call(main_func_ref, &[arg_argc, arg_argv])
            };

            let result = bcx.inst_results(call_inst)[0];
            bcx.ins().return_(&[result]);
            bcx.seal_all_blocks();
            bcx.finalize();
        }
        m.define_function(
            cmain_func_id,
            &mut ctx,
            &mut cranelift_codegen::binemit::NullTrapSink {},
        ).unwrap();
    }
}
<|endoftext|>


<commit_before>use core::models::*;
use super::colors;

pub fn print_comment_and_parent(item: &Option<&HnItem>, comments: &Option<Vec<HnItem>>) {
    match *item {
        Some(ref item) => {
            match *comments {
                Some(ref comments) => print_comments(item, comments),
                None => could_not_get_any_commments_for_item(item),
            }
        }
        None => (),
    }
}

pub fn print_headline_with_author(item: &HnItem, index: &i32) {
    let s = create_headline_with_author(item, index).unwrap(); // Not handling errs
    println!("{}", s);
}

fn create_headline_with_author(item: &HnItem, index: &i32) -> Result<String, String> {
    match item.title {
        Some(_) => {
            let s = format!("[{:3}] {:80} ~ {}",
                            index,
                            item.title.as_ref().unwrap(),
                            item.by);
            Ok(s)

        }
        None => Err(String::from("Not headline")),
    }
}

pub fn could_not_get_any_commments_for_item(item: &HnItem) {
    println!("Could not get comments for item with id {}", item.id)
}

pub fn print_filename_of_loaded_page(filen: &str, title: &str) {
    println!("{} {} {} {}", "Downloaded page", title, "into file", filen);
}
pub fn could_not_load_page(title: &str) {
    println!("Could not download to file with title {}", title);
}

pub fn print_no_connection() {
    println!("Could not detect internet connection, please check it and try again");
}

pub fn print_comments(item: &HnItem, comments: &Vec<HnItem>) {
    let coloring = colors::CliColoring::new(colors::Theme::Disabled);  // todo, probably from app_domain

    if comments.len() > 0 {
        match item.title {
            Some(ref title) => println!("Comments for item id {} with title {}", &item.id, title),
            None => println!("Comments for item id {}", &item.id),
        }
        let mut comment_index = 0;
        for comment in comments {
            comment_index += 1;
            let res = create_comment_row(&comment_index, &comment);
            if res.is_some() {
                if comment_index % 2 == 0 {
                    coloring.zebra_coloring();
                }

                println!("{}", res.unwrap());
                coloring.reset_colors();
            } else {
                comment_index -= 1;
            }
        }
    } else {
        println!("No comments for {}", item.id);
    }
    println!("") // this adds extra space after comments and prevent the input being interfered with bg coloring
}

pub fn print_invalid_numb() {
    println!("Received invalid number");
}

pub fn print_over_limit_but_using_index(numb:usize) {
    println!("Over the limit, using index {}", numb);
}

pub fn print_could_not_get_story(numb:usize) {
    println!("Could not get story at index {}", numb);
}

fn create_comment_row(index: &i32, item: &HnItem) -> Option<String> {
    match item.text_unescaped() {
        Some(ref text) => {
            let mut s = format!("[{:3}] {:80} ~{}", index, text, &item.by); // TODO This needs to handle unicode characters to utf8 or something similar (snap's -> snap's)
            match item.kids {
                Some(ref kids) => s.push_str(&format!(" with [{:3}] replies", kids.len())),
                None => ()
            }
            s.push_str("\n-----");
            Some(s)
        }
        None => None,
    }

}

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

    #[test]
    fn create_headline_with_author_test() {
        use std::fs::File;
        use std::io::prelude::*;
        use serde_json;
        let mut contents = String::new();
        File::open("res/test/item.json")
            .and_then(|mut file| file.read_to_string(&mut contents))
            .unwrap();
        let deserialized: HnItem = serde_json::from_str(&contents).unwrap();
        let index = 1;
        let s: String = create_headline_with_author(&deserialized, &index).unwrap();
        assert!(s.len() != 0);
        assert!(s.contains("1"));
        assert!(s.contains("dhouston"));
        assert!(s.contains("My YC app: Dropbox - Throw away your USB drive"));
        assert!(deserialized.by.len() != 0);
        assert!(deserialized.title.unwrap().len() != 0);
    }

    #[test]
    fn create_comment_row_test() {
        use std::fs::File;
        use std::io::prelude::*;
        use serde_json;
        let mut contents = String::new();
        File::open("res/test/children-item.json")
            .and_then(|mut file| file.read_to_string(&mut contents))
            .unwrap();
        let deserialized: HnItem = serde_json::from_str(&contents).unwrap();
        let commentStr = create_comment_row(&1, &deserialized).unwrap();
        assert!(commentStr.contains("is not a valid concern. Unless you are planning"));
        assert!(commentStr.contains("cholantesh"));

    }

    #[test]
    fn test_cli_color() {}
}<commit_msg>Removed unnecessary test stub<commit_after>use core::models::*;
use super::colors;

pub fn print_comment_and_parent(item: &Option<&HnItem>, comments: &Option<Vec<HnItem>>) {
    match *item {
        Some(ref item) => {
            match *comments {
                Some(ref comments) => print_comments(item, comments),
                None => could_not_get_any_commments_for_item(item),
            }
        }
        None => (),
    }
}

pub fn print_headline_with_author(item: &HnItem, index: &i32) {
    let s = create_headline_with_author(item, index).unwrap(); // Not handling errs
    println!("{}", s);
}

fn create_headline_with_author(item: &HnItem, index: &i32) -> Result<String, String> {
    match item.title {
        Some(_) => {
            let s = format!("[{:3}] {:80} ~ {}",
                            index,
                            item.title.as_ref().unwrap(),
                            item.by);
            Ok(s)

        }
        None => Err(String::from("Not headline")),
    }
}

pub fn could_not_get_any_commments_for_item(item: &HnItem) {
    println!("Could not get comments for item with id {}", item.id)
}

pub fn print_filename_of_loaded_page(filen: &str, title: &str) {
    println!("{} {} {} {}", "Downloaded page", title, "into file", filen);
}
pub fn could_not_load_page(title: &str) {
    println!("Could not download to file with title {}", title);
}

pub fn print_no_connection() {
    println!("Could not detect internet connection, please check it and try again");
}

pub fn print_comments(item: &HnItem, comments: &Vec<HnItem>) {
    let coloring = colors::CliColoring::new(colors::Theme::Disabled);  // todo, probably from app_domain

    if comments.len() > 0 {
        match item.title {
            Some(ref title) => println!("Comments for item id {} with title {}", &item.id, title),
            None => println!("Comments for item id {}", &item.id),
        }
        let mut comment_index = 0;
        for comment in comments {
            comment_index += 1;
            let res = create_comment_row(&comment_index, &comment);
            if res.is_some() {
                if comment_index % 2 == 0 {
                    coloring.zebra_coloring();
                }

                println!("{}", res.unwrap());
                coloring.reset_colors();
            } else {
                comment_index -= 1;
            }
        }
    } else {
        println!("No comments for {}", item.id);
    }
    println!("") // this adds extra space after comments and prevent the input being interfered with bg coloring
}

pub fn print_invalid_numb() {
    println!("Received invalid number");
}

pub fn print_over_limit_but_using_index(numb:usize) {
    println!("Over the limit, using index {}", numb);
}

pub fn print_could_not_get_story(numb:usize) {
    println!("Could not get story at index {}", numb);
}

fn create_comment_row(index: &i32, item: &HnItem) -> Option<String> {
    match item.text_unescaped() {
        Some(ref text) => {
            let mut s = format!("[{:3}] {:80} ~{}", index, text, &item.by); // TODO This needs to handle unicode characters to utf8 or something similar (snap's -> snap's)
            match item.kids {
                Some(ref kids) => s.push_str(&format!(" with [{:3}] replies", kids.len())),
                None => ()
            }
            s.push_str("\n-----");
            Some(s)
        }
        None => None,
    }

}

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

    #[test]
    fn create_headline_with_author_test() {
        use std::fs::File;
        use std::io::prelude::*;
        use serde_json;
        let mut contents = String::new();
        File::open("res/test/item.json")
            .and_then(|mut file| file.read_to_string(&mut contents))
            .unwrap();
        let deserialized: HnItem = serde_json::from_str(&contents).unwrap();
        let index = 1;
        let s: String = create_headline_with_author(&deserialized, &index).unwrap();
        assert!(s.len() != 0);
        assert!(s.contains("1"));
        assert!(s.contains("dhouston"));
        assert!(s.contains("My YC app: Dropbox - Throw away your USB drive"));
        assert!(deserialized.by.len() != 0);
        assert!(deserialized.title.unwrap().len() != 0);
    }

    #[test]
    fn create_comment_row_test() {
        use std::fs::File;
        use std::io::prelude::*;
        use serde_json;
        let mut contents = String::new();
        File::open("res/test/children-item.json")
            .and_then(|mut file| file.read_to_string(&mut contents))
            .unwrap();
        let deserialized: HnItem = serde_json::from_str(&contents).unwrap();
        let commentStr = create_comment_row(&1, &deserialized).unwrap();
        assert!(commentStr.contains("is not a valid concern. Unless you are planning"));
        assert!(commentStr.contains("cholantesh"));

    }
}<|endoftext|>