<commit_before>#[derive(Default, Debug)]
pub struct RegStatus {
    // CU
    coproc_usability: [bool; 4],

    // RP
    low_power: bool,

    // FR
    fpregs_extend: bool,

    // RE
    reverse_endian: bool,

    // DS
    diag_status: DiagnosticStatus,

    // IM
    interrupt_mask: InterruptMask,

    // KX
    kernel_mode_64bit: bool,

    // SX
    supervisor_mode_64bit: bool,

    // UX
    user_mode_64bit: bool,

    // KSU
    mode: Mode,

    // ERL
    error_level: ErrorLevel,

    // EXL
    exception_level: ExceptionLevel,

    // IE
    interrupt_enabled: bool,
}

impl RegStatus {
    pub fn write(&mut self, data: u32) {
        let coproc = data >> 28;
        self.coproc_usability[3] = (coproc & 0b1000) != 0;
        self.coproc_usability[2] = (coproc & 0b0100) != 0;
        self.coproc_usability[1] = (coproc & 0b0010) != 0;
        self.coproc_usability[0] = (coproc & 0b0001) != 0;

        self.low_power = ((data >> 27) & 0b1) != 0;
        self.fpregs_extend = ((data >> 26) & 0b1) != 0;
        self.reverse_endian = ((data >> 25) & 0b1) != 0;

        let diag_status = ((data >> 16) & 0xff) as u8;
        self.diag_status.write(diag_status);
        let interrupt_mask = ((data >> 8) & 0xff) as u8;
        self.interrupt_mask.write(interrupt_mask);

        self.kernel_mode_64bit = ((data >> 7) & 0b1) != 0;
        self.supervisor_mode_64bit = ((data >> 6) & 0b1) != 0;
        self.user_mode_64bit = ((data >> 5) & 0b1) != 0;

        let mode = ((data >> 3) & 0b11) as u8;
        self.mode = match mode {
            0b00 => Mode::Kernel,
            0b01 => Mode::Supervisor,
            0b10 => Mode::User,
            _ => panic!("Invalid mode {:#b}", mode),
        };

        self.error_level = if ((data >> 2) & 0b1) != 0 {
            ErrorLevel::Normal
        } else {
            ErrorLevel::Error
        };

        self.exception_level = if ((data >> 2) & 0b1) != 0 {
            ExceptionLevel::Normal
        } else {
            ExceptionLevel::Exception
        };

        self.interrupt_enabled = (data & 0b1) != 0;
    }
}

#[derive(Debug, Default)]
struct DiagnosticStatus {
    // ITS
    instruction_trace_support: bool,

    // BEV
    tlb_exception_vector_location: ExceptionVectorLocation,

    // TS
    tlb_shutdown: bool,

    // SR
    soft_reset_or_nmi_occurred: bool,

    // CH
    condition_bit: bool,
}

impl DiagnosticStatus {
    fn write(&mut self, data: u8) {
        self.instruction_trace_support = 0b10000000 != 0;

    }
}

#[derive(Debug, Default)]
struct InterruptMask {
    // IM(7)
    timer_interrupt: bool,

    // IM(6:2)
    external_interrupt: [bool; 5],

    // IM(1:0)
    software_interrupt: [bool; 2],
}

impl InterruptMask {
    fn write(&mut self, data: u8) {
        self.timer_interrupt = (data & 0b10000000) != 0;
        self.external_interrupt[4] = (data & 0b01000000) != 0;
        self.external_interrupt[3] = (data & 0b00100000) != 0;
        self.external_interrupt[2] = (data & 0b00010000) != 0;
        self.external_interrupt[1] = (data & 0b00001000) != 0;
        self.external_interrupt[0] = (data & 0b00000100) != 0;
        self.software_interrupt[1] = (data & 0b00000010) != 0;
        self.software_interrupt[0] = (data & 0b00000001) != 0;
    }
}

#[derive(Debug)]
enum Mode {
    // 10 User
    User,

    // 01 Supervisor
    Supervisor,

    // 00 Kernel
    Kernel,
}

impl Default for Mode {
    fn default() -> Mode {
        Mode::Kernel
    }
}

#[derive(Debug)]
enum ExceptionVectorLocation {
    Normal,
    Bootstrap,
}

impl Default for ExceptionVectorLocation {
    fn default() -> ExceptionVectorLocation {
        ExceptionVectorLocation::Normal
    }
}

#[derive(Debug)]
enum ErrorLevel {
    Normal,
    Error,
}

impl Default for ErrorLevel {
    fn default() -> ErrorLevel {
        ErrorLevel::Normal
    }
}

#[derive(Debug)]
enum ExceptionLevel {
    Normal,
    Exception,
}

impl Default for ExceptionLevel {
    fn default() -> ExceptionLevel {
        ExceptionLevel::Normal
    }
}
<commit_msg>Changed enums to use From and completed DiagnosticStatus<commit_after>#[derive(Default, Debug)]
pub struct RegStatus {
    // CU
    coproc_usability: [bool; 4],

    // RP
    low_power: bool,

    // FR
    fpregs_extend: bool,

    // RE
    reverse_endian: bool,

    // DS
    diag_status: DiagnosticStatus,

    // IM
    interrupt_mask: InterruptMask,

    // KX
    kernel_mode_64bit: bool,

    // SX
    supervisor_mode_64bit: bool,

    // UX
    user_mode_64bit: bool,

    // KSU
    mode: Mode,

    // ERL
    error_level: ErrorLevel,

    // EXL
    exception_level: ExceptionLevel,

    // IE
    interrupt_enabled: bool,
}

impl RegStatus {
    pub fn write(&mut self, data: u32) {
        let coproc = data >> 28;
        self.coproc_usability[3] = (coproc & 0b1000) != 0;
        self.coproc_usability[2] = (coproc & 0b0100) != 0;
        self.coproc_usability[1] = (coproc & 0b0010) != 0;
        self.coproc_usability[0] = (coproc & 0b0001) != 0;

        self.low_power = ((data >> 27) & 0b1) != 0;
        self.fpregs_extend = ((data >> 26) & 0b1) != 0;
        self.reverse_endian = ((data >> 25) & 0b1) != 0;

        let diag_status = ((data >> 16) & 0b111111111) as u16;
        self.diag_status.write(diag_status);
        let interrupt_mask = ((data >> 8) & 0xff) as u8;
        self.interrupt_mask.write(interrupt_mask);

        self.kernel_mode_64bit = ((data >> 7) & 0b1) != 0;
        self.supervisor_mode_64bit = ((data >> 6) & 0b1) != 0;
        self.user_mode_64bit = ((data >> 5) & 0b1) != 0;

        self.mode = data.into();

        self.error_level = data.into();
        self.exception_level = data.into();

        self.interrupt_enabled = (data & 0b1) != 0;
    }
}

#[derive(Debug, Default)]
struct DiagnosticStatus {
    // ITS
    instruction_trace_support: bool,

    // BEV
    tlb_exception_vector_location: ExceptionVectorLocation,

    // TS
    tlb_shutdown: bool,

    // SR
    soft_reset_or_nmi_occurred: bool,

    // CH
    condition_bit: bool,
}

impl DiagnosticStatus {
    fn write(&mut self, data: u16) {
        self.instruction_trace_support = 0b10000000 != 0;
        self.tlb_exception_vector_location = data.into();
        self.tlb_shutdown = 0b100000 != 0;
        self.soft_reset_or_nmi_occurred = 0b10000 != 0;
        self.condition_bit = 0b100 != 0;
    }
}

#[derive(Debug, Default)]
struct InterruptMask {
    // IM(7)
    timer_interrupt: bool,

    // IM(6:2)
    external_interrupt: [bool; 5],

    // IM(1:0)
    software_interrupt: [bool; 2],
}

impl InterruptMask {
    fn write(&mut self, data: u8) {
        self.timer_interrupt = (data & 0b10000000) != 0;
        self.external_interrupt[4] = (data & 0b01000000) != 0;
        self.external_interrupt[3] = (data & 0b00100000) != 0;
        self.external_interrupt[2] = (data & 0b00010000) != 0;
        self.external_interrupt[1] = (data & 0b00001000) != 0;
        self.external_interrupt[0] = (data & 0b00000100) != 0;
        self.software_interrupt[1] = (data & 0b00000010) != 0;
        self.software_interrupt[0] = (data & 0b00000001) != 0;
    }
}

#[derive(Debug)]
enum Mode {
    // 10 User
    User,

    // 01 Supervisor
    Supervisor,

    // 00 Kernel
    Kernel,
}

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

impl From<u32> for Mode {
    fn from(f: u32) -> Self {
        match (f >> 3) & 0b11 {
            0b00 => Mode::Kernel,
            0b01 => Mode::Supervisor,
            0b10 => Mode::User,
            _ => panic!("Invalid mode {:#b}", f),
        }
    }
}

#[derive(Debug)]
enum ExceptionVectorLocation {
    Normal,
    Bootstrap,
}

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

impl From<u16> for ExceptionVectorLocation {
    fn from(f: u16) -> Self {
        if f & 0b001000000 == 0 {
            ExceptionVectorLocation::Normal
        } else {
            ExceptionVectorLocation::Bootstrap
        }
    }
}

#[derive(Debug)]
enum ErrorLevel {
    Normal,
    Error,
}

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

impl From<u32> for ErrorLevel {
    fn from(f: u32) -> Self {
        if ((f >> 2) & 0b1) != 0 {
            ErrorLevel::Normal
        } else {
            ErrorLevel::Error
        }
    }
}

#[derive(Debug)]
enum ExceptionLevel {
    Normal,
    Exception,
}

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

impl From<u32> for ExceptionLevel {
    fn from(f: u32) -> Self {
        if ((f >> 2) & 0b1) != 0 {
            ExceptionLevel::Normal
        } else {
            ExceptionLevel::Exception
        }
    }
}
<|endoftext|>


<commit_before>// Bloom
//
// HTTP REST API caching middleware
// Copyright: 2017, Valerian Saliou <valerian@valeriansaliou.name>
// License: Mozilla Public License v2.0 (MPL v2.0)

use std::str;
use hyper::{Method, HttpVersion, StatusCode, Headers, Body};
use hyper::server::Request;
use futures::{Future, Stream};

use ::APP_CONF;
use ::APP_CACHE_STORE;
use header::janitor::HeaderJanitor;
use header::response_ignore::HeaderResponseBloomResponseIgnore;
use header::response_ttl::HeaderResponseBloomResponseTTL;

pub struct CacheWrite;

pub struct CacheWriteResult {
    pub body: Result<String, Option<String>>,
    pub value: Option<String>
}

impl CacheWrite {
    pub fn save(key: &str, req: &Request, status: &StatusCode,
        headers: &Headers, body: Body) -> CacheWriteResult {
        // TODO: unsafe for event loop, see: \
        // https://docs.rs/futures/0.1.14/futures/stream/trait.Stream.html\
        //   #method.wait
        // FIX: green-threads?

        // TODO: fix next() chunk infinite wait (if no. chunk > 1)

        let body_result = body
            .map_err(|_| ())
            .fold(Vec::new(), |mut vector, chunk| {
                vector.extend_from_slice(&chunk);

                Ok(vector)
            })
            .and_then(|vector| {
                String::from_utf8(vector).map_err(|_| ())
            })
            .wait();

        match body_result {
            Ok(body_value) => {
                debug!("checking whether to write cache for key: {}", key);

                if Self::is_cacheable(&req.method(), status, headers)
                    == true {
                    debug!("key: {} cacheable, writing cache", key);

                    // Acquire TTL from response, or fallback to default TTL
                    let ttl = match
                        headers.get::<HeaderResponseBloomResponseTTL>() {
                        None => APP_CONF.cache.ttl_default,
                        Some(value) => value.0
                    };

                    // Generate storable value
                    let value = format!("{}\n{}\n{}",
                        CacheWrite::generate_chain_banner(&req.version(),
                            status),
                        CacheWrite::generate_chain_headers(headers),
                        body_value);

                    // Write to cache
                    match APP_CACHE_STORE.set(key, &value, ttl) {
                        Ok(_) => {
                            debug!("wrote cache for key: {}", key);

                            CacheWriteResult {
                                body: Ok(body_value),
                                value: Some(value)
                            }
                        }
                        Err(err) => {
                            warn!("could not write cache for key: {} \
                                    because: {}", key, err);

                            CacheWriteResult {
                                body: Err(Some(body_value)),
                                value: Some(value)
                            }
                        }
                    }
                } else {
                    debug!("key: {} not cacheable, ignoring", key);

                    // Not cacheable, ignore
                    CacheWriteResult {
                        body: Err(Some(body_value)),
                        value: None
                    }
                }
            }
            _ => {
                error!("failed unwrapping body value for key: {}, ignoring",
                    key);

                CacheWriteResult {
                    body: Err(None),
                    value: None
                }
            }
        }
    }

    fn is_cacheable(method: &Method, status: &StatusCode, headers: &Headers)
        -> bool {
        Self::is_cacheable_method(method) == true &&
            Self::is_cacheable_status(status) == true &&
            Self::is_cacheable_response(headers) == true
    }

    fn is_cacheable_method(method: &Method) -> bool {
        match *method {
            Method::Get | Method::Head => true,
            _ => false
        }
    }

    fn is_cacheable_status(status: &StatusCode) -> bool {
        match *status {
            StatusCode::Ok
            | StatusCode::NonAuthoritativeInformation
            | StatusCode::NoContent
            | StatusCode::ResetContent
            | StatusCode::PartialContent
            | StatusCode::MultiStatus
            | StatusCode::AlreadyReported
            | StatusCode::MultipleChoices
            | StatusCode::MovedPermanently
            | StatusCode::Found
            | StatusCode::SeeOther
            | StatusCode::PermanentRedirect
            | StatusCode::Unauthorized
            | StatusCode::PaymentRequired
            | StatusCode::Forbidden
            | StatusCode::NotFound
            | StatusCode::MethodNotAllowed
            | StatusCode::Gone
            | StatusCode::UriTooLong
            | StatusCode::Locked
            | StatusCode::FailedDependency
            | StatusCode::NotImplemented => {
                true
            }
            _ => {
                false
            }
        }
    }

    fn is_cacheable_response(headers: &Headers) -> bool {
        // Ignore responses with 'Bloom-Response-Ignore'
        headers.has::<HeaderResponseBloomResponseIgnore>() == false
    }

    fn generate_chain_banner(version: &HttpVersion, status: &StatusCode) ->
        String {
        format!("{} {}", version, status)
    }

    fn generate_chain_headers(headers: &Headers) -> String {
        headers.iter()
            .filter(|header_view| {
                HeaderJanitor::is_contextual(&header_view) == false
            })
            .map(|header_view| {
                format!("{}: {}\n", header_view.name(),
                    header_view.value_string())
            })
            .collect()
    }
}

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

    #[test]
    fn it_asserts_valid_cacheable_method() {
        assert_eq!(CacheWrite::is_cacheable_method(&Method::Get),
            true, "GET");
        assert_eq!(CacheWrite::is_cacheable_method(&Method::Head),
            true, "HEAD");
        assert_eq!(CacheWrite::is_cacheable_method(&Method::Options),
            false, "OPTIONS");
        assert_eq!(CacheWrite::is_cacheable_method(&Method::Post),
            false, "POST");
    }

    #[test]
    fn it_asserts_valid_cacheable_status() {
        assert_eq!(CacheWrite::is_cacheable_status(&StatusCode::Ok),
            true, "200 OK");
        assert_eq!(CacheWrite::is_cacheable_status(&StatusCode::Unauthorized),
            true, "401 OK");
        assert_eq!(CacheWrite::is_cacheable_status(&StatusCode::BadRequest),
            false, "400 Bad Request");
        assert_eq!(CacheWrite::is_cacheable_status(&StatusCode::InternalServerError),
            false, "500 Internal Server Error");
    }
}
<commit_msg>Notice<commit_after>// Bloom
//
// HTTP REST API caching middleware
// Copyright: 2017, Valerian Saliou <valerian@valeriansaliou.name>
// License: Mozilla Public License v2.0 (MPL v2.0)

use std::str;
use hyper::{Method, HttpVersion, StatusCode, Headers, Body};
use hyper::server::Request;
use futures::{Future, Stream};

use ::APP_CONF;
use ::APP_CACHE_STORE;
use header::janitor::HeaderJanitor;
use header::response_ignore::HeaderResponseBloomResponseIgnore;
use header::response_ttl::HeaderResponseBloomResponseTTL;

pub struct CacheWrite;

pub struct CacheWriteResult {
    pub body: Result<String, Option<String>>,
    pub value: Option<String>
}

impl CacheWrite {
    pub fn save(key: &str, req: &Request, status: &StatusCode,
        headers: &Headers, body: Body) -> CacheWriteResult {
        // TODO: wait() is unsafe for event loop, see: \
        // https://docs.rs/futures/0.1.14/futures/stream/trait.Stream.html\
        //   #method.wait
        // FIX: green-threads?

        // TODO: fix next() chunk infinite wait (if no. chunk > 1)

        let body_result = body
            .map_err(|_| ())
            .fold(Vec::new(), |mut vector, chunk| {
                vector.extend_from_slice(&chunk);

                Ok(vector)
            })
            .and_then(|vector| {
                String::from_utf8(vector).map_err(|_| ())
            })
            .wait();

        match body_result {
            Ok(body_value) => {
                debug!("checking whether to write cache for key: {}", key);

                if Self::is_cacheable(&req.method(), status, headers)
                    == true {
                    debug!("key: {} cacheable, writing cache", key);

                    // Acquire TTL from response, or fallback to default TTL
                    let ttl = match
                        headers.get::<HeaderResponseBloomResponseTTL>() {
                        None => APP_CONF.cache.ttl_default,
                        Some(value) => value.0
                    };

                    // Generate storable value
                    let value = format!("{}\n{}\n{}",
                        CacheWrite::generate_chain_banner(&req.version(),
                            status),
                        CacheWrite::generate_chain_headers(headers),
                        body_value);

                    // Write to cache
                    match APP_CACHE_STORE.set(key, &value, ttl) {
                        Ok(_) => {
                            debug!("wrote cache for key: {}", key);

                            CacheWriteResult {
                                body: Ok(body_value),
                                value: Some(value)
                            }
                        }
                        Err(err) => {
                            warn!("could not write cache for key: {} \
                                    because: {}", key, err);

                            CacheWriteResult {
                                body: Err(Some(body_value)),
                                value: Some(value)
                            }
                        }
                    }
                } else {
                    debug!("key: {} not cacheable, ignoring", key);

                    // Not cacheable, ignore
                    CacheWriteResult {
                        body: Err(Some(body_value)),
                        value: None
                    }
                }
            }
            _ => {
                error!("failed unwrapping body value for key: {}, ignoring",
                    key);

                CacheWriteResult {
                    body: Err(None),
                    value: None
                }
            }
        }
    }

    fn is_cacheable(method: &Method, status: &StatusCode, headers: &Headers)
        -> bool {
        Self::is_cacheable_method(method) == true &&
            Self::is_cacheable_status(status) == true &&
            Self::is_cacheable_response(headers) == true
    }

    fn is_cacheable_method(method: &Method) -> bool {
        match *method {
            Method::Get | Method::Head => true,
            _ => false
        }
    }

    fn is_cacheable_status(status: &StatusCode) -> bool {
        match *status {
            StatusCode::Ok
            | StatusCode::NonAuthoritativeInformation
            | StatusCode::NoContent
            | StatusCode::ResetContent
            | StatusCode::PartialContent
            | StatusCode::MultiStatus
            | StatusCode::AlreadyReported
            | StatusCode::MultipleChoices
            | StatusCode::MovedPermanently
            | StatusCode::Found
            | StatusCode::SeeOther
            | StatusCode::PermanentRedirect
            | StatusCode::Unauthorized
            | StatusCode::PaymentRequired
            | StatusCode::Forbidden
            | StatusCode::NotFound
            | StatusCode::MethodNotAllowed
            | StatusCode::Gone
            | StatusCode::UriTooLong
            | StatusCode::Locked
            | StatusCode::FailedDependency
            | StatusCode::NotImplemented => {
                true
            }
            _ => {
                false
            }
        }
    }

    fn is_cacheable_response(headers: &Headers) -> bool {
        // Ignore responses with 'Bloom-Response-Ignore'
        headers.has::<HeaderResponseBloomResponseIgnore>() == false
    }

    fn generate_chain_banner(version: &HttpVersion, status: &StatusCode) ->
        String {
        format!("{} {}", version, status)
    }

    fn generate_chain_headers(headers: &Headers) -> String {
        headers.iter()
            .filter(|header_view| {
                HeaderJanitor::is_contextual(&header_view) == false
            })
            .map(|header_view| {
                format!("{}: {}\n", header_view.name(),
                    header_view.value_string())
            })
            .collect()
    }
}

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

    #[test]
    fn it_asserts_valid_cacheable_method() {
        assert_eq!(CacheWrite::is_cacheable_method(&Method::Get),
            true, "GET");
        assert_eq!(CacheWrite::is_cacheable_method(&Method::Head),
            true, "HEAD");
        assert_eq!(CacheWrite::is_cacheable_method(&Method::Options),
            false, "OPTIONS");
        assert_eq!(CacheWrite::is_cacheable_method(&Method::Post),
            false, "POST");
    }

    #[test]
    fn it_asserts_valid_cacheable_status() {
        assert_eq!(CacheWrite::is_cacheable_status(&StatusCode::Ok),
            true, "200 OK");
        assert_eq!(CacheWrite::is_cacheable_status(&StatusCode::Unauthorized),
            true, "401 OK");
        assert_eq!(CacheWrite::is_cacheable_status(&StatusCode::BadRequest),
            false, "400 Bad Request");
        assert_eq!(CacheWrite::is_cacheable_status(&StatusCode::InternalServerError),
            false, "500 Internal Server Error");
    }
}
<|endoftext|>


<commit_before>use std::io;

use crate::backend::Backend;
use crate::buffer::Cell;
use crate::layout::Rect;
use crate::style::{Color, Modifier, Style};
use crate::symbols::{bar, block};
#[cfg(unix)]
use crate::symbols::{line, DOT};
#[cfg(unix)]
use pancurses::{chtype, ToChtype};
use unicode_segmentation::UnicodeSegmentation;

pub struct CursesBackend {
    curses: easycurses::EasyCurses,
}

impl CursesBackend {
    pub fn new() -> Option<CursesBackend> {
        let curses = easycurses::EasyCurses::initialize_system()?;
        Some(CursesBackend { curses })
    }

    pub fn with_curses(curses: easycurses::EasyCurses) -> CursesBackend {
        CursesBackend { curses }
    }

    pub fn get_curses(&self) -> &easycurses::EasyCurses {
        &self.curses
    }

    pub fn get_curses_mut(&mut self) -> &mut easycurses::EasyCurses {
        &mut self.curses
    }
}

impl Backend for CursesBackend {
    fn draw<'a, I>(&mut self, content: I) -> io::Result<()>
    where
        I: Iterator<Item = (u16, u16, &'a Cell)>,
    {
        let mut last_col = 0;
        let mut last_row = 0;
        let mut style = Style {
            fg: Color::Reset,
            bg: Color::Reset,
            modifier: Modifier::empty(),
        };
        let mut curses_style = CursesStyle {
            fg: easycurses::Color::White,
            bg: easycurses::Color::Black,
        };
        let mut update_color = false;
        for (col, row, cell) in content {
            // eprintln!("{:?}", cell);
            if row != last_row || col != last_col + 1 {
                self.curses.move_rc(i32::from(row), i32::from(col));
            }
            last_col = col;
            last_row = row;
            if cell.style.modifier != style.modifier {
                apply_modifier_diff(&mut self.curses.win, style.modifier, cell.style.modifier);
                style.modifier = cell.style.modifier;
            };
            if cell.style.fg != style.fg {
                update_color = true;
                if let Some(ccolor) = cell.style.fg.into() {
                    style.fg = cell.style.fg;
                    curses_style.fg = ccolor;
                } else {
                    style.fg = Color::White;
                    curses_style.fg = easycurses::Color::White;
                }
            };
            if cell.style.bg != style.bg {
                update_color = true;
                if let Some(ccolor) = cell.style.bg.into() {
                    style.bg = cell.style.bg;
                    curses_style.bg = ccolor;
                } else {
                    style.bg = Color::Black;
                    curses_style.bg = easycurses::Color::Black;
                }
            };
            if update_color {
                self.curses
                    .set_color_pair(easycurses::ColorPair::new(curses_style.fg, curses_style.bg));
            };
            update_color = false;
            draw(&mut self.curses, cell.symbol.as_str());
        }
        self.curses.win.attrset(pancurses::Attribute::Normal);
        self.curses.set_color_pair(easycurses::ColorPair::new(
            easycurses::Color::White,
            easycurses::Color::Black,
        ));
        Ok(())
    }
    fn hide_cursor(&mut self) -> io::Result<()> {
        self.curses
            .set_cursor_visibility(easycurses::CursorVisibility::Invisible);
        Ok(())
    }
    fn show_cursor(&mut self) -> io::Result<()> {
        self.curses
            .set_cursor_visibility(easycurses::CursorVisibility::Visible);
        Ok(())
    }
    fn get_cursor(&mut self) -> io::Result<(u16, u16)> {
        let (y, x) = self.curses.get_cursor_rc();
        Ok((x as u16, y as u16))
    }
    fn set_cursor(&mut self, x: u16, y: u16) -> io::Result<()> {
        self.curses.move_rc(i32::from(y), i32::from(x));
        Ok(())
    }
    fn clear(&mut self) -> io::Result<()> {
        self.curses.clear();
        // self.curses.refresh();
        Ok(())
    }
    fn size(&self) -> Result<Rect, io::Error> {
        let (nrows, ncols) = self.curses.get_row_col_count();
        Ok(Rect::new(0, 0, ncols as u16, nrows as u16))
    }
    fn flush(&mut self) -> io::Result<()> {
        self.curses.refresh();
        Ok(())
    }
}

struct CursesStyle {
    fg: easycurses::Color,
    bg: easycurses::Color,
}

#[cfg(unix)]
/// Deals with lack of unicode support for ncurses on unix
fn draw(curses: &mut easycurses::EasyCurses, symbol: &str) {
    for grapheme in symbol.graphemes(true) {
        let ch = match grapheme {
            line::TOP_RIGHT => pancurses::ACS_URCORNER(),
            line::VERTICAL => pancurses::ACS_VLINE(),
            line::HORIZONTAL => pancurses::ACS_HLINE(),
            line::TOP_LEFT => pancurses::ACS_ULCORNER(),
            line::BOTTOM_RIGHT => pancurses::ACS_LRCORNER(),
            line::BOTTOM_LEFT => pancurses::ACS_LLCORNER(),
            line::VERTICAL_LEFT => pancurses::ACS_RTEE(),
            line::VERTICAL_RIGHT => pancurses::ACS_LTEE(),
            line::HORIZONTAL_DOWN => pancurses::ACS_TTEE(),
            line::HORIZONTAL_UP => pancurses::ACS_BTEE(),
            block::FULL => pancurses::ACS_BLOCK(),
            block::SEVEN_EIGHTHS => pancurses::ACS_BLOCK(),
            block::THREE_QUATERS => pancurses::ACS_BLOCK(),
            block::FIVE_EIGHTHS => pancurses::ACS_BLOCK(),
            block::HALF => pancurses::ACS_BLOCK(),
            block::THREE_EIGHTHS => ' ' as chtype,
            block::ONE_QUATER => ' ' as chtype,
            block::ONE_EIGHTH => ' ' as chtype,
            bar::SEVEN_EIGHTHS => pancurses::ACS_BLOCK(),
            bar::THREE_QUATERS => pancurses::ACS_BLOCK(),
            bar::FIVE_EIGHTHS => pancurses::ACS_BLOCK(),
            bar::HALF => pancurses::ACS_BLOCK(),
            bar::THREE_EIGHTHS => pancurses::ACS_S9(),
            bar::ONE_QUATER => pancurses::ACS_S9(),
            bar::ONE_EIGHTH => pancurses::ACS_S9(),
            DOT => pancurses::ACS_BULLET(),
            unicode_char => {
                if unicode_char.is_ascii() {
                    let mut chars = unicode_char.chars();
                    if let Some(ch) = chars.next() {
                        ch.to_chtype()
                    } else {
                        pancurses::ACS_BLOCK()
                    }
                } else {
                    pancurses::ACS_BLOCK()
                }
            }
        };
        curses.win.addch(ch);
    }
}

#[cfg(windows)]
fn draw(curses: &mut easycurses::EasyCurses, symbol: &str) {
    for grapheme in symbol.graphemes(true) {
        let ch = match grapheme {
            block::SEVEN_EIGHTHS => block::FULL,
            block::THREE_QUATERS => block::FULL,
            block::FIVE_EIGHTHS => block::HALF,
            block::THREE_EIGHTHS => block::HALF,
            block::ONE_QUATER => block::HALF,
            block::ONE_EIGHTH => " ",
            bar::SEVEN_EIGHTHS => bar::FULL,
            bar::THREE_QUATERS => bar::FULL,
            bar::FIVE_EIGHTHS => bar::HALF,
            bar::THREE_EIGHTHS => bar::HALF,
            bar::ONE_QUATER => bar::HALF,
            bar::ONE_EIGHTH => " ",
            ch => ch,
        };
        // curses.win.addch(ch);
        curses.print(ch);
    }
}

impl From<Color> for Option<easycurses::Color> {
    fn from(color: Color) -> Option<easycurses::Color> {
        match color {
            Color::Reset => None,
            Color::Black => Some(easycurses::Color::Black),
            Color::Red | Color::LightRed => Some(easycurses::Color::Red),
            Color::Green | Color::LightGreen => Some(easycurses::Color::Green),
            Color::Yellow | Color::LightYellow => Some(easycurses::Color::Yellow),
            Color::Magenta | Color::LightMagenta => Some(easycurses::Color::Magenta),
            Color::Cyan | Color::LightCyan => Some(easycurses::Color::Cyan),
            Color::White | Color::Gray | Color::DarkGray => Some(easycurses::Color::White),
            Color::Blue | Color::LightBlue => Some(easycurses::Color::Blue),
            Color::Indexed(_) => None,
            Color::Rgb(_, _, _) => None,
        }
    }
}

fn apply_modifier_diff(win: &mut pancurses::Window, from: Modifier, to: Modifier) {
    remove_modifier(win, from - to);
    add_modifier(win, to - from);
}

fn remove_modifier(win: &mut pancurses::Window, remove: Modifier) {
    if remove.contains(Modifier::BOLD) {
        win.attroff(pancurses::Attribute::Bold);
    }
    if remove.contains(Modifier::DIM) {
        win.attroff(pancurses::Attribute::Dim);
    }
    if remove.contains(Modifier::ITALIC) {
        win.attroff(pancurses::Attribute::Italic);
    }
    if remove.contains(Modifier::UNDERLINED) {
        win.attroff(pancurses::Attribute::Underline);
    }
    if remove.contains(Modifier::SLOW_BLINK) || remove.contains(Modifier::RAPID_BLINK) {
        win.attroff(pancurses::Attribute::Blink);
    }
    if remove.contains(Modifier::REVERSED) {
        win.attroff(pancurses::Attribute::Reverse);
    }
    if remove.contains(Modifier::HIDDEN) {
        win.attroff(pancurses::Attribute::Invisible);
    }
    if remove.contains(Modifier::CROSSED_OUT) {
        win.attroff(pancurses::Attribute::Strikeout);
    }
}

fn add_modifier(win: &mut pancurses::Window, add: Modifier) {
    if add.contains(Modifier::BOLD) {
        win.attron(pancurses::Attribute::Bold);
    }
    if add.contains(Modifier::DIM) {
        win.attron(pancurses::Attribute::Dim);
    }
    if add.contains(Modifier::ITALIC) {
        win.attron(pancurses::Attribute::Italic);
    }
    if add.contains(Modifier::UNDERLINED) {
        win.attron(pancurses::Attribute::Underline);
    }
    if add.contains(Modifier::SLOW_BLINK) || add.contains(Modifier::RAPID_BLINK) {
        win.attron(pancurses::Attribute::Blink);
    }
    if add.contains(Modifier::REVERSED) {
        win.attron(pancurses::Attribute::Reverse);
    }
    if add.contains(Modifier::HIDDEN) {
        win.attron(pancurses::Attribute::Invisible);
    }
    if add.contains(Modifier::CROSSED_OUT) {
        win.attron(pancurses::Attribute::Strikeout);
    }
}
<commit_msg>typo in curses.rs<commit_after>use std::io;

use crate::backend::Backend;
use crate::buffer::Cell;
use crate::layout::Rect;
use crate::style::{Color, Modifier, Style};
use crate::symbols::{bar, block};
#[cfg(unix)]
use crate::symbols::{line, DOT};
#[cfg(unix)]
use pancurses::{chtype, ToChtype};
use unicode_segmentation::UnicodeSegmentation;

pub struct CursesBackend {
    curses: easycurses::EasyCurses,
}

impl CursesBackend {
    pub fn new() -> Option<CursesBackend> {
        let curses = easycurses::EasyCurses::initialize_system()?;
        Some(CursesBackend { curses })
    }

    pub fn with_curses(curses: easycurses::EasyCurses) -> CursesBackend {
        CursesBackend { curses }
    }

    pub fn get_curses(&self) -> &easycurses::EasyCurses {
        &self.curses
    }

    pub fn get_curses_mut(&mut self) -> &mut easycurses::EasyCurses {
        &mut self.curses
    }
}

impl Backend for CursesBackend {
    fn draw<'a, I>(&mut self, content: I) -> io::Result<()>
    where
        I: Iterator<Item = (u16, u16, &'a Cell)>,
    {
        let mut last_col = 0;
        let mut last_row = 0;
        let mut style = Style {
            fg: Color::Reset,
            bg: Color::Reset,
            modifier: Modifier::empty(),
        };
        let mut curses_style = CursesStyle {
            fg: easycurses::Color::White,
            bg: easycurses::Color::Black,
        };
        let mut update_color = false;
        for (col, row, cell) in content {
            // eprintln!("{:?}", cell);
            if row != last_row || col != last_col + 1 {
                self.curses.move_rc(i32::from(row), i32::from(col));
            }
            last_col = col;
            last_row = row;
            if cell.style.modifier != style.modifier {
                apply_modifier_diff(&mut self.curses.win, style.modifier, cell.style.modifier);
                style.modifier = cell.style.modifier;
            };
            if cell.style.fg != style.fg {
                update_color = true;
                if let Some(ccolor) = cell.style.fg.into() {
                    style.fg = cell.style.fg;
                    curses_style.fg = ccolor;
                } else {
                    style.fg = Color::White;
                    curses_style.fg = easycurses::Color::White;
                }
            };
            if cell.style.bg != style.bg {
                update_color = true;
                if let Some(ccolor) = cell.style.bg.into() {
                    style.bg = cell.style.bg;
                    curses_style.bg = ccolor;
                } else {
                    style.bg = Color::Black;
                    curses_style.bg = easycurses::Color::Black;
                }
            };
            if update_color {
                self.curses
                    .set_color_pair(easycurses::ColorPair::new(curses_style.fg, curses_style.bg));
            };
            update_color = false;
            draw(&mut self.curses, cell.symbol.as_str());
        }
        self.curses.win.attrset(pancurses::Attribute::Normal);
        self.curses.set_color_pair(easycurses::ColorPair::new(
            easycurses::Color::White,
            easycurses::Color::Black,
        ));
        Ok(())
    }
    fn hide_cursor(&mut self) -> io::Result<()> {
        self.curses
            .set_cursor_visibility(easycurses::CursorVisibility::Invisible);
        Ok(())
    }
    fn show_cursor(&mut self) -> io::Result<()> {
        self.curses
            .set_cursor_visibility(easycurses::CursorVisibility::Visible);
        Ok(())
    }
    fn get_cursor(&mut self) -> io::Result<(u16, u16)> {
        let (y, x) = self.curses.get_cursor_rc();
        Ok((x as u16, y as u16))
    }
    fn set_cursor(&mut self, x: u16, y: u16) -> io::Result<()> {
        self.curses.move_rc(i32::from(y), i32::from(x));
        Ok(())
    }
    fn clear(&mut self) -> io::Result<()> {
        self.curses.clear();
        // self.curses.refresh();
        Ok(())
    }
    fn size(&self) -> Result<Rect, io::Error> {
        let (nrows, ncols) = self.curses.get_row_col_count();
        Ok(Rect::new(0, 0, ncols as u16, nrows as u16))
    }
    fn flush(&mut self) -> io::Result<()> {
        self.curses.refresh();
        Ok(())
    }
}

struct CursesStyle {
    fg: easycurses::Color,
    bg: easycurses::Color,
}

#[cfg(unix)]
/// Deals with lack of unicode support for ncurses on unix
fn draw(curses: &mut easycurses::EasyCurses, symbol: &str) {
    for grapheme in symbol.graphemes(true) {
        let ch = match grapheme {
            line::TOP_RIGHT => pancurses::ACS_URCORNER(),
            line::VERTICAL => pancurses::ACS_VLINE(),
            line::HORIZONTAL => pancurses::ACS_HLINE(),
            line::TOP_LEFT => pancurses::ACS_ULCORNER(),
            line::BOTTOM_RIGHT => pancurses::ACS_LRCORNER(),
            line::BOTTOM_LEFT => pancurses::ACS_LLCORNER(),
            line::VERTICAL_LEFT => pancurses::ACS_RTEE(),
            line::VERTICAL_RIGHT => pancurses::ACS_LTEE(),
            line::HORIZONTAL_DOWN => pancurses::ACS_TTEE(),
            line::HORIZONTAL_UP => pancurses::ACS_BTEE(),
            block::FULL => pancurses::ACS_BLOCK(),
            block::SEVEN_EIGHTHS => pancurses::ACS_BLOCK(),
            block::THREE_QUARTERS => pancurses::ACS_BLOCK(),
            block::FIVE_EIGHTHS => pancurses::ACS_BLOCK(),
            block::HALF => pancurses::ACS_BLOCK(),
            block::THREE_EIGHTHS => ' ' as chtype,
            block::ONE_QUARTER => ' ' as chtype,
            block::ONE_EIGHTH => ' ' as chtype,
            bar::SEVEN_EIGHTHS => pancurses::ACS_BLOCK(),
            bar::THREE_QUARTERS => pancurses::ACS_BLOCK(),
            bar::FIVE_EIGHTHS => pancurses::ACS_BLOCK(),
            bar::HALF => pancurses::ACS_BLOCK(),
            bar::THREE_EIGHTHS => pancurses::ACS_S9(),
            bar::ONE_QUARTER => pancurses::ACS_S9(),
            bar::ONE_EIGHTH => pancurses::ACS_S9(),
            DOT => pancurses::ACS_BULLET(),
            unicode_char => {
                if unicode_char.is_ascii() {
                    let mut chars = unicode_char.chars();
                    if let Some(ch) = chars.next() {
                        ch.to_chtype()
                    } else {
                        pancurses::ACS_BLOCK()
                    }
                } else {
                    pancurses::ACS_BLOCK()
                }
            }
        };
        curses.win.addch(ch);
    }
}

#[cfg(windows)]
fn draw(curses: &mut easycurses::EasyCurses, symbol: &str) {
    for grapheme in symbol.graphemes(true) {
        let ch = match grapheme {
            block::SEVEN_EIGHTHS => block::FULL,
            block::THREE_QUARTERS => block::FULL,
            block::FIVE_EIGHTHS => block::HALF,
            block::THREE_EIGHTHS => block::HALF,
            block::ONE_QUARTER => block::HALF,
            block::ONE_EIGHTH => " ",
            bar::SEVEN_EIGHTHS => bar::FULL,
            bar::THREE_QUARTERS => bar::FULL,
            bar::FIVE_EIGHTHS => bar::HALF,
            bar::THREE_EIGHTHS => bar::HALF,
            bar::ONE_QUARTER => bar::HALF,
            bar::ONE_EIGHTH => " ",
            ch => ch,
        };
        // curses.win.addch(ch);
        curses.print(ch);
    }
}

impl From<Color> for Option<easycurses::Color> {
    fn from(color: Color) -> Option<easycurses::Color> {
        match color {
            Color::Reset => None,
            Color::Black => Some(easycurses::Color::Black),
            Color::Red | Color::LightRed => Some(easycurses::Color::Red),
            Color::Green | Color::LightGreen => Some(easycurses::Color::Green),
            Color::Yellow | Color::LightYellow => Some(easycurses::Color::Yellow),
            Color::Magenta | Color::LightMagenta => Some(easycurses::Color::Magenta),
            Color::Cyan | Color::LightCyan => Some(easycurses::Color::Cyan),
            Color::White | Color::Gray | Color::DarkGray => Some(easycurses::Color::White),
            Color::Blue | Color::LightBlue => Some(easycurses::Color::Blue),
            Color::Indexed(_) => None,
            Color::Rgb(_, _, _) => None,
        }
    }
}

fn apply_modifier_diff(win: &mut pancurses::Window, from: Modifier, to: Modifier) {
    remove_modifier(win, from - to);
    add_modifier(win, to - from);
}

fn remove_modifier(win: &mut pancurses::Window, remove: Modifier) {
    if remove.contains(Modifier::BOLD) {
        win.attroff(pancurses::Attribute::Bold);
    }
    if remove.contains(Modifier::DIM) {
        win.attroff(pancurses::Attribute::Dim);
    }
    if remove.contains(Modifier::ITALIC) {
        win.attroff(pancurses::Attribute::Italic);
    }
    if remove.contains(Modifier::UNDERLINED) {
        win.attroff(pancurses::Attribute::Underline);
    }
    if remove.contains(Modifier::SLOW_BLINK) || remove.contains(Modifier::RAPID_BLINK) {
        win.attroff(pancurses::Attribute::Blink);
    }
    if remove.contains(Modifier::REVERSED) {
        win.attroff(pancurses::Attribute::Reverse);
    }
    if remove.contains(Modifier::HIDDEN) {
        win.attroff(pancurses::Attribute::Invisible);
    }
    if remove.contains(Modifier::CROSSED_OUT) {
        win.attroff(pancurses::Attribute::Strikeout);
    }
}

fn add_modifier(win: &mut pancurses::Window, add: Modifier) {
    if add.contains(Modifier::BOLD) {
        win.attron(pancurses::Attribute::Bold);
    }
    if add.contains(Modifier::DIM) {
        win.attron(pancurses::Attribute::Dim);
    }
    if add.contains(Modifier::ITALIC) {
        win.attron(pancurses::Attribute::Italic);
    }
    if add.contains(Modifier::UNDERLINED) {
        win.attron(pancurses::Attribute::Underline);
    }
    if add.contains(Modifier::SLOW_BLINK) || add.contains(Modifier::RAPID_BLINK) {
        win.attron(pancurses::Attribute::Blink);
    }
    if add.contains(Modifier::REVERSED) {
        win.attron(pancurses::Attribute::Reverse);
    }
    if add.contains(Modifier::HIDDEN) {
        win.attron(pancurses::Attribute::Invisible);
    }
    if add.contains(Modifier::CROSSED_OUT) {
        win.attron(pancurses::Attribute::Strikeout);
    }
}
<|endoftext|>


<commit_before>// Copyright © 2016, Canal TP and/or its affiliates. All rights reserved.
//
// This file is part of Navitia,
//     the software to build cool stuff with public transport.
//
// Hope you'll enjoy and contribute to this project,
//     powered by Canal TP (www.canaltp.fr).
// Help us simplify mobility and open public transport:
//     a non ending quest to the responsive locomotion way of traveling!
//
// LICENCE: This program is free software; you can redistribute it
// and/or modify it under the terms of the GNU Affero General Public
// License as published by the Free Software Foundation, either
// version 3 of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public
// License along with this program. If not, see
// <http://www.gnu.org/licenses/>.
//
// Stay tuned using
// twitter @navitia
// IRC #navitia on freenode
// https://groups.google.com/d/forum/navitia
// www.navitia.io

extern crate docopt;
extern crate csv;
extern crate rustc_serialize;
extern crate mimir;
#[macro_use]
extern crate log;
extern crate geo;

use std::path::Path;
use mimir::rubber::Rubber;
use mimir::objects::Admin;
use std::fs;
use std::rc::Rc;
use std::collections::BTreeMap;

type AdminFromInsee = BTreeMap<String, Rc<Admin>>;

#[derive(RustcDecodable, RustcEncodable)]
pub struct Bano {
    pub id: String,
    pub nb: String,
    pub street: String,
    pub zip: String,
    pub city: String,
    pub src: String,
    pub lat: f64,
    pub lon: f64,
}

impl Bano {
    pub fn insee(&self) -> &str {
        assert!(self.id.len() >= 5);
        self.id[..5].trim_left_matches('0')
    }
    pub fn fantoir(&self) -> &str {
        assert!(self.id.len() >= 10);
        &self.id[..10]
    }
    pub fn into_addr(self, admins: &AdminFromInsee) -> mimir::Addr {
        let street_name = format!("{} ({})", self.street, self.city);
        let addr_name = format!("{} {}", self.nb, self.street);
        let addr_label = format!("{} ({})", addr_name, self.city);
        let street_id = format!("street:{}", self.fantoir().to_string());
        let admin = admins.get(&format!("admin:fr:{}", self.insee()));

        let street = mimir::Street {
            id: street_id,
            street_name: self.street,
            label: street_name.to_string(),
            administrative_regions: admin.map_or(vec![], |a| vec![a.clone()]),
            weight: 1,
            zip_codes: vec![self.zip.clone()],
            coord: mimir::Coord::new(self.lat, self.lon),
        };
        mimir::Addr {
            id: format!("addr:{};{}", self.lon, self.lat),
            house_number: self.nb,
            street: street,
            label: addr_label,
            coord: mimir::Coord::new(self.lat, self.lon),
            weight: 1,
            zip_codes: vec![self.zip.clone()],
        }
    }
}

fn index_bano<I>(cnx_string: &str, dataset: &str, files: I)
    where I: Iterator<Item = std::path::PathBuf>
{
    let doc_type = "addr";
    let mut rubber = Rubber::new(cnx_string);

    let admins_by_insee = rubber.get_admins_from_dataset(dataset)
        .unwrap_or_else(|err| {
            info!("Administratives regions not found in es db for dataset {}. (error: {})",
                  dataset,
                  err);
            vec![]
        })
        .into_iter()
        .map(|mut a| {
            a.boundary = None; // to save some space we remove the admin boundary
            (a.id.to_string(), Rc::new(a))
        })
        .collect();

    let addr_index = rubber.make_index(doc_type, dataset).unwrap();
    info!("Add data in elasticsearch db.");
    for f in files {
        info!("importing {:?}...", &f);
        let mut rdr = csv::Reader::from_file(&f).unwrap().has_headers(false);

        let iter = rdr.decode().map(|r| {
            let b: Bano = r.unwrap();
            b.into_addr(&admins_by_insee)
        });
        match rubber.bulk_index(&addr_index, iter) {
            Err(e) => panic!("failed to bulk insert file {:?} because: {}", &f, e),
            Ok(nb) => info!("importing {:?}: {} addresses added.", &f, nb),
        }
    }
    rubber.publish_index(doc_type, dataset, addr_index, true).unwrap();
}

#[derive(RustcDecodable, Debug)]
struct Args {
    flag_input: String,
    flag_connection_string: String,
    flag_dataset: String,
}

static USAGE: &'static str = "
Usage:
    bano2mimir --input=<input> [--connection-string=<connection-string>] [--dataset=<dataset>]

    -i, --input=<input>           Bano files. Can be either a directory or a file.
    -c, --connection-string=<connection-string>
                                  Elasticsearch parameters, [default: http://localhost:9200/munin]
    -d, --dataset=<dataset>       Name of the dataset, [default: fr]
";

fn main() {
    mimir::logger_init().unwrap();
    info!("importing bano into Mimir");

    let args: Args = docopt::Docopt::new(USAGE)
        .and_then(|d| d.decode())
        .unwrap_or_else(|e| e.exit());

    let file_path = Path::new(&args.flag_input);
    if file_path.is_dir() {
        let paths: std::fs::ReadDir = fs::read_dir(&args.flag_input).unwrap();
        index_bano(&args.flag_connection_string,
                   &args.flag_dataset,
                   paths.map(|p| p.unwrap().path()));
    } else {
        index_bano(&args.flag_connection_string,
                   &args.flag_dataset,
                   std::iter::once(std::path::PathBuf::from(&args.flag_input)));
    }
}
<commit_msg>refctoring<commit_after>// Copyright © 2016, Canal TP and/or its affiliates. All rights reserved.
//
// This file is part of Navitia,
//     the software to build cool stuff with public transport.
//
// Hope you'll enjoy and contribute to this project,
//     powered by Canal TP (www.canaltp.fr).
// Help us simplify mobility and open public transport:
//     a non ending quest to the responsive locomotion way of traveling!
//
// LICENCE: This program is free software; you can redistribute it
// and/or modify it under the terms of the GNU Affero General Public
// License as published by the Free Software Foundation, either
// version 3 of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public
// License along with this program. If not, see
// <http://www.gnu.org/licenses/>.
//
// Stay tuned using
// twitter @navitia
// IRC #navitia on freenode
// https://groups.google.com/d/forum/navitia
// www.navitia.io

extern crate docopt;
extern crate csv;
extern crate rustc_serialize;
extern crate mimir;
#[macro_use]
extern crate log;
extern crate geo;

use std::path::Path;
use mimir::rubber::Rubber;
use mimir::objects::{Admin, Addr, DocType, IsGeoData};
use std::fs;
use std::rc::Rc;
use std::collections::BTreeMap;

type AdminFromInsee = BTreeMap<String, Rc<Admin>>;

#[derive(RustcDecodable, RustcEncodable)]
pub struct Bano {
    pub id: String,
    pub nb: String,
    pub street: String,
    pub zip: String,
    pub city: String,
    pub src: String,
    pub lat: f64,
    pub lon: f64,
}

impl Bano {
    pub fn insee(&self) -> &str {
        assert!(self.id.len() >= 5);
        self.id[..5].trim_left_matches('0')
    }
    pub fn fantoir(&self) -> &str {
        assert!(self.id.len() >= 10);
        &self.id[..10]
    }
    pub fn into_addr(self, admins: &AdminFromInsee) -> mimir::Addr {
        let street_name = format!("{} ({})", self.street, self.city);
        let addr_name = format!("{} {}", self.nb, self.street);
        let addr_label = format!("{} ({})", addr_name, self.city);
        let street_id = format!("street:{}", self.fantoir().to_string());
        let admin = admins.get(&format!("admin:fr:{}", self.insee()));

        let street = mimir::Street {
            id: street_id,
            street_name: self.street,
            label: street_name.to_string(),
            administrative_regions: admin.map_or(vec![], |a| vec![a.clone()]),
            weight: 1,
            zip_codes: vec![self.zip.clone()],
            coord: mimir::Coord::new(self.lat, self.lon),
        };
        mimir::Addr {
            id: format!("addr:{};{}", self.lon, self.lat),
            house_number: self.nb,
            street: street,
            label: addr_label,
            coord: mimir::Coord::new(self.lat, self.lon),
            weight: 1,
            zip_codes: vec![self.zip.clone()],
        }
    }
}

fn index_bano<I>(cnx_string: &str, dataset: &str, files: I)
    where I: Iterator<Item = std::path::PathBuf>
{
    let mut rubber = Rubber::new(cnx_string);

    let admins_by_insee = rubber.get_admins_from_dataset(dataset)
        .unwrap_or_else(|err| {
            info!("Administratives regions not found in es db for dataset {}. (error: {})",
                  dataset,
                  err);
            vec![]
        })
        .into_iter()
        .map(|mut a| {
            a.boundary = None; // to save some space we remove the admin boundary
            (a.id.to_string(), Rc::new(a))
        })
        .collect();

    let addr_index = rubber.make_index(Addr::doc_type(), dataset).unwrap();
    info!("Add data in elasticsearch db.");
    for f in files {
        info!("importing {:?}...", &f);
        let mut rdr = csv::Reader::from_file(&f).unwrap().has_headers(false);

        let iter = rdr.decode().map(|r| {
            let b: Bano = r.unwrap();
            b.into_addr(&admins_by_insee)
        });
        match rubber.bulk_index(&addr_index, iter) {
            Err(e) => panic!("failed to bulk insert file {:?} because: {}", &f, e),
            Ok(nb) => info!("importing {:?}: {} addresses added.", &f, nb),
        }
    }
    rubber.publish_index(Addr::doc_type(), dataset, addr_index, Addr::is_geo_data()).unwrap();
}

#[derive(RustcDecodable, Debug)]
struct Args {
    flag_input: String,
    flag_connection_string: String,
    flag_dataset: String,
}

static USAGE: &'static str = "
Usage:
    bano2mimir --input=<input> [--connection-string=<connection-string>] [--dataset=<dataset>]

    -i, --input=<input>           Bano files. Can be either a directory or a file.
    -c, --connection-string=<connection-string>
                                  Elasticsearch parameters, [default: http://localhost:9200/munin]
    -d, --dataset=<dataset>       Name of the dataset, [default: fr]
";

fn main() {
    mimir::logger_init().unwrap();
    info!("importing bano into Mimir");

    let args: Args = docopt::Docopt::new(USAGE)
        .and_then(|d| d.decode())
        .unwrap_or_else(|e| e.exit());

    let file_path = Path::new(&args.flag_input);
    if file_path.is_dir() {
        let paths: std::fs::ReadDir = fs::read_dir(&args.flag_input).unwrap();
        index_bano(&args.flag_connection_string,
                   &args.flag_dataset,
                   paths.map(|p| p.unwrap().path()));
    } else {
        index_bano(&args.flag_connection_string,
                   &args.flag_dataset,
                   std::iter::once(std::path::PathBuf::from(&args.flag_input)));
    }
}
<|endoftext|>


<commit_before>// Inspired by Paul Woolcock's cargo-fmt (https://github.com/pwoolcoc/cargo-fmt/).

#![deny(warnings)]

use cargo_metadata;

use std::cmp::Ordering;
use std::collections::{BTreeMap, BTreeSet};
use std::env;
use std::fs;
use std::hash::{Hash, Hasher};
use std::io::{self, Write};
use std::iter::FromIterator;
use std::path::{Path, PathBuf};
use std::process::Command;
use std::str;

use structopt::StructOpt;

#[derive(StructOpt, Debug)]
#[structopt(
    bin_name = "cargo fmt",
    author = "",
    about = "This utility formats all bin and lib files of \
             the current crate using rustfmt."
)]
pub struct Opts {
    /// No output printed to stdout
    #[structopt(short = "q", long = "quiet")]
    quiet: bool,

    /// Use verbose output
    #[structopt(short = "v", long = "verbose")]
    verbose: bool,

    /// Print rustfmt version and exit
    #[structopt(long = "version")]
    version: bool,

    /// Specify package to format (only usable in workspaces)
    #[structopt(short = "p", long = "package", value_name = "package")]
    packages: Vec<String>,

    /// Options passed to rustfmt
    // 'raw = true' to make `--` explicit.
    #[structopt(name = "rustfmt_options", raw(raw = "true"))]
    rustfmt_options: Vec<String>,

    /// Format all packages (only usable in workspaces)
    #[structopt(long = "all")]
    format_all: bool,
}

fn main() {
    let exit_status = execute();
    std::io::stdout().flush().unwrap();
    std::process::exit(exit_status);
}

const SUCCESS: i32 = 0;
const FAILURE: i32 = 1;

fn execute() -> i32 {
    // Drop extra `fmt` argument provided by `cargo`.
    let mut found_fmt = false;
    let args = env::args().filter(|x| {
        if found_fmt {
            true
        } else {
            found_fmt = x == "fmt";
            x != "fmt"
        }
    });

    let opts = Opts::from_iter(args);

    let verbosity = match (opts.verbose, opts.quiet) {
        (false, false) => Verbosity::Normal,
        (false, true) => Verbosity::Quiet,
        (true, false) => Verbosity::Verbose,
        (true, true) => {
            print_usage_to_stderr("quiet mode and verbose mode are not compatible");
            return FAILURE;
        }
    };

    if opts.version {
        return handle_command_status(get_version());
    }

    let strategy = CargoFmtStrategy::from_opts(&opts);

    handle_command_status(format_crate(verbosity, &strategy, opts.rustfmt_options))
}

fn print_usage_to_stderr(reason: &str) {
    eprintln!("{}", reason);
    let app = Opts::clap();
    app.after_help("")
        .write_help(&mut io::stderr())
        .expect("failed to write to stderr");
}

#[derive(Debug, Clone, Copy, PartialEq)]
pub enum Verbosity {
    Verbose,
    Normal,
    Quiet,
}

fn handle_command_status(status: Result<i32, io::Error>) -> i32 {
    match status {
        Err(e) => {
            print_usage_to_stderr(&e.to_string());
            FAILURE
        }
        Ok(status) => status,
    }
}

fn get_version() -> Result<i32, io::Error> {
    let mut command = Command::new("rustfmt")
        .stdout(std::process::Stdio::inherit())
        .args(&[String::from("--version")])
        .spawn()
        .map_err(|e| match e.kind() {
            io::ErrorKind::NotFound => io::Error::new(
                io::ErrorKind::Other,
                "Could not run rustfmt, please make sure it is in your PATH.",
            ),
            _ => e,
        })?;
    let result = command.wait()?;
    if result.success() {
        Ok(SUCCESS)
    } else {
        Ok(result.code().unwrap_or(SUCCESS))
    }
}

fn format_crate(
    verbosity: Verbosity,
    strategy: &CargoFmtStrategy,
    rustfmt_args: Vec<String>,
) -> Result<i32, io::Error> {
    let targets = if rustfmt_args
        .iter()
        .any(|s| ["--print-config", "-h", "--help", "-V", "--version"].contains(&s.as_str()))
    {
        BTreeSet::new()
    } else {
        get_targets(strategy)?
    };

    // Currently only bin and lib files get formatted.
    run_rustfmt(&targets, &rustfmt_args, verbosity)
}

/// Target uses a `path` field for equality and hashing.
#[derive(Debug)]
pub struct Target {
    /// A path to the main source file of the target.
    path: PathBuf,
    /// A kind of target (e.g., lib, bin, example, ...).
    kind: String,
    /// Rust edition for this target.
    edition: String,
}

impl Target {
    pub fn from_target(target: &cargo_metadata::Target) -> Self {
        let path = PathBuf::from(&target.src_path);
        let canonicalized = fs::canonicalize(&path).unwrap_or(path);

        Target {
            path: canonicalized,
            kind: target.kind[0].clone(),
            edition: target.edition.clone(),
        }
    }
}

impl PartialEq for Target {
    fn eq(&self, other: &Target) -> bool {
        self.path == other.path
    }
}

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

impl Ord for Target {
    fn cmp(&self, other: &Target) -> Ordering {
        self.path.cmp(&other.path)
    }
}

impl Eq for Target {}

impl Hash for Target {
    fn hash<H: Hasher>(&self, state: &mut H) {
        self.path.hash(state);
    }
}

#[derive(Debug, PartialEq, Eq)]
pub enum CargoFmtStrategy {
    /// Format every packages and dependencies.
    All,
    /// Format packages that are specified by the command line argument.
    Some(Vec<String>),
    /// Format the root packages only.
    Root,
}

impl CargoFmtStrategy {
    pub fn from_opts(opts: &Opts) -> CargoFmtStrategy {
        match (opts.format_all, opts.packages.is_empty()) {
            (false, true) => CargoFmtStrategy::Root,
            (true, _) => CargoFmtStrategy::All,
            (false, false) => CargoFmtStrategy::Some(opts.packages.clone()),
        }
    }
}

/// Based on the specified `CargoFmtStrategy`, returns a set of main source files.
fn get_targets(strategy: &CargoFmtStrategy) -> Result<BTreeSet<Target>, io::Error> {
    let mut targets = BTreeSet::new();

    match *strategy {
        CargoFmtStrategy::Root => get_targets_root_only(&mut targets)?,
        CargoFmtStrategy::All => get_targets_recursive(None, &mut targets, &mut BTreeSet::new())?,
        CargoFmtStrategy::Some(ref hitlist) => get_targets_with_hitlist(hitlist, &mut targets)?,
    }

    if targets.is_empty() {
        Err(io::Error::new(
            io::ErrorKind::Other,
            "Failed to find targets".to_owned(),
        ))
    } else {
        Ok(targets)
    }
}

fn get_targets_root_only(targets: &mut BTreeSet<Target>) -> Result<(), io::Error> {
    let metadata = get_cargo_metadata(None)?;
    let current_dir = env::current_dir()?.canonicalize()?;
    let current_dir_manifest = current_dir.join("Cargo.toml");
    let workspace_root_path = PathBuf::from(&metadata.workspace_root).canonicalize()?;
    let in_workspace_root = workspace_root_path == current_dir;

    for package in metadata.packages {
        if in_workspace_root || PathBuf::from(&package.manifest_path) == current_dir_manifest {
            for target in package.targets {
                targets.insert(Target::from_target(&target));
            }
        }
    }

    Ok(())
}

fn get_targets_recursive(
    manifest_path: Option<&Path>,
    mut targets: &mut BTreeSet<Target>,
    visited: &mut BTreeSet<String>,
) -> Result<(), io::Error> {
    let metadata = get_cargo_metadata(manifest_path)?;

    for package in metadata.packages {
        add_targets(&package.targets, &mut targets);

        // Look for local dependencies.
        for dependency in package.dependencies {
            if dependency.source.is_some() || visited.contains(&dependency.name) {
                continue;
            }

            let mut manifest_path = PathBuf::from(&package.manifest_path);

            manifest_path.pop();
            manifest_path.push(&dependency.name);
            manifest_path.push("Cargo.toml");

            if manifest_path.exists() {
                visited.insert(dependency.name);
                get_targets_recursive(Some(&manifest_path), &mut targets, visited)?;
            }
        }
    }

    Ok(())
}

fn get_targets_with_hitlist(
    hitlist: &[String],
    targets: &mut BTreeSet<Target>,
) -> Result<(), io::Error> {
    let metadata = get_cargo_metadata(None)?;

    let mut workspace_hitlist: BTreeSet<&String> = BTreeSet::from_iter(hitlist);

    for package in metadata.packages {
        if workspace_hitlist.remove(&package.name) {
            for target in package.targets {
                targets.insert(Target::from_target(&target));
            }
        }
    }

    if workspace_hitlist.is_empty() {
        Ok(())
    } else {
        let package = workspace_hitlist.iter().next().unwrap();
        Err(io::Error::new(
            io::ErrorKind::InvalidInput,
            format!("package `{}` is not a member of the workspace", package),
        ))
    }
}

fn add_targets(target_paths: &[cargo_metadata::Target], targets: &mut BTreeSet<Target>) {
    for target in target_paths {
        targets.insert(Target::from_target(target));
    }
}

fn run_rustfmt(
    targets: &BTreeSet<Target>,
    fmt_args: &[String],
    verbosity: Verbosity,
) -> Result<i32, io::Error> {
    let by_edition = targets
        .iter()
        .inspect(|t| {
            if verbosity == Verbosity::Verbose {
                println!("[{} ({})] {:?}", t.kind, t.edition, t.path)
            }
        })
        .fold(BTreeMap::new(), |mut h, t| {
            h.entry(&t.edition).or_insert_with(Vec::new).push(&t.path);
            h
        });

    let mut status = vec![];
    for (edition, files) in by_edition {
        let stdout = if verbosity == Verbosity::Quiet {
            std::process::Stdio::null()
        } else {
            std::process::Stdio::inherit()
        };

        if verbosity == Verbosity::Verbose {
            print!("rustfmt");
            print!(" --edition {}", edition);
            fmt_args.iter().for_each(|f| print!(" {}", f));
            files.iter().for_each(|f| print!(" {}", f.display()));
            println!();
        }

        let mut command = Command::new("rustfmt")
            .stdout(stdout)
            .args(files)
            .args(&["--edition", edition])
            .args(fmt_args)
            .spawn()
            .map_err(|e| match e.kind() {
                io::ErrorKind::NotFound => io::Error::new(
                    io::ErrorKind::Other,
                    "Could not run rustfmt, please make sure it is in your PATH.",
                ),
                _ => e,
            })?;

        status.push(command.wait()?);
    }

    Ok(status
        .iter()
        .filter_map(|s| if s.success() { None } else { s.code() })
        .next()
        .unwrap_or(SUCCESS))
}

fn get_cargo_metadata(manifest_path: Option<&Path>) -> Result<cargo_metadata::Metadata, io::Error> {
    let mut cmd = cargo_metadata::MetadataCommand::new();
    cmd.no_deps();
    if let Some(manifest_path) = manifest_path {
        cmd.manifest_path(manifest_path);
    }
    match cmd.exec() {
        Ok(metadata) => Ok(metadata),
        Err(error) => Err(io::Error::new(io::ErrorKind::Other, error.to_string())),
    }
}

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

    #[test]
    fn default_options() {
        let empty: Vec<String> = vec![];
        let o = Opts::from_iter(&empty);
        assert_eq!(false, o.quiet);
        assert_eq!(false, o.verbose);
        assert_eq!(false, o.version);
        assert_eq!(empty, o.packages);
        assert_eq!(empty, o.rustfmt_options);
        assert_eq!(false, o.format_all);
    }

    #[test]
    fn good_options() {
        let o = Opts::from_iter(&[
            "test",
            "-q",
            "-p",
            "p1",
            "-p",
            "p2",
            "--",
            "--edition",
            "2018",
        ]);
        assert_eq!(true, o.quiet);
        assert_eq!(false, o.verbose);
        assert_eq!(false, o.version);
        assert_eq!(vec!["p1", "p2"], o.packages);
        assert_eq!(vec!["--edition", "2018"], o.rustfmt_options);
        assert_eq!(false, o.format_all);
    }

    #[test]
    fn unexpected_option() {
        assert!(
            Opts::clap()
                .get_matches_from_safe(&["test", "unexpected"])
                .is_err()
        );
    }

    #[test]
    fn unexpected_flag() {
        assert!(
            Opts::clap()
                .get_matches_from_safe(&["test", "--flag"])
                .is_err()
        );
    }

    #[test]
    fn mandatory_separator() {
        assert!(
            Opts::clap()
                .get_matches_from_safe(&["test", "--check"])
                .is_err()
        );
        assert!(
            !Opts::clap()
                .get_matches_from_safe(&["test", "--", "--check"])
                .is_err()
        );
    }

    #[test]
    fn multiple_packages_one_by_one() {
        let o = Opts::from_iter(&[
            "test",
            "-p",
            "package1",
            "--package",
            "package2",
            "-p",
            "package3",
        ]);
        assert_eq!(3, o.packages.len());
    }

    #[test]
    fn multiple_packages_grouped() {
        let o = Opts::from_iter(&[
            "test",
            "--package",
            "package1",
            "package2",
            "-p",
            "package3",
            "package4",
        ]);
        assert_eq!(4, o.packages.len());
    }

    #[test]
    fn empty_packages_1() {
        assert!(Opts::clap().get_matches_from_safe(&["test", "-p"]).is_err());
    }

    #[test]
    fn empty_packages_2() {
        assert!(
            Opts::clap()
                .get_matches_from_safe(&["test", "-p", "--", "--check"])
                .is_err()
        );
    }

    #[test]
    fn empty_packages_3() {
        assert!(
            Opts::clap()
                .get_matches_from_safe(&["test", "-p", "--verbose"])
                .is_err()
        );
    }

    #[test]
    fn empty_packages_4() {
        assert!(
            Opts::clap()
                .get_matches_from_safe(&["test", "-p", "--check"])
                .is_err()
        );
    }
}
<commit_msg>fix: run in sub dirs/workspace member dirs (#3652)<commit_after>// Inspired by Paul Woolcock's cargo-fmt (https://github.com/pwoolcoc/cargo-fmt/).

#![deny(warnings)]

use cargo_metadata;

use std::cmp::Ordering;
use std::collections::{BTreeMap, BTreeSet};
use std::env;
use std::fs;
use std::hash::{Hash, Hasher};
use std::io::{self, Write};
use std::iter::FromIterator;
use std::path::{Path, PathBuf};
use std::process::Command;
use std::str;

use structopt::StructOpt;

#[derive(StructOpt, Debug)]
#[structopt(
    bin_name = "cargo fmt",
    author = "",
    about = "This utility formats all bin and lib files of \
             the current crate using rustfmt."
)]
pub struct Opts {
    /// No output printed to stdout
    #[structopt(short = "q", long = "quiet")]
    quiet: bool,

    /// Use verbose output
    #[structopt(short = "v", long = "verbose")]
    verbose: bool,

    /// Print rustfmt version and exit
    #[structopt(long = "version")]
    version: bool,

    /// Specify package to format (only usable in workspaces)
    #[structopt(short = "p", long = "package", value_name = "package")]
    packages: Vec<String>,

    /// Options passed to rustfmt
    // 'raw = true' to make `--` explicit.
    #[structopt(name = "rustfmt_options", raw(raw = "true"))]
    rustfmt_options: Vec<String>,

    /// Format all packages (only usable in workspaces)
    #[structopt(long = "all")]
    format_all: bool,
}

fn main() {
    let exit_status = execute();
    std::io::stdout().flush().unwrap();
    std::process::exit(exit_status);
}

const SUCCESS: i32 = 0;
const FAILURE: i32 = 1;

fn execute() -> i32 {
    // Drop extra `fmt` argument provided by `cargo`.
    let mut found_fmt = false;
    let args = env::args().filter(|x| {
        if found_fmt {
            true
        } else {
            found_fmt = x == "fmt";
            x != "fmt"
        }
    });

    let opts = Opts::from_iter(args);

    let verbosity = match (opts.verbose, opts.quiet) {
        (false, false) => Verbosity::Normal,
        (false, true) => Verbosity::Quiet,
        (true, false) => Verbosity::Verbose,
        (true, true) => {
            print_usage_to_stderr("quiet mode and verbose mode are not compatible");
            return FAILURE;
        }
    };

    if opts.version {
        return handle_command_status(get_version());
    }

    let strategy = CargoFmtStrategy::from_opts(&opts);

    handle_command_status(format_crate(verbosity, &strategy, opts.rustfmt_options))
}

fn print_usage_to_stderr(reason: &str) {
    eprintln!("{}", reason);
    let app = Opts::clap();
    app.after_help("")
        .write_help(&mut io::stderr())
        .expect("failed to write to stderr");
}

#[derive(Debug, Clone, Copy, PartialEq)]
pub enum Verbosity {
    Verbose,
    Normal,
    Quiet,
}

fn handle_command_status(status: Result<i32, io::Error>) -> i32 {
    match status {
        Err(e) => {
            print_usage_to_stderr(&e.to_string());
            FAILURE
        }
        Ok(status) => status,
    }
}

fn get_version() -> Result<i32, io::Error> {
    let mut command = Command::new("rustfmt")
        .stdout(std::process::Stdio::inherit())
        .args(&[String::from("--version")])
        .spawn()
        .map_err(|e| match e.kind() {
            io::ErrorKind::NotFound => io::Error::new(
                io::ErrorKind::Other,
                "Could not run rustfmt, please make sure it is in your PATH.",
            ),
            _ => e,
        })?;
    let result = command.wait()?;
    if result.success() {
        Ok(SUCCESS)
    } else {
        Ok(result.code().unwrap_or(SUCCESS))
    }
}

fn format_crate(
    verbosity: Verbosity,
    strategy: &CargoFmtStrategy,
    rustfmt_args: Vec<String>,
) -> Result<i32, io::Error> {
    let targets = if rustfmt_args
        .iter()
        .any(|s| ["--print-config", "-h", "--help", "-V", "--version"].contains(&s.as_str()))
    {
        BTreeSet::new()
    } else {
        get_targets(strategy)?
    };

    // Currently only bin and lib files get formatted.
    run_rustfmt(&targets, &rustfmt_args, verbosity)
}

/// Target uses a `path` field for equality and hashing.
#[derive(Debug)]
pub struct Target {
    /// A path to the main source file of the target.
    path: PathBuf,
    /// A kind of target (e.g., lib, bin, example, ...).
    kind: String,
    /// Rust edition for this target.
    edition: String,
}

impl Target {
    pub fn from_target(target: &cargo_metadata::Target) -> Self {
        let path = PathBuf::from(&target.src_path);
        let canonicalized = fs::canonicalize(&path).unwrap_or(path);

        Target {
            path: canonicalized,
            kind: target.kind[0].clone(),
            edition: target.edition.clone(),
        }
    }
}

impl PartialEq for Target {
    fn eq(&self, other: &Target) -> bool {
        self.path == other.path
    }
}

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

impl Ord for Target {
    fn cmp(&self, other: &Target) -> Ordering {
        self.path.cmp(&other.path)
    }
}

impl Eq for Target {}

impl Hash for Target {
    fn hash<H: Hasher>(&self, state: &mut H) {
        self.path.hash(state);
    }
}

#[derive(Debug, PartialEq, Eq)]
pub enum CargoFmtStrategy {
    /// Format every packages and dependencies.
    All,
    /// Format packages that are specified by the command line argument.
    Some(Vec<String>),
    /// Format the root packages only.
    Root,
}

impl CargoFmtStrategy {
    pub fn from_opts(opts: &Opts) -> CargoFmtStrategy {
        match (opts.format_all, opts.packages.is_empty()) {
            (false, true) => CargoFmtStrategy::Root,
            (true, _) => CargoFmtStrategy::All,
            (false, false) => CargoFmtStrategy::Some(opts.packages.clone()),
        }
    }
}

/// Based on the specified `CargoFmtStrategy`, returns a set of main source files.
fn get_targets(strategy: &CargoFmtStrategy) -> Result<BTreeSet<Target>, io::Error> {
    let mut targets = BTreeSet::new();

    match *strategy {
        CargoFmtStrategy::Root => get_targets_root_only(&mut targets)?,
        CargoFmtStrategy::All => get_targets_recursive(None, &mut targets, &mut BTreeSet::new())?,
        CargoFmtStrategy::Some(ref hitlist) => get_targets_with_hitlist(hitlist, &mut targets)?,
    }

    if targets.is_empty() {
        Err(io::Error::new(
            io::ErrorKind::Other,
            "Failed to find targets".to_owned(),
        ))
    } else {
        Ok(targets)
    }
}

fn get_targets_root_only(targets: &mut BTreeSet<Target>) -> Result<(), io::Error> {
    let metadata = get_cargo_metadata(None)?;
    let current_dir = env::current_dir()?.canonicalize()?;
    let current_dir_manifest = current_dir.join("Cargo.toml");
    let workspace_root_path = PathBuf::from(&metadata.workspace_root).canonicalize()?;
    let in_workspace_root = workspace_root_path == current_dir;

    let package_targets = match metadata.packages.len() {
        1 => metadata.packages.into_iter().next().unwrap().targets,
        _ => metadata
            .packages
            .into_iter()
            .filter(|p| {
                in_workspace_root
                    || PathBuf::from(&p.manifest_path)
                        .canonicalize()
                        .unwrap_or_default()
                        == current_dir_manifest
            })
            .map(|p| p.targets)
            .flatten()
            .collect(),
    };

    for target in package_targets {
        targets.insert(Target::from_target(&target));
    }

    Ok(())
}

fn get_targets_recursive(
    manifest_path: Option<&Path>,
    mut targets: &mut BTreeSet<Target>,
    visited: &mut BTreeSet<String>,
) -> Result<(), io::Error> {
    let metadata = get_cargo_metadata(manifest_path)?;

    for package in metadata.packages {
        add_targets(&package.targets, &mut targets);

        // Look for local dependencies.
        for dependency in package.dependencies {
            if dependency.source.is_some() || visited.contains(&dependency.name) {
                continue;
            }

            let mut manifest_path = PathBuf::from(&package.manifest_path);

            manifest_path.pop();
            manifest_path.push(&dependency.name);
            manifest_path.push("Cargo.toml");

            if manifest_path.exists() {
                visited.insert(dependency.name);
                get_targets_recursive(Some(&manifest_path), &mut targets, visited)?;
            }
        }
    }

    Ok(())
}

fn get_targets_with_hitlist(
    hitlist: &[String],
    targets: &mut BTreeSet<Target>,
) -> Result<(), io::Error> {
    let metadata = get_cargo_metadata(None)?;

    let mut workspace_hitlist: BTreeSet<&String> = BTreeSet::from_iter(hitlist);

    for package in metadata.packages {
        if workspace_hitlist.remove(&package.name) {
            for target in package.targets {
                targets.insert(Target::from_target(&target));
            }
        }
    }

    if workspace_hitlist.is_empty() {
        Ok(())
    } else {
        let package = workspace_hitlist.iter().next().unwrap();
        Err(io::Error::new(
            io::ErrorKind::InvalidInput,
            format!("package `{}` is not a member of the workspace", package),
        ))
    }
}

fn add_targets(target_paths: &[cargo_metadata::Target], targets: &mut BTreeSet<Target>) {
    for target in target_paths {
        targets.insert(Target::from_target(target));
    }
}

fn run_rustfmt(
    targets: &BTreeSet<Target>,
    fmt_args: &[String],
    verbosity: Verbosity,
) -> Result<i32, io::Error> {
    let by_edition = targets
        .iter()
        .inspect(|t| {
            if verbosity == Verbosity::Verbose {
                println!("[{} ({})] {:?}", t.kind, t.edition, t.path)
            }
        })
        .fold(BTreeMap::new(), |mut h, t| {
            h.entry(&t.edition).or_insert_with(Vec::new).push(&t.path);
            h
        });

    let mut status = vec![];
    for (edition, files) in by_edition {
        let stdout = if verbosity == Verbosity::Quiet {
            std::process::Stdio::null()
        } else {
            std::process::Stdio::inherit()
        };

        if verbosity == Verbosity::Verbose {
            print!("rustfmt");
            print!(" --edition {}", edition);
            fmt_args.iter().for_each(|f| print!(" {}", f));
            files.iter().for_each(|f| print!(" {}", f.display()));
            println!();
        }

        let mut command = Command::new("rustfmt")
            .stdout(stdout)
            .args(files)
            .args(&["--edition", edition])
            .args(fmt_args)
            .spawn()
            .map_err(|e| match e.kind() {
                io::ErrorKind::NotFound => io::Error::new(
                    io::ErrorKind::Other,
                    "Could not run rustfmt, please make sure it is in your PATH.",
                ),
                _ => e,
            })?;

        status.push(command.wait()?);
    }

    Ok(status
        .iter()
        .filter_map(|s| if s.success() { None } else { s.code() })
        .next()
        .unwrap_or(SUCCESS))
}

fn get_cargo_metadata(manifest_path: Option<&Path>) -> Result<cargo_metadata::Metadata, io::Error> {
    let mut cmd = cargo_metadata::MetadataCommand::new();
    cmd.no_deps();
    if let Some(manifest_path) = manifest_path {
        cmd.manifest_path(manifest_path);
    }
    match cmd.exec() {
        Ok(metadata) => Ok(metadata),
        Err(error) => Err(io::Error::new(io::ErrorKind::Other, error.to_string())),
    }
}

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

    #[test]
    fn default_options() {
        let empty: Vec<String> = vec![];
        let o = Opts::from_iter(&empty);
        assert_eq!(false, o.quiet);
        assert_eq!(false, o.verbose);
        assert_eq!(false, o.version);
        assert_eq!(empty, o.packages);
        assert_eq!(empty, o.rustfmt_options);
        assert_eq!(false, o.format_all);
    }

    #[test]
    fn good_options() {
        let o = Opts::from_iter(&[
            "test",
            "-q",
            "-p",
            "p1",
            "-p",
            "p2",
            "--",
            "--edition",
            "2018",
        ]);
        assert_eq!(true, o.quiet);
        assert_eq!(false, o.verbose);
        assert_eq!(false, o.version);
        assert_eq!(vec!["p1", "p2"], o.packages);
        assert_eq!(vec!["--edition", "2018"], o.rustfmt_options);
        assert_eq!(false, o.format_all);
    }

    #[test]
    fn unexpected_option() {
        assert!(
            Opts::clap()
                .get_matches_from_safe(&["test", "unexpected"])
                .is_err()
        );
    }

    #[test]
    fn unexpected_flag() {
        assert!(
            Opts::clap()
                .get_matches_from_safe(&["test", "--flag"])
                .is_err()
        );
    }

    #[test]
    fn mandatory_separator() {
        assert!(
            Opts::clap()
                .get_matches_from_safe(&["test", "--check"])
                .is_err()
        );
        assert!(
            !Opts::clap()
                .get_matches_from_safe(&["test", "--", "--check"])
                .is_err()
        );
    }

    #[test]
    fn multiple_packages_one_by_one() {
        let o = Opts::from_iter(&[
            "test",
            "-p",
            "package1",
            "--package",
            "package2",
            "-p",
            "package3",
        ]);
        assert_eq!(3, o.packages.len());
    }

    #[test]
    fn multiple_packages_grouped() {
        let o = Opts::from_iter(&[
            "test",
            "--package",
            "package1",
            "package2",
            "-p",
            "package3",
            "package4",
        ]);
        assert_eq!(4, o.packages.len());
    }

    #[test]
    fn empty_packages_1() {
        assert!(Opts::clap().get_matches_from_safe(&["test", "-p"]).is_err());
    }

    #[test]
    fn empty_packages_2() {
        assert!(
            Opts::clap()
                .get_matches_from_safe(&["test", "-p", "--", "--check"])
                .is_err()
        );
    }

    #[test]
    fn empty_packages_3() {
        assert!(
            Opts::clap()
                .get_matches_from_safe(&["test", "-p", "--verbose"])
                .is_err()
        );
    }

    #[test]
    fn empty_packages_4() {
        assert!(
            Opts::clap()
                .get_matches_from_safe(&["test", "-p", "--check"])
                .is_err()
        );
    }
}
<|endoftext|>


<commit_before>#![crate_name = "objc"]
#![crate_type = "lib"]

#![feature(core, std_misc, unsafe_destructor, unsafe_no_drop_flag)]

extern crate libc;
extern crate malloc_buf;

#[cfg(test)]
extern crate objc_test_utils;

pub use id::{Id, IdSlice, Owned, Ownership, Shared, ShareId};
pub use encode::{encode, Encode, EncodePtr};
pub use message::{send_message, Message, MessageArguments, ToMessage};
pub use weak::WeakId;

#[macro_use]
mod macros;

pub mod runtime;
mod id;
pub mod block;
pub mod declare;
mod encode;
mod message;
mod weak;

#[cfg(test)]
mod test_utils;
<commit_msg>Warn on missing docs.<commit_after>//! Objective-C Runtime bindings and wrapper for Rust.

#![crate_name = "objc"]
#![crate_type = "lib"]

#![feature(core, std_misc, unsafe_destructor, unsafe_no_drop_flag)]
#![warn(missing_docs)]

extern crate libc;
extern crate malloc_buf;

#[cfg(test)]
extern crate objc_test_utils;

pub use id::{Id, IdSlice, Owned, Ownership, Shared, ShareId};
pub use encode::{encode, Encode, EncodePtr};
pub use message::{send_message, Message, MessageArguments, ToMessage};
pub use weak::WeakId;

#[macro_use]
mod macros;

pub mod runtime;
mod id;
pub mod block;
pub mod declare;
mod encode;
mod message;
mod weak;

#[cfg(test)]
mod test_utils;
<|endoftext|>


<commit_before>// Copyright (c) 2016 Anatoly Ikorsky
//
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. All files in the project carrying such notice may not be copied,
// modified, or distributed except according to those terms.

use errors::*;

use std::borrow::Cow;

enum ParserState {
    TopLevel,
    // (string_delimiter, last_char)
    InStringLiteral(char, char),
    MaybeInNamedParam,
    InNamedParam,
}

use self::ParserState::*;

pub fn parse_named_params<'a>(query: &'a str) -> Result<(Option<Vec<String>>, Cow<'a, str>)> {
    let mut state = TopLevel;
    let mut have_positional = false;
    let mut cur_param = 0;
    // Vec<(start_offset, end_offset, name)>
    let mut params = Vec::new();
    for (i, c) in query.chars().enumerate() {
        let mut rematch = false;
        match state {
            TopLevel => {
                match c {
                    ':' => state = MaybeInNamedParam,
                    '\'' => state = InStringLiteral('\'', '\''),
                    '"' => state = InStringLiteral('"', '"'),
                    '?' => have_positional = true,
                    _ => (),
                }
            },
            InStringLiteral(separator, prev_char) => {
                match c {
                    x if x == separator && prev_char != '\\' => state = TopLevel,
                    x => state = InStringLiteral(separator, x),
                }
            },
            MaybeInNamedParam => {
                match c {
                    'a' ... 'z' | '_' => {
                        params.push((i - 1, 0, String::with_capacity(16)));
                        params[cur_param].2.push(c);
                        state = InNamedParam;
                    },
                    _ => rematch = true,
                }
            },
            InNamedParam => {
                match c {
                    'a' ... 'z' | '0' ... '9' | '_' => params[cur_param].2.push(c),
                    _ => {
                        params[cur_param].1 = i;
                        cur_param += 1;
                        rematch = true;
                    }
                }
            },
        }
        if rematch {
            match c {
                ':' => state = MaybeInNamedParam,
                '\'' => state = InStringLiteral('\'', '\''),
                '"' => state = InStringLiteral('"', '"'),
                _ => state = TopLevel,
            }
        }
    }
    match state {
        InNamedParam => params[cur_param].1 = query.len(),
        _ => (),
    }
    if params.len() > 0 {
        if have_positional {
            return Err(ErrorKind::MixedParams.into());
        }
        let mut real_query = String::with_capacity(query.len());
        let mut last = 0;
        let mut out_params = Vec::with_capacity(params.len());
        for (start, end, name) in params.into_iter() {
            real_query.push_str(&query[last..start]);
            real_query.push('?');
            last = end;
            out_params.push(name);
        }
        real_query.push_str(&query[last..]);
        Ok((Some(out_params), real_query.into()))
    } else {
        Ok((None, query.into()))
    }
}

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

    #[test]
    fn should_parse_named_params() {
        let result = parse_named_params(":a :b").unwrap();
        assert_eq!((Some(vec!["a".to_string(), "b".into()]), "? ?".into()), result);

        let result = parse_named_params("SELECT (:a-10)").unwrap();
        assert_eq!((Some(vec!["a".to_string()]), "SELECT (?-10)".into()), result);

        let result = parse_named_params(r#"SELECT '"\':a' "'\"':c" :b"#).unwrap();
        assert_eq!((Some(vec!["b".to_string()]), r#"SELECT '"\':a' "'\"':c" ?"#.into()), result);

        let result = parse_named_params(r":a_Aa:b").unwrap();
        assert_eq!((Some(vec!["a_".to_string(), "b".into()]), r"?Aa?".into()), result);

        let result = parse_named_params(r"::b").unwrap();
        assert_eq!((Some(vec!["b".to_string()]), r":?".into()), result);

        let err = parse_named_params(r":a ?").unwrap_err();
        match err.into_kind() {
            ErrorKind::MixedParams => (),
            _ => unreachable!(),
        }
    }

    #[test]
    fn should_allow_numbers_in_param_name() {
        let result = parse_named_params(":a1 :a2").unwrap();
        assert_eq!((Some(vec!["a1".to_string(), "a2".to_string()]), "? ?".into()), result);

        let result = parse_named_params(":1a :2a").unwrap();
        assert_eq!((None, ":1a :2a".into()), result);
    }

    #[cfg(feature = "nightly")]
    mod bench {
        use test;
        use super::super::parse_named_params;

        #[bench]
        fn parse_ten_named_params(bencher: &mut test::Bencher) {
            bencher.iter(|| {
                let result = parse_named_params(r#"
                SELECT :one, :two, :three, :four, :five, :six, :seven, :eight, :nine, :ten
                "#).unwrap();
                test::black_box(result);
            });
        }

        #[bench]
        fn parse_zero_named_params(bencher: &mut test::Bencher) {
            bencher.iter(|| {
                let result = parse_named_params(r"
                SELECT one, two, three, four, five, six, seven, eight, nine, ten
                ").unwrap();
                test::black_box(result);
            });
        }
    }
}
<commit_msg>Fix parse_named_params: special chrs in the query<commit_after>// Copyright (c) 2016 Anatoly Ikorsky
//
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. All files in the project carrying such notice may not be copied,
// modified, or distributed except according to those terms.

use errors::*;

use std::borrow::Cow;

enum ParserState {
    TopLevel,
    // (string_delimiter, last_char)
    InStringLiteral(char, char),
    MaybeInNamedParam,
    InNamedParam,
}

use self::ParserState::*;

pub fn parse_named_params<'a>(query: &'a str) -> Result<(Option<Vec<String>>, Cow<'a, str>)> {
    let mut state = TopLevel;
    let mut have_positional = false;
    let mut cur_param = 0;
    // Vec<(start_offset, end_offset, name)>
    let mut params = Vec::new();
    for (i, c) in query.char_indices() {
        let mut rematch = false;
        match state {
            TopLevel => {
                match c {
                    ':' => state = MaybeInNamedParam,
                    '\'' => state = InStringLiteral('\'', '\''),
                    '"' => state = InStringLiteral('"', '"'),
                    '?' => have_positional = true,
                    _ => (),
                }
            },
            InStringLiteral(separator, prev_char) => {
                match c {
                    x if x == separator && prev_char != '\\' => state = TopLevel,
                    x => state = InStringLiteral(separator, x),
                }
            },
            MaybeInNamedParam => {
                match c {
                    'a' ... 'z' | '_' => {
                        params.push((i - 1, 0, String::with_capacity(16)));
                        params[cur_param].2.push(c);
                        state = InNamedParam;
                    },
                    _ => rematch = true,
                }
            },
            InNamedParam => {
                match c {
                    'a' ... 'z' | '0' ... '9' | '_' => params[cur_param].2.push(c),
                    _ => {
                        params[cur_param].1 = i;
                        cur_param += 1;
                        rematch = true;
                    }
                }
            },
        }
        if rematch {
            match c {
                ':' => state = MaybeInNamedParam,
                '\'' => state = InStringLiteral('\'', '\''),
                '"' => state = InStringLiteral('"', '"'),
                _ => state = TopLevel,
            }
        }
    }
    match state {
        InNamedParam => params[cur_param].1 = query.len(),
        _ => (),
    }
    if params.len() > 0 {
        if have_positional {
            return Err(ErrorKind::MixedParams.into());
        }
        let mut real_query = String::with_capacity(query.len());
        let mut last = 0;
        let mut out_params = Vec::with_capacity(params.len());
        for (start, end, name) in params.into_iter() {
            real_query.push_str(&query[last..start]);
            real_query.push('?');
            last = end;
            out_params.push(name);
        }
        real_query.push_str(&query[last..]);
        Ok((Some(out_params), real_query.into()))
    } else {
        Ok((None, query.into()))
    }
}

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

    #[test]
    fn should_parse_named_params() {
        let result = parse_named_params(":a :b").unwrap();
        assert_eq!((Some(vec!["a".to_string(), "b".into()]), "? ?".into()), result);

        let result = parse_named_params("SELECT (:a-10)").unwrap();
        assert_eq!((Some(vec!["a".to_string()]), "SELECT (?-10)".into()), result);

        let result = parse_named_params(r#"SELECT '"\':a' "'\"':c" :b"#).unwrap();
        assert_eq!((Some(vec!["b".to_string()]), r#"SELECT '"\':a' "'\"':c" ?"#.into()), result);

        let result = parse_named_params(r":a_Aa:b").unwrap();
        assert_eq!((Some(vec!["a_".to_string(), "b".into()]), r"?Aa?".into()), result);

        let result = parse_named_params(r"::b").unwrap();
        assert_eq!((Some(vec!["b".to_string()]), r":?".into()), result);

        let err = parse_named_params(r":a ?").unwrap_err();
        match err.into_kind() {
            ErrorKind::MixedParams => (),
            _ => unreachable!(),
        }
    }

    #[test]
    fn should_allow_numbers_in_param_name() {
        let result = parse_named_params(":a1 :a2").unwrap();
        assert_eq!((Some(vec!["a1".to_string(), "a2".to_string()]), "? ?".into()), result);

        let result = parse_named_params(":1a :2a").unwrap();
        assert_eq!((None, ":1a :2a".into()), result);
    }

    #[test]
    fn special_characters_in_query() {
        let result = parse_named_params(r"SELECT 1 FROM été WHERE thing = :param;").unwrap();
        assert_eq!((Some(vec!["param".to_string()]), "SELECT 1 FROM été WHERE thing = ?;".into()), result);
    }

    #[cfg(feature = "nightly")]
    mod bench {
        use test;
        use super::super::parse_named_params;

        #[bench]
        fn parse_ten_named_params(bencher: &mut test::Bencher) {
            bencher.iter(|| {
                let result = parse_named_params(r#"
                SELECT :one, :two, :three, :four, :five, :six, :seven, :eight, :nine, :ten
                "#).unwrap();
                test::black_box(result);
            });
        }

        #[bench]
        fn parse_zero_named_params(bencher: &mut test::Bencher) {
            bencher.iter(|| {
                let result = parse_named_params(r"
                SELECT one, two, three, four, five, six, seven, eight, nine, ten
                ").unwrap();
                test::black_box(result);
            });
        }
    }
}
<|endoftext|>