<commit_before>/*fn replace_words<'a>(words: &'a Vec<&'a str>, sentence: &'a str) -> Vec<String> {
    let temp = sentence.split(' ').collect();
    let mut result: Vec<String>;
    for w in temp {}
}*/

fn match_head_of_str(a: &str, b: &str) -> bool {
    let len1 = a.chars().count();
    let len2 = b.chars().count();

    if len1 >= len2 {
        return a.starts_with(b);
    } else {
        return b.starts_with(a);
    }
}

fn main() {
    let words = vec!["cat", "bat", "rat"];
    let sentence = "the cattle was rattled by the battery";
    //println!("{:?}", replace_words(&words, &sentence));
    println!("{:?}", match_head_of_str("aa", "aaab"));
}
<commit_msg>finish<commit_after>fn replace_words<'a>(words: &'a Vec<&'a str>, sentence: &'a str) -> Vec<String> {
    let temp: Vec<&str> = sentence.split(' ').collect();
    let mut result: Vec<String> = vec![];
    'outer: for w_in_sentence in temp {
        for word in words {
            if match_head_of_str(word, w_in_sentence) {
                result.push(word.to_string());
                continue 'outer;
            }
        }
        result.push(w_in_sentence.to_string());
    }
    result
}

fn match_head_of_str(a: &str, b: &str) -> bool {
    let len1 = a.chars().count();
    let len2 = b.chars().count();

    if len1 >= len2 {
        return a.starts_with(b);
    } else {
        return b.starts_with(a);
    }
}

fn main() {
    let words = vec!["cat", "bat", "rat"];
    let sentence = "the cattle was rattled by the battery";
    //println!("{:?}", match_head_of_str("aa", "aaab"));
    println!("{:?}", replace_words(&words, &sentence));
}
<|endoftext|>


<commit_before>use cssparser::{Parser, ParserInput};
use std::collections::hash_map::Entry;
use std::collections::{HashMap, HashSet};
use std::ptr;
use std::str::{self, FromStr};

use libc;
use url::Url;

use glib::translate::*;
use glib_sys::{gboolean, gpointer, GList};

use crate::allowed_url::AllowedUrl;
use crate::attributes::Attribute;
use crate::croco::*;
use crate::error::LoadingError;
use crate::io::{self, BinaryData};
use crate::properties::{parse_attribute_value_into_parsed_property, Declaration, SpecifiedValues};
use crate::util::utf8_cstr;

pub struct DeclarationList {
    // Maps property_name -> Declaration
    declarations: HashMap<Attribute, Declaration>,
}

type Selector = String;

/// Contains all the mappings of selectors to style declarations
/// that result from loading an SVG document.
pub struct CssRules {
    selectors_to_declarations: HashMap<Selector, DeclarationList>,
}

impl DeclarationList {
    fn new() -> DeclarationList {
        DeclarationList {
            declarations: HashMap::new(),
        }
    }

    fn add_declaration(&mut self, declaration: Declaration) {
        match self.declarations.entry(declaration.attribute) {
            Entry::Occupied(mut e) => {
                let decl = e.get_mut();

                if !decl.important {
                    *decl = declaration;
                }
            }

            Entry::Vacant(v) => {
                v.insert(declaration);
            }
        }
    }
}

impl CssRules {
    pub fn new() -> CssRules {
        CssRules {
            selectors_to_declarations: HashMap::new(),
        }
    }

    pub fn parse(&mut self, base_url: Option<&Url>, buf: &str) {
        if buf.len() == 0 {
            return; // libcroco doesn't like empty strings :(
        }

        unsafe {
            let mut handler_data = DocHandlerData {
                base_url,
                css_rules: self,
                selector: ptr::null_mut(),
            };

            let doc_handler = cr_doc_handler_new();
            init_cr_doc_handler(&mut *doc_handler);

            (*doc_handler).app_data = &mut handler_data as *mut _ as gpointer;

            let buf_ptr = buf.as_ptr() as *mut _;
            let buf_len = buf.len() as libc::c_ulong;

            let parser = cr_parser_new_from_buf(buf_ptr, buf_len, CR_UTF_8, false.to_glib());
            if parser.is_null() {
                cr_doc_handler_unref(doc_handler);
                return;
            }

            cr_parser_set_sac_handler(parser, doc_handler);
            cr_doc_handler_unref(doc_handler);

            cr_parser_set_use_core_grammar(parser, false.to_glib());
            cr_parser_parse(parser);

            cr_parser_destroy(parser);
        }
    }

    pub fn load_css(&mut self, aurl: &AllowedUrl) -> Result<(), LoadingError> {
        io::acquire_data(aurl, None)
            .and_then(|data| {
                let BinaryData {
                    data: bytes,
                    content_type,
                } = data;

                if content_type.as_ref().map(String::as_ref) == Some("text/css") {
                    Ok(bytes)
                } else {
                    rsvg_log!("\"{}\" is not of type text/css; ignoring", aurl);
                    Err(LoadingError::BadCss)
                }
            })
            .and_then(|bytes| {
                String::from_utf8(bytes).map_err(|_| {
                    rsvg_log!(
                        "\"{}\" does not contain valid UTF-8 CSS data; ignoring",
                        aurl
                    );
                    LoadingError::BadCss
                })
            })
            .and_then(|utf8| {
                self.parse(Some(&aurl), &utf8);
                Ok(()) // FIXME: return CSS parsing errors
            })
    }

    fn add_declaration(&mut self, selector: &str, declaration: Declaration) {
        let decl_list = self
            .selectors_to_declarations
            .entry(selector.to_string())
            .or_insert_with(|| DeclarationList::new());

        decl_list.add_declaration(declaration);
    }

    /// Takes CSS rules which match the given `selector` name and applies them
    /// to the `values`.
    pub fn lookup_apply(
        &self,
        selector: &str,
        values: &mut SpecifiedValues,
        important_styles: &mut HashSet<Attribute>,
    ) -> bool {
        if let Some(decl_list) = self.selectors_to_declarations.get(selector) {
            for (_, declaration) in decl_list.declarations.iter() {
                values.set_property_from_declaration(declaration, important_styles);
            }

            true
        } else {
            false
        }
    }
}

struct DocHandlerData<'a> {
    base_url: Option<&'a Url>,
    css_rules: &'a mut CssRules,
    selector: *mut CRSelector,
}

macro_rules! get_doc_handler_data {
    ($doc_handler:expr) => {
        &mut *((*$doc_handler).app_data as *mut DocHandlerData)
    };
}

fn init_cr_doc_handler(handler: &mut CRDocHandler) {
    handler.import_style = Some(css_import_style);
    handler.start_selector = Some(css_start_selector);
    handler.end_selector = Some(css_end_selector);
    handler.property = Some(css_property);
    handler.error = Some(css_error);
    handler.unrecoverable_error = Some(css_unrecoverable_error);
}

unsafe extern "C" fn css_import_style(
    a_this: *mut CRDocHandler,
    _a_media_list: *mut GList,
    a_uri: CRString,
    _a_uri_default_ns: CRString,
    _a_location: CRParsingLocation,
) {
    let handler_data = get_doc_handler_data!(a_this);

    if a_uri.is_null() {
        return;
    }

    let raw_uri = cr_string_peek_raw_str(a_uri);
    let uri = utf8_cstr(raw_uri);

    if let Ok(aurl) = AllowedUrl::from_href(uri, handler_data.base_url) {
        // FIXME: handle CSS errors
        let _ = handler_data.css_rules.load_css(&aurl);
    } else {
        rsvg_log!("disallowed URL \"{}\" for importing CSS", uri);
    }
}

unsafe extern "C" fn css_start_selector(
    a_this: *mut CRDocHandler,
    a_selector_list: *mut CRSelector,
) {
    let handler_data = get_doc_handler_data!(a_this);

    cr_selector_ref(a_selector_list);
    handler_data.selector = a_selector_list;
}

unsafe extern "C" fn css_end_selector(
    a_this: *mut CRDocHandler,
    _a_selector_list: *mut CRSelector,
) {
    let handler_data = get_doc_handler_data!(a_this);

    cr_selector_unref(handler_data.selector);
    handler_data.selector = ptr::null_mut();
}

unsafe extern "C" fn css_property(
    a_this: *mut CRDocHandler,
    a_name: CRString,
    a_expression: CRTerm,
    a_is_important: gboolean,
) {
    let handler_data = get_doc_handler_data!(a_this);

    if a_name.is_null() || a_expression.is_null() || handler_data.selector.is_null() {
        return;
    }

    let mut cur_sel = handler_data.selector;
    while !cur_sel.is_null() {
        let simple_sel = (*cur_sel).simple_sel;

        if !simple_sel.is_null() {
            let raw_selector_name = cr_simple_sel_to_string(simple_sel) as *mut libc::c_char;

            if !raw_selector_name.is_null() {
                let raw_prop_name = cr_string_peek_raw_str(a_name);
                let prop_name = utf8_cstr(raw_prop_name);

                let prop_value =
                    <String as FromGlibPtrFull<_>>::from_glib_full(cr_term_to_string(a_expression));

                let selector_name =
                    <String as FromGlibPtrFull<_>>::from_glib_full(raw_selector_name);

                let important = from_glib(a_is_important);

                if let Ok(attribute) = Attribute::from_str(prop_name) {
                    let mut input = ParserInput::new(&prop_value);
                    let mut parser = Parser::new(&mut input);

                    match parse_attribute_value_into_parsed_property(attribute, &mut parser, true) {
                        Ok(property) => {
                            let declaration = Declaration {
                                attribute,
                                property,
                                important,
                            };

                            handler_data
                                .css_rules
                                .add_declaration(&selector_name, declaration);
                        }
                        Err(_) => (), // invalid property name or invalid value; ignore
                    }
                }
                // else unknown property name; ignore
            }
        }

        cur_sel = (*cur_sel).next;
    }
}

unsafe extern "C" fn css_error(_a_this: *mut CRDocHandler) {
    println!("CSS parsing error");
}

unsafe extern "C" fn css_unrecoverable_error(_a_this: *mut CRDocHandler) {
    println!("CSS unrecoverable error");
}
<commit_msg>Add a DeclarationList.iter() method<commit_after>use cssparser::{Parser, ParserInput};
use std::collections::hash_map::{Entry, Iter as HashMapIter};
use std::collections::{HashMap, HashSet};
use std::ptr;
use std::str::{self, FromStr};

use libc;
use url::Url;

use glib::translate::*;
use glib_sys::{gboolean, gpointer, GList};

use crate::allowed_url::AllowedUrl;
use crate::attributes::Attribute;
use crate::croco::*;
use crate::error::LoadingError;
use crate::io::{self, BinaryData};
use crate::properties::{parse_attribute_value_into_parsed_property, Declaration, SpecifiedValues};
use crate::util::utf8_cstr;

pub struct DeclarationList {
    // Maps property_name -> Declaration
    declarations: HashMap<Attribute, Declaration>,
}

type Selector = String;

/// Contains all the mappings of selectors to style declarations
/// that result from loading an SVG document.
pub struct CssRules {
    selectors_to_declarations: HashMap<Selector, DeclarationList>,
}

impl DeclarationList {
    fn new() -> DeclarationList {
        DeclarationList {
            declarations: HashMap::new(),
        }
    }

    fn add_declaration(&mut self, declaration: Declaration) {
        match self.declarations.entry(declaration.attribute) {
            Entry::Occupied(mut e) => {
                let decl = e.get_mut();

                if !decl.important {
                    *decl = declaration;
                }
            }

            Entry::Vacant(v) => {
                v.insert(declaration);
            }
        }
    }

    pub fn iter(&self) -> DeclarationListIter {
        DeclarationListIter(self.declarations.iter())
    }
}

pub struct DeclarationListIter<'a>(HashMapIter<'a, Attribute, Declaration>);

impl<'a> Iterator for DeclarationListIter<'a> {
    type Item = &'a Declaration;

    fn next(&mut self) -> Option<Self::Item> {
        self.0.next().map(|(_attribute, declaration)| declaration)
    }
}

impl CssRules {
    pub fn new() -> CssRules {
        CssRules {
            selectors_to_declarations: HashMap::new(),
        }
    }

    pub fn parse(&mut self, base_url: Option<&Url>, buf: &str) {
        if buf.len() == 0 {
            return; // libcroco doesn't like empty strings :(
        }

        unsafe {
            let mut handler_data = DocHandlerData {
                base_url,
                css_rules: self,
                selector: ptr::null_mut(),
            };

            let doc_handler = cr_doc_handler_new();
            init_cr_doc_handler(&mut *doc_handler);

            (*doc_handler).app_data = &mut handler_data as *mut _ as gpointer;

            let buf_ptr = buf.as_ptr() as *mut _;
            let buf_len = buf.len() as libc::c_ulong;

            let parser = cr_parser_new_from_buf(buf_ptr, buf_len, CR_UTF_8, false.to_glib());
            if parser.is_null() {
                cr_doc_handler_unref(doc_handler);
                return;
            }

            cr_parser_set_sac_handler(parser, doc_handler);
            cr_doc_handler_unref(doc_handler);

            cr_parser_set_use_core_grammar(parser, false.to_glib());
            cr_parser_parse(parser);

            cr_parser_destroy(parser);
        }
    }

    pub fn load_css(&mut self, aurl: &AllowedUrl) -> Result<(), LoadingError> {
        io::acquire_data(aurl, None)
            .and_then(|data| {
                let BinaryData {
                    data: bytes,
                    content_type,
                } = data;

                if content_type.as_ref().map(String::as_ref) == Some("text/css") {
                    Ok(bytes)
                } else {
                    rsvg_log!("\"{}\" is not of type text/css; ignoring", aurl);
                    Err(LoadingError::BadCss)
                }
            })
            .and_then(|bytes| {
                String::from_utf8(bytes).map_err(|_| {
                    rsvg_log!(
                        "\"{}\" does not contain valid UTF-8 CSS data; ignoring",
                        aurl
                    );
                    LoadingError::BadCss
                })
            })
            .and_then(|utf8| {
                self.parse(Some(&aurl), &utf8);
                Ok(()) // FIXME: return CSS parsing errors
            })
    }

    fn add_declaration(&mut self, selector: &str, declaration: Declaration) {
        let decl_list = self
            .selectors_to_declarations
            .entry(selector.to_string())
            .or_insert_with(|| DeclarationList::new());

        decl_list.add_declaration(declaration);
    }

    /// Takes CSS rules which match the given `selector` name and applies them
    /// to the `values`.
    pub fn lookup_apply(
        &self,
        selector: &str,
        values: &mut SpecifiedValues,
        important_styles: &mut HashSet<Attribute>,
    ) -> bool {
        if let Some(decl_list) = self.selectors_to_declarations.get(selector) {
            for declaration in decl_list.iter() {
                values.set_property_from_declaration(declaration, important_styles);
            }

            true
        } else {
            false
        }
    }
}

struct DocHandlerData<'a> {
    base_url: Option<&'a Url>,
    css_rules: &'a mut CssRules,
    selector: *mut CRSelector,
}

macro_rules! get_doc_handler_data {
    ($doc_handler:expr) => {
        &mut *((*$doc_handler).app_data as *mut DocHandlerData)
    };
}

fn init_cr_doc_handler(handler: &mut CRDocHandler) {
    handler.import_style = Some(css_import_style);
    handler.start_selector = Some(css_start_selector);
    handler.end_selector = Some(css_end_selector);
    handler.property = Some(css_property);
    handler.error = Some(css_error);
    handler.unrecoverable_error = Some(css_unrecoverable_error);
}

unsafe extern "C" fn css_import_style(
    a_this: *mut CRDocHandler,
    _a_media_list: *mut GList,
    a_uri: CRString,
    _a_uri_default_ns: CRString,
    _a_location: CRParsingLocation,
) {
    let handler_data = get_doc_handler_data!(a_this);

    if a_uri.is_null() {
        return;
    }

    let raw_uri = cr_string_peek_raw_str(a_uri);
    let uri = utf8_cstr(raw_uri);

    if let Ok(aurl) = AllowedUrl::from_href(uri, handler_data.base_url) {
        // FIXME: handle CSS errors
        let _ = handler_data.css_rules.load_css(&aurl);
    } else {
        rsvg_log!("disallowed URL \"{}\" for importing CSS", uri);
    }
}

unsafe extern "C" fn css_start_selector(
    a_this: *mut CRDocHandler,
    a_selector_list: *mut CRSelector,
) {
    let handler_data = get_doc_handler_data!(a_this);

    cr_selector_ref(a_selector_list);
    handler_data.selector = a_selector_list;
}

unsafe extern "C" fn css_end_selector(
    a_this: *mut CRDocHandler,
    _a_selector_list: *mut CRSelector,
) {
    let handler_data = get_doc_handler_data!(a_this);

    cr_selector_unref(handler_data.selector);
    handler_data.selector = ptr::null_mut();
}

unsafe extern "C" fn css_property(
    a_this: *mut CRDocHandler,
    a_name: CRString,
    a_expression: CRTerm,
    a_is_important: gboolean,
) {
    let handler_data = get_doc_handler_data!(a_this);

    if a_name.is_null() || a_expression.is_null() || handler_data.selector.is_null() {
        return;
    }

    let mut cur_sel = handler_data.selector;
    while !cur_sel.is_null() {
        let simple_sel = (*cur_sel).simple_sel;

        if !simple_sel.is_null() {
            let raw_selector_name = cr_simple_sel_to_string(simple_sel) as *mut libc::c_char;

            if !raw_selector_name.is_null() {
                let raw_prop_name = cr_string_peek_raw_str(a_name);
                let prop_name = utf8_cstr(raw_prop_name);

                let prop_value =
                    <String as FromGlibPtrFull<_>>::from_glib_full(cr_term_to_string(a_expression));

                let selector_name =
                    <String as FromGlibPtrFull<_>>::from_glib_full(raw_selector_name);

                let important = from_glib(a_is_important);

                if let Ok(attribute) = Attribute::from_str(prop_name) {
                    let mut input = ParserInput::new(&prop_value);
                    let mut parser = Parser::new(&mut input);

                    match parse_attribute_value_into_parsed_property(attribute, &mut parser, true) {
                        Ok(property) => {
                            let declaration = Declaration {
                                attribute,
                                property,
                                important,
                            };

                            handler_data
                                .css_rules
                                .add_declaration(&selector_name, declaration);
                        }
                        Err(_) => (), // invalid property name or invalid value; ignore
                    }
                }
                // else unknown property name; ignore
            }
        }

        cur_sel = (*cur_sel).next;
    }
}

unsafe extern "C" fn css_error(_a_this: *mut CRDocHandler) {
    println!("CSS parsing error");
}

unsafe extern "C" fn css_unrecoverable_error(_a_this: *mut CRDocHandler) {
    println!("CSS unrecoverable error");
}
<|endoftext|>


<commit_before>// use std::slice::SliceConcatExt;

pub fn verse(i: u8) -> String {
    if i == 0 {
        return "No more bottles of beer on the wall, no more bottles of beer.\nGo to the store \
                and buy some more, 99 bottles of beer on the wall.\n"
            .to_string();
    };

    let mut s = String::new();
    verse1(i, &mut s);
    verse2(i - 1, &mut s);
    s
}

fn verse1(i: u8, s: &mut String) {
    // plural s
    let plural_s = if i == 1 {
        ""
    } else {
        "s"
    };
    s.push_str(&format!("{} bottle{} of beer on the wall, {} bottle{} of beer.\n",
                        i,
                        plural_s,
                        i,
                        plural_s))
}

fn verse2(i: u8, s: &mut String) {
    if i == 0 {
        s.push_str("Take it down and pass it around, no more bottles of beer on the wall.\n")
    } else {
        // plural s
        let plural_s = if i == 1 {
            ""
        } else {
            "s"
        };
        s.push_str(&format!("Take one down and pass it around, {} bottle{} of beer on the wall.\n",
                            i,
                            plural_s))
    }
}

pub fn sing(start: u8, end: u8) -> String {
    (end..start + 1).rev().map(verse).collect::<Vec<String>>().join("\n")
}
<commit_msg>Rust: Beer Song - more readable<commit_after>// just hard code all special cases
const VERSES: [&'static str; 3] =
    ["No more bottles of beer on the wall, no more bottles of beer.\nGo to the store and buy \
      some more, 99 bottles of beer on the wall.\n",
     "1 bottle of beer on the wall, 1 bottle of beer.\nTake it down and pass it around, no more \
      bottles of beer on the wall.\n",
     "2 bottles of beer on the wall, 2 bottles of beer.\nTake one down and pass it around, 1 \
      bottle of beer on the wall.\n"];

pub fn verse(i: usize) -> String {
    match i {
        0 | 1 | 2 => VERSES[i].to_string(),
        _ => {
            format!("{0} bottles of beer on the wall, {0} bottles of beer.\nTake one down and \
                     pass it around, {1} bottles of beer on the wall.\n",
                    i,
                    i - 1)
        }
    }
}

pub fn sing(start: usize, end: usize) -> String {
    (end..start + 1).rev().map(verse).collect::<Vec<String>>().join("\n")
}
<|endoftext|>


<commit_before>// Copyright 2016 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! A container for all the tabs being edited. Also functions as main dispatch for RPC.

use std::collections::BTreeMap;
use std::io::{self, Read, Write};
use std::path::{PathBuf, Path};
use std::fs::File;
use std::sync::{Arc, Mutex};
use serde_json::value::Value;

use xi_rope::rope::Rope;
use editor::Editor;
use rpc::{CoreCommand, EditCommand};
use styles::{Style, StyleMap};
use MainPeer;

/// ViewIdentifiers are the primary means of routing messages between xi-core and a client view.
pub type ViewIdentifier = String;

/// BufferIdentifiers uniquely identify open buffers.
type BufferIdentifier = String;

// TODO: proposed new name: something like "Core" or "CoreState" or "EditorState"? "Documents?"
pub struct Tabs<W: Write> {
    /// maps file names to buffer identifiers. If a client asks to open a file that is already
    /// open, we treat it as a request for a new view.
    open_files: BTreeMap<PathBuf, BufferIdentifier>,
    /// maps buffer identifiers (filenames) to editor instances
    buffers: BTreeMap<BufferIdentifier, Arc<Mutex<Editor<W>>>>,
    /// maps view identifiers to editor instances. All actions originate in a view; this lets us
    /// route messages correctly when multiple views share a buffer.
    views: BTreeMap<ViewIdentifier, BufferIdentifier>,
    id_counter: usize,
    kill_ring: Arc<Mutex<Rope>>,
    style_map: Arc<Mutex<StyleMap>>,
}

#[derive(Clone)]
pub struct TabCtx<W: Write> {
    kill_ring: Arc<Mutex<Rope>>,
    rpc_peer: MainPeer<W>,
    style_map: Arc<Mutex<StyleMap>>,
}

impl<W: Write + Send + 'static> Tabs<W> {
    pub fn new() -> Tabs<W> {
        Tabs {
            open_files: BTreeMap::new(),
            buffers: BTreeMap::new(),
            views: BTreeMap::new(),
            id_counter: 0,
            kill_ring: Arc::new(Mutex::new(Rope::from(""))),
            style_map: Arc::new(Mutex::new(StyleMap::new())),
        }
    }

    fn new_tab_ctx(&self, peer: &MainPeer<W>) -> TabCtx<W> {
        TabCtx {
            kill_ring: self.kill_ring.clone(),
            rpc_peer: peer.clone(),
            style_map: self.style_map.clone(),
        }
    }

    fn next_view_id(&mut self) -> ViewIdentifier {
        self.id_counter += 1;
        format!("view-id-{}", self.id_counter)
    }

    fn next_buffer_id(&mut self) -> BufferIdentifier {
        self.id_counter += 1;
        format!("buffer-id-{}", self.id_counter)
    }

    pub fn do_rpc(&mut self, cmd: CoreCommand, rpc_peer: &MainPeer<W>) -> Option<Value> {
        use rpc::CoreCommand::*;

        match cmd {
            CloseView { view_id } => {
                self.do_close_view(view_id);
                None
            },

            NewView { file_path } => Some(Value::String(self.do_new_view(rpc_peer, file_path))),
            Save { view_id, file_path } => self.do_save(view_id, file_path),
            Edit { view_id, edit_command } => self.do_edit(view_id, edit_command),
        }
    }

    /// Creates a new view and associates it with a buffer.
    ///
    /// This function always creates a new view and associates it with a buffer (which we access
    ///through an `Editor` instance). This buffer may be existing, or it may be created.
    ///
    ///A `new_view` request is handled differently depending on the `file_path` argument, and on
    ///application state. If `file_path` is given and a buffer associated with that file is already
    ///open, we create a new view into the existing buffer. If `file_path` is given and that file
    ///_isn't_ open, we load that file into a new buffer. If `file_path` is not given, we create a
    ///new empty buffer.
    fn do_new_view(&mut self, rpc_peer: &MainPeer<W>, file_path: Option<&str>) -> ViewIdentifier {
        // three code paths: new buffer, open file, and new view into existing buffer
        let view_id = self.next_view_id();
        if let Some(file_path) = file_path.map(PathBuf::from) {
            // TODO: here, we should eventually be adding views to the existing editor.
            // for the time being, we just create a new empty view.
            if self.open_files.contains_key(&file_path) {
                let buffer_id = self.next_buffer_id();
                self.new_empty_view(rpc_peer, &view_id, buffer_id);
                // let buffer_id = self.open_files.get(&file_path).unwrap().to_owned();
                //self.add_view(&view_id, buffer_id);
            } else {
                // not open: create new buffer_id and open file
                let buffer_id = self.next_buffer_id();
                self.open_files.insert(file_path.to_owned(), buffer_id.clone());
                self.new_view_with_file(rpc_peer, &view_id, buffer_id.clone(), &file_path);
                // above fn has two branches: set path after
                self.buffers.get(&buffer_id).unwrap().lock().unwrap().set_path(&file_path);
            }
        } else {
            // file_path was nil: create a new empty buffer.
            let buffer_id = self.next_buffer_id();
            self.new_empty_view(rpc_peer, &view_id, buffer_id);
        }
        view_id
    }

    fn do_close_view(&mut self, view_id: &str) {
        self.close_view(view_id);
    }

    fn new_empty_view(&mut self, rpc_peer: &MainPeer<W>,
                      view_id: &str, buffer_id: BufferIdentifier) {
        let editor = Editor::new(self.new_tab_ctx(rpc_peer), view_id);
        self.finalize_new_view(view_id, buffer_id, editor);
    }

    fn new_view_with_file(&mut self, rpc_peer: &MainPeer<W>, view_id: &str, buffer_id: BufferIdentifier, path: &Path) {
        match self.read_file(&path) {
            Ok(contents) => {
                let editor = Editor::with_text(self.new_tab_ctx(rpc_peer), view_id, contents);
                self.finalize_new_view(view_id, buffer_id, editor)
            }
            Err(err) => {
                // TODO: we should be reporting errors to the client
                // (if this is even an error? we treat opening a non-existent file as a new buffer,
                // but set the editor's path)
                print_err!("unable to read file: {}, error: {:?}", buffer_id, err);
               self.new_empty_view(rpc_peer, view_id, buffer_id);
            }
        }
    }

    /// Adds a new view to an existing editor instance.
    #[allow(unreachable_code, unused_variables, dead_code)]
    fn add_view(&mut self, view_id: &str, buffer_id: BufferIdentifier) {
        panic!("add_view should not currently be accessible");
        let editor = self.buffers.get(&buffer_id).expect("missing editor_id for view_id");
        self.views.insert(view_id.to_owned(), buffer_id);
        editor.lock().unwrap().add_view(view_id);
    }

    fn finalize_new_view(&mut self, view_id: &str, buffer_id: String, editor: Arc<Mutex<Editor<W>>>) {
        self.views.insert(view_id.to_owned(), buffer_id.clone());
        self.buffers.insert(buffer_id, editor.clone());
    }

    fn read_file<P: AsRef<Path>>(&self, path: P) -> io::Result<String> {
        let mut f = File::open(path)?;
        let mut s = String::new();
        f.read_to_string(&mut s)?;
        Ok(s)
    }

    fn close_view(&mut self, view_id: &str) {
        let buf_id = self.views.remove(view_id).expect("missing buffer id when closing view");
        let has_views = {
            let editor = self.buffers.get(&buf_id).expect("missing editor when closing view");
            editor.lock().unwrap().remove_view(view_id);
            editor.lock().unwrap().has_views()
        };

        if !has_views {
            self.buffers.remove(&buf_id);
        }
    }

    fn do_save(&mut self, view_id: &str, file_path: &str) -> Option<Value> {
        let buffer_id = self.views.get(view_id)
            .expect(&format!("missing buffer id for view {}", view_id));
        let editor = self.buffers.get(buffer_id)
            .expect(&format!("missing editor for buffer {}", buffer_id));
        let file_path = PathBuf::from(file_path);

        // if this is a new path for an existing file, we have a bit of housekeeping to do:
        if let Some(prev_path) = editor.lock().unwrap().get_path() {
            if prev_path != file_path {
                self.open_files.remove(prev_path);
            }
        }
        editor.lock().unwrap().do_save(&file_path);
        self.open_files.insert(file_path, buffer_id.to_owned());
        None
    }

    fn do_edit(&mut self, view_id: &str, cmd: EditCommand) -> Option<Value> {
        let buffer_id = self.views.get(view_id)
            .expect(&format!("missing buffer id for view {}", view_id));
        if let Some(editor) = self.buffers.get(buffer_id) {
            Editor::do_rpc(editor, view_id, cmd)
        } else {
            print_err!("buffer not found: {}, for view {}", buffer_id, view_id);
            None
        }
    }

    pub fn handle_idle(&self) {
        for editor in self.buffers.values() {
            editor.lock().unwrap().render();
        }
    }
}

impl<W: Write> TabCtx<W> {
    pub fn update_view(&self, view_id: &str, update: &Value) {
        self.rpc_peer.send_rpc_notification("update",
            &json!({
                "view_id": view_id,
                "update": update,
            }));
    }

    pub fn scroll_to(&self, view_id: &str, line: usize, col: usize) {
        self.rpc_peer.send_rpc_notification("scroll_to",
            &json!({
                "view_id": view_id,
                "line": line,
                "col": col,
            }));
    }

    pub fn get_kill_ring(&self) -> Rope {
        self.kill_ring.lock().unwrap().clone()
    }

    pub fn set_kill_ring(&self, val: Rope) {
        let mut kill_ring = self.kill_ring.lock().unwrap();
        *kill_ring = val;
    }

    pub fn alert(&self, msg: &str) {
        self.rpc_peer.send_rpc_notification("alert",
            &json!({
                "msg": msg,
            }));
    }

    // Get the index for a given style. If the style is not in the existing
    // style map, then issues a def_style request to the front end. Intended
    // to be reasonably efficient, but ideally callers would do their own
    // indexing.
    pub fn get_style_id(&self, style: &Style) -> usize {
        let mut style_map = self.style_map.lock().unwrap();
        if let Some(ix) = style_map.lookup(style) {
            return ix;
        }
        let ix = style_map.add(style);
        self.rpc_peer.send_rpc_notification("def_style", &style.to_json(ix));
        ix
    }
}
<commit_msg>Fix re-opening file opens empty buffer<commit_after>// Copyright 2016 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! A container for all the tabs being edited. Also functions as main dispatch for RPC.

use std::collections::BTreeMap;
use std::io::{self, Read, Write};
use std::path::{PathBuf, Path};
use std::fs::File;
use std::sync::{Arc, Mutex};
use serde_json::value::Value;

use xi_rope::rope::Rope;
use editor::Editor;
use rpc::{CoreCommand, EditCommand};
use styles::{Style, StyleMap};
use MainPeer;

/// ViewIdentifiers are the primary means of routing messages between xi-core and a client view.
pub type ViewIdentifier = String;

/// BufferIdentifiers uniquely identify open buffers.
type BufferIdentifier = String;

// TODO: proposed new name: something like "Core" or "CoreState" or "EditorState"? "Documents?"
pub struct Tabs<W: Write> {
    /// maps file names to buffer identifiers. If a client asks to open a file that is already
    /// open, we treat it as a request for a new view.
    open_files: BTreeMap<PathBuf, BufferIdentifier>,
    /// maps buffer identifiers (filenames) to editor instances
    buffers: BTreeMap<BufferIdentifier, Arc<Mutex<Editor<W>>>>,
    /// maps view identifiers to editor instances. All actions originate in a view; this lets us
    /// route messages correctly when multiple views share a buffer.
    views: BTreeMap<ViewIdentifier, BufferIdentifier>,
    id_counter: usize,
    kill_ring: Arc<Mutex<Rope>>,
    style_map: Arc<Mutex<StyleMap>>,
}

#[derive(Clone)]
pub struct TabCtx<W: Write> {
    kill_ring: Arc<Mutex<Rope>>,
    rpc_peer: MainPeer<W>,
    style_map: Arc<Mutex<StyleMap>>,
}

impl<W: Write + Send + 'static> Tabs<W> {
    pub fn new() -> Tabs<W> {
        Tabs {
            open_files: BTreeMap::new(),
            buffers: BTreeMap::new(),
            views: BTreeMap::new(),
            id_counter: 0,
            kill_ring: Arc::new(Mutex::new(Rope::from(""))),
            style_map: Arc::new(Mutex::new(StyleMap::new())),
        }
    }

    fn new_tab_ctx(&self, peer: &MainPeer<W>) -> TabCtx<W> {
        TabCtx {
            kill_ring: self.kill_ring.clone(),
            rpc_peer: peer.clone(),
            style_map: self.style_map.clone(),
        }
    }

    fn next_view_id(&mut self) -> ViewIdentifier {
        self.id_counter += 1;
        format!("view-id-{}", self.id_counter)
    }

    fn next_buffer_id(&mut self) -> BufferIdentifier {
        self.id_counter += 1;
        format!("buffer-id-{}", self.id_counter)
    }

    pub fn do_rpc(&mut self, cmd: CoreCommand, rpc_peer: &MainPeer<W>) -> Option<Value> {
        use rpc::CoreCommand::*;

        match cmd {
            CloseView { view_id } => {
                self.do_close_view(view_id);
                None
            },

            NewView { file_path } => Some(Value::String(self.do_new_view(rpc_peer, file_path))),
            Save { view_id, file_path } => self.do_save(view_id, file_path),
            Edit { view_id, edit_command } => self.do_edit(view_id, edit_command),
        }
    }

    /// Creates a new view and associates it with a buffer.
    ///
    /// This function always creates a new view and associates it with a buffer (which we access
    ///through an `Editor` instance). This buffer may be existing, or it may be created.
    ///
    ///A `new_view` request is handled differently depending on the `file_path` argument, and on
    ///application state. If `file_path` is given and a buffer associated with that file is already
    ///open, we create a new view into the existing buffer. If `file_path` is given and that file
    ///_isn't_ open, we load that file into a new buffer. If `file_path` is not given, we create a
    ///new empty buffer.
    fn do_new_view(&mut self, rpc_peer: &MainPeer<W>, file_path: Option<&str>) -> ViewIdentifier {
        // three code paths: new buffer, open file, and new view into existing buffer
        let view_id = self.next_view_id();
        if let Some(file_path) = file_path.map(PathBuf::from) {
            // TODO: here, we should eventually be adding views to the existing editor.
            // for the time being, we just create a new empty view.
            if self.open_files.contains_key(&file_path) {
                let buffer_id = self.next_buffer_id();
                self.new_empty_view(rpc_peer, &view_id, buffer_id);
                // let buffer_id = self.open_files.get(&file_path).unwrap().to_owned();
                //self.add_view(&view_id, buffer_id);
            } else {
                // not open: create new buffer_id and open file
                let buffer_id = self.next_buffer_id();
                self.open_files.insert(file_path.to_owned(), buffer_id.clone());
                self.new_view_with_file(rpc_peer, &view_id, buffer_id.clone(), &file_path);
                // above fn has two branches: set path after
                self.buffers.get(&buffer_id).unwrap().lock().unwrap().set_path(&file_path);
            }
        } else {
            // file_path was nil: create a new empty buffer.
            let buffer_id = self.next_buffer_id();
            self.new_empty_view(rpc_peer, &view_id, buffer_id);
        }
        view_id
    }

    fn do_close_view(&mut self, view_id: &str) {
        self.close_view(view_id);
    }

    fn new_empty_view(&mut self, rpc_peer: &MainPeer<W>,
                      view_id: &str, buffer_id: BufferIdentifier) {
        let editor = Editor::new(self.new_tab_ctx(rpc_peer), view_id);
        self.finalize_new_view(view_id, buffer_id, editor);
    }

    fn new_view_with_file(&mut self, rpc_peer: &MainPeer<W>, view_id: &str, buffer_id: BufferIdentifier, path: &Path) {
        match self.read_file(&path) {
            Ok(contents) => {
                let editor = Editor::with_text(self.new_tab_ctx(rpc_peer), view_id, contents);
                self.finalize_new_view(view_id, buffer_id, editor)
            }
            Err(err) => {
                // TODO: we should be reporting errors to the client
                // (if this is even an error? we treat opening a non-existent file as a new buffer,
                // but set the editor's path)
                print_err!("unable to read file: {}, error: {:?}", buffer_id, err);
               self.new_empty_view(rpc_peer, view_id, buffer_id);
            }
        }
    }

    /// Adds a new view to an existing editor instance.
    #[allow(unreachable_code, unused_variables, dead_code)]
    fn add_view(&mut self, view_id: &str, buffer_id: BufferIdentifier) {
        panic!("add_view should not currently be accessible");
        let editor = self.buffers.get(&buffer_id).expect("missing editor_id for view_id");
        self.views.insert(view_id.to_owned(), buffer_id);
        editor.lock().unwrap().add_view(view_id);
    }

    fn finalize_new_view(&mut self, view_id: &str, buffer_id: String, editor: Arc<Mutex<Editor<W>>>) {
        self.views.insert(view_id.to_owned(), buffer_id.clone());
        self.buffers.insert(buffer_id, editor.clone());
    }

    fn read_file<P: AsRef<Path>>(&self, path: P) -> io::Result<String> {
        let mut f = File::open(path)?;
        let mut s = String::new();
        f.read_to_string(&mut s)?;
        Ok(s)
    }

    fn close_view(&mut self, view_id: &str) {
        let buf_id = self.views.remove(view_id).expect("missing buffer id when closing view");
        let (has_views, path) = {
            let editor = self.buffers.get(&buf_id).expect("missing editor when closing view");
            let mut editor = editor.lock().unwrap();
            editor.remove_view(view_id);
            (editor.has_views(), editor.get_path().map(PathBuf::from))
        };

        if !has_views {
            self.buffers.remove(&buf_id);
            if let Some(path) = path {
                self.open_files.remove(&path);
            }
        }
    }

    fn do_save(&mut self, view_id: &str, file_path: &str) -> Option<Value> {
        let buffer_id = self.views.get(view_id)
            .expect(&format!("missing buffer id for view {}", view_id));
        let editor = self.buffers.get(buffer_id)
            .expect(&format!("missing editor for buffer {}", buffer_id));
        let file_path = PathBuf::from(file_path);

        // if this is a new path for an existing file, we have a bit of housekeeping to do:
        if let Some(prev_path) = editor.lock().unwrap().get_path() {
            if prev_path != file_path {
                self.open_files.remove(prev_path);
            }
        }
        editor.lock().unwrap().do_save(&file_path);
        self.open_files.insert(file_path, buffer_id.to_owned());
        None
    }

    fn do_edit(&mut self, view_id: &str, cmd: EditCommand) -> Option<Value> {
        let buffer_id = self.views.get(view_id)
            .expect(&format!("missing buffer id for view {}", view_id));
        if let Some(editor) = self.buffers.get(buffer_id) {
            Editor::do_rpc(editor, view_id, cmd)
        } else {
            print_err!("buffer not found: {}, for view {}", buffer_id, view_id);
            None
        }
    }

    pub fn handle_idle(&self) {
        for editor in self.buffers.values() {
            editor.lock().unwrap().render();
        }
    }
}

impl<W: Write> TabCtx<W> {
    pub fn update_view(&self, view_id: &str, update: &Value) {
        self.rpc_peer.send_rpc_notification("update",
            &json!({
                "view_id": view_id,
                "update": update,
            }));
    }

    pub fn scroll_to(&self, view_id: &str, line: usize, col: usize) {
        self.rpc_peer.send_rpc_notification("scroll_to",
            &json!({
                "view_id": view_id,
                "line": line,
                "col": col,
            }));
    }

    pub fn get_kill_ring(&self) -> Rope {
        self.kill_ring.lock().unwrap().clone()
    }

    pub fn set_kill_ring(&self, val: Rope) {
        let mut kill_ring = self.kill_ring.lock().unwrap();
        *kill_ring = val;
    }

    pub fn alert(&self, msg: &str) {
        self.rpc_peer.send_rpc_notification("alert",
            &json!({
                "msg": msg,
            }));
    }

    // Get the index for a given style. If the style is not in the existing
    // style map, then issues a def_style request to the front end. Intended
    // to be reasonably efficient, but ideally callers would do their own
    // indexing.
    pub fn get_style_id(&self, style: &Style) -> usize {
        let mut style_map = self.style_map.lock().unwrap();
        if let Some(ix) = style_map.lookup(style) {
            return ix;
        }
        let ix = style_map.add(style);
        self.rpc_peer.send_rpc_notification("def_style", &style.to_json(ix));
        ix
    }
}
<|endoftext|>


<commit_before>fn main() {
    print_number(5);
}

fn print_number(x: i32) {
    println!("x is : {}", x);
}
<commit_msg>sum function<commit_after>fn main() {
    print_sum(5, 6);
}

fn print_sum(x: i32, y: i32) {
    println!("sum is : {}", x + y);
}

<|endoftext|>


<commit_before>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

//! The Peer actor owns the underlying connection and is responsible for listening for
//! and opening substreams as well as negotiating particular protocols on those substreams.
use crate::{
    counters,
    peer_manager::PeerManagerError,
    protocols::wire::messaging::v1::NetworkMessage,
    transport,
    transport::{Connection, ConnectionMetadata},
    ProtocolId,
};
use bytes::BytesMut;
use futures::{
    self,
    channel::oneshot,
    io::{AsyncRead, AsyncWrite},
    stream::StreamExt,
    FutureExt, SinkExt, TryFutureExt,
};
use libra_logger::prelude::*;
use libra_types::PeerId;
use netcore::compat::IoCompat;
use serde::{export::Formatter, Serialize};
use std::{fmt::Debug, io, time::Duration};
use stream_ratelimiter::*;
use tokio::runtime::Handle;
use tokio_util::codec::{FramedRead, FramedWrite, LengthDelimitedCodec};

// Rate-limit configuration for inbound messages. Allows 100 messages for every 10ms window.
pub const MESSAGE_RATE_LIMIT_WINDOW: Duration = Duration::from_millis(10);
pub const MESSAGE_RATE_LIMIT_COUNT: usize = 100;

#[cfg(test)]
mod test;

#[derive(Debug)]
pub enum PeerRequest {
    SendMessage(
        NetworkMessage,
        ProtocolId,
        oneshot::Sender<Result<(), PeerManagerError>>,
    ),
    CloseConnection,
}

#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize)]
pub enum DisconnectReason {
    Requested,
    ConnectionLost,
}

impl std::fmt::Display for DisconnectReason {
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
        write!(
            f,
            "{}",
            match self {
                DisconnectReason::Requested => "Requested",
                DisconnectReason::ConnectionLost => "ConnectionLost",
            }
        )
    }
}

#[derive(Debug)]
pub enum PeerNotification {
    NewMessage(NetworkMessage),
    PeerDisconnected(ConnectionMetadata, DisconnectReason),
}

enum State {
    Connected,
    ShuttingDown(DisconnectReason),
}

pub struct Peer<TSocket> {
    /// A handle to a tokio executor.
    executor: Handle,
    /// Connection specific information.
    connection_metadata: ConnectionMetadata,
    /// Underlying connection.
    connection: Option<TSocket>,
    /// Channel to receive requests for opening new outbound substreams.
    requests_rx: channel::Receiver<PeerRequest>,
    /// Channel to send peer notifications to PeerManager.
    peer_notifs_tx: channel::Sender<PeerNotification>,
    /// Channel to notify about new inbound RPC substreams.
    rpc_notifs_tx: channel::Sender<PeerNotification>,
    /// Channel to notify about new inbound DirectSend substreams.
    direct_send_notifs_tx: channel::Sender<PeerNotification>,
    /// Flag to indicate if the actor is being shut down.
    state: State,
    /// The maximum size of an inbound or outbound request frame
    /// Currently, requests are only a single frame
    max_frame_size: usize,
}

impl<TSocket> Peer<TSocket>
where
    TSocket: AsyncRead + AsyncWrite + Send + 'static,
{
    pub fn new(
        executor: Handle,
        connection: Connection<TSocket>,
        requests_rx: channel::Receiver<PeerRequest>,
        peer_notifs_tx: channel::Sender<PeerNotification>,
        rpc_notifs_tx: channel::Sender<PeerNotification>,
        direct_send_notifs_tx: channel::Sender<PeerNotification>,
        max_frame_size: usize,
    ) -> Self {
        let Connection {
            metadata: connection_metadata,
            socket,
        } = connection;
        Self {
            executor,
            connection_metadata,
            connection: Some(socket),
            requests_rx,
            peer_notifs_tx,
            rpc_notifs_tx,
            direct_send_notifs_tx,
            state: State::Connected,
            max_frame_size,
        }
    }

    fn peer_id(&self) -> PeerId {
        self.connection_metadata.peer_id()
    }

    pub async fn start(mut self) {
        let self_peer_id = self.peer_id();
        info!(
            "Starting Peer actor for peer: {:?}",
            self_peer_id.short_str()
        );

        // Split the connection into a ReadHalf and a WriteHalf.
        let (reader, writer) = tokio::io::split(IoCompat::new(self.connection.take().unwrap()));
        let mut codec_builder = LengthDelimitedCodec::builder();
        codec_builder
            .max_frame_length(self.max_frame_size)
            .length_field_length(4)
            .big_endian();
        // Convert ReadHalf to Stream of length-delimited messages.

        let reader = FramedRead::new(reader, codec_builder.new_codec()).fuse();
        // Create a rate-limited stream of inbound messages.
        let mut reader = reader
            .ratelimit(MESSAGE_RATE_LIMIT_WINDOW, MESSAGE_RATE_LIMIT_COUNT)
            .fuse();

        // Convert WriteHalf to Sink of length-delimited messages.
        let writer = FramedWrite::new(writer, codec_builder.new_codec());
        // Start writer "process" as a separate task. We receive two handles to communicate with
        // the task:
        // `write_reqs_tx`: Instruction to send a NetworkMessage on the wire.
        // `close_tx`: Instruction to close the underlying connection.
        let (write_reqs_tx, close_tx) =
            Self::start_writer_task(&self.executor, self_peer_id, writer);
        // Start main Peer event loop.
        loop {
            match self.state {
                State::Connected => {
                    futures::select! {
                        maybe_req = self.requests_rx.next() => {
                            if let Some(request) = maybe_req {
                                self.handle_request(request, write_reqs_tx.clone()).await;
                            } else {
                                // This branch will only be taken if all PeerRequest senders for this Peer
                                // get dropped.
                                break;
                            }
                        },
                        maybe_message = reader.next() => {
                            match maybe_message {
                                Some(Ok(message)) =>  {
                                    if let Err(err) = self.handle_inbound_message(message, write_reqs_tx.clone()).await {
                                        warn!("Error in handling inbound message from peer: {}. Error: {:?}",
                                            self_peer_id.short_str(), err);
                                    }
                                },
                                Some(Err(err)) => {
                                    warn!("Failure in reading messages from socket from peer: {}. Error: {:?}",
                                        self_peer_id.short_str(), err);
                                    self.close_connection( DisconnectReason::ConnectionLost).await;
                                }
                                None => {
                                    warn!("Received connection closed event for peer: {}",
                                        self_peer_id.short_str());
                                    self.close_connection(DisconnectReason::ConnectionLost).await;
                                }
                            }
                        },
                    }
                }
                State::ShuttingDown(reason) => {
                    // Send a close instruction to the writer task. On receipt of this instruction, the writer
                    // task drops all pending outbound messages and closes the connection.
                    if let Err(e) = close_tx.send(()) {
                        info!(
                            "Failed to send close instruction to writer task. It must already be terminating/terminated. Error: {:?}",
                            e
                        );
                    }
                    // Send a PeerDisconnected event to upstream.
                    if let Err(e) = self
                        .peer_notifs_tx
                        .send(PeerNotification::PeerDisconnected(
                            self.connection_metadata.clone(),
                            reason,
                        ))
                        .await
                    {
                        warn!(
                            "Failed to notify upstream about disconnection of peer: {}; error: {:?}",
                            self.peer_id().short_str(),
                            e
                        );
                    }
                    debug!("Peer actor '{}' shutdown", self.peer_id().short_str());
                    break;
                }
            }
        }
    }

    // Start a new task on the given executor which is responsible for writing outbound messages on
    // the wire. The function returns two channels which can be used to send intructions to the
    // task:
    // 1. The first channel is used to send outbound NetworkMessages to the task
    // 2. The second channel is used to instruct the task to close the connection and terminate.
    // If outbound messages are queued when the task receives a close instruction, it discards
    // them and immediately closes the connection.
    fn start_writer_task<T: tokio::io::AsyncWrite + Send + Unpin + 'static>(
        executor: &Handle,
        self_peer_id: PeerId,
        mut writer: FramedWrite<T, LengthDelimitedCodec>,
    ) -> (
        channel::Sender<(
            NetworkMessage,
            oneshot::Sender<Result<(), PeerManagerError>>,
        )>,
        oneshot::Sender<()>,
    ) {
        let (write_reqs_tx, mut write_reqs_rx): (
            channel::Sender<(
                NetworkMessage,
                oneshot::Sender<Result<(), PeerManagerError>>,
            )>,
            _,
        ) = channel::new(1024, &counters::PENDING_WIRE_MESSAGES);
        let (close_tx, close_rx) = oneshot::channel();
        let writer_task = async move {
            let mut close_rx = close_rx.into_stream();
            loop {
                futures::select! {
                    (message, ack_ch) = write_reqs_rx.select_next_some() => {
                        if let Err(e) = writer
                            .send(
                                lcs::to_bytes(&message)
                                    .expect("Outbound message failed to serialize")
                                    .into(),
                            )
                            .map_ok(|_| ack_ch.send(Ok(())))
                            .await
                        {
                            warn!(
                                "Error in sending message to peer: {}. Error: {:?}",
                                self_peer_id.short_str(),
                                e
                            );
                            break;
                        }
                    },
                    _ = close_rx.select_next_some() => {
                        break;
                    }
                }
            }
            info!("Closing connection to peer: {}", self_peer_id.short_str());
            let flush_and_close = async move {
                writer.flush().await?;
                writer.close().await?;
                Ok(()) as io::Result<()>
            };
            match tokio::time::timeout(transport::TRANSPORT_TIMEOUT, flush_and_close).await {
                Err(_) => {
                    info!(
                        "Timeout in flush/close of connection to peer: {}",
                        self_peer_id.short_str()
                    );
                }
                Ok(Err(e)) => {
                    info!(
                        "Failure in flush/close of connection to peer: {}. Error: {:?}",
                        self_peer_id.short_str(),
                        e
                    );
                }
                Ok(Ok(())) => {
                    info!("Closed connection to peer: {}", self_peer_id.short_str());
                }
            }
        };
        executor.spawn(writer_task);
        (write_reqs_tx, close_tx)
    }

    async fn handle_inbound_message(
        &mut self,
        message: BytesMut,
        mut write_reqs_tx: channel::Sender<(
            NetworkMessage,
            oneshot::Sender<Result<(), PeerManagerError>>,
        )>,
    ) -> Result<(), PeerManagerError> {
        trace!("Received message from Peer {}", self.peer_id().short_str(),);
        // Read inbound message from stream.
        let message = message.freeze();
        let message: NetworkMessage = lcs::from_bytes(&message)?;
        match message {
            NetworkMessage::RpcRequest(_) | NetworkMessage::RpcResponse(_) => {
                let notif = PeerNotification::NewMessage(message);
                self.rpc_notifs_tx.send(notif).await.map_err(|err| {
                    warn!("Failed to send notification to RPC actor. Error: {:?}", err);
                    err
                })?;
                Ok(())
            }
            NetworkMessage::DirectSendMsg(_) => {
                let notif = PeerNotification::NewMessage(message);
                self.direct_send_notifs_tx
                    .send(notif)
                    .await
                    .map_err(|err| {
                        warn!(
                            "Failed to send notification to DirectSend actor. Error: {:?}",
                            err
                        );
                        err
                    })?;
                Ok(())
            }
            NetworkMessage::Ping(nonce) => {
                let pong = NetworkMessage::Pong(nonce);
                let (ack_tx, _) = oneshot::channel();
                // Resond to a ping right away.
                write_reqs_tx.send((pong, ack_tx)).await?;
                Ok(())
            }
            _ => unreachable!("Unhandled"),
        }
    }

    async fn handle_request<'a>(
        &'a mut self,
        request: PeerRequest,
        mut write_reqs_tx: channel::Sender<(
            NetworkMessage,
            oneshot::Sender<Result<(), PeerManagerError>>,
        )>,
    ) {
        trace!(
            "Peer {} PeerRequest::{:?}",
            self.peer_id().short_str(),
            request
        );
        match request {
            PeerRequest::SendMessage(message, protocol, channel) => {
                if let Err(e) = write_reqs_tx.send((message, channel)).await {
                    error!(
                        "Failed to send message for protocol {} to peer: {}. Error: {:?}",
                        protocol,
                        self.peer_id().short_str(),
                        e
                    );
                }
            }
            PeerRequest::CloseConnection => {
                self.close_connection(DisconnectReason::Requested).await;
            }
        }
    }

    async fn close_connection(&mut self, reason: DisconnectReason) {
        // Set the state of the actor to `State::ShuttingDown` to true ensures that the peer actor
        // will terminate and close the connection.
        self.state = State::ShuttingDown(reason);
    }
}

pub struct PeerHandle {
    peer_id: PeerId,
    sender: channel::Sender<PeerRequest>,
}

impl Clone for PeerHandle {
    fn clone(&self) -> Self {
        Self {
            peer_id: self.peer_id,
            sender: self.sender.clone(),
        }
    }
}

impl PeerHandle {
    pub fn new(peer_id: PeerId, sender: channel::Sender<PeerRequest>) -> Self {
        Self { peer_id, sender }
    }

    pub fn peer_id(&self) -> PeerId {
        self.peer_id
    }

    pub async fn send_message(
        &mut self,
        message: NetworkMessage,
        protocol: ProtocolId,
    ) -> Result<(), PeerManagerError> {
        // If we fail to send the request to the Peer, then it must have already been shutdown.
        let (oneshot_tx, oneshot_rx) = oneshot::channel();
        if self
            .sender
            .send(PeerRequest::SendMessage(message, protocol, oneshot_tx))
            .await
            .is_err()
        {
            error!(
                "Sending message to Peer {} \
                 failed because it has already been shutdown.",
                self.peer_id.short_str()
            );
        }
        oneshot_rx
            .await
            // The send_message request can get dropped/canceled if the peer
            // connection is in the process of shutting down.
            .map_err(|_| PeerManagerError::NotConnected(self.peer_id))?
    }

    pub async fn disconnect(&mut self) {
        // If we fail to send the request to the Peer, then it must have already been shutdown.
        if self
            .sender
            .send(PeerRequest::CloseConnection)
            .await
            .is_err()
        {
            error!(
                "Sending CloseConnection request to Peer {} \
                 failed because it has already been shutdown.",
                self.peer_id.short_str()
            );
        }
    }
}
<commit_msg>[network] eliminate unreachable that is very reachable<commit_after>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

//! The Peer actor owns the underlying connection and is responsible for listening for
//! and opening substreams as well as negotiating particular protocols on those substreams.
use crate::{
    counters,
    peer_manager::PeerManagerError,
    protocols::wire::messaging::v1::NetworkMessage,
    transport,
    transport::{Connection, ConnectionMetadata},
    ProtocolId,
};
use bytes::BytesMut;
use futures::{
    self,
    channel::oneshot,
    io::{AsyncRead, AsyncWrite},
    stream::StreamExt,
    FutureExt, SinkExt, TryFutureExt,
};
use libra_logger::prelude::*;
use libra_types::PeerId;
use netcore::compat::IoCompat;
use serde::{export::Formatter, Serialize};
use std::{fmt::Debug, io, time::Duration};
use stream_ratelimiter::*;
use tokio::runtime::Handle;
use tokio_util::codec::{FramedRead, FramedWrite, LengthDelimitedCodec};

// Rate-limit configuration for inbound messages. Allows 100 messages for every 10ms window.
pub const MESSAGE_RATE_LIMIT_WINDOW: Duration = Duration::from_millis(10);
pub const MESSAGE_RATE_LIMIT_COUNT: usize = 100;

#[cfg(test)]
mod test;

#[derive(Debug)]
pub enum PeerRequest {
    SendMessage(
        NetworkMessage,
        ProtocolId,
        oneshot::Sender<Result<(), PeerManagerError>>,
    ),
    CloseConnection,
}

#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize)]
pub enum DisconnectReason {
    Requested,
    ConnectionLost,
}

impl std::fmt::Display for DisconnectReason {
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
        write!(
            f,
            "{}",
            match self {
                DisconnectReason::Requested => "Requested",
                DisconnectReason::ConnectionLost => "ConnectionLost",
            }
        )
    }
}

#[derive(Debug)]
pub enum PeerNotification {
    NewMessage(NetworkMessage),
    PeerDisconnected(ConnectionMetadata, DisconnectReason),
}

enum State {
    Connected,
    ShuttingDown(DisconnectReason),
}

pub struct Peer<TSocket> {
    /// A handle to a tokio executor.
    executor: Handle,
    /// Connection specific information.
    connection_metadata: ConnectionMetadata,
    /// Underlying connection.
    connection: Option<TSocket>,
    /// Channel to receive requests for opening new outbound substreams.
    requests_rx: channel::Receiver<PeerRequest>,
    /// Channel to send peer notifications to PeerManager.
    peer_notifs_tx: channel::Sender<PeerNotification>,
    /// Channel to notify about new inbound RPC substreams.
    rpc_notifs_tx: channel::Sender<PeerNotification>,
    /// Channel to notify about new inbound DirectSend substreams.
    direct_send_notifs_tx: channel::Sender<PeerNotification>,
    /// Flag to indicate if the actor is being shut down.
    state: State,
    /// The maximum size of an inbound or outbound request frame
    /// Currently, requests are only a single frame
    max_frame_size: usize,
}

impl<TSocket> Peer<TSocket>
where
    TSocket: AsyncRead + AsyncWrite + Send + 'static,
{
    pub fn new(
        executor: Handle,
        connection: Connection<TSocket>,
        requests_rx: channel::Receiver<PeerRequest>,
        peer_notifs_tx: channel::Sender<PeerNotification>,
        rpc_notifs_tx: channel::Sender<PeerNotification>,
        direct_send_notifs_tx: channel::Sender<PeerNotification>,
        max_frame_size: usize,
    ) -> Self {
        let Connection {
            metadata: connection_metadata,
            socket,
        } = connection;
        Self {
            executor,
            connection_metadata,
            connection: Some(socket),
            requests_rx,
            peer_notifs_tx,
            rpc_notifs_tx,
            direct_send_notifs_tx,
            state: State::Connected,
            max_frame_size,
        }
    }

    fn peer_id(&self) -> PeerId {
        self.connection_metadata.peer_id()
    }

    pub async fn start(mut self) {
        let self_peer_id = self.peer_id();
        info!(
            "Starting Peer actor for peer: {:?}",
            self_peer_id.short_str()
        );

        // Split the connection into a ReadHalf and a WriteHalf.
        let (reader, writer) = tokio::io::split(IoCompat::new(self.connection.take().unwrap()));
        let mut codec_builder = LengthDelimitedCodec::builder();
        codec_builder
            .max_frame_length(self.max_frame_size)
            .length_field_length(4)
            .big_endian();
        // Convert ReadHalf to Stream of length-delimited messages.

        let reader = FramedRead::new(reader, codec_builder.new_codec()).fuse();
        // Create a rate-limited stream of inbound messages.
        let mut reader = reader
            .ratelimit(MESSAGE_RATE_LIMIT_WINDOW, MESSAGE_RATE_LIMIT_COUNT)
            .fuse();

        // Convert WriteHalf to Sink of length-delimited messages.
        let writer = FramedWrite::new(writer, codec_builder.new_codec());
        // Start writer "process" as a separate task. We receive two handles to communicate with
        // the task:
        // `write_reqs_tx`: Instruction to send a NetworkMessage on the wire.
        // `close_tx`: Instruction to close the underlying connection.
        let (write_reqs_tx, close_tx) =
            Self::start_writer_task(&self.executor, self_peer_id, writer);
        // Start main Peer event loop.
        loop {
            match self.state {
                State::Connected => {
                    futures::select! {
                        maybe_req = self.requests_rx.next() => {
                            if let Some(request) = maybe_req {
                                self.handle_request(request, write_reqs_tx.clone()).await;
                            } else {
                                // This branch will only be taken if all PeerRequest senders for this Peer
                                // get dropped.
                                break;
                            }
                        },
                        maybe_message = reader.next() => {
                            match maybe_message {
                                Some(Ok(message)) =>  {
                                    if let Err(err) = self.handle_inbound_message(message, write_reqs_tx.clone()).await {
                                        warn!("Error in handling inbound message from peer: {}. Error: {:?}",
                                            self_peer_id.short_str(), err);
                                    }
                                },
                                Some(Err(err)) => {
                                    warn!("Failure in reading messages from socket from peer: {}. Error: {:?}",
                                        self_peer_id.short_str(), err);
                                    self.close_connection( DisconnectReason::ConnectionLost).await;
                                }
                                None => {
                                    warn!("Received connection closed event for peer: {}",
                                        self_peer_id.short_str());
                                    self.close_connection(DisconnectReason::ConnectionLost).await;
                                }
                            }
                        },
                    }
                }
                State::ShuttingDown(reason) => {
                    // Send a close instruction to the writer task. On receipt of this instruction, the writer
                    // task drops all pending outbound messages and closes the connection.
                    if let Err(e) = close_tx.send(()) {
                        info!(
                            "Failed to send close instruction to writer task. It must already be terminating/terminated. Error: {:?}",
                            e
                        );
                    }
                    // Send a PeerDisconnected event to upstream.
                    if let Err(e) = self
                        .peer_notifs_tx
                        .send(PeerNotification::PeerDisconnected(
                            self.connection_metadata.clone(),
                            reason,
                        ))
                        .await
                    {
                        warn!(
                            "Failed to notify upstream about disconnection of peer: {}; error: {:?}",
                            self.peer_id().short_str(),
                            e
                        );
                    }
                    debug!("Peer actor '{}' shutdown", self.peer_id().short_str());
                    break;
                }
            }
        }
    }

    // Start a new task on the given executor which is responsible for writing outbound messages on
    // the wire. The function returns two channels which can be used to send intructions to the
    // task:
    // 1. The first channel is used to send outbound NetworkMessages to the task
    // 2. The second channel is used to instruct the task to close the connection and terminate.
    // If outbound messages are queued when the task receives a close instruction, it discards
    // them and immediately closes the connection.
    fn start_writer_task<T: tokio::io::AsyncWrite + Send + Unpin + 'static>(
        executor: &Handle,
        self_peer_id: PeerId,
        mut writer: FramedWrite<T, LengthDelimitedCodec>,
    ) -> (
        channel::Sender<(
            NetworkMessage,
            oneshot::Sender<Result<(), PeerManagerError>>,
        )>,
        oneshot::Sender<()>,
    ) {
        let (write_reqs_tx, mut write_reqs_rx): (
            channel::Sender<(
                NetworkMessage,
                oneshot::Sender<Result<(), PeerManagerError>>,
            )>,
            _,
        ) = channel::new(1024, &counters::PENDING_WIRE_MESSAGES);
        let (close_tx, close_rx) = oneshot::channel();
        let writer_task = async move {
            let mut close_rx = close_rx.into_stream();
            loop {
                futures::select! {
                    (message, ack_ch) = write_reqs_rx.select_next_some() => {
                        if let Err(e) = writer
                            .send(
                                lcs::to_bytes(&message)
                                    .expect("Outbound message failed to serialize")
                                    .into(),
                            )
                            .map_ok(|_| ack_ch.send(Ok(())))
                            .await
                        {
                            warn!(
                                "Error in sending message to peer: {}. Error: {:?}",
                                self_peer_id.short_str(),
                                e
                            );
                            break;
                        }
                    },
                    _ = close_rx.select_next_some() => {
                        break;
                    }
                }
            }
            info!("Closing connection to peer: {}", self_peer_id.short_str());
            let flush_and_close = async move {
                writer.flush().await?;
                writer.close().await?;
                Ok(()) as io::Result<()>
            };
            match tokio::time::timeout(transport::TRANSPORT_TIMEOUT, flush_and_close).await {
                Err(_) => {
                    info!(
                        "Timeout in flush/close of connection to peer: {}",
                        self_peer_id.short_str()
                    );
                }
                Ok(Err(e)) => {
                    info!(
                        "Failure in flush/close of connection to peer: {}. Error: {:?}",
                        self_peer_id.short_str(),
                        e
                    );
                }
                Ok(Ok(())) => {
                    info!("Closed connection to peer: {}", self_peer_id.short_str());
                }
            }
        };
        executor.spawn(writer_task);
        (write_reqs_tx, close_tx)
    }

    async fn handle_inbound_message(
        &mut self,
        message: BytesMut,
        mut write_reqs_tx: channel::Sender<(
            NetworkMessage,
            oneshot::Sender<Result<(), PeerManagerError>>,
        )>,
    ) -> Result<(), PeerManagerError> {
        trace!("Received message from Peer {}", self.peer_id().short_str());
        // Read inbound message from stream.
        let message = message.freeze();
        let message: NetworkMessage = lcs::from_bytes(&message)?;
        match message {
            NetworkMessage::DirectSendMsg(_) => {
                let notif = PeerNotification::NewMessage(message);
                self.direct_send_notifs_tx
                    .send(notif)
                    .await
                    .map_err(|err| {
                        warn!(
                            "Failed to send notification to DirectSend actor. Error: {:?}",
                            err
                        );
                        err
                    })?;
            }
            NetworkMessage::Error(error) => {
                warn!(
                    "Peer {} sent an error message: {:?}",
                    self.peer_id().short_str(),
                    error,
                );
            }
            NetworkMessage::Ping(nonce) => {
                let pong = NetworkMessage::Pong(nonce);
                let (ack_tx, _) = oneshot::channel();
                // Resond to a ping right away.
                write_reqs_tx.send((pong, ack_tx)).await?;
            }
            NetworkMessage::Pong(_nonce) => {
                // TODO(davidiw) forward to a pong pub/sub and move HealthChecker to leverage this
            }
            NetworkMessage::RpcRequest(_) | NetworkMessage::RpcResponse(_) => {
                let notif = PeerNotification::NewMessage(message);
                self.rpc_notifs_tx.send(notif).await.map_err(|err| {
                    warn!("Failed to send notification to RPC actor. Error: {:?}", err);
                    err
                })?;
            }
        };
        Ok(())
    }

    async fn handle_request<'a>(
        &'a mut self,
        request: PeerRequest,
        mut write_reqs_tx: channel::Sender<(
            NetworkMessage,
            oneshot::Sender<Result<(), PeerManagerError>>,
        )>,
    ) {
        trace!(
            "Peer {} PeerRequest::{:?}",
            self.peer_id().short_str(),
            request
        );
        match request {
            PeerRequest::SendMessage(message, protocol, channel) => {
                if let Err(e) = write_reqs_tx.send((message, channel)).await {
                    error!(
                        "Failed to send message for protocol {} to peer: {}. Error: {:?}",
                        protocol,
                        self.peer_id().short_str(),
                        e
                    );
                }
            }
            PeerRequest::CloseConnection => {
                self.close_connection(DisconnectReason::Requested).await;
            }
        }
    }

    async fn close_connection(&mut self, reason: DisconnectReason) {
        // Set the state of the actor to `State::ShuttingDown` to true ensures that the peer actor
        // will terminate and close the connection.
        self.state = State::ShuttingDown(reason);
    }
}

pub struct PeerHandle {
    peer_id: PeerId,
    sender: channel::Sender<PeerRequest>,
}

impl Clone for PeerHandle {
    fn clone(&self) -> Self {
        Self {
            peer_id: self.peer_id,
            sender: self.sender.clone(),
        }
    }
}

impl PeerHandle {
    pub fn new(peer_id: PeerId, sender: channel::Sender<PeerRequest>) -> Self {
        Self { peer_id, sender }
    }

    pub fn peer_id(&self) -> PeerId {
        self.peer_id
    }

    pub async fn send_message(
        &mut self,
        message: NetworkMessage,
        protocol: ProtocolId,
    ) -> Result<(), PeerManagerError> {
        // If we fail to send the request to the Peer, then it must have already been shutdown.
        let (oneshot_tx, oneshot_rx) = oneshot::channel();
        if self
            .sender
            .send(PeerRequest::SendMessage(message, protocol, oneshot_tx))
            .await
            .is_err()
        {
            error!(
                "Sending message to Peer {} \
                 failed because it has already been shutdown.",
                self.peer_id.short_str()
            );
        }
        oneshot_rx
            .await
            // The send_message request can get dropped/canceled if the peer
            // connection is in the process of shutting down.
            .map_err(|_| PeerManagerError::NotConnected(self.peer_id))?
    }

    pub async fn disconnect(&mut self) {
        // If we fail to send the request to the Peer, then it must have already been shutdown.
        if self
            .sender
            .send(PeerRequest::CloseConnection)
            .await
            .is_err()
        {
            error!(
                "Sending CloseConnection request to Peer {} \
                 failed because it has already been shutdown.",
                self.peer_id.short_str()
            );
        }
    }
}
<|endoftext|>


<commit_before>use autograd::{Variable, VariableArgs, VarAccess};
use tensor::{NumLimits, Tensor};
use std::slice::{Iter, IterMut};
use torch;
use itertools::zip;

type Var64List = Vec<Variable<f64>>;

type Layer = fn(&Var64List) -> Var64List;
type PartialLayer = FnMut(&Var64List) -> Tensor<f64>;

pub fn contiguous(v: &Var64List) -> Var64List {
    v.iter().map(|v| v.contiguous()).collect()
}

pub fn get_numerical_jacobian(func: &mut PartialLayer,
                              input: &Var64List,
                              target: &Var64List,
                              eps: Option<f64>)
                              -> Vec<Tensor<f64>> {

    let eps = match eps {
        Some(e) => e,
        None => 1e-3,
    };
    let input_ = contiguous(input);
    let input = &input_;
    let output_size = func(input).numel();
    // XXX look at when this may not be a flat vector
    let jacobian: Vec<Tensor<f64>> = target
        .iter()
        .map(|v| ::torch::zeros([v.numel(), output_size]))
        .collect();

    let x_tensors: Vec<Tensor<f64>> = target
        .iter()
        .filter_map(|v| if v.requires_grad() {
                        Some(v.data_borrow().clone())
                    } else {
                        None
                    })
        .collect();
    let j_tensors = jacobian.clone();

    let mut outa = torch::double_tensor(output_size);
    let mut outb = torch::double_tensor(output_size);

    for (ref x_tensor_, ref mut d_tensor) in zip(x_tensors, j_tensors) {
        let x_tensor: &Tensor<f64> = x_tensor_;
        let mut flat_tensor = x_tensor.view([-1]);
        for i in 0..flat_tensor.numel() {
            let orig = flat_tensor[i];
            flat_tensor[i] = orig - eps;
            outa.copy_(&func(input));
            flat_tensor[i] = orig + eps;
            outb.copy_(&func(input));
            flat_tensor[i] = orig;

            outb.addt_(-1., &outa).div_(2. * eps);
            d_tensor.s([i as isize]).copy_(&outb);
        }
    }
    jacobian
}

pub fn zero_gradients(input: &mut Var64List) {
    for v in input {
        if let &mut Some(ref mut grad) = v.grad() {
            grad.detach_();
            grad.data().zero_();
        }
    }
}

pub fn iter_gradients(input: &mut Var64List) -> Vec<Option<Tensor<f64>>> {
    input
        .iter_mut()
        .map(|v| if v.requires_grad() {
                 if let &mut Some(ref mut grad) = v.grad() {
                     Some(grad.data().clone())
                 } else {
                     None
                 }
             } else {
                 None
             })
        .collect()
}

pub fn get_analytical_jacobian(input: &mut Var64List, output: &Variable<f64>) -> Vec<Tensor<f64>> {
    let mut jacobian: Vec<Tensor<f64>> = input
        .iter()
        .map(|v| ::torch::zeros([v.numel(), output.numel()]))
        .collect();
    let grad_output: Tensor<f64> = torch::zeros(output.data_borrow().size());
    let mut flat_grad_output = grad_output.view([-1]);

    for i in 0..flat_grad_output.numel() {
        flat_grad_output.zero_();
        flat_grad_output[i] = 1.;
        zero_gradients(input);
        for (ref mut jacobian_x, ref d_x_) in zip(jacobian.iter_mut(), iter_gradients(input)) {
            let d_x_: &Option<Tensor<f64>> = d_x_;
            if let &Some(ref d_x) = d_x_ {
                jacobian_x.s([-1, i as isize]).copy_(d_x);
            }

        }

    }
    jacobian
}

//
//       Check gradients computed via small finite differences
//       against analytical gradients
//
//    The check between numerical and analytical has the same behaviour as
//    numpy.allclose https://docs.scipy.org/doc/numpy/reference/generated/numpy.allclose.html
//    meaning it check that
//        absolute(a - n) <= (atol + rtol * absolute(n))
//    is true for all elements of analytical jacobian a and numerical jacobian n.
//
//    Args:
//        func: function that takes Vec<Variable> inputs and returns
//            a Vec<Variable>
//        inputs: Vec<Variable>
//        eps: perturbation for finite differences
//        atol: absolute tolerance
//        rtol: relative tolerance
//
//    Returns:
//        True if all differences satisfy allclose condition

pub fn gradcheck(func: Layer,
                 inputs: &mut Var64List,
                 eps: Option<f64>,
                 atol: Option<f64>,
                 rtol: Option<f64>)
                 -> bool {
    let eps = match eps {
        Some(e) => e,
        None => 1e-6,
    };
    let atol = match atol {
        Some(e) => e,
        None => 1e-5,
    };
    let rtol = match rtol {
        Some(e) => e,
        None => 1e-3,
    };
    let output = func(inputs);
    for (i, ref o) in output.iter().enumerate() {
        if !o.requires_grad() {
            continue;
        }
        let mut f = move |input: &Var64List| func(input)[i].data().clone();
        let analytical = get_analytical_jacobian(inputs, o);
        let numerical = get_numerical_jacobian(&mut f, inputs, inputs, Some(eps));
        for (ref a, ref n) in zip(analytical, numerical) {
            if !zip(a.sub(n).abs().iter(), n.abs().mul(rtol).add(atol).iter())
                    .all(|(a, b)| a <= b) {
                return false;
            }
        }
    }
    zero_gradients(inputs);
    let mut output = func(inputs);
    let args = VariableArgs::build().volatile(true).done();

    let grads = output
        .iter()
        .map(|o| Variable::new_args(o.data_borrow().new(o.size()).zero_(), &args))
        .collect();
    torch::autograd::backward(&mut output, &grads, None, None);
    true
}
<commit_msg>pass in grad check tolerances in struct, add gradgradcheck comment<commit_after>use autograd::{Variable, VariableArgs, VarAccess};
use tensor::{NumLimits, Tensor};
use std::slice::{Iter, IterMut};
use torch;
use itertools::zip;

type Var64List = Vec<Variable<f64>>;

type Layer = fn(&Var64List) -> Var64List;
type PartialLayer = FnMut(&Var64List) -> Tensor<f64>;

pub fn contiguous(v: &Var64List) -> Var64List {
    v.iter().map(|v| v.contiguous()).collect()
}

pub fn get_numerical_jacobian(func: &mut PartialLayer,
                              input: &Var64List,
                              target: &Var64List,
                              eps: Option<f64>)
                              -> Vec<Tensor<f64>> {

    let eps = match eps {
        Some(e) => e,
        None => 1e-3,
    };
    let input_ = contiguous(input);
    let input = &input_;
    let output_size = func(input).numel();
    // XXX look at when this may not be a flat vector
    let jacobian: Vec<Tensor<f64>> = target
        .iter()
        .map(|v| ::torch::zeros([v.numel(), output_size]))
        .collect();

    let x_tensors: Vec<Tensor<f64>> = target
        .iter()
        .filter_map(|v| if v.requires_grad() {
                        Some(v.data_borrow().clone())
                    } else {
                        None
                    })
        .collect();
    let j_tensors = jacobian.clone();

    let mut outa = torch::double_tensor(output_size);
    let mut outb = torch::double_tensor(output_size);

    for (ref x_tensor_, ref mut d_tensor) in zip(x_tensors, j_tensors) {
        let x_tensor: &Tensor<f64> = x_tensor_;
        let mut flat_tensor = x_tensor.view([-1]);
        for i in 0..flat_tensor.numel() {
            let orig = flat_tensor[i];
            flat_tensor[i] = orig - eps;
            outa.copy_(&func(input));
            flat_tensor[i] = orig + eps;
            outb.copy_(&func(input));
            flat_tensor[i] = orig;

            outb.addt_(-1., &outa).div_(2. * eps);
            d_tensor.s([i as isize]).copy_(&outb);
        }
    }
    jacobian
}

pub fn zero_gradients(input: &mut Var64List) {
    for v in input {
        if let &mut Some(ref mut grad) = v.grad() {
            grad.detach_();
            grad.data().zero_();
        }
    }
}

pub fn iter_gradients(input: &mut Var64List) -> Vec<Option<Tensor<f64>>> {
    input
        .iter_mut()
        .map(|v| if v.requires_grad() {
                 if let &mut Some(ref mut grad) = v.grad() {
                     Some(grad.data().clone())
                 } else {
                     None
                 }
             } else {
                 None
             })
        .collect()
}

pub fn get_analytical_jacobian(input: &mut Var64List, output: &Variable<f64>) -> Vec<Tensor<f64>> {
    let mut jacobian: Vec<Tensor<f64>> = input
        .iter()
        .map(|v| ::torch::zeros([v.numel(), output.numel()]))
        .collect();
    let grad_output: Tensor<f64> = torch::zeros(output.data_borrow().size());
    let mut flat_grad_output = grad_output.view([-1]);

    for i in 0..flat_grad_output.numel() {
        flat_grad_output.zero_();
        flat_grad_output[i] = 1.;
        zero_gradients(input);
        for (ref mut jacobian_x, ref d_x_) in zip(jacobian.iter_mut(), iter_gradients(input)) {
            let d_x_: &Option<Tensor<f64>> = d_x_;
            if let &Some(ref d_x) = d_x_ {
                jacobian_x.s([-1, i as isize]).copy_(d_x);
            }

        }

    }
    jacobian
}

#[derive(Debug, Clone, Default)]
pub struct GradValues {
    pub eps: Option<f64>,
    pub atol: Option<f64>,
    pub rtol: Option<f64>,
}

//
//       Check gradients computed via small finite differences
//       against analytical gradients
//
//    The check between numerical and analytical has the same behaviour as
//    numpy.allclose https://docs.scipy.org/doc/numpy/reference/generated/numpy.allclose.html
//    meaning it check that
//        absolute(a - n) <= (atol + rtol * absolute(n))
//    is true for all elements of analytical jacobian a and numerical jacobian n.
//
//    Args:
//        func: function that takes Vec<Variable> inputs and returns
//            a Vec<Variable>
//        inputs: Vec<Variable>
//        eps: perturbation for finite differences
//        atol: absolute tolerance
//        rtol: relative tolerance
//
//    Returns:
//        True if all differences satisfy allclose condition
pub fn gradcheck(func: Layer, inputs: &mut Var64List, values: GradValues) -> bool {
    let eps = match values.eps {
        Some(e) => e,
        None => 1e-6,
    };
    let atol = match values.atol {
        Some(e) => e,
        None => 1e-5,
    };
    let rtol = match values.rtol {
        Some(e) => e,
        None => 1e-3,
    };
    let output = func(inputs);
    for (i, ref o) in output.iter().enumerate() {
        if !o.requires_grad() {
            continue;
        }
        let mut f = move |input: &Var64List| func(input)[i].data().clone();
        let analytical = get_analytical_jacobian(inputs, o);
        let numerical = get_numerical_jacobian(&mut f, inputs, inputs, Some(eps));
        for (ref a, ref n) in zip(analytical, numerical) {
            if !zip(a.sub(n).abs().iter(), n.abs().mul(rtol).add(atol).iter())
                   .all(|(a, b)| a <= b) {
                return false;
            }
        }
    }
    zero_gradients(inputs);
    let mut output = func(inputs);
    let args = VariableArgs::build().volatile(true).done();

    let grads = output
        .iter()
        .map(|o| Variable::new_args(o.data_borrow().new(o.size()).zero_(), &args))
        .collect();
    torch::autograd::backward(&mut output, &grads, None, None);
    true
}

//       Check gradients of gradients computed via small finite differences
//       against analytical gradients
//    This function checks that backpropagating through the gradients computed
//    to the given grad_outputs are correct.
//
//    The check between numerical and analytical has the same behaviour as
//    numpy.allclose https://docs.scipy.org/doc/numpy/reference/generated/numpy.allclose.html
//    meaning it check that
//        absolute(a - n) <= (atol + rtol * absolute(n))
//    is true for all elements of analytical gradient a and numerical gradient n.
//
//    Args:
//        func: Python function that takes Variable inputs and returns
//            a tuple of Variables
//        inputs: tuple of Variables
//        grad_outputs: tuple of Variables
//        eps: perturbation for finite differences
//        atol: absolute tolerance
//        rtol: relative tolerance
//
//    Returns:
//        True if all differences satisfy allclose condition
/*
pub fn gradgradcheck(func: Layer,
                 inputs: &mut Var64List,
                 grad_outputs: &mut Var64List,
                 values: GradValues)
                 -> bool {
    let mut f = move |input: &Var64List| {
        let outputs = func(input);
        let inputs = inputs.iter().map(|v| )

                 }

*/
<|endoftext|>