<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

//! Common handling of keyboard input and state management for text input controls

use dom::bindings::codegen::Bindings::KeyboardEventBinding::KeyboardEventMethods;
use dom::bindings::js::JSRef;
use dom::keyboardevent::KeyboardEvent;
use servo_util::str::DOMString;

use std::cmp::{min, max};
use std::default::Default;

#[jstraceable]
struct TextPoint {
    /// 0-based line number
    line: uint,
    /// 0-based column number
    index: uint,
}

/// Encapsulated state for handling keyboard input in a single or multiline text input control.
#[jstraceable]
pub struct TextInput {
    /// Current text input content, split across lines without trailing '\n'
    lines: Vec<DOMString>,
    /// Current cursor input point
    edit_point: TextPoint,
    /// Selection range, beginning and end point that can span multiple lines.
    _selection: Option<(TextPoint, TextPoint)>,
    /// Is this a multiline input?
    multiline: bool,
}

/// Resulting action to be taken by the owner of a text input that is handling an event.
pub enum KeyReaction {
    TriggerDefaultAction,
    DispatchInput,
    Nothing,
}

impl Default for TextPoint {
    fn default() -> TextPoint {
        TextPoint {
            line: 0,
            index: 0,
        }
    }
}

/// Control whether this control should allow multiple lines.
#[deriving(PartialEq)]
pub enum Lines {
    Single,
    Multiple,
}

/// The direction in which to delete a character.
#[deriving(PartialEq)]
enum DeleteDir {
    Forward,
    Backward
}

impl TextInput {
    /// Instantiate a new text input control
    pub fn new(lines: Lines, initial: DOMString) -> TextInput {
        let mut i = TextInput {
            lines: vec!(),
            edit_point: Default::default(),
            _selection: None,
            multiline: lines == Multiple,
        };
        i.set_content(initial);
        i
    }

    /// Return the current line under the editing point
    fn get_current_line(&self) -> &DOMString {
        &self.lines[self.edit_point.line]
    }

    /// Insert a character at the current editing point
    fn insert_char(&mut self, ch: char) {
        //TODO: handle replacing selection with character
        let new_line = {
            let prefix = self.get_current_line().as_slice().slice_chars(0, self.edit_point.index);
            let suffix = self.get_current_line().as_slice().slice_chars(self.edit_point.index,
                                                                        self.current_line_length());
            let mut new_line = prefix.to_string();
            new_line.push(ch);
            new_line.push_str(suffix.as_slice());
            new_line
        };

        self.lines[self.edit_point.line] = new_line;
        self.edit_point.index += 1;
    }

    /// Remove a character at the current editing point
    fn delete_char(&mut self, dir: DeleteDir) {
        let forward = dir == Forward;

        //TODO: handle deleting selection
        let prefix_end = if forward {
            self.edit_point.index
        } else {
            if self.multiline {
                //TODO: handle backspacing from position 0 of current line
                if self.edit_point.index == 0 {
                    return;
                }
            } else if self.edit_point.index == 0 {
                return;
            }
            self.edit_point.index - 1
        };
        let suffix_start = if forward {
            let is_eol = self.edit_point.index == self.current_line_length();
            if self.multiline {
                //TODO: handle deleting from end position of current line
                if is_eol {
                    return;
                }
            } else if is_eol {
                return;
            }
            self.edit_point.index + 1
        } else {
            self.edit_point.index
        };

        let new_line = {
            let prefix = self.get_current_line().as_slice().slice_chars(0, prefix_end);
            let suffix = self.get_current_line().as_slice().slice_chars(suffix_start,
                                                                        self.current_line_length());
            let mut new_line = prefix.to_string();
            new_line.push_str(suffix);
            new_line
        };

        self.lines[self.edit_point.line] = new_line;

        if !forward {
            self.adjust_horizontal(-1);
        }
    }

    /// Return the length of the current line under the editing point.
    fn current_line_length(&self) -> uint {
        self.lines[self.edit_point.line].char_len()
    }

    /// Adjust the editing point position by a given of lines. The resulting column is
    /// as close to the original column position as possible.
    fn adjust_vertical(&mut self, adjust: int) {
        if !self.multiline {
            return;
        }

        if adjust < 0 && self.edit_point.line as int + adjust < 0 {
            self.edit_point.index = 0;
            self.edit_point.line = 0;
            return;
        } else if adjust > 0 && self.edit_point.line + adjust as uint >= self.lines.len() {
            self.edit_point.line = self.lines.len() - 1;
            self.edit_point.index = self.current_line_length();
            return;
        }

        self.edit_point.line = (self.edit_point.line as int + adjust) as uint;
        self.edit_point.index = min(self.current_line_length(), self.edit_point.index);
    }

    /// Adjust the editing point position by a given number of columns. If the adjustment
    /// requested is larger than is available in the current line, the editing point is
    /// adjusted vertically and the process repeats with the remaining adjustment requested.
    fn adjust_horizontal(&mut self, adjust: int) {
        if adjust < 0 {
            let remaining = self.edit_point.index;
            if adjust.abs() as uint > remaining && self.edit_point.line > 0 {
                self.adjust_vertical(-1);
                self.edit_point.index = self.current_line_length();
                self.adjust_horizontal(adjust + remaining as int);
            } else {
                self.edit_point.index = max(0, self.edit_point.index as int + adjust) as uint;
            }
        } else {
            let remaining = self.current_line_length() - self.edit_point.index;
            if adjust as uint > remaining && self.edit_point.line < self.lines.len() - 1 {
                self.edit_point.index = 0;
                self.adjust_vertical(1);
                self.adjust_horizontal(adjust - remaining as int);
            } else {
                self.edit_point.index = min(self.current_line_length(),
                                            self.edit_point.index + adjust as uint);
            }
        }
    }

    /// Deal with a newline input.
    fn handle_return(&mut self) -> KeyReaction {
        if !self.multiline {
            return TriggerDefaultAction;
        }

        //TODO: support replacing selection with newline
        let prefix = self.get_current_line().as_slice().slice_chars(0, self.edit_point.index).to_string();
        let suffix = self.get_current_line().as_slice().slice_chars(self.edit_point.index,
                                                                    self.current_line_length()).to_string();
        self.lines[self.edit_point.line] = prefix;
        self.lines.insert(self.edit_point.line + 1, suffix);
        return DispatchInput;
    }

    /// Process a given `KeyboardEvent` and return an action for the caller to execute.
    pub fn handle_keydown(&mut self, event: JSRef<KeyboardEvent>) -> KeyReaction {
        match event.Key().as_slice() {
            // printable characters have single-character key values
            c if c.len() == 1 => {
                self.insert_char(c.char_at(0));
                return DispatchInput;
            }
            "Space" => {
                self.insert_char(' ');
                DispatchInput
            }
            "Delete" => {
                self.delete_char(Forward);
                DispatchInput
            }
            "Backspace" => {
                self.delete_char(Backward);
                DispatchInput
            }
            "ArrowLeft" => {
                self.adjust_horizontal(-1);
                Nothing
            }
            "ArrowRight" => {
                self.adjust_horizontal(1);
                Nothing
            }
            "ArrowUp" => {
                self.adjust_vertical(-1);
                Nothing
            }
            "ArrowDown" => {
                self.adjust_vertical(1);
                Nothing
            }
            "Enter" => self.handle_return(),
            "Home" => {
                self.edit_point.index = 0;
                Nothing
            }
            "End" => {
                self.edit_point.index = self.current_line_length();
                Nothing
            }
            "PageUp" => {
                self.adjust_vertical(-28);
                Nothing
            }
            "PageDown" => {
                self.adjust_vertical(28);
                Nothing
            }
            "Tab" => TriggerDefaultAction,
            _ => Nothing,
        }
    }

    /// Get the current contents of the text input. Multiple lines are joined by \n.
    pub fn get_content(&self) -> DOMString {
        let mut content = "".to_string();
        for (i, line) in self.lines.iter().enumerate() {
            content.push_str(line.as_slice());
            if i < self.lines.len() - 1 {
                content.push('\n');
            }
        }
        content
    }

    /// Set the current contents of the text input. If this is control supports multiple lines,
    /// any \n encountered will be stripped and force a new logical line.
    pub fn set_content(&mut self, content: DOMString) {
        self.lines = if self.multiline {
            content.as_slice().split('\n').map(|s| s.to_string()).collect()
        } else {
            vec!(content)
        };
        self.edit_point.line = min(self.edit_point.line, self.lines.len() - 1);
        self.edit_point.index = min(self.edit_point.index, self.current_line_length() - 1);
    }
}
<commit_msg>auto merge of #4284 : ema-fox/servo/textinput_selection, r=jdm<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

//! Common handling of keyboard input and state management for text input controls

use dom::bindings::codegen::Bindings::KeyboardEventBinding::KeyboardEventMethods;
use dom::bindings::js::JSRef;
use dom::keyboardevent::KeyboardEvent;
use servo_util::str::DOMString;

use std::cmp::{min, max};
use std::default::Default;

#[jstraceable]
struct TextPoint {
    /// 0-based line number
    line: uint,
    /// 0-based column number
    index: uint,
}

/// Encapsulated state for handling keyboard input in a single or multiline text input control.
#[jstraceable]
pub struct TextInput {
    /// Current text input content, split across lines without trailing '\n'
    lines: Vec<DOMString>,
    /// Current cursor input point
    edit_point: TextPoint,
    /// Beginning of selection range with edit_point as end that can span multiple lines.
    selection_begin: Option<TextPoint>,
    /// Is this a multiline input?
    multiline: bool,
}

/// Resulting action to be taken by the owner of a text input that is handling an event.
pub enum KeyReaction {
    TriggerDefaultAction,
    DispatchInput,
    Nothing,
}

impl Default for TextPoint {
    fn default() -> TextPoint {
        TextPoint {
            line: 0,
            index: 0,
        }
    }
}

/// Control whether this control should allow multiple lines.
#[deriving(PartialEq)]
pub enum Lines {
    Single,
    Multiple,
}

/// The direction in which to delete a character.
#[deriving(PartialEq)]
enum DeleteDir {
    Forward,
    Backward
}

impl TextInput {
    /// Instantiate a new text input control
    pub fn new(lines: Lines, initial: DOMString) -> TextInput {
        let mut i = TextInput {
            lines: vec!(),
            edit_point: Default::default(),
            selection_begin: None,
            multiline: lines == Multiple,
        };
        i.set_content(initial);
        i
    }

    fn replace_selection(&mut self, insert: String) {
        let begin = self.selection_begin.take().unwrap();
        let end = self.edit_point;
        let (begin, end) = if begin.line < end.line || (begin.line == end.line && begin.index < end.index) {
            (begin, end)
        } else {
            (end, begin)
        };

        let new_lines = {
            let prefix = self.lines[begin.line].slice_chars(0, begin.index);
            let suffix = self.lines[end.line].slice_chars(end.index, self.lines[end.line].char_len());
            let lines_prefix = self.lines.slice(0, begin.line);
            let lines_suffix = self.lines.slice(end.line + 1, self.lines.len());

            let mut insert_lines = if self.multiline {
                insert.as_slice().split('\n').map(|s| s.to_string()).collect()
            } else {
                vec!(insert)
            };

            let mut new_line = prefix.to_string();
            new_line.push_str(insert_lines[0].as_slice());
            insert_lines[0] = new_line;

            let last_insert_lines_index = insert_lines.len() - 1;
            self.edit_point.index = insert_lines[last_insert_lines_index].char_len();
            self.edit_point.line = begin.line + last_insert_lines_index;

            insert_lines[last_insert_lines_index].push_str(suffix);

            let mut new_lines = vec!();
            new_lines.push_all(lines_prefix);
            new_lines.push_all(insert_lines.as_slice());
            new_lines.push_all(lines_suffix);
            new_lines
        };

        self.lines = new_lines;
    }

    /// Insert a character at the current editing point
    fn insert_char(&mut self, ch: char) {
        if self.selection_begin.is_none() {
            self.selection_begin = Some(self.edit_point);
        }
        self.replace_selection(ch.to_string());
    }

    /// Remove a character at the current editing point
    fn delete_char(&mut self, dir: DeleteDir) {
        if self.selection_begin.is_none() {
            self.adjust_horizontal(if dir == Forward {1} else {-1}, true);
        }
        self.replace_selection("".to_string());
    }

    /// Return the length of the current line under the editing point.
    fn current_line_length(&self) -> uint {
        self.lines[self.edit_point.line].char_len()
    }

    /// Adjust the editing point position by a given of lines. The resulting column is
    /// as close to the original column position as possible.
    fn adjust_vertical(&mut self, adjust: int, select: bool) {
        if !self.multiline {
            return;
        }

        if select {
            if self.selection_begin.is_none() {
                self.selection_begin = Some(self.edit_point);
            }
        } else {
            self.selection_begin = None;
        }

        if adjust < 0 && self.edit_point.line as int + adjust < 0 {
            self.edit_point.index = 0;
            self.edit_point.line = 0;
            return;
        } else if adjust > 0 && self.edit_point.line + adjust as uint >= self.lines.len() {
            self.edit_point.line = self.lines.len() - 1;
            self.edit_point.index = self.current_line_length();
            return;
        }

        self.edit_point.line = (self.edit_point.line as int + adjust) as uint;
        self.edit_point.index = min(self.current_line_length(), self.edit_point.index);
    }

    /// Adjust the editing point position by a given number of columns. If the adjustment
    /// requested is larger than is available in the current line, the editing point is
    /// adjusted vertically and the process repeats with the remaining adjustment requested.
    fn adjust_horizontal(&mut self, adjust: int, select: bool) {
        if select {
            if self.selection_begin.is_none() {
                self.selection_begin = Some(self.edit_point);
            }
        } else {
            self.selection_begin = None;
        }

        if adjust < 0 {
            let remaining = self.edit_point.index;
            if adjust.abs() as uint > remaining && self.edit_point.line > 0 {
                self.adjust_vertical(-1, select);
                self.edit_point.index = self.current_line_length();
                self.adjust_horizontal(adjust + remaining as int, select);
            } else {
                self.edit_point.index = max(0, self.edit_point.index as int + adjust) as uint;
            }
        } else {
            let remaining = self.current_line_length() - self.edit_point.index;
            if adjust as uint > remaining && self.edit_point.line < self.lines.len() - 1 {
                self.edit_point.index = 0;
                self.adjust_vertical(1, select);
                self.adjust_horizontal(adjust - remaining as int, select);
            } else {
                self.edit_point.index = min(self.current_line_length(),
                                            self.edit_point.index + adjust as uint);
            }
        }
    }

    /// Deal with a newline input.
    fn handle_return(&mut self) -> KeyReaction {
        if !self.multiline {
            return TriggerDefaultAction;
        }
        self.insert_char('\n');
        return DispatchInput;
    }

    /// Process a given `KeyboardEvent` and return an action for the caller to execute.
    pub fn handle_keydown(&mut self, event: JSRef<KeyboardEvent>) -> KeyReaction {
        match event.Key().as_slice() {
            // printable characters have single-character key values
            c if c.len() == 1 => {
                self.insert_char(c.char_at(0));
                return DispatchInput;
            }
            "Space" => {
                self.insert_char(' ');
                DispatchInput
            }
            "Delete" => {
                self.delete_char(Forward);
                DispatchInput
            }
            "Backspace" => {
                self.delete_char(Backward);
                DispatchInput
            }
            "ArrowLeft" => {
                self.adjust_horizontal(-1, event.ShiftKey());
                Nothing
            }
            "ArrowRight" => {
                self.adjust_horizontal(1, event.ShiftKey());
                Nothing
            }
            "ArrowUp" => {
                self.adjust_vertical(-1, event.ShiftKey());
                Nothing
            }
            "ArrowDown" => {
                self.adjust_vertical(1, event.ShiftKey());
                Nothing
            }
            "Enter" => self.handle_return(),
            "Home" => {
                self.edit_point.index = 0;
                Nothing
            }
            "End" => {
                self.edit_point.index = self.current_line_length();
                Nothing
            }
            "PageUp" => {
                self.adjust_vertical(-28, event.ShiftKey());
                Nothing
            }
            "PageDown" => {
                self.adjust_vertical(28, event.ShiftKey());
                Nothing
            }
            "Tab" => TriggerDefaultAction,
            _ => Nothing,
        }
    }

    /// Get the current contents of the text input. Multiple lines are joined by \n.
    pub fn get_content(&self) -> DOMString {
        let mut content = "".to_string();
        for (i, line) in self.lines.iter().enumerate() {
            content.push_str(line.as_slice());
            if i < self.lines.len() - 1 {
                content.push('\n');
            }
        }
        content
    }

    /// Set the current contents of the text input. If this is control supports multiple lines,
    /// any \n encountered will be stripped and force a new logical line.
    pub fn set_content(&mut self, content: DOMString) {
        self.lines = if self.multiline {
            content.as_slice().split('\n').map(|s| s.to_string()).collect()
        } else {
            vec!(content)
        };
        self.edit_point.line = min(self.edit_point.line, self.lines.len() - 1);
        self.edit_point.index = min(self.edit_point.index, self.current_line_length() - 1);
    }
}
<|endoftext|>


<commit_before>#![feature(proc_macro)]
#![feature(proc_macro_lib)]
#![recursion_limit = "128"]

#[macro_use] extern crate quote;

extern crate proc_macro;
extern crate syn;

use proc_macro::TokenStream;
use std::str::FromStr;

// Yield mock generated code for template
//     Hello, {{name}} ({{age}})
#[proc_macro_derive(StacheDisplay)]
pub fn stach(input: TokenStream) -> TokenStream {
    let s = input.to_string();
    let ast = syn::parse_macro_input(&s).unwrap();

    let gen = quote! {
        impl<'a> std::fmt::Display for Greeting<'a> {
            fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
                use display_html_safe::DisplayHtmlSafe;

                f.write_str("Hello, ")?;
                DisplayHtmlSafe::fmt(&self.name, f)?;
                f.write_str(" (")?;
                DisplayHtmlSafe::fmt(&self.age, f)?;
                f.write_str(")\n")?;
                Ok(())
            }
        }
    };

    gen.parse().unwrap()
}

#[cfg(test)]
mod tests {
    #[test]
    fn it_works() {
    }
}
<commit_msg>Use macro input to generate impl for correct struct<commit_after>#![feature(proc_macro)]
#![feature(proc_macro_lib)]
#![recursion_limit = "128"]

#[macro_use] extern crate quote;

extern crate proc_macro;
extern crate syn;

use proc_macro::TokenStream;
use std::str::FromStr;

// Yield mock generated code for template
//     Hello, {{name}} ({{age}})
#[proc_macro_derive(StacheDisplay)]
pub fn stach(input: TokenStream) -> TokenStream {
    let s = input.to_string();
    let ast = syn::parse_macro_input(&s).unwrap();

    let type_name = &ast.ident;
    let generics = &ast.generics;

    let gen = quote! {
        impl #generics std::fmt::Display for #type_name #generics {
            fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
                use display_html_safe::DisplayHtmlSafe;

                f.write_str("Hello, ")?;
                DisplayHtmlSafe::fmt(&self.name, f)?;
                f.write_str(" (")?;
                DisplayHtmlSafe::fmt(&self.age, f)?;
                f.write_str(")\n")?;
                Ok(())
            }
        }
    };

    gen.parse().unwrap()
}

#[cfg(test)]
mod tests {
    #[test]
    fn it_works() {
    }
}
<|endoftext|>


<commit_before>extern crate open;

use kay::{ActorSystem, World, Networking};
use monet::glium::glutin::WindowBuilder;
use stagemaster::UserInterfaceID;
use std::net::SocketAddr;
use std::time::Instant;

pub fn ensure_crossplatform_proper_thread<F: Fn() -> () + Send + 'static>(callback: F) {
    // Makes sure that:
    // a) on Windows we use a dummy thread with manually set stack size
    // b) on Mac/Linux we use the main thread, because we have to create the UI there

    if cfg!(windows) {
        let dummy_thread = ::std::thread::Builder::new()
            .stack_size(32 * 1024 * 1024)
            .spawn(callback)
            .unwrap();
        dummy_thread.join().unwrap();
    } else {
        callback();
    }
}

pub fn first_time_open_wiki_release_page() {
    let mut dir = ::std::env::temp_dir();
    dir.push("cb_seen_wiki.txt");
    if !::std::path::Path::new(&dir).exists() {
        let url = "https://github.com/citybound/citybound/wiki/Road-&-Traffic-Prototype-1.2";
        if let Err(_err) = open::that(url) {
            println!("Please open {:?} in your browser!", url);
        };
        ::std::fs::File::create(dir).expect("should be able to create tmp file");
    }
}

use std::panic::{set_hook, PanicInfo};
use backtrace::Backtrace;
use std::fs::File;
use std::io::Write;

pub fn set_error_hook(ui_id: UserInterfaceID, mut world: World) {
    let callback: Box<FnMut(&PanicInfo)> = Box::new(move |panic_info| {

        let title = "SIMULATION BROKE :(";

        let message = match panic_info.payload().downcast_ref::<String>() {
            Some(string) => (string.clone()),
            None => {
                match panic_info.payload().downcast_ref::<&'static str>() {
                    Some(static_str) => (*static_str).to_string(),
                    None => "Weird error type".to_string(),
                }
            }
        };

        let backtrace = Backtrace::new();
        let location = format!(
            "at {}, line {}",
            panic_info.location().map(|l| l.file()).unwrap_or("unknown"),
            panic_info.location().map(|l| l.line()).unwrap_or(0)
        );

        let body = format!(
            "WHAT HAPPENED: {}\nWHERE IT HAPPENED:\n{}\nWHERE EXACTLY:\n{:?}",
            message,
            location,
            backtrace
        );

        let small_body = format!(
            "{}\n{}\nDETAILS IN cb_last_error.txt (AUTO-OPENED)",
            message,
            location
        );

        let report_guide = "HOW TO REPORT BUGS: https://github.com/citybound/citybound/blob/master/CONTRIBUTING.md#reporting-bugs";

        println!(
            "{}\n{}\nALSO SEE cb_last_error.txt (AUTO-OPENED)",
            title,
            body
        );

        {
            if let Ok(mut file) = File::create("./cb_last_error.txt") {
                if let Err(_) = write!(file, "{}\n{}\n\nDETAILS:\n{}", title, report_guide, body) {
                    println!("Error writing error file, lol");
                }
            };
        }

        if let Err(_) = open::that("./cb_last_error.txt") {
            println!("Couldn't open error file");
        };

        ui_id.add_debug_text(
            title.to_owned().into(),
            small_body.into(),
            [1.0, 0.0, 0.0, 1.0],
            true,
            &mut world,
        );
        ui_id.on_panic(&mut world);
    });

    set_hook(unsafe { ::std::mem::transmute(callback) });
}

pub fn networking_from_env_args() -> Networking {
    println!("{:?}", ::std::env::args().collect::<Vec<_>>());

    if ::std::env::args().nth(1).is_none() {
        Networking::new(0, vec!["127.0.0.1:3500".parse().unwrap()])
    } else {
        let machine_id: u8 = ::std::env::args()
            .nth(1)
            .expect("expected machine_id")
            .parse()
            .unwrap();
        let network: Vec<SocketAddr> = ::std::env::args()
            .nth(2)
            .expect("expected network")
            .split(',')
            .map(|addr_str| addr_str.parse().unwrap())
            .collect();

        Networking::new(machine_id, network)
    }

}

pub fn build_window(machine_id: u8) -> WindowBuilder {
    WindowBuilder::new()
        .with_title(format!("Citybound (machine {})", machine_id))
        .with_dimensions(1920, 1080)
        .with_multitouch()
}

pub fn print_version(user_interface: UserInterfaceID, world: &mut World) {
    user_interface.add_debug_text(
        "Version".to_owned().into(),
        ::ENV.version.to_owned().into(),
        [0.0, 0.0, 0.0, 1.0],
        true,
        world,
    );
}

pub fn print_instance_counts(system: &mut ActorSystem, user_interface: UserInterfaceID) {
    user_interface.add_debug_text(
        "Number of actors".to_owned().into(),
        system.get_instance_counts().into(),
        [0.0, 0.0, 0.0, 1.0],
        false,
        &mut system.world(),
    );
}

pub fn print_network_turn(system: &mut ActorSystem, user_interface: UserInterfaceID) {
    user_interface.add_debug_text(
        "Networking turn".to_owned().into(),
        system.networking_debug_all_n_turns().into(),
        [0.0, 0.0, 0.0, 1.0],
        false,
        &mut system.world(),
    );
}

pub struct FrameCounter {
    last_frame: Instant,
    elapsed_ms_collected: Vec<f32>,
}

impl FrameCounter {
    pub fn new() -> FrameCounter {
        FrameCounter {
            last_frame: Instant::now(),
            elapsed_ms_collected: Vec::new(),
        }
    }

    pub fn start_frame(&mut self) {
        let elapsed_ms = self.last_frame.elapsed().as_secs() as f32 * 1000.0 +
            self.last_frame.elapsed().subsec_nanos() as f32 / 10.0E5;

        self.elapsed_ms_collected.push(elapsed_ms);

        if self.elapsed_ms_collected.len() > 10 {
            self.elapsed_ms_collected.remove(0);
        }

        self.last_frame = Instant::now();
    }

    pub fn print_fps(&self, user_interface: UserInterfaceID, world: &mut World) {
        let avg_elapsed_ms = self.elapsed_ms_collected.iter().sum::<f32>() /
            (self.elapsed_ms_collected.len() as f32);

        user_interface.add_debug_text(
            "Frame".to_owned().into(),
            format!("{:.1} FPS", 1000.0 * 1.0 / avg_elapsed_ms).into(),
            [0.0, 0.0, 0.0, 0.5],
            false,
            world,
        );
    }
}
<commit_msg>Error formatting<commit_after>extern crate open;

use kay::{ActorSystem, World, Networking};
use monet::glium::glutin::WindowBuilder;
use stagemaster::UserInterfaceID;
use std::net::SocketAddr;
use std::time::Instant;

pub fn ensure_crossplatform_proper_thread<F: Fn() -> () + Send + 'static>(callback: F) {
    // Makes sure that:
    // a) on Windows we use a dummy thread with manually set stack size
    // b) on Mac/Linux we use the main thread, because we have to create the UI there

    if cfg!(windows) {
        let dummy_thread = ::std::thread::Builder::new()
            .stack_size(32 * 1024 * 1024)
            .spawn(callback)
            .unwrap();
        dummy_thread.join().unwrap();
    } else {
        callback();
    }
}

pub fn first_time_open_wiki_release_page() {
    let mut dir = ::std::env::temp_dir();
    dir.push("cb_seen_wiki.txt");
    if !::std::path::Path::new(&dir).exists() {
        let url = "https://github.com/citybound/citybound/wiki/Road-&-Traffic-Prototype-1.2";
        if let Err(_err) = open::that(url) {
            println!("Please open {:?} in your browser!", url);
        };
        ::std::fs::File::create(dir).expect("should be able to create tmp file");
    }
}

use std::panic::{set_hook, PanicInfo};
use backtrace::Backtrace;
use std::fs::File;
use std::io::Write;

pub fn set_error_hook(ui_id: UserInterfaceID, mut world: World) {
    let callback: Box<FnMut(&PanicInfo)> = Box::new(move |panic_info| {

        let title = "SIMULATION BROKE :(";

        let message = match panic_info.payload().downcast_ref::<String>() {
            Some(string) => (string.clone()),
            None => {
                match panic_info.payload().downcast_ref::<&'static str>() {
                    Some(static_str) => (*static_str).to_string(),
                    None => "Weird error type".to_string(),
                }
            }
        };

        let backtrace = Backtrace::new();
        let location = format!(
            "at {}, line {}",
            panic_info.location().map(|l| l.file()).unwrap_or("unknown"),
            panic_info.location().map(|l| l.line()).unwrap_or(0)
        );

        let body = format!(
            "WHAT HAPPENED:\n{}\nWHERE IT HAPPENED:\n{}\nWHERE EXACTLY:\n{:?}",
            message,
            location,
            backtrace
        );

        let small_body = format!(
            "{}\n{}\nDETAILS IN cb_last_error.txt (AUTO-OPENED)",
            message,
            location
        );

        let report_guide = "HOW TO REPORT BUGS: https://github.com/citybound/citybound/blob/master/CONTRIBUTING.md#reporting-bugs";

        println!(
            "{}\n{}\nALSO SEE cb_last_error.txt (AUTO-OPENED)",
            title,
            body
        );

        {
            if let Ok(mut file) = File::create("./cb_last_error.txt") {
                if let Err(_) = write!(file, "{}\n{}\n\nDETAILS:\n{}", title, report_guide, body) {
                    println!("Error writing error file, lol");
                }
            };
        }

        if let Err(_) = open::that("./cb_last_error.txt") {
            println!("Couldn't open error file");
        };

        ui_id.add_debug_text(
            title.to_owned().into(),
            small_body.into(),
            [1.0, 0.0, 0.0, 1.0],
            true,
            &mut world,
        );
        ui_id.on_panic(&mut world);
    });

    set_hook(unsafe { ::std::mem::transmute(callback) });
}

pub fn networking_from_env_args() -> Networking {
    println!("{:?}", ::std::env::args().collect::<Vec<_>>());

    if ::std::env::args().nth(1).is_none() {
        Networking::new(0, vec!["127.0.0.1:3500".parse().unwrap()])
    } else {
        let machine_id: u8 = ::std::env::args()
            .nth(1)
            .expect("expected machine_id")
            .parse()
            .unwrap();
        let network: Vec<SocketAddr> = ::std::env::args()
            .nth(2)
            .expect("expected network")
            .split(',')
            .map(|addr_str| addr_str.parse().unwrap())
            .collect();

        Networking::new(machine_id, network)
    }

}

pub fn build_window(machine_id: u8) -> WindowBuilder {
    WindowBuilder::new()
        .with_title(format!("Citybound (machine {})", machine_id))
        .with_dimensions(1920, 1080)
        .with_multitouch()
}

pub fn print_version(user_interface: UserInterfaceID, world: &mut World) {
    user_interface.add_debug_text(
        "Version".to_owned().into(),
        ::ENV.version.to_owned().into(),
        [0.0, 0.0, 0.0, 1.0],
        true,
        world,
    );
}

pub fn print_instance_counts(system: &mut ActorSystem, user_interface: UserInterfaceID) {
    user_interface.add_debug_text(
        "Number of actors".to_owned().into(),
        system.get_instance_counts().into(),
        [0.0, 0.0, 0.0, 1.0],
        false,
        &mut system.world(),
    );
}

pub fn print_network_turn(system: &mut ActorSystem, user_interface: UserInterfaceID) {
    user_interface.add_debug_text(
        "Networking turn".to_owned().into(),
        system.networking_debug_all_n_turns().into(),
        [0.0, 0.0, 0.0, 1.0],
        false,
        &mut system.world(),
    );
}

pub struct FrameCounter {
    last_frame: Instant,
    elapsed_ms_collected: Vec<f32>,
}

impl FrameCounter {
    pub fn new() -> FrameCounter {
        FrameCounter {
            last_frame: Instant::now(),
            elapsed_ms_collected: Vec::new(),
        }
    }

    pub fn start_frame(&mut self) {
        let elapsed_ms = self.last_frame.elapsed().as_secs() as f32 * 1000.0 +
            self.last_frame.elapsed().subsec_nanos() as f32 / 10.0E5;

        self.elapsed_ms_collected.push(elapsed_ms);

        if self.elapsed_ms_collected.len() > 10 {
            self.elapsed_ms_collected.remove(0);
        }

        self.last_frame = Instant::now();
    }

    pub fn print_fps(&self, user_interface: UserInterfaceID, world: &mut World) {
        let avg_elapsed_ms = self.elapsed_ms_collected.iter().sum::<f32>() /
            (self.elapsed_ms_collected.len() as f32);

        user_interface.add_debug_text(
            "Frame".to_owned().into(),
            format!("{:.1} FPS", 1000.0 * 1.0 / avg_elapsed_ms).into(),
            [0.0, 0.0, 0.0, 0.5],
            false,
            world,
        );
    }
}
<|endoftext|>


<commit_before>extern crate mio;
extern crate regex;

#[cfg(test)]
mod tests;

mod route;
mod request;
mod response;

use std::io::Result;
use std::io::prelude::*;
use std::net::ToSocketAddrs;
use std::collections::HashMap;
use mio::tcp::{TcpListener, TcpStream};
use mio::util::Slab;
use mio::*;

use route::*;
use request::*;
use response::*;

struct Client {
    sock:   TcpStream,
    token:  Token,
    events: EventSet,
    i_buf:  Vec<u8>,
    o_buf:  Vec<u8>,
}

impl Client {
    fn new(sock: TcpStream, token: Token) -> Client {
        Client {
            sock:   sock,
            token:  token,
            events: EventSet::hup(),
            i_buf:  Vec::new(),
            o_buf:  Vec::new(),
        }
    }

    fn readable(&mut self) -> Result<bool> {
        let mut buf: Vec<u8> = Vec::with_capacity(2048);

        match self.sock.try_read_buf(&mut buf) {
            Ok(size)  => {
                match size {
                    Some(sz) => {
                        println!("read {} ({}) bytes", sz, buf.len());
                        self.events.remove(EventSet::readable());
                        self.events.insert(EventSet::writable());
                        self.i_buf.extend(buf);
                        return Ok(true);
                    },
                    None     => {
                        return Ok(false);
                    },
                }
            },
            Err(e)  => {
                panic!("failed to read from socket! <token: {:?}> <error: {:?}>", self.token, e);
            },
        }

        Ok(false)
    }

    /* write the client's output buffer to the socket.
     *
     * the following return values mean:
     *  - Ok(true):  we can close the connection
     *  - Ok(false): keep listening for writeable event and continue next time
     *  - Err(e):    something dun fucked up
     */
    fn writable(&mut self) -> Result<bool> {
        let tmp = self.o_buf.clone();
        let out = tmp.as_slice();
        match self.sock.write(&out) {
            Ok(sz)  => {
                if sz == self.o_buf.len() {
                    /* we did it! */
                    self.events.remove(EventSet::writable());
                    return Ok(true);
                } else {
                    let tmp: Vec<u8> = self.o_buf.split_off(sz);
                    println!("{:?}, -{}, {:?}", out, sz, tmp);
                    self.o_buf = tmp;

                    return Ok(false);
                }
            },
            Err(e)  => {
                panic!("failed to write to socket! <token: {:?}> <error: {:?}>", self.token, e);
            }
        }

        Ok(false)
    }

    fn register(&mut self, evl: &mut EventLoop<Canteen>) -> Result<()> {
        self.events.insert(EventSet::readable());

        evl.register(&self.sock, self.token, self.events, PollOpt::edge() | PollOpt::oneshot())
           .or_else(|e| {
               panic!("failed to register client! <token: {:?}> <error: {:?}>", self.token, e);
           })
    }

    fn reregister(&mut self, evl: &mut EventLoop<Canteen>) -> Result<()> {
        evl.reregister(&self.sock, self.token, self.events, PollOpt::edge() | PollOpt::oneshot())
           .or_else(|e| {
               panic!("failed to re-register client! <token: {:?}> <error: {:?}>", self.token, e);
           })
    }
}

/* our primary object. similar interface to Flask, the
 * Python microframework. much faster, however! :)
 */
pub struct Canteen {
    routes: HashMap<String, Route>,
    server: TcpListener,
    token:  Token,
    conns:  Slab<Client>,
}

impl Handler for Canteen {
    type Timeout = ();
    type Message = u32;

    fn ready(&mut self, evl: &mut EventLoop<Canteen>, token: Token, events: EventSet) {
        if events.is_error() || events.is_hup() {
            self.reset_connection(token);
            return;
        }

        if events.is_readable() {
            if self.token == token {
                self.accept(evl);
            } else {
                self.readable(evl, token)
                    .and_then(|_| self.get_client(token)
                                      .reregister(evl))
                    .unwrap_or_else(|e| {
                        panic!("read event failed! <token: {:?}> <error: {:?}>", token, e);
                    });
            }

            return;
        }

        if events.is_writable() {
            match self.get_client(token).writable() {
                Ok(true)    => { self.reset_connection(token); },
                Ok(false)   => { let _ = self.get_client(token).reregister(evl); },
                Err(_)      => { panic!("something really bad happened!"); },
            }
        }
    }
}

impl Canteen {
    fn new(addr: A) -> Canteen {
        Canteen {
            routes: HashMap::new(),
            server: TcpListener::bind(&addr.to_socket_addrs().unwrap().next().unwrap()).unwrap(),
            token:  Token(1),
            conns:  Slab::new_starting_at(Token(2), 2048),
        }
    }

    fn add_route(&mut self, path: &str, mlist: Vec<Method>, handler: fn(Request) -> Response) {
        let pc = String::from(path);

        if self.routes.contains_key(&pc) {
            panic!("a route handler for {} has already been defined!", path);
        }

        self.routes.insert(String::from(path), Route::new(&path, mlist, handler));
    }

    fn get_client<'a>(&'a mut self, token: Token) -> &'a mut Client {
        &mut self.conns[token]
    }

    fn accept(&mut self, evl: &mut EventLoop<Canteen>) {
        let (sock, _) = match self.server.accept() {
            Ok(s)   => {
                match s {
                    Some(sock)  => sock,
                    None        => {
                        panic!("failed to accept new connection!");
                    }
                }
            },
            Err(e)  => {
                panic!("failed to accept new connection! <error: {:?}>", e);
            },
        };

        match self.conns.insert_with(|token| Client::new(sock, token)) {
            Some(token) => {
                match self.get_client(token).register(evl) {
                    Ok(_)   => {},
                    Err(e)  => {
                        panic!("failed to register client! <token: {:?}> <error: {:?}>", token, e);
                    },
                }
            },
            None        => {
                panic!("failed to add client connection!");
            },
        }

        self.reregister(evl);
    }

    fn find_handler(&self, req: &Request) -> (fn(Request) -> Response) {
        let mut handler: fn(Request) -> Response = Route::_no_op;

        for (_, route) in &self.routes {
            match (route).is_match(req) {
                true  => { handler = route.handler; break; },
                false => continue,
            }
        }

        handler
    }

    fn readable(&mut self, evl: &mut EventLoop<Canteen>, token: Token) -> Result<bool> {
        match self.get_client(token).readable() {
            Ok(true)    => {
                let buf = self.get_client(token).i_buf.clone();
                let rqstr = String::from_utf8(buf).unwrap();
                let req = Request::from_str(&rqstr);
                let handler: fn(Request) -> Response = self.find_handler(&req);

                self.get_client(token).o_buf.extend(handler(req).gen_output());
            },
            Ok(false)   => {},
            Err(e)      => {
                panic!("message wasn't actually readable! <error: {:?}>", e);
            },
        };

        let _ = self.get_client(token).reregister(evl);

        Ok(true)
    }

    fn reset_connection(&mut self, token: Token) {
        /* kill the connection */
        self.conns.remove(token);
    }

    fn register(&mut self, evl: &mut EventLoop<Canteen>) -> Result<()> {
        evl.register(&self.server, self.token, EventSet::readable(), PollOpt::edge() | PollOpt::oneshot())
           .or_else(|e| {
               panic!("failed to register server! <token: {:?}> <error: {:?}>", self.token, e);
           })
    }

    fn reregister(&mut self, evl: &mut EventLoop<Canteen>) {
        match evl.reregister(&self.server, self.token,
                             EventSet::readable(),
                             PollOpt::edge() | PollOpt::oneshot()) {
            Ok(_)   => {},
            Err(e)  => {
               panic!("failed to register server! <token: {:?}> <error: {:?}>", self.token, e);
           }
        };
    }

    fn run(&mut self) {
        let mut evl = EventLoop::new().unwrap();
        self.register(&mut evl).ok();
        evl.run(self).unwrap();
    }
}

fn my_handler(req: Request) -> Response {
    let mut res = Response::new();

    res.set_content_type("text/html");
    res.append(String::from("\

It's alive!

Welcome to Canteen! :)
"));

    res
}

fn main() {
    let mut cnt = Canteen::new(("127.0.0.1", 8080));
    cnt.add_route("/hello", vec![Method::Get], my_handler);
    cnt.run();
}
<commit_msg>allow for setting a default handler<commit_after>extern crate mio;
extern crate regex;

#[cfg(test)]
mod tests;

mod route;
mod request;
mod response;

use std::io::Result;
use std::io::prelude::*;
use std::net::ToSocketAddrs;
use std::collections::HashMap;
use mio::tcp::{TcpListener, TcpStream};
use mio::util::Slab;
use mio::*;

use route::*;
use request::*;
use response::*;

struct Client {
    sock:   TcpStream,
    token:  Token,
    events: EventSet,
    i_buf:  Vec<u8>,
    o_buf:  Vec<u8>,
}

impl Client {
    fn new(sock: TcpStream, token: Token) -> Client {
        Client {
            sock:   sock,
            token:  token,
            events: EventSet::hup(),
            i_buf:  Vec::new(),
            o_buf:  Vec::new(),
        }
    }

    fn readable(&mut self) -> Result<bool> {
        let mut buf: Vec<u8> = Vec::with_capacity(2048);

        match self.sock.try_read_buf(&mut buf) {
            Ok(size)  => {
                match size {
                    Some(sz) => {
                        println!("read {} ({}) bytes", sz, buf.len());
                        self.events.remove(EventSet::readable());
                        self.events.insert(EventSet::writable());
                        self.i_buf.extend(buf);
                        return Ok(true);
                    },
                    None     => {
                        return Ok(false);
                    },
                }
            },
            Err(e)  => {
                panic!("failed to read from socket! <token: {:?}> <error: {:?}>", self.token, e);
            },
        }

        Ok(false)
    }

    /* write the client's output buffer to the socket.
     *
     * the following return values mean:
     *  - Ok(true):  we can close the connection
     *  - Ok(false): keep listening for writeable event and continue next time
     *  - Err(e):    something dun fucked up
     */
    fn writable(&mut self) -> Result<bool> {
        let tmp = self.o_buf.clone();
        let out = tmp.as_slice();
        match self.sock.write(&out) {
            Ok(sz)  => {
                if sz == self.o_buf.len() {
                    /* we did it! */
                    self.events.remove(EventSet::writable());
                    return Ok(true);
                } else {
                    let tmp: Vec<u8> = self.o_buf.split_off(sz);
                    println!("{:?}, -{}, {:?}", out, sz, tmp);
                    self.o_buf = tmp;

                    return Ok(false);
                }
            },
            Err(e)  => {
                panic!("failed to write to socket! <token: {:?}> <error: {:?}>", self.token, e);
            }
        }

        Ok(false)
    }

    fn register(&mut self, evl: &mut EventLoop<Canteen>) -> Result<()> {
        self.events.insert(EventSet::readable());

        evl.register(&self.sock, self.token, self.events, PollOpt::edge() | PollOpt::oneshot())
           .or_else(|e| {
               panic!("failed to register client! <token: {:?}> <error: {:?}>", self.token, e);
           })
    }

    fn reregister(&mut self, evl: &mut EventLoop<Canteen>) -> Result<()> {
        evl.reregister(&self.sock, self.token, self.events, PollOpt::edge() | PollOpt::oneshot())
           .or_else(|e| {
               panic!("failed to re-register client! <token: {:?}> <error: {:?}>", self.token, e);
           })
    }
}

/* our primary object. similar interface to Flask, the
 * Python microframework. much faster, however! :)
 */
pub struct Canteen {
    routes:  HashMap<String, Route>,
    server:  TcpListener,
    token:   Token,
    conns:   Slab<Client>,
    default: fn(Request) -> Response,
}

impl Handler for Canteen {
    type Timeout = ();
    type Message = u32;

    fn ready(&mut self, evl: &mut EventLoop<Canteen>, token: Token, events: EventSet) {
        if events.is_error() || events.is_hup() {
            self.reset_connection(token);
            return;
        }

        if events.is_readable() {
            if self.token == token {
                self.accept(evl);
            } else {
                self.readable(evl, token)
                    .and_then(|_| self.get_client(token)
                                      .reregister(evl))
                    .unwrap_or_else(|e| {
                        panic!("read event failed! <token: {:?}> <error: {:?}>", token, e);
                    });
            }

            return;
        }

        if events.is_writable() {
            match self.get_client(token).writable() {
                Ok(true)    => { self.reset_connection(token); },
                Ok(false)   => { let _ = self.get_client(token).reregister(evl); },
                Err(_)      => { panic!("something really bad happened!"); },
            }
        }
    }
}

impl Canteen {
    fn new(addr: A) -> Canteen {
        Canteen {
            routes:  HashMap::new(),
            server:  TcpListener::bind(&addr.to_socket_addrs().unwrap().next().unwrap()).unwrap(),
            token:   Token(1),
            conns:   Slab::new_starting_at(Token(2), 2048),
            default: Route::_no_op,
        }
    }

    fn add_route(&mut self, path: &str, mlist: Vec<Method>, handler: fn(Request) -> Response) {
        let pc = String::from(path);

        if self.routes.contains_key(&pc) {
            panic!("a route handler for {} has already been defined!", path);
        }

        self.routes.insert(String::from(path), Route::new(&path, mlist, handler));
    }

    pub fn set_default(&mut self, handler: fn(Request) -> Response) {
        self.default = handler;
    }

    fn get_client<'a>(&'a mut self, token: Token) -> &'a mut Client {
        &mut self.conns[token]
    }

    fn accept(&mut self, evl: &mut EventLoop<Canteen>) {
        let (sock, _) = match self.server.accept() {
            Ok(s)   => {
                match s {
                    Some(sock)  => sock,
                    None        => {
                        panic!("failed to accept new connection!");
                    }
                }
            },
            Err(e)  => {
                panic!("failed to accept new connection! <error: {:?}>", e);
            },
        };

        match self.conns.insert_with(|token| Client::new(sock, token)) {
            Some(token) => {
                match self.get_client(token).register(evl) {
                    Ok(_)   => {},
                    Err(e)  => {
                        panic!("failed to register client! <token: {:?}> <error: {:?}>", token, e);
                    },
                }
            },
            None        => {
                panic!("failed to add client connection!");
            },
        }

        self.reregister(evl);
    }

    fn find_handler(&self, req: &Request) -> (fn(Request) -> Response) {
        let mut handler: fn(Request) -> Response = self.default;

        for (_, route) in &self.routes {
            match (route).is_match(req) {
                true  => { handler = route.handler; break; },
                false => continue,
            }
        }

        handler
    }

    fn readable(&mut self, evl: &mut EventLoop<Canteen>, token: Token) -> Result<bool> {
        match self.get_client(token).readable() {
            Ok(true)    => {
                let buf = self.get_client(token).i_buf.clone();
                let rqstr = String::from_utf8(buf).unwrap();
                let req = Request::from_str(&rqstr);
                let handler: fn(Request) -> Response = self.find_handler(&req);

                self.get_client(token).o_buf.extend(handler(req).gen_output());
            },
            Ok(false)   => {},
            Err(e)      => {
                panic!("message wasn't actually readable! <error: {:?}>", e);
            },
        };

        let _ = self.get_client(token).reregister(evl);

        Ok(true)
    }

    fn reset_connection(&mut self, token: Token) {
        /* kill the connection */
        self.conns.remove(token);
    }

    fn register(&mut self, evl: &mut EventLoop<Canteen>) -> Result<()> {
        evl.register(&self.server, self.token, EventSet::readable(), PollOpt::edge() | PollOpt::oneshot())
           .or_else(|e| {
               panic!("failed to register server! <token: {:?}> <error: {:?}>", self.token, e);
           })
    }

    fn reregister(&mut self, evl: &mut EventLoop<Canteen>) {
        match evl.reregister(&self.server, self.token,
                             EventSet::readable(),
                             PollOpt::edge() | PollOpt::oneshot()) {
            Ok(_)   => {},
            Err(e)  => {
               panic!("failed to register server! <token: {:?}> <error: {:?}>", self.token, e);
           }
        };
    }

    fn run(&mut self) {
        let mut evl = EventLoop::new().unwrap();
        self.register(&mut evl).ok();
        evl.run(self).unwrap();
    }
}

fn my_handler(req: Request) -> Response {
    let mut res = Response::new();

    res.set_content_type("text/html");
    res.append(String::from("\

It's alive!

Welcome to Canteen! :)
"));

    res
}

fn main() {
    let mut cnt = Canteen::new(("127.0.0.1", 8080));
    cnt.add_route("/hello", vec![Method::Get], my_handler);
    cnt.set_default(Route::err_404);
    cnt.run();
}
<|endoftext|>


<commit_before>// Note: More specifically this lint is largely inspired (aka copied) from
// *rustc*'s
// [`missing_doc`].
//
// [`missing_doc`]: https://github.com/rust-lang/rust/blob/cf9cf7c923eb01146971429044f216a3ca905e06/compiler/rustc_lint/src/builtin.rs#L415
//

use clippy_utils::attrs::is_doc_hidden;
use clippy_utils::diagnostics::span_lint;
use rustc_ast::ast;
use rustc_hir as hir;
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::ty;
use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::source_map::Span;
use rustc_span::sym;

declare_clippy_lint! {
    /// ### What it does
    /// Warns if there is missing doc for any documentable item
    /// (public or private).
    ///
    /// ### Why is this bad?
    /// Doc is good. *rustc* has a `MISSING_DOCS`
    /// allowed-by-default lint for
    /// public members, but has no way to enforce documentation of private items.
    /// This lint fixes that.
    pub MISSING_DOCS_IN_PRIVATE_ITEMS,
    restriction,
    "detects missing documentation for public and private members"
}

pub struct MissingDoc {
    /// Stack of whether #[doc(hidden)] is set
    /// at each level which has lint attributes.
    doc_hidden_stack: Vec<bool>,
}

impl Default for MissingDoc {
    #[must_use]
    fn default() -> Self {
        Self::new()
    }
}

impl MissingDoc {
    #[must_use]
    pub fn new() -> Self {
        Self {
            doc_hidden_stack: vec![false],
        }
    }

    fn doc_hidden(&self) -> bool {
        *self.doc_hidden_stack.last().expect("empty doc_hidden_stack")
    }

    fn check_missing_docs_attrs(
        &self,
        cx: &LateContext<'_>,
        attrs: &[ast::Attribute],
        sp: Span,
        article: &'static str,
        desc: &'static str,
    ) {
        // If we're building a test harness, then warning about
        // documentation is probably not really relevant right now.
        if cx.sess().opts.test {
            return;
        }

        // `#[doc(hidden)]` disables missing_docs check.
        if self.doc_hidden() {
            return;
        }

        if sp.from_expansion() {
            return;
        }

        let has_doc = attrs
            .iter()
            .any(|a| a.doc_str().is_some());
        if !has_doc {
            span_lint(
                cx,
                MISSING_DOCS_IN_PRIVATE_ITEMS,
                sp,
                &format!("missing documentation for {} {}", article, desc),
            );
        }
    }
}

impl_lint_pass!(MissingDoc => [MISSING_DOCS_IN_PRIVATE_ITEMS]);

impl<'tcx> LateLintPass<'tcx> for MissingDoc {
    fn enter_lint_attrs(&mut self, _: &LateContext<'tcx>, attrs: &'tcx [ast::Attribute]) {
        let doc_hidden = self.doc_hidden() || is_doc_hidden(attrs);
        self.doc_hidden_stack.push(doc_hidden);
    }

    fn exit_lint_attrs(&mut self, _: &LateContext<'tcx>, _: &'tcx [ast::Attribute]) {
        self.doc_hidden_stack.pop().expect("empty doc_hidden_stack");
    }

    fn check_crate(&mut self, cx: &LateContext<'tcx>, krate: &'tcx hir::Crate<'_>) {
        let attrs = cx.tcx.hir().attrs(hir::CRATE_HIR_ID);
        self.check_missing_docs_attrs(cx, attrs, krate.module().inner, "the", "crate");
    }

    fn check_item(&mut self, cx: &LateContext<'tcx>, it: &'tcx hir::Item<'_>) {
        match it.kind {
            hir::ItemKind::Fn(..) => {
                // ignore main()
                if it.ident.name == sym::main {
                    let def_key = cx.tcx.hir().def_key(it.def_id);
                    if def_key.parent == Some(hir::def_id::CRATE_DEF_INDEX) {
                        return;
                    }
                }
            },
            hir::ItemKind::Const(..)
            | hir::ItemKind::Enum(..)
            | hir::ItemKind::Mod(..)
            | hir::ItemKind::Static(..)
            | hir::ItemKind::Struct(..)
            | hir::ItemKind::Trait(..)
            | hir::ItemKind::TraitAlias(..)
            | hir::ItemKind::TyAlias(..)
            | hir::ItemKind::Union(..)
            | hir::ItemKind::OpaqueTy(..) => {},
            hir::ItemKind::ExternCrate(..)
            | hir::ItemKind::ForeignMod { .. }
            | hir::ItemKind::GlobalAsm(..)
            | hir::ItemKind::Impl { .. }
            | hir::ItemKind::Use(..) => return,
        };

        let (article, desc) = cx.tcx.article_and_description(it.def_id.to_def_id());

        let attrs = cx.tcx.hir().attrs(it.hir_id());
        self.check_missing_docs_attrs(cx, attrs, it.span, article, desc);
    }

    fn check_trait_item(&mut self, cx: &LateContext<'tcx>, trait_item: &'tcx hir::TraitItem<'_>) {
        let (article, desc) = cx.tcx.article_and_description(trait_item.def_id.to_def_id());

        let attrs = cx.tcx.hir().attrs(trait_item.hir_id());
        self.check_missing_docs_attrs(cx, attrs, trait_item.span, article, desc);
    }

    fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx hir::ImplItem<'_>) {
        // If the method is an impl for a trait, don't doc.
        match cx.tcx.associated_item(impl_item.def_id).container {
            ty::TraitContainer(_) => return,
            ty::ImplContainer(cid) => {
                if cx.tcx.impl_trait_ref(cid).is_some() {
                    return;
                }
            },
        }

        let (article, desc) = cx.tcx.article_and_description(impl_item.def_id.to_def_id());
        let attrs = cx.tcx.hir().attrs(impl_item.hir_id());
        self.check_missing_docs_attrs(cx, attrs, impl_item.span, article, desc);
    }

    fn check_field_def(&mut self, cx: &LateContext<'tcx>, sf: &'tcx hir::FieldDef<'_>) {
        if !sf.is_positional() {
            let attrs = cx.tcx.hir().attrs(sf.hir_id);
            self.check_missing_docs_attrs(cx, attrs, sf.span, "a", "struct field");
        }
    }

    fn check_variant(&mut self, cx: &LateContext<'tcx>, v: &'tcx hir::Variant<'_>) {
        let attrs = cx.tcx.hir().attrs(v.id);
        self.check_missing_docs_attrs(cx, attrs, v.span, "a", "variant");
    }
}
<commit_msg>Treat macros as HIR items<commit_after>// Note: More specifically this lint is largely inspired (aka copied) from
// *rustc*'s
// [`missing_doc`].
//
// [`missing_doc`]: https://github.com/rust-lang/rust/blob/cf9cf7c923eb01146971429044f216a3ca905e06/compiler/rustc_lint/src/builtin.rs#L415
//

use clippy_utils::attrs::is_doc_hidden;
use clippy_utils::diagnostics::span_lint;
use rustc_ast::ast;
use rustc_hir as hir;
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::ty;
use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::source_map::Span;
use rustc_span::sym;

declare_clippy_lint! {
    /// ### What it does
    /// Warns if there is missing doc for any documentable item
    /// (public or private).
    ///
    /// ### Why is this bad?
    /// Doc is good. *rustc* has a `MISSING_DOCS`
    /// allowed-by-default lint for
    /// public members, but has no way to enforce documentation of private items.
    /// This lint fixes that.
    pub MISSING_DOCS_IN_PRIVATE_ITEMS,
    restriction,
    "detects missing documentation for public and private members"
}

pub struct MissingDoc {
    /// Stack of whether #[doc(hidden)] is set
    /// at each level which has lint attributes.
    doc_hidden_stack: Vec<bool>,
}

impl Default for MissingDoc {
    #[must_use]
    fn default() -> Self {
        Self::new()
    }
}

impl MissingDoc {
    #[must_use]
    pub fn new() -> Self {
        Self {
            doc_hidden_stack: vec![false],
        }
    }

    fn doc_hidden(&self) -> bool {
        *self.doc_hidden_stack.last().expect("empty doc_hidden_stack")
    }

    fn check_missing_docs_attrs(
        &self,
        cx: &LateContext<'_>,
        attrs: &[ast::Attribute],
        sp: Span,
        article: &'static str,
        desc: &'static str,
    ) {
        // If we're building a test harness, then warning about
        // documentation is probably not really relevant right now.
        if cx.sess().opts.test {
            return;
        }

        // `#[doc(hidden)]` disables missing_docs check.
        if self.doc_hidden() {
            return;
        }

        if sp.from_expansion() {
            return;
        }

        let has_doc = attrs
            .iter()
            .any(|a| a.doc_str().is_some());
        if !has_doc {
            span_lint(
                cx,
                MISSING_DOCS_IN_PRIVATE_ITEMS,
                sp,
                &format!("missing documentation for {} {}", article, desc),
            );
        }
    }
}

impl_lint_pass!(MissingDoc => [MISSING_DOCS_IN_PRIVATE_ITEMS]);

impl<'tcx> LateLintPass<'tcx> for MissingDoc {
    fn enter_lint_attrs(&mut self, _: &LateContext<'tcx>, attrs: &'tcx [ast::Attribute]) {
        let doc_hidden = self.doc_hidden() || is_doc_hidden(attrs);
        self.doc_hidden_stack.push(doc_hidden);
    }

    fn exit_lint_attrs(&mut self, _: &LateContext<'tcx>, _: &'tcx [ast::Attribute]) {
        self.doc_hidden_stack.pop().expect("empty doc_hidden_stack");
    }

    fn check_crate(&mut self, cx: &LateContext<'tcx>, krate: &'tcx hir::Crate<'_>) {
        let attrs = cx.tcx.hir().attrs(hir::CRATE_HIR_ID);
        self.check_missing_docs_attrs(cx, attrs, krate.module().inner, "the", "crate");
    }

    fn check_item(&mut self, cx: &LateContext<'tcx>, it: &'tcx hir::Item<'_>) {
        match it.kind {
            hir::ItemKind::Fn(..) => {
                // ignore main()
                if it.ident.name == sym::main {
                    let def_key = cx.tcx.hir().def_key(it.def_id);
                    if def_key.parent == Some(hir::def_id::CRATE_DEF_INDEX) {
                        return;
                    }
                }
            },
            hir::ItemKind::Const(..)
            | hir::ItemKind::Enum(..)
            | hir::ItemKind::Mod(..)
            | hir::ItemKind::Macro(..)
            | hir::ItemKind::Static(..)
            | hir::ItemKind::Struct(..)
            | hir::ItemKind::Trait(..)
            | hir::ItemKind::TraitAlias(..)
            | hir::ItemKind::TyAlias(..)
            | hir::ItemKind::Union(..)
            | hir::ItemKind::OpaqueTy(..) => {},
            hir::ItemKind::ExternCrate(..)
            | hir::ItemKind::ForeignMod { .. }
            | hir::ItemKind::GlobalAsm(..)
            | hir::ItemKind::Impl { .. }
            | hir::ItemKind::Use(..) => return,
        };

        let (article, desc) = cx.tcx.article_and_description(it.def_id.to_def_id());

        let attrs = cx.tcx.hir().attrs(it.hir_id());
        self.check_missing_docs_attrs(cx, attrs, it.span, article, desc);
    }

    fn check_trait_item(&mut self, cx: &LateContext<'tcx>, trait_item: &'tcx hir::TraitItem<'_>) {
        let (article, desc) = cx.tcx.article_and_description(trait_item.def_id.to_def_id());

        let attrs = cx.tcx.hir().attrs(trait_item.hir_id());
        self.check_missing_docs_attrs(cx, attrs, trait_item.span, article, desc);
    }

    fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx hir::ImplItem<'_>) {
        // If the method is an impl for a trait, don't doc.
        match cx.tcx.associated_item(impl_item.def_id).container {
            ty::TraitContainer(_) => return,
            ty::ImplContainer(cid) => {
                if cx.tcx.impl_trait_ref(cid).is_some() {
                    return;
                }
            },
        }

        let (article, desc) = cx.tcx.article_and_description(impl_item.def_id.to_def_id());
        let attrs = cx.tcx.hir().attrs(impl_item.hir_id());
        self.check_missing_docs_attrs(cx, attrs, impl_item.span, article, desc);
    }

    fn check_field_def(&mut self, cx: &LateContext<'tcx>, sf: &'tcx hir::FieldDef<'_>) {
        if !sf.is_positional() {
            let attrs = cx.tcx.hir().attrs(sf.hir_id);
            self.check_missing_docs_attrs(cx, attrs, sf.span, "a", "struct field");
        }
    }

    fn check_variant(&mut self, cx: &LateContext<'tcx>, v: &'tcx hir::Variant<'_>) {
        let attrs = cx.tcx.hir().attrs(v.id);
        self.check_missing_docs_attrs(cx, attrs, v.span, "a", "variant");
    }
}
<|endoftext|>


<commit_before>#![feature(test)]

extern crate test;
extern crate fruently;

#[cfg(test)]
mod tests {
    use test::Bencher;
    use fruently::fluent::Fluent;
    use std::collections::HashMap;
    use fruently::forwardable::JsonForwardable;

    #[bench]
    fn benchmark_fruently(b: &mut Bencher) {
        let mut obj: HashMap<String, String> = HashMap::new();
        obj.insert("name".to_string(), "fruently".to_string());
        b.iter(|| {
            let fruently = Fluent::new("0.0.0.0:24224", "test");
            let _ = fruently.post(&obj);
        });
    }
}
<commit_msg>benchmarks: Add msgpack benchmark<commit_after>#![feature(test)]

extern crate test;
extern crate fruently;

#[cfg(test)]
mod tests {
    use test::Bencher;
    use fruently::fluent::Fluent;
    use std::collections::HashMap;

    #[bench]
    fn benchmark_json_forwardable(b: &mut Bencher) {
        use fruently::forwardable::JsonForwardable;

        let mut obj: HashMap<String, String> = HashMap::new();
        obj.insert("name".to_string(), "fruently".to_string());
        b.iter(|| {
            let fruently = Fluent::new("0.0.0.0:24224", "test");
            let _ = fruently.post(&obj);
        });
    }

    #[bench]
    fn benchmark_msgpack_forwardable(b: &mut Bencher) {
        use fruently::forwardable::MsgpackForwardable;

        let mut obj: HashMap<String, String> = HashMap::new();
        obj.insert("name".to_string(), "fruently".to_string());
        b.iter(|| {
            let fruently = Fluent::new("0.0.0.0:24224", "test");
            let _ = fruently.post(&obj);
        });
    }
}
<|endoftext|>


<commit_before>//  * This file is part of the uutils coreutils package.
//  *
//  * (c) Aleksander Bielawski <pabzdzdzwiagief@gmail.com>
//  *
//  * For the full copyright and license information, please view the LICENSE
//  * file that was distributed with this source code.

#[macro_use]
extern crate uucore;

use clap::{crate_version, App, Arg};
use retain_mut::RetainMut;
use std::fs::OpenOptions;
use std::io::{copy, sink, stdin, stdout, Error, ErrorKind, Read, Result, Write};
use std::path::PathBuf;
use uucore::display::Quotable;

#[cfg(unix)]
use uucore::libc;

static ABOUT: &str = "Copy standard input to each FILE, and also to standard output.";

mod options {
    pub const APPEND: &str = "append";
    pub const IGNORE_INTERRUPTS: &str = "ignore-interrupts";
    pub const FILE: &str = "file";
}

#[allow(dead_code)]
struct Options {
    append: bool,
    ignore_interrupts: bool,
    files: Vec<String>,
}

fn usage() -> String {
    format!("{0} [OPTION]... [FILE]...", uucore::execution_phrase())
}

pub fn uumain(args: impl uucore::Args) -> i32 {
    let usage = usage();

    let matches = uu_app().usage(&usage[..]).get_matches_from(args);

    let options = Options {
        append: matches.is_present(options::APPEND),
        ignore_interrupts: matches.is_present(options::IGNORE_INTERRUPTS),
        files: matches
            .values_of(options::FILE)
            .map(|v| v.map(ToString::to_string).collect())
            .unwrap_or_default(),
    };

    match tee(options) {
        Ok(_) => 0,
        Err(_) => 1,
    }
}

pub fn uu_app() -> App<'static, 'static> {
    App::new(uucore::util_name())
        .version(crate_version!())
        .about(ABOUT)
        .after_help("If a FILE is -, it refers to a file named - .")
        .arg(
            Arg::with_name(options::APPEND)
                .long(options::APPEND)
                .short("a")
                .help("append to the given FILEs, do not overwrite"),
        )
        .arg(
            Arg::with_name(options::IGNORE_INTERRUPTS)
                .long(options::IGNORE_INTERRUPTS)
                .short("i")
                .help("ignore interrupt signals (ignored on non-Unix platforms)"),
        )
        .arg(Arg::with_name(options::FILE).multiple(true))
}

#[cfg(unix)]
fn ignore_interrupts() -> Result<()> {
    let ret = unsafe { libc::signal(libc::SIGINT, libc::SIG_IGN) };
    if ret == libc::SIG_ERR {
        return Err(Error::new(ErrorKind::Other, ""));
    }
    Ok(())
}

#[cfg(not(unix))]
fn ignore_interrupts() -> Result<()> {
    // Do nothing.
    Ok(())
}

fn tee(options: Options) -> Result<()> {
    if options.ignore_interrupts {
        ignore_interrupts()?
    }
    let mut writers: Vec<NamedWriter> = options
        .files
        .clone()
        .into_iter()
        .map(|file| NamedWriter {
            name: file.clone(),
            inner: open(file, options.append),
        })
        .collect();

    writers.insert(
        0,
        NamedWriter {
            name: "'standard output'".to_owned(),
            inner: Box::new(stdout()),
        },
    );

    let mut output = MultiWriter::new(writers);
    let input = &mut NamedReader {
        inner: Box::new(stdin()) as Box<dyn Read>,
    };

    // TODO: replaced generic 'copy' call to be able to stop copying
    // if all outputs are closed (due to errors)
    if copy(input, &mut output).is_err() || output.flush().is_err() || output.error_occurred() {
        Err(Error::new(ErrorKind::Other, ""))
    } else {
        Ok(())
    }
}

fn open(name: String, append: bool) -> Box<dyn Write> {
    let path = PathBuf::from(name.clone());
    let inner: Box<dyn Write> = {
        let mut options = OpenOptions::new();
        let mode = if append {
            options.append(true)
        } else {
            options.truncate(true)
        };
        match mode.write(true).create(true).open(path.as_path()) {
            Ok(file) => Box::new(file),
            Err(_) => Box::new(sink()),
        }
    };
    Box::new(NamedWriter { inner, name }) as Box<dyn Write>
}

struct MultiWriter {
    writers: Vec<NamedWriter>,
    initial_len: usize,
}

impl MultiWriter {
    fn new(writers: Vec<NamedWriter>) -> Self {
        Self {
            initial_len: writers.len(),
            writers,
        }
    }
    fn error_occurred(&self) -> bool {
        self.writers.len() != self.initial_len
    }
}

impl Write for MultiWriter {
    fn write(&mut self, buf: &[u8]) -> Result<usize> {
        RetainMut::retain_mut(&mut self.writers, |writer| {
            let result = writer.write_all(buf);
            match result {
                Err(f) => {
                    show_error!("{}: {}", writer.name.maybe_quote(), f);
                    false
                }
                _ => true,
            }
        });
        Ok(buf.len())
    }

    fn flush(&mut self) -> Result<()> {
        RetainMut::retain_mut(&mut self.writers, |writer| {
            let result = writer.flush();
            match result {
                Err(f) => {
                    show_error!("{}: {}", writer.name.maybe_quote(), f);
                    false
                }
                _ => true,
            }
        });
        Ok(())
    }
}

struct NamedWriter {
    inner: Box<dyn Write>,
    pub name: String,
}

impl Write for NamedWriter {
    fn write(&mut self, buf: &[u8]) -> Result<usize> {
        self.inner.write(buf)
    }

    fn flush(&mut self) -> Result<()> {
        self.inner.flush()
    }
}

struct NamedReader {
    inner: Box<dyn Read>,
}

impl Read for NamedReader {
    fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
        match self.inner.read(buf) {
            Err(f) => {
                show_error!("stdin: {}", f);
                Err(f)
            }
            okay => okay,
        }
    }
}
<commit_msg>tee: return UResult from uumain() function<commit_after>//  * This file is part of the uutils coreutils package.
//  *
//  * (c) Aleksander Bielawski <pabzdzdzwiagief@gmail.com>
//  *
//  * For the full copyright and license information, please view the LICENSE
//  * file that was distributed with this source code.

#[macro_use]
extern crate uucore;

use clap::{crate_version, App, Arg};
use retain_mut::RetainMut;
use std::fs::OpenOptions;
use std::io::{copy, sink, stdin, stdout, Error, ErrorKind, Read, Result, Write};
use std::path::PathBuf;
use uucore::display::Quotable;
use uucore::error::UResult;

#[cfg(unix)]
use uucore::libc;

static ABOUT: &str = "Copy standard input to each FILE, and also to standard output.";

mod options {
    pub const APPEND: &str = "append";
    pub const IGNORE_INTERRUPTS: &str = "ignore-interrupts";
    pub const FILE: &str = "file";
}

#[allow(dead_code)]
struct Options {
    append: bool,
    ignore_interrupts: bool,
    files: Vec<String>,
}

fn usage() -> String {
    format!("{0} [OPTION]... [FILE]...", uucore::execution_phrase())
}

#[uucore_procs::gen_uumain]
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
    let usage = usage();

    let matches = uu_app().usage(&usage[..]).get_matches_from(args);

    let options = Options {
        append: matches.is_present(options::APPEND),
        ignore_interrupts: matches.is_present(options::IGNORE_INTERRUPTS),
        files: matches
            .values_of(options::FILE)
            .map(|v| v.map(ToString::to_string).collect())
            .unwrap_or_default(),
    };

    match tee(options) {
        Ok(_) => Ok(()),
        Err(_) => Err(1.into()),
    }
}

pub fn uu_app() -> App<'static, 'static> {
    App::new(uucore::util_name())
        .version(crate_version!())
        .about(ABOUT)
        .after_help("If a FILE is -, it refers to a file named - .")
        .arg(
            Arg::with_name(options::APPEND)
                .long(options::APPEND)
                .short("a")
                .help("append to the given FILEs, do not overwrite"),
        )
        .arg(
            Arg::with_name(options::IGNORE_INTERRUPTS)
                .long(options::IGNORE_INTERRUPTS)
                .short("i")
                .help("ignore interrupt signals (ignored on non-Unix platforms)"),
        )
        .arg(Arg::with_name(options::FILE).multiple(true))
}

#[cfg(unix)]
fn ignore_interrupts() -> Result<()> {
    let ret = unsafe { libc::signal(libc::SIGINT, libc::SIG_IGN) };
    if ret == libc::SIG_ERR {
        return Err(Error::new(ErrorKind::Other, ""));
    }
    Ok(())
}

#[cfg(not(unix))]
fn ignore_interrupts() -> Result<()> {
    // Do nothing.
    Ok(())
}

fn tee(options: Options) -> Result<()> {
    if options.ignore_interrupts {
        ignore_interrupts()?
    }
    let mut writers: Vec<NamedWriter> = options
        .files
        .clone()
        .into_iter()
        .map(|file| NamedWriter {
            name: file.clone(),
            inner: open(file, options.append),
        })
        .collect();

    writers.insert(
        0,
        NamedWriter {
            name: "'standard output'".to_owned(),
            inner: Box::new(stdout()),
        },
    );

    let mut output = MultiWriter::new(writers);
    let input = &mut NamedReader {
        inner: Box::new(stdin()) as Box<dyn Read>,
    };

    // TODO: replaced generic 'copy' call to be able to stop copying
    // if all outputs are closed (due to errors)
    if copy(input, &mut output).is_err() || output.flush().is_err() || output.error_occurred() {
        Err(Error::new(ErrorKind::Other, ""))
    } else {
        Ok(())
    }
}

fn open(name: String, append: bool) -> Box<dyn Write> {
    let path = PathBuf::from(name.clone());
    let inner: Box<dyn Write> = {
        let mut options = OpenOptions::new();
        let mode = if append {
            options.append(true)
        } else {
            options.truncate(true)
        };
        match mode.write(true).create(true).open(path.as_path()) {
            Ok(file) => Box::new(file),
            Err(_) => Box::new(sink()),
        }
    };
    Box::new(NamedWriter { inner, name }) as Box<dyn Write>
}

struct MultiWriter {
    writers: Vec<NamedWriter>,
    initial_len: usize,
}

impl MultiWriter {
    fn new(writers: Vec<NamedWriter>) -> Self {
        Self {
            initial_len: writers.len(),
            writers,
        }
    }
    fn error_occurred(&self) -> bool {
        self.writers.len() != self.initial_len
    }
}

impl Write for MultiWriter {
    fn write(&mut self, buf: &[u8]) -> Result<usize> {
        RetainMut::retain_mut(&mut self.writers, |writer| {
            let result = writer.write_all(buf);
            match result {
                Err(f) => {
                    show_error!("{}: {}", writer.name.maybe_quote(), f);
                    false
                }
                _ => true,
            }
        });
        Ok(buf.len())
    }

    fn flush(&mut self) -> Result<()> {
        RetainMut::retain_mut(&mut self.writers, |writer| {
            let result = writer.flush();
            match result {
                Err(f) => {
                    show_error!("{}: {}", writer.name.maybe_quote(), f);
                    false
                }
                _ => true,
            }
        });
        Ok(())
    }
}

struct NamedWriter {
    inner: Box<dyn Write>,
    pub name: String,
}

impl Write for NamedWriter {
    fn write(&mut self, buf: &[u8]) -> Result<usize> {
        self.inner.write(buf)
    }

    fn flush(&mut self) -> Result<()> {
        self.inner.flush()
    }
}

struct NamedReader {
    inner: Box<dyn Read>,
}

impl Read for NamedReader {
    fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
        match self.inner.read(buf) {
            Err(f) => {
                show_error!("stdin: {}", f);
                Err(f)
            }
            okay => okay,
        }
    }
}
<|endoftext|>


<commit_before>//! Error management
//!
//! Depending on a compilation flag, the content of the `Context` enum
//! can change. In the default case, it will only have one variant:
//! `Context::Code(I, ErrorKind<E=u32>)` (with `I` and `E` configurable).
//! It contains an error code and the input position that triggered it.
//!
//! If you activate the `verbose-errors` compilation flags, it will add another
//! variant to the enum: `Context::List(Vec<(I, ErrorKind<E>)>)`.
//! This variant aggregates positions and error codes as the code backtracks
//! through the nested parsers.
//! The verbose errors feature allows for very flexible error management:
//! you can know precisely which parser got to which part of the input.
//! The main drawback is that it is a lot slower than default error
//! management.
use util::{ErrorKind, Convert};
use std::convert::From;

/// Contains the error that a parser can return
///
/// If you use the `verbose-errors` compilation feature,
/// `nom::Err` will be the enum defined here,
/// otherwise, it will amount to a `ErrorKind<E=u32>`.
///
/// It can represent a linked list of errors, indicating the path taken in the parsing tree, with corresponding position in the input data.
/// It depends on P, the input position (for a &[u8] parser, it would be a &[u8]), and E, the custom error type (by default, u32)
#[derive(Debug, PartialEq, Eq, Clone)]
pub enum Context<I, E = u32> {
  /// An error code, represented by an ErrorKind, which can contain a custom error code represented by E
  Code(I, ErrorKind<E>),
  List(Vec<(I, ErrorKind<E>)>),
}

impl<I, F, E: From<F>> Convert<Context<I, F>> for Context<I, E> {
  fn convert(c: Context<I, F>) -> Self {
    match c {
      Context::Code(i, e) => Context::Code(i, ErrorKind::convert(e)),
      Context::List(mut v) => {
        Context::List(
          v.drain(..)
            .map(|(i, e)| (i, ErrorKind::convert(e)))
            .collect(),
        )
      }
    }
  }
}

impl<I, E> Context<I, E> {
  /// Convert Err into ErrorKind.
  ///
  /// This allows application code to use ErrorKind and stay independent from the verbose-errors features activation.
  pub fn into_error_kind(self) -> ErrorKind<E> {
    match self {
      Context::Code(_, kind) => kind,
      Context::List(mut v) => {
        let (_, kind) = v.remove(0);
        kind
      }
    }
  }
}

/*
impl<I,O,E> IResult<I,O,E> {
  /// Maps a `IResult<I, O, E>` to `IResult<I, O, N>` by appling a function
  /// to a contained `Error` value, leaving `Done` and `Incomplete` value
  /// untouched.
  #[inline]
  pub fn map_err<N, F>(self, f: F) -> IResult<I, O, N>
   where F: FnOnce(Err<I, E>) -> Err<I, N> {
    match self {
      Error(e)      => Error(f(e)),
      Incomplete(n) => Incomplete(n),
      Done(i, o)    => Done(i, o),
    }
  }

  /// Unwrap the contained `Error(I, E)` value, or panic if the `IResult` is not
  /// `Error`.
  pub fn unwrap_err(self) -> Err<I, E> {
    match self {
      Error(e)      => e,
      Done(_, _)    => panic!("unwrap_err() called on an IResult that is Done"),
      Incomplete(_) => panic!("unwrap_err() called on an IResult that is Incomplete"),
    }
  }

  /// Convert the IResult to a std::result::Result
  pub fn to_full_result(self) -> Result<O, IError<I,E>> {
    match self {
      Done(_, o)    => Ok(o),
      Incomplete(n) => Err(IError::Incomplete(n)),
      Error(e)      => Err(IError::Error(e))
    }
  }

  /// Convert the IResult to a std::result::Result
  pub fn to_result(self) -> Result<O, Err<I,E>> {
    match self {
      Done(_, o)    => Ok(o),
      Error(e)      => Err(e),
      Incomplete(_) => panic!("to_result() called on an IResult that is Incomplete")
    }
  }
}

#[cfg(feature = "std")]
use std::any::Any;
#[cfg(feature = "std")]
use std::{error,fmt};
#[cfg(feature = "std")]
use std::fmt::Debug;
#[cfg(feature = "std")]
impl<P:Debug+Any,E:Debug+Any> error::Error for Err<P,E> {
  fn description(&self) -> &str {
    let kind = match *self {
      Err::Code(ref e) | Err::Node(ref e, _) | Err::Position(ref e, _) | Err::NodePosition(ref e, _, _) => e
    };
    kind.description()
  }
}

#[cfg(feature = "std")]
impl<P:fmt::Debug,E:fmt::Debug> fmt::Display for Err<P,E> {
  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
    match *self {
      Err::Code(ref e) | Err::Node(ref e, _) => {
        write!(f, "{:?}", e)
      },
      Err::Position(ref e, ref p) | Err::NodePosition(ref e, ref p, _) => {
        write!(f, "{:?}:{:?}", p, e)
      }
    }
  }
}
*/

/// translate parser result from IResult<I,O,u32> to IResult<I,O,E> with a custom type
///
/// ```
/// # #[macro_use] extern crate nom;
/// # use nom::ErrorKind;
/// # use nom::Context;
/// # use nom::Err;
/// # fn main() {
///     #[derive(Debug,Clone,PartialEq)]
///     pub struct ErrorStr(String);
///
///     // Convert to IResult<&[u8], &[u8], ErrorStr>
///     impl From<u32> for ErrorStr {
///       fn from(i: u32) -> Self {
///         ErrorStr(format!("custom error code: {}", i))
///       }
///     }
///
///     // will add a Custom(42) error to the error chain
///     named!(err_test, add_return_error!(ErrorKind::Custom(42), tag!("abcd")));
///
///     // Convert to IResult<&[u8], &[u8], ErrorStr>
///     named!(parser<&[u8], &[u8], ErrorStr>, fix_error!(ErrorStr, err_test));
///
///     let a = &b"efghblah"[..];
///     //assert_eq!(parser(a), Err(Err::Error(Context::Code(a, ErrorKind::Custom(ErrorStr("custom error code: 42".to_string()))))));
///     let list = vec!((a, ErrorKind::Tag), (a, ErrorKind::Custom(ErrorStr("custom error code: 42".to_string()))));
///     assert_eq!(
///       parser(a),
///       Err(Err::Error(Context::List(list)))
///     );
/// # }
/// ```
#[macro_export]
macro_rules! fix_error (
  ($i:expr, $t:ty, $submac:ident!( $($args:tt)* )) => (
    {
      use ::std::result::Result::*;
      use $crate::{Err,Convert,ErrorKind,Context};

      match $submac!($i, $($args)*) {
        Err(e)     => {
          let e2 = match e {
            Err::Error(err) => {
              let err2 = match err {
                Context::Code(i, code) => {
                  let code2: ErrorKind<$t> = ErrorKind::convert(code);
                  Context::Code(i, code2)
                },
                Context::List(mut v) => {
                  Context::List(v.drain(..).map(|(i, code)| {
                    let code2: ErrorKind<$t> = ErrorKind::convert(code);
                    (i, code2)
                  }).collect())
                }
              };
              Err::Error(err2)
            },
            Err::Failure(err) => {
              let err2 = match err {
                Context::Code(i, code) => {
                  let code2: ErrorKind<$t> = ErrorKind::convert(code);
                  Context::Code(i, code2)
                },
                Context::List(mut v) => {
                  Context::List(v.drain(..).map(|(i, code)| {
                    let code2: ErrorKind<$t> = ErrorKind::convert(code);
                    (i, code2)
                  }).collect())
                }
              };
              Err::Failure(err2)
            },
            Err::Incomplete(i) => Err::Incomplete(i),
          };
          Err(e2)
        },
        Ok((i, o)) => Ok((i, o)),
      }
    }
  );
  ($i:expr, $t:ty, $f:expr) => (
    fix_error!($i, $t, call!($f));
  );
);

/// `flat_map!(R -> IResult<R,S>, S -> IResult<S,T>) => R -> IResult<R, T>`
///
/// combines a parser R -> IResult<R,S> and
/// a parser S -> IResult<S,T> to return another
/// parser R -> IResult<R,T>
#[macro_export]
macro_rules! flat_map(
  ($i:expr, $submac:ident!( $($args:tt)* ), $submac2:ident!( $($args2:tt)* )) => (
    flat_map!(__impl $i, $submac!($($args)*), $submac2!($($args2)*));
  );
  ($i:expr, $submac:ident!( $($args:tt)* ), $g:expr) => (
    flat_map!(__impl $i, $submac!($($args)*), call!($g));
  );
  ($i:expr, $f:expr, $submac:ident!( $($args:tt)* )) => (
    flat_map!(__impl $i, call!($f), $submac!($($args)*));
  );
  ($i:expr, $f:expr, $g:expr) => (
    flat_map!(_impl $i, call!($f), call!($g));
  );
  (__impl $i:expr, $submac:ident!( $($args:tt)* ), $submac2:ident!( $($args2:tt)* )) => (
    {
      use ::std::result::Result::*;
      use $crate::{Err,Convert};

      match $submac!($i, $($args)*) {
        Err(e)     => Err(Err::convert(e)),
        Ok((i, o)) => match $submac2!(o, $($args2)*) {
          Err(e)     => Err(Err::convert(e)),
          Ok((_,o2)) => Ok((i,o2)),
        },
      }
    }
  );
);
<commit_msg>fix typo<commit_after>//! Error management
//!
//! Depending on a compilation flag, the content of the `Context` enum
//! can change. In the default case, it will only have one variant:
//! `Context::Code(I, ErrorKind<E=u32>)` (with `I` and `E` configurable).
//! It contains an error code and the input position that triggered it.
//!
//! If you activate the `verbose-errors` compilation flags, it will add another
//! variant to the enum: `Context::List(Vec<(I, ErrorKind<E>)>)`.
//! This variant aggregates positions and error codes as the code backtracks
//! through the nested parsers.
//! The verbose errors feature allows for very flexible error management:
//! you can know precisely which parser got to which part of the input.
//! The main drawback is that it is a lot slower than default error
//! management.
use util::{ErrorKind, Convert};
use std::convert::From;

/// Contains the error that a parser can return
///
/// If you use the `verbose-errors` compilation feature,
/// `nom::Err` will be the enum defined here,
/// otherwise, it will amount to a `ErrorKind<E=u32>`.
///
/// It can represent a linked list of errors, indicating the path taken in the parsing tree, with corresponding position in the input data.
/// It depends on P, the input position (for a &[u8] parser, it would be a &[u8]), and E, the custom error type (by default, u32)
#[derive(Debug, PartialEq, Eq, Clone)]
pub enum Context<I, E = u32> {
  /// An error code, represented by an ErrorKind, which can contain a custom error code represented by E
  Code(I, ErrorKind<E>),
  List(Vec<(I, ErrorKind<E>)>),
}

impl<I, F, E: From<F>> Convert<Context<I, F>> for Context<I, E> {
  fn convert(c: Context<I, F>) -> Self {
    match c {
      Context::Code(i, e) => Context::Code(i, ErrorKind::convert(e)),
      Context::List(mut v) => {
        Context::List(
          v.drain(..)
            .map(|(i, e)| (i, ErrorKind::convert(e)))
            .collect(),
        )
      }
    }
  }
}

impl<I, E> Context<I, E> {
  /// Convert Err into ErrorKind.
  ///
  /// This allows application code to use ErrorKind and stay independent from the verbose-errors features activation.
  pub fn into_error_kind(self) -> ErrorKind<E> {
    match self {
      Context::Code(_, kind) => kind,
      Context::List(mut v) => {
        let (_, kind) = v.remove(0);
        kind
      }
    }
  }
}

/*
impl<I,O,E> IResult<I,O,E> {
  /// Maps a `IResult<I, O, E>` to `IResult<I, O, N>` by appling a function
  /// to a contained `Error` value, leaving `Done` and `Incomplete` value
  /// untouched.
  #[inline]
  pub fn map_err<N, F>(self, f: F) -> IResult<I, O, N>
   where F: FnOnce(Err<I, E>) -> Err<I, N> {
    match self {
      Error(e)      => Error(f(e)),
      Incomplete(n) => Incomplete(n),
      Done(i, o)    => Done(i, o),
    }
  }

  /// Unwrap the contained `Error(I, E)` value, or panic if the `IResult` is not
  /// `Error`.
  pub fn unwrap_err(self) -> Err<I, E> {
    match self {
      Error(e)      => e,
      Done(_, _)    => panic!("unwrap_err() called on an IResult that is Done"),
      Incomplete(_) => panic!("unwrap_err() called on an IResult that is Incomplete"),
    }
  }

  /// Convert the IResult to a std::result::Result
  pub fn to_full_result(self) -> Result<O, IError<I,E>> {
    match self {
      Done(_, o)    => Ok(o),
      Incomplete(n) => Err(IError::Incomplete(n)),
      Error(e)      => Err(IError::Error(e))
    }
  }

  /// Convert the IResult to a std::result::Result
  pub fn to_result(self) -> Result<O, Err<I,E>> {
    match self {
      Done(_, o)    => Ok(o),
      Error(e)      => Err(e),
      Incomplete(_) => panic!("to_result() called on an IResult that is Incomplete")
    }
  }
}

#[cfg(feature = "std")]
use std::any::Any;
#[cfg(feature = "std")]
use std::{error,fmt};
#[cfg(feature = "std")]
use std::fmt::Debug;
#[cfg(feature = "std")]
impl<P:Debug+Any,E:Debug+Any> error::Error for Err<P,E> {
  fn description(&self) -> &str {
    let kind = match *self {
      Err::Code(ref e) | Err::Node(ref e, _) | Err::Position(ref e, _) | Err::NodePosition(ref e, _, _) => e
    };
    kind.description()
  }
}

#[cfg(feature = "std")]
impl<P:fmt::Debug,E:fmt::Debug> fmt::Display for Err<P,E> {
  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
    match *self {
      Err::Code(ref e) | Err::Node(ref e, _) => {
        write!(f, "{:?}", e)
      },
      Err::Position(ref e, ref p) | Err::NodePosition(ref e, ref p, _) => {
        write!(f, "{:?}:{:?}", p, e)
      }
    }
  }
}
*/

/// translate parser result from IResult<I,O,u32> to IResult<I,O,E> with a custom type
///
/// ```
/// # #[macro_use] extern crate nom;
/// # use nom::ErrorKind;
/// # use nom::Context;
/// # use nom::Err;
/// # fn main() {
///     #[derive(Debug,Clone,PartialEq)]
///     pub struct ErrorStr(String);
///
///     // Convert to IResult<&[u8], &[u8], ErrorStr>
///     impl From<u32> for ErrorStr {
///       fn from(i: u32) -> Self {
///         ErrorStr(format!("custom error code: {}", i))
///       }
///     }
///
///     // will add a Custom(42) error to the error chain
///     named!(err_test, add_return_error!(ErrorKind::Custom(42), tag!("abcd")));
///
///     // Convert to IResult<&[u8], &[u8], ErrorStr>
///     named!(parser<&[u8], &[u8], ErrorStr>, fix_error!(ErrorStr, err_test));
///
///     let a = &b"efghblah"[..];
///     //assert_eq!(parser(a), Err(Err::Error(Context::Code(a, ErrorKind::Custom(ErrorStr("custom error code: 42".to_string()))))));
///     let list = vec!((a, ErrorKind::Tag), (a, ErrorKind::Custom(ErrorStr("custom error code: 42".to_string()))));
///     assert_eq!(
///       parser(a),
///       Err(Err::Error(Context::List(list)))
///     );
/// # }
/// ```
#[macro_export]
macro_rules! fix_error (
  ($i:expr, $t:ty, $submac:ident!( $($args:tt)* )) => (
    {
      use ::std::result::Result::*;
      use $crate::{Err,Convert,ErrorKind,Context};

      match $submac!($i, $($args)*) {
        Err(e)     => {
          let e2 = match e {
            Err::Error(err) => {
              let err2 = match err {
                Context::Code(i, code) => {
                  let code2: ErrorKind<$t> = ErrorKind::convert(code);
                  Context::Code(i, code2)
                },
                Context::List(mut v) => {
                  Context::List(v.drain(..).map(|(i, code)| {
                    let code2: ErrorKind<$t> = ErrorKind::convert(code);
                    (i, code2)
                  }).collect())
                }
              };
              Err::Error(err2)
            },
            Err::Failure(err) => {
              let err2 = match err {
                Context::Code(i, code) => {
                  let code2: ErrorKind<$t> = ErrorKind::convert(code);
                  Context::Code(i, code2)
                },
                Context::List(mut v) => {
                  Context::List(v.drain(..).map(|(i, code)| {
                    let code2: ErrorKind<$t> = ErrorKind::convert(code);
                    (i, code2)
                  }).collect())
                }
              };
              Err::Failure(err2)
            },
            Err::Incomplete(i) => Err::Incomplete(i),
          };
          Err(e2)
        },
        Ok((i, o)) => Ok((i, o)),
      }
    }
  );
  ($i:expr, $t:ty, $f:expr) => (
    fix_error!($i, $t, call!($f));
  );
);

/// `flat_map!(R -> IResult<R,S>, S -> IResult<S,T>) => R -> IResult<R, T>`
///
/// combines a parser R -> IResult<R,S> and
/// a parser S -> IResult<S,T> to return another
/// parser R -> IResult<R,T>
#[macro_export]
macro_rules! flat_map(
  ($i:expr, $submac:ident!( $($args:tt)* ), $submac2:ident!( $($args2:tt)* )) => (
    flat_map!(__impl $i, $submac!($($args)*), $submac2!($($args2)*));
  );
  ($i:expr, $submac:ident!( $($args:tt)* ), $g:expr) => (
    flat_map!(__impl $i, $submac!($($args)*), call!($g));
  );
  ($i:expr, $f:expr, $submac:ident!( $($args:tt)* )) => (
    flat_map!(__impl $i, call!($f), $submac!($($args)*));
  );
  ($i:expr, $f:expr, $g:expr) => (
    flat_map!(__impl $i, call!($f), call!($g));
  );
  (__impl $i:expr, $submac:ident!( $($args:tt)* ), $submac2:ident!( $($args2:tt)* )) => (
    {
      use ::std::result::Result::*;
      use $crate::{Err,Convert};

      match $submac!($i, $($args)*) {
        Err(e)     => Err(Err::convert(e)),
        Ok((i, o)) => match $submac2!(o, $($args2)*) {
          Err(e)     => Err(Err::convert(e)),
          Ok((_,o2)) => Ok((i,o2)),
        },
      }
    }
  );
);
<|endoftext|>