<commit_before>// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use std::fmt;
use std::io;
use std::path::PathBuf;

use externalfiles::ExternalHtml;

#[derive(Clone)]
pub struct Layout {
    pub logo: String,
    pub favicon: String,
    pub external_html: ExternalHtml,
    pub krate: String,
}

pub struct Page<'a> {
    pub title: &'a str,
    pub css_class: &'a str,
    pub root_path: &'a str,
    pub description: &'a str,
    pub keywords: &'a str,
    pub resource_suffix: &'a str,
}

pub fn render<T: fmt::Display, S: fmt::Display>(
    dst: &mut dyn io::Write, layout: &Layout, page: &Page, sidebar: &S, t: &T,
    css_file_extension: bool, themes: &[PathBuf])
    -> io::Result<()>
{
    write!(dst,
"<!DOCTYPE html>\
\
\
    <meta charset=\"utf-8\">\
    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\
    <meta name=\"generator\" content=\"rustdoc\">\
    <meta name=\"description\" content=\"{description}\">\
    <meta name=\"keywords\" content=\"{keywords}\">\
    <title>{title}</title>\
    <link rel=\"stylesheet\" type=\"text/css\" href=\"{root_path}normalize{suffix}.css\">\
    <link rel=\"stylesheet\" type=\"text/css\" href=\"{root_path}rustdoc{suffix}.css\" \
          id=\"mainThemeStyle\">\
    {themes}\
    <link rel=\"stylesheet\" type=\"text/css\" href=\"{root_path}dark{suffix}.css\">\
    <link rel=\"stylesheet\" type=\"text/css\" href=\"{root_path}light{suffix}.css\" \
          id=\"themeStyle\">\
    \
    {css_extension}\
    {favicon}\
    {in_header}\
\
\
    \
    {before_content}\
    \

☰
\
        {logo}\
        {sidebar}\
    \

\
        <button id=\"theme-picker\" aria-label=\"Pick another theme!\">\
            \
        </button>\

\

\
    \
    \
        <form class=\"search-form js-only\">\

\
                <input class=\"search-input\" name=\"search\" \
                       autocomplete=\"off\" \
                       placeholder=\"Click or press ‘S’ to search, ‘?’ for more options…\" \
                       type=\"search\">\
                \
                    \
                \

\
        </form>\
    \

{content}
\

\

\
    \

\

Help
\

\

Keyboard Shortcuts
\

\

?
\

Show this help dialog
\

S
\

Focus the search field
\

↑
\

Move up in search results
\

↓
\

Move down in search results
\

↹
\

Switch tab
\

⏎
\

Go to active search result
\

+
\

Expand all sections
\

-
\

Collapse all sections
\

\

\

\

Search Tricks
\

\
                    Prefix searches with a type followed by a colon (e.g. \
                    fn:) to restrict the search to a given type.\

\

\
                    Accepted types are: fn, mod, \
                    struct, enum, \
                    trait, type, macro, \
                    and const.\

\

\
                    Search functions by type signature (e.g. \
                    vec -> usize or * -> vec)\

\

\
                    Search multiple things at once by splitting your query with comma (e.g. \
                    str,u8 or String,struct:Vec,test)\

\

\

\
    \
    {after_content}\
    \
    \
    \
    \
\
",
    css_extension = if css_file_extension {
        format!("<link rel=\"stylesheet\" type=\"text/css\" href=\"{root_path}theme{suffix}.css\">",
                root_path = page.root_path,
                suffix=page.resource_suffix)
    } else {
        String::new()
    },
    content   = *t,
    root_path = page.root_path,
    css_class = page.css_class,
    logo      = if layout.logo.is_empty() {
        String::new()
    } else {
        format!("\
                 ",
                page.root_path, layout.krate,
                layout.logo)
    },
    title     = page.title,
    description = page.description,
    keywords = page.keywords,
    favicon   = if layout.favicon.is_empty() {
        String::new()
    } else {
        format!(r#"<link rel="shortcut icon" href="{}">"#, layout.favicon)
    },
    in_header = layout.external_html.in_header,
    before_content = layout.external_html.before_content,
    after_content = layout.external_html.after_content,
    sidebar   = *sidebar,
    krate     = layout.krate,
    themes = themes.iter()
                   .filter_map(|t| t.file_stem())
                   .filter_map(|t| t.to_str())
                   .map(|t| format!(r#"<link rel="stylesheet" type="text/css" href="{}{}{}.css">"#,
                                    page.root_path,
                                    t,
                                    page.resource_suffix))
                   .collect::<String>(),
    suffix=page.resource_suffix,
    )
}

pub fn redirect(dst: &mut dyn io::Write, url: &str) -> io::Result<()> {
    //

"##,
    url = url,
    )
}
<commit_msg>[librustdoc] Disable spellcheck for search field<commit_after>// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use std::fmt;
use std::io;
use std::path::PathBuf;

use externalfiles::ExternalHtml;

#[derive(Clone)]
pub struct Layout {
    pub logo: String,
    pub favicon: String,
    pub external_html: ExternalHtml,
    pub krate: String,
}

pub struct Page<'a> {
    pub title: &'a str,
    pub css_class: &'a str,
    pub root_path: &'a str,
    pub description: &'a str,
    pub keywords: &'a str,
    pub resource_suffix: &'a str,
}

pub fn render<T: fmt::Display, S: fmt::Display>(
    dst: &mut dyn io::Write, layout: &Layout, page: &Page, sidebar: &S, t: &T,
    css_file_extension: bool, themes: &[PathBuf])
    -> io::Result<()>
{
    write!(dst,
"<!DOCTYPE html>\
\
\
    <meta charset=\"utf-8\">\
    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\
    <meta name=\"generator\" content=\"rustdoc\">\
    <meta name=\"description\" content=\"{description}\">\
    <meta name=\"keywords\" content=\"{keywords}\">\
    <title>{title}</title>\
    <link rel=\"stylesheet\" type=\"text/css\" href=\"{root_path}normalize{suffix}.css\">\
    <link rel=\"stylesheet\" type=\"text/css\" href=\"{root_path}rustdoc{suffix}.css\" \
          id=\"mainThemeStyle\">\
    {themes}\
    <link rel=\"stylesheet\" type=\"text/css\" href=\"{root_path}dark{suffix}.css\">\
    <link rel=\"stylesheet\" type=\"text/css\" href=\"{root_path}light{suffix}.css\" \
          id=\"themeStyle\">\
    \
    {css_extension}\
    {favicon}\
    {in_header}\
\
\
    \
    {before_content}\
    \

☰
\
        {logo}\
        {sidebar}\
    \

\
        <button id=\"theme-picker\" aria-label=\"Pick another theme!\">\
            \
        </button>\

\

\
    \
    \
        <form class=\"search-form js-only\">\

\
                <input class=\"search-input\" name=\"search\" \
                       autocomplete=\"off\" \
                       spellcheck=\"false\" \
                       placeholder=\"Click or press ‘S’ to search, ‘?’ for more options…\" \
                       type=\"search\">\
                \
                    \
                \

\
        </form>\
    \

{content}
\

\

\
    \

\

Help
\

\

Keyboard Shortcuts
\

\

?
\

Show this help dialog
\

S
\

Focus the search field
\

↑
\

Move up in search results
\

↓
\

Move down in search results
\

↹
\

Switch tab
\

⏎
\

Go to active search result
\

+
\

Expand all sections
\

-
\

Collapse all sections
\

\

\

\

Search Tricks
\

\
                    Prefix searches with a type followed by a colon (e.g. \
                    fn:) to restrict the search to a given type.\

\

\
                    Accepted types are: fn, mod, \
                    struct, enum, \
                    trait, type, macro, \
                    and const.\

\

\
                    Search functions by type signature (e.g. \
                    vec -> usize or * -> vec)\

\

\
                    Search multiple things at once by splitting your query with comma (e.g. \
                    str,u8 or String,struct:Vec,test)\

\

\

\
    \
    {after_content}\
    \
    \
    \
    \
\
",
    css_extension = if css_file_extension {
        format!("<link rel=\"stylesheet\" type=\"text/css\" href=\"{root_path}theme{suffix}.css\">",
                root_path = page.root_path,
                suffix=page.resource_suffix)
    } else {
        String::new()
    },
    content   = *t,
    root_path = page.root_path,
    css_class = page.css_class,
    logo      = if layout.logo.is_empty() {
        String::new()
    } else {
        format!("\
                 ",
                page.root_path, layout.krate,
                layout.logo)
    },
    title     = page.title,
    description = page.description,
    keywords = page.keywords,
    favicon   = if layout.favicon.is_empty() {
        String::new()
    } else {
        format!(r#"<link rel="shortcut icon" href="{}">"#, layout.favicon)
    },
    in_header = layout.external_html.in_header,
    before_content = layout.external_html.before_content,
    after_content = layout.external_html.after_content,
    sidebar   = *sidebar,
    krate     = layout.krate,
    themes = themes.iter()
                   .filter_map(|t| t.file_stem())
                   .filter_map(|t| t.to_str())
                   .map(|t| format!(r#"<link rel="stylesheet" type="text/css" href="{}{}{}.css">"#,
                                    page.root_path,
                                    t,
                                    page.resource_suffix))
                   .collect::<String>(),
    suffix=page.resource_suffix,
    )
}

pub fn redirect(dst: &mut dyn io::Write, url: &str) -> io::Result<()> {
    //

"##,
    url = url,
    )
}
<|endoftext|>


<commit_before>use crate::utils::{match_def_path, paths, span_lint_and_note};
use rustc_hir::def_id::DefId;
use rustc_hir::{AsyncGeneratorKind, Body, BodyId, GeneratorKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::GeneratorInteriorTypeCause;
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::Span;

declare_clippy_lint! {
    /// **What it does:** Checks for calls to await while holding a
    /// non-async-aware MutexGuard.
    ///
    /// **Why is this bad?** The Mutex types found in std::sync and parking_lot
    /// are not designed to operate in an async context across await points.
    ///
    /// There are two potential solutions. One is to use an asynx-aware Mutex
    /// type. Many asynchronous foundation crates provide such a Mutex type. The
    /// other solution is to ensure the mutex is unlocked before calling await,
    /// either by introducing a scope or an explicit call to Drop::drop.
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    ///
    /// ```rust,ignore
    /// use std::sync::Mutex;
    ///
    /// async fn foo(x: &Mutex<u32>) {
    ///   let guard = x.lock().unwrap();
    ///   *guard += 1;
    ///   bar.await;
    /// }
    /// ```
    ///
    /// Use instead:
    /// ```rust,ignore
    /// use std::sync::Mutex;
    ///
    /// async fn foo(x: &Mutex<u32>) {
    ///   {
    ///     let guard = x.lock().unwrap();
    ///     *guard += 1;
    ///   }
    ///   bar.await;
    /// }
    /// ```
    pub AWAIT_HOLDING_LOCK,
    correctness,
    "Inside an async function, holding a MutexGuard while calling await"
}

declare_clippy_lint! {
    /// **What it does:** Checks for calls to await while holding a
    /// `RefCell` `Ref` or `RefMut`.
    ///
    /// **Why is this bad?** `RefCell` refs only check for exclusive mutable access
    /// at runtime. Holding onto a `RefCell` ref across an `await` suspension point
    /// risks panics from a mutable ref shared while other refs are outstanding.
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    ///
    /// ```rust,ignore
    /// use std::cell::RefCell;
    ///
    /// async fn foo(x: &RefCell<u32>) {
    ///   let b = x.borrow_mut()();
    ///   *ref += 1;
    ///   bar.await;
    /// }
    /// ```
    ///
    /// Use instead:
    /// ```rust,ignore
    /// use std::cell::RefCell;
    ///
    /// async fn foo(x: &RefCell<u32>) {
    ///   {
    ///     let b = x.borrow_mut();
    ///     *ref += 1;
    ///   }
    ///   bar.await;
    /// }
    /// ```
    pub AWAIT_HOLDING_REFCELL_REF,
    correctness,
    "Inside an async function, holding a RefCell ref while calling await"
}

declare_lint_pass!(AwaitHolding => [AWAIT_HOLDING_LOCK, AWAIT_HOLDING_REFCELL_REF]);

impl LateLintPass<'_> for AwaitHolding {
    fn check_body(&mut self, cx: &LateContext<'_>, body: &'_ Body<'_>) {
        use AsyncGeneratorKind::{Block, Closure, Fn};
        if let Some(GeneratorKind::Async(Block | Closure | Fn)) = body.generator_kind {
            let body_id = BodyId {
                hir_id: body.value.hir_id,
            };
            let def_id = cx.tcx.hir().body_owner_def_id(body_id);
            let typeck_results = cx.tcx.typeck(def_id);
            check_interior_types(cx, &typeck_results.generator_interior_types, body.value.span);
        }
    }
}

fn check_interior_types(cx: &LateContext<'_>, ty_causes: &[GeneratorInteriorTypeCause<'_>], span: Span) {
    for ty_cause in ty_causes {
        if let rustc_middle::ty::Adt(adt, _) = ty_cause.ty.kind() {
            if is_mutex_guard(cx, adt.did) {
                span_lint_and_note(
                    cx,
                    AWAIT_HOLDING_LOCK,
                    ty_cause.span,
                    "this MutexGuard is held across an 'await' point. Consider using an async-aware Mutex type or ensuring the MutexGuard is dropped before calling await.",
                    ty_cause.scope_span.or(Some(span)),
                    "these are all the await points this lock is held through",
                );
            }
            if is_refcell_ref(cx, adt.did) {
                span_lint_and_note(
                        cx,
                        AWAIT_HOLDING_REFCELL_REF,
                        ty_cause.span,
                        "this RefCell Ref is held across an 'await' point. Consider ensuring the Ref is dropped before calling await.",
                        ty_cause.scope_span.or(Some(span)),
                        "these are all the await points this ref is held through",
                    );
            }
        }
    }
}

fn is_mutex_guard(cx: &LateContext<'_>, def_id: DefId) -> bool {
    match_def_path(cx, def_id, &paths::MUTEX_GUARD)
        || match_def_path(cx, def_id, &paths::RWLOCK_READ_GUARD)
        || match_def_path(cx, def_id, &paths::RWLOCK_WRITE_GUARD)
        || match_def_path(cx, def_id, &paths::PARKING_LOT_MUTEX_GUARD)
        || match_def_path(cx, def_id, &paths::PARKING_LOT_RWLOCK_READ_GUARD)
        || match_def_path(cx, def_id, &paths::PARKING_LOT_RWLOCK_WRITE_GUARD)
}

fn is_refcell_ref(cx: &LateContext<'_>, def_id: DefId) -> bool {
    match_def_path(cx, def_id, &paths::REFCELL_REF) || match_def_path(cx, def_id, &paths::REFCELL_REFMUT)
}
<commit_msg>Fix `await_holding_refcell_ref` examples for clarify<commit_after>use crate::utils::{match_def_path, paths, span_lint_and_note};
use rustc_hir::def_id::DefId;
use rustc_hir::{AsyncGeneratorKind, Body, BodyId, GeneratorKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::GeneratorInteriorTypeCause;
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::Span;

declare_clippy_lint! {
    /// **What it does:** Checks for calls to await while holding a
    /// non-async-aware MutexGuard.
    ///
    /// **Why is this bad?** The Mutex types found in std::sync and parking_lot
    /// are not designed to operate in an async context across await points.
    ///
    /// There are two potential solutions. One is to use an asynx-aware Mutex
    /// type. Many asynchronous foundation crates provide such a Mutex type. The
    /// other solution is to ensure the mutex is unlocked before calling await,
    /// either by introducing a scope or an explicit call to Drop::drop.
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    ///
    /// ```rust,ignore
    /// use std::sync::Mutex;
    ///
    /// async fn foo(x: &Mutex<u32>) {
    ///   let guard = x.lock().unwrap();
    ///   *guard += 1;
    ///   bar.await;
    /// }
    /// ```
    ///
    /// Use instead:
    /// ```rust,ignore
    /// use std::sync::Mutex;
    ///
    /// async fn foo(x: &Mutex<u32>) {
    ///   {
    ///     let guard = x.lock().unwrap();
    ///     *guard += 1;
    ///   }
    ///   bar.await;
    /// }
    /// ```
    pub AWAIT_HOLDING_LOCK,
    correctness,
    "Inside an async function, holding a MutexGuard while calling await"
}

declare_clippy_lint! {
    /// **What it does:** Checks for calls to await while holding a
    /// `RefCell` `Ref` or `RefMut`.
    ///
    /// **Why is this bad?** `RefCell` refs only check for exclusive mutable access
    /// at runtime. Holding onto a `RefCell` ref across an `await` suspension point
    /// risks panics from a mutable ref shared while other refs are outstanding.
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    ///
    /// ```rust,ignore
    /// use std::cell::RefCell;
    ///
    /// async fn foo(x: &RefCell<u32>) {
    ///   let mut y = x.borrow_mut();
    ///   *y += 1;
    ///   bar.await;
    /// }
    /// ```
    ///
    /// Use instead:
    /// ```rust,ignore
    /// use std::cell::RefCell;
    ///
    /// async fn foo(x: &RefCell<u32>) {
    ///   {
    ///      let mut y = x.borrow_mut();
    ///      *y += 1;
    ///   }
    ///   bar.await;
    /// }
    /// ```
    pub AWAIT_HOLDING_REFCELL_REF,
    correctness,
    "Inside an async function, holding a RefCell ref while calling await"
}

declare_lint_pass!(AwaitHolding => [AWAIT_HOLDING_LOCK, AWAIT_HOLDING_REFCELL_REF]);

impl LateLintPass<'_> for AwaitHolding {
    fn check_body(&mut self, cx: &LateContext<'_>, body: &'_ Body<'_>) {
        use AsyncGeneratorKind::{Block, Closure, Fn};
        if let Some(GeneratorKind::Async(Block | Closure | Fn)) = body.generator_kind {
            let body_id = BodyId {
                hir_id: body.value.hir_id,
            };
            let def_id = cx.tcx.hir().body_owner_def_id(body_id);
            let typeck_results = cx.tcx.typeck(def_id);
            check_interior_types(cx, &typeck_results.generator_interior_types, body.value.span);
        }
    }
}

fn check_interior_types(cx: &LateContext<'_>, ty_causes: &[GeneratorInteriorTypeCause<'_>], span: Span) {
    for ty_cause in ty_causes {
        if let rustc_middle::ty::Adt(adt, _) = ty_cause.ty.kind() {
            if is_mutex_guard(cx, adt.did) {
                span_lint_and_note(
                    cx,
                    AWAIT_HOLDING_LOCK,
                    ty_cause.span,
                    "this MutexGuard is held across an 'await' point. Consider using an async-aware Mutex type or ensuring the MutexGuard is dropped before calling await.",
                    ty_cause.scope_span.or(Some(span)),
                    "these are all the await points this lock is held through",
                );
            }
            if is_refcell_ref(cx, adt.did) {
                span_lint_and_note(
                        cx,
                        AWAIT_HOLDING_REFCELL_REF,
                        ty_cause.span,
                        "this RefCell Ref is held across an 'await' point. Consider ensuring the Ref is dropped before calling await.",
                        ty_cause.scope_span.or(Some(span)),
                        "these are all the await points this ref is held through",
                    );
            }
        }
    }
}

fn is_mutex_guard(cx: &LateContext<'_>, def_id: DefId) -> bool {
    match_def_path(cx, def_id, &paths::MUTEX_GUARD)
        || match_def_path(cx, def_id, &paths::RWLOCK_READ_GUARD)
        || match_def_path(cx, def_id, &paths::RWLOCK_WRITE_GUARD)
        || match_def_path(cx, def_id, &paths::PARKING_LOT_MUTEX_GUARD)
        || match_def_path(cx, def_id, &paths::PARKING_LOT_RWLOCK_READ_GUARD)
        || match_def_path(cx, def_id, &paths::PARKING_LOT_RWLOCK_WRITE_GUARD)
}

fn is_refcell_ref(cx: &LateContext<'_>, def_id: DefId) -> bool {
    match_def_path(cx, def_id, &paths::REFCELL_REF) || match_def_path(cx, def_id, &paths::REFCELL_REFMUT)
}
<|endoftext|>


<commit_before>//! Checks for useless borrowed references.
//!
//! This lint is **warn** by default

use rustc::lint::*;
use rustc::hir::{MutImmutable, Pat, PatKind, BindingAnnotation};
use rustc::ty;
use utils::{span_lint, in_macro};

/// **What it does:** Checks for useless borrowed references.
///
/// **Why is this bad?** It is completely useless and make the code look more
/// complex than it
/// actually is.
///
/// **Known problems:** None.
///
/// **Example:**
/// ```rust
///     let mut v = Vec::<String>::new();
///     let _ = v.iter_mut().filter(|&ref a| a.is_empty());
/// ```
/// This clojure takes a reference on something that has been matched as a
/// reference and
/// de-referenced.
/// As such, it could just be |a| a.is_empty()
declare_lint! {
    pub NEEDLESS_BORROWED_REFERENCE,
    Warn,
    "taking a needless borrowed reference"
}

#[derive(Copy, Clone)]
pub struct NeedlessBorrowedRef;

impl LintPass for NeedlessBorrowedRef {
    fn get_lints(&self) -> LintArray {
        lint_array!(NEEDLESS_BORROWED_REFERENCE)
    }
}

impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NeedlessBorrowedRef {
    fn check_pat(&mut self, cx: &LateContext<'a, 'tcx>, pat: &'tcx Pat) {
        if in_macro(pat.span) {
            // OK, simple enough, lints doesn't check in macro.
            return;
        }

        if_let_chain! {[
            // Pat is a pattern whose node
            // is a binding which "involves" an immutable reference...
            let PatKind::Binding(BindingAnnotation::Ref, ..) = pat.node,
            // Pattern's type is a reference. Get the type and mutability of referenced value (tam: TypeAndMut).
            let ty::TyRef(_, ref tam) = cx.tables.pat_ty(pat).sty,
            // Only lint immutable refs, because `&mut ref T` may be useful.
            tam.mutbl == MutImmutable,
        ], {
            span_lint(cx, NEEDLESS_BORROWED_REFERENCE, pat.span, "this pattern takes a reference on something that is being de-referenced")
        }}
    }
}
<commit_msg>Improve needless_borrowed_ref and add suggestion to it.<commit_after>//! Checks for useless borrowed references.
//!
//! This lint is **warn** by default

use rustc::lint::*;
<<<<<<< HEAD
use rustc::hir::{MutImmutable, Pat, PatKind, BindingAnnotation};
=======
use rustc::hir::{MutImmutable, Pat, PatKind};
>>>>>>> e30bf721... Improve needless_borrowed_ref and add suggestion to it.
use rustc::ty;
use utils::{span_lint_and_then, in_macro, snippet};
use syntax_pos::{Span, BytePos};

/// **What it does:** Checks for useless borrowed references.
///
/// **Why is this bad?** It is completely useless and make the code look more
/// complex than it
/// actually is.
///
/// **Known problems:** None.
///
/// **Example:**
/// ```rust
///     let mut v = Vec::<String>::new();
///     let _ = v.iter_mut().filter(|&ref a| a.is_empty());
/// ```
/// This clojure takes a reference on something that has been matched as a
/// reference and
/// de-referenced.
/// As such, it could just be |a| a.is_empty()
declare_lint! {
    pub NEEDLESS_BORROWED_REFERENCE,
    Warn,
    "taking a needless borrowed reference"
}

#[derive(Copy, Clone)]
pub struct NeedlessBorrowedRef;

impl LintPass for NeedlessBorrowedRef {
    fn get_lints(&self) -> LintArray {
        lint_array!(NEEDLESS_BORROWED_REFERENCE)
    }
}

impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NeedlessBorrowedRef {
    fn check_pat(&mut self, cx: &LateContext<'a, 'tcx>, pat: &'tcx Pat) {
        if in_macro(pat.span) {
            // OK, simple enough, lints doesn't check in macro.
            return;
        }

        if_let_chain! {[
            // Pat is a pattern whose node
            // is a binding which "involves" an immutable reference...
            let PatKind::Binding(BindingAnnotation::Ref, ..) = pat.node,
            // Pattern's type is a reference. Get the type and mutability of referenced value (tam: TypeAndMut).
            let ty::TyRef(_, ref tam) = cx.tables.pat_ty(pat).sty,
            // Only lint immutable refs, because `&mut ref T` may be useful.
            let PatKind::Ref(ref sub_pat, MutImmutable) = pat.node,

            // Check sub_pat got a 'ref' keyword.
            let ty::TyRef(_, _) = cx.tables.pat_ty(sub_pat).sty,
        ], {
            let part_to_keep = Span{ lo: pat.span.lo + BytePos(5), hi: pat.span.hi, ctxt: pat.span.ctxt };
            span_lint_and_then(cx, NEEDLESS_BORROWED_REFERENCE, pat.span,
                               "this pattern takes a reference on something that is being de-referenced",
                               |db| {
                                   let hint = snippet(cx, part_to_keep, "..").into_owned();
                                   db.span_suggestion(pat.span, "try removing the `&ref` part and just keep", hint);
                               });
        }}
    }
}
<|endoftext|>


<commit_before>use std::os;
use std::io::{self, fs, File};
use std::io::fs::PathExtensions;

use rustc_serialize::{Decodable, Decoder};

use git2::Config as GitConfig;

use util::{GitRepo, HgRepo, CargoResult, human, ChainError, internal};
use util::Config;

#[derive(Copy, Debug, PartialEq)]
pub enum VersionControl { Git, Hg, NoVcs }

pub struct NewOptions<'a> {
    pub version_control: Option<VersionControl>,
    pub bin: bool,
    pub path: &'a str,
}

impl Decodable for VersionControl {
    fn decode<D: Decoder>(d: &mut D) -> Result<VersionControl, D::Error> {
        Ok(match try!(d.read_str()).as_slice() {
            "git" => VersionControl::Git,
            "hg" => VersionControl::Hg,
            "none" => VersionControl::NoVcs,
            n => {
                let err = format!("could not decode '{}' as version control", n);
                return Err(d.error(err.as_slice()));
            }
        })
    }
}

struct CargoNewConfig {
    name: Option<String>,
    email: Option<String>,
    version_control: Option<VersionControl>,
}

pub fn new(opts: NewOptions, config: &Config) -> CargoResult<()> {
    let path = config.cwd().join(opts.path);
    if path.exists() {
        return Err(human(format!("Destination `{}` already exists",
                                 path.display())))
    }
    let name = path.filename_str().unwrap();
    for c in name.chars() {
        if c.is_alphanumeric() { continue }
        if c == '_' || c == '-' { continue }
        return Err(human(format!("Invalid character `{}` in crate name: `{}`",
                                 c, name).as_slice()));
    }
    mk(config, &path, name, &opts).chain_error(|| {
        human(format!("Failed to create project `{}` at `{}`",
                      name, path.display()))
    })
}

fn existing_vcs_repo(path: &Path) -> bool {
    GitRepo::discover(path).is_ok() || HgRepo::discover(path).is_ok()
}

fn mk(config: &Config, path: &Path, name: &str,
      opts: &NewOptions) -> CargoResult<()> {
    let cfg = try!(global_config(config));
    let mut ignore = "/target\n".to_string();
    let in_existing_vcs_repo = existing_vcs_repo(&path.dir_path());
    if !opts.bin {
        ignore.push_str("/Cargo.lock\n");
    }

    let vcs = match (opts.version_control, cfg.version_control, in_existing_vcs_repo) {
        (None, None, false) => VersionControl::Git,
        (None, Some(option), false) => option,
        (Some(option), _, false) => option,
        (_, _, true) => VersionControl::NoVcs,
    };

    match vcs {
        VersionControl::Git => {
            try!(GitRepo::init(path));
            try!(File::create(&path.join(".gitignore")).write(ignore.as_bytes()));
        },
        VersionControl::Hg => {
            try!(HgRepo::init(path));
            try!(File::create(&path.join(".hgignore")).write(ignore.as_bytes()));
        },
        VersionControl::NoVcs => {
            try!(fs::mkdir(path, io::USER_RWX));
        },
    };

    let (author_name, email) = try!(discover_author());
    // Hoo boy, sure glad we've got exhaustivenes checking behind us.
    let author = match (cfg.name, cfg.email, author_name, email) {
        (Some(name), Some(email), _, _) |
        (Some(name), None, _, Some(email)) |
        (None, Some(email), name, _) |
        (None, None, name, Some(email)) => format!("{} <{}>", name, email),
        (Some(name), None, _, None) |
        (None, None, name, None) => name,
    };

    try!(File::create(&path.join("Cargo.toml")).write_str(format!(
r#"[package]

name = "{}"
version = "0.0.1"
authors = ["{}"]
"#, name, author).as_slice()));

    try!(fs::mkdir(&path.join("src"), io::USER_RWX));

    if opts.bin {
        try!(File::create(&path.join("src/main.rs")).write_str("\
fn main() {
    println!(\"Hello, world!\");
}
"));
    } else {
        try!(File::create(&path.join("src/lib.rs")).write_str("\
#[test]
fn it_works() {
}
"));
    }

    Ok(())
}

fn discover_author() -> CargoResult<(String, Option<String>)> {
    let git_config = GitConfig::open_default().ok();
    let git_config = git_config.as_ref();
    let name = git_config.and_then(|g| g.get_str("user.name").ok())
                         .map(|s| s.to_string())
                         .or_else(|| os::getenv("USER"))      // unix
                         .or_else(|| os::getenv("USERNAME")); // windows
    let name = match name {
        Some(name) => name,
        None => {
            let username_var = if cfg!(windows) {"USERNAME"} else {"USER"};
            return Err(human(format!("could not determine the current \
                                      user, please set ${}", username_var)))
        }
    };
    let email = git_config.and_then(|g| g.get_str("user.email").ok());

    let name = name.as_slice().trim().to_string();
    let email = email.map(|s| s.as_slice().trim().to_string());

    Ok((name, email))
}

fn global_config(config: &Config) -> CargoResult<CargoNewConfig> {
    let name = try!(config.get_string("cargo-new.name")).map(|s| s.0);
    let email = try!(config.get_string("cargo-new.email")).map(|s| s.0);
    let vcs = try!(config.get_string("cargo-new.vcs"));

    let vcs = match vcs.as_ref().map(|p| (&p.0[], &p.1)) {
        Some(("git", _)) => Some(VersionControl::Git),
        Some(("hg", _)) => Some(VersionControl::Hg),
        Some(("none", _)) => Some(VersionControl::NoVcs),
        Some((s, p)) => {
            return Err(internal(format!("invalid configuration for key \
                                         `cargo-new.vcs`, unknown vcs `{}` \
                                         (found in {:?})", s, p)))
        }
        None => None
    };
    Ok(CargoNewConfig {
        name: name,
        email: email,
        version_control: vcs,
    })
}
<commit_msg>Auto merge of #1247 - tshepang:hgignore-love, r=alexcrichton<commit_after>use std::os;
use std::io::{self, fs, File};
use std::io::fs::PathExtensions;

use rustc_serialize::{Decodable, Decoder};

use git2::Config as GitConfig;

use util::{GitRepo, HgRepo, CargoResult, human, ChainError, internal};
use util::Config;

#[derive(Copy, Debug, PartialEq)]
pub enum VersionControl { Git, Hg, NoVcs }

pub struct NewOptions<'a> {
    pub version_control: Option<VersionControl>,
    pub bin: bool,
    pub path: &'a str,
}

impl Decodable for VersionControl {
    fn decode<D: Decoder>(d: &mut D) -> Result<VersionControl, D::Error> {
        Ok(match try!(d.read_str()).as_slice() {
            "git" => VersionControl::Git,
            "hg" => VersionControl::Hg,
            "none" => VersionControl::NoVcs,
            n => {
                let err = format!("could not decode '{}' as version control", n);
                return Err(d.error(err.as_slice()));
            }
        })
    }
}

struct CargoNewConfig {
    name: Option<String>,
    email: Option<String>,
    version_control: Option<VersionControl>,
}

pub fn new(opts: NewOptions, config: &Config) -> CargoResult<()> {
    let path = config.cwd().join(opts.path);
    if path.exists() {
        return Err(human(format!("Destination `{}` already exists",
                                 path.display())))
    }
    let name = path.filename_str().unwrap();
    for c in name.chars() {
        if c.is_alphanumeric() { continue }
        if c == '_' || c == '-' { continue }
        return Err(human(format!("Invalid character `{}` in crate name: `{}`",
                                 c, name).as_slice()));
    }
    mk(config, &path, name, &opts).chain_error(|| {
        human(format!("Failed to create project `{}` at `{}`",
                      name, path.display()))
    })
}

fn existing_vcs_repo(path: &Path) -> bool {
    GitRepo::discover(path).is_ok() || HgRepo::discover(path).is_ok()
}

fn mk(config: &Config, path: &Path, name: &str,
      opts: &NewOptions) -> CargoResult<()> {
    let cfg = try!(global_config(config));
    let mut ignore = "target\n".to_string();
    let in_existing_vcs_repo = existing_vcs_repo(&path.dir_path());
    if !opts.bin {
        ignore.push_str("Cargo.lock\n");
    }

    let vcs = match (opts.version_control, cfg.version_control, in_existing_vcs_repo) {
        (None, None, false) => VersionControl::Git,
        (None, Some(option), false) => option,
        (Some(option), _, false) => option,
        (_, _, true) => VersionControl::NoVcs,
    };

    match vcs {
        VersionControl::Git => {
            try!(GitRepo::init(path));
            try!(File::create(&path.join(".gitignore")).write(ignore.as_bytes()));
        },
        VersionControl::Hg => {
            try!(HgRepo::init(path));
            try!(File::create(&path.join(".hgignore")).write(ignore.as_bytes()));
        },
        VersionControl::NoVcs => {
            try!(fs::mkdir(path, io::USER_RWX));
        },
    };

    let (author_name, email) = try!(discover_author());
    // Hoo boy, sure glad we've got exhaustivenes checking behind us.
    let author = match (cfg.name, cfg.email, author_name, email) {
        (Some(name), Some(email), _, _) |
        (Some(name), None, _, Some(email)) |
        (None, Some(email), name, _) |
        (None, None, name, Some(email)) => format!("{} <{}>", name, email),
        (Some(name), None, _, None) |
        (None, None, name, None) => name,
    };

    try!(File::create(&path.join("Cargo.toml")).write_str(format!(
r#"[package]

name = "{}"
version = "0.0.1"
authors = ["{}"]
"#, name, author).as_slice()));

    try!(fs::mkdir(&path.join("src"), io::USER_RWX));

    if opts.bin {
        try!(File::create(&path.join("src/main.rs")).write_str("\
fn main() {
    println!(\"Hello, world!\");
}
"));
    } else {
        try!(File::create(&path.join("src/lib.rs")).write_str("\
#[test]
fn it_works() {
}
"));
    }

    Ok(())
}

fn discover_author() -> CargoResult<(String, Option<String>)> {
    let git_config = GitConfig::open_default().ok();
    let git_config = git_config.as_ref();
    let name = git_config.and_then(|g| g.get_str("user.name").ok())
                         .map(|s| s.to_string())
                         .or_else(|| os::getenv("USER"))      // unix
                         .or_else(|| os::getenv("USERNAME")); // windows
    let name = match name {
        Some(name) => name,
        None => {
            let username_var = if cfg!(windows) {"USERNAME"} else {"USER"};
            return Err(human(format!("could not determine the current \
                                      user, please set ${}", username_var)))
        }
    };
    let email = git_config.and_then(|g| g.get_str("user.email").ok());

    let name = name.as_slice().trim().to_string();
    let email = email.map(|s| s.as_slice().trim().to_string());

    Ok((name, email))
}

fn global_config(config: &Config) -> CargoResult<CargoNewConfig> {
    let name = try!(config.get_string("cargo-new.name")).map(|s| s.0);
    let email = try!(config.get_string("cargo-new.email")).map(|s| s.0);
    let vcs = try!(config.get_string("cargo-new.vcs"));

    let vcs = match vcs.as_ref().map(|p| (&p.0[], &p.1)) {
        Some(("git", _)) => Some(VersionControl::Git),
        Some(("hg", _)) => Some(VersionControl::Hg),
        Some(("none", _)) => Some(VersionControl::NoVcs),
        Some((s, p)) => {
            return Err(internal(format!("invalid configuration for key \
                                         `cargo-new.vcs`, unknown vcs `{}` \
                                         (found in {:?})", s, p)))
        }
        None => None
    };
    Ok(CargoNewConfig {
        name: name,
        email: email,
        version_control: vcs,
    })
}
<|endoftext|>


<commit_before>//! Messages to and from the server.
use std::borrow::ToOwned;
use std::io::{Result as IoResult};
use std::str::FromStr;
use client::data::Command;

/// IRC Message data.
#[derive(Clone, PartialEq, Debug)]
pub struct Message {
    /// Message tags as defined by [IRCv3.2](http://ircv3.net/specs/core/message-tags-3.2.html).
    pub tags: Option<Vec<Tag>>,
    /// The message prefix (or source) as defined by [RFC 2812](http://tools.ietf.org/html/rfc2812).
    pub prefix: Option<String>,
    /// The IRC command.
    pub command: Command,
}

impl Message {
    /// Creates a new Message.
    pub fn new(prefix: Option<&str>, command: &str, args: Vec<&str>, suffix: Option<&str>)
        -> IoResult<Message> {
        Message::with_tags(None, prefix, command, args, suffix)
    }

    /// Creates a new Message optionally including IRCv3.2 message tags.
    pub fn with_tags(tags: Option<Vec<Tag>>, prefix: Option<&str>, command: &str,
                     args: Vec<&str>, suffix: Option<&str>) -> IoResult<Message> {
        Ok(Message {
            tags: tags,
            prefix: prefix.map(|s| s.to_owned()),
            command: try!(Command::new(command, args, suffix)),
        })
    }

    /// Gets the nickname of the message source, if it exists.
    pub fn source_nickname(&self) -> Option<&str> {
        // <prefix> ::= <servername> | <nick> [ '!' <user> ] [ '@' <host> ]
        // <servername> ::= <host>
        self.prefix.as_ref().and_then(|s|
            match (s.find('!'), s.find('@'), s.find('.')) {
                (Some(i), _, _) => Some(&s[..i]), // nick!user
                (None, Some(i), _) => Some(&s[..i]), // nick@host
                (None, None, None) => Some(&s), // nick
                _ => None // server.name
            }
        )
    }

    /// Converts a Message into a String according to the IRC protocol.
    pub fn into_string(&self) -> String {
        // TODO: tags
        let mut ret = String::new();
        if let Some(ref prefix) = self.prefix {
            ret.push(':');
            ret.push_str(&prefix);
            ret.push(' ');
        }
        let cmd: String = From::from(&self.command);
        ret.push_str(&cmd);
        ret.push_str("\r\n");
        ret
    }
}

impl From<Command> for Message {
    fn from(cmd: Command) -> Message {
        Message { tags: None, prefix: None, command: cmd }
    }
}

impl FromStr for Message {
    type Err = &'static str;
    fn from_str(s: &str) -> Result<Message, &'static str> {
        let mut state = s.clone();
        if s.len() == 0 { return Err("Cannot parse an empty string as a message.") }
        let tags = if state.starts_with("@") {
            let tags = state.find(' ').map(|i| &state[1..i]);
            state = state.find(' ').map_or("", |i| &state[i+1..]);
            tags.map(|ts| ts.split(";").filter(|s| s.len() != 0).map(|s: &str| {
                let mut iter = s.splitn(2, "=");
                let (fst, snd) = (iter.next(), iter.next());
                Tag(fst.unwrap_or("").to_owned(), snd.map(|s| s.to_owned()))
            }).collect::<Vec<_>>())
        } else {
            None
        };
        let prefix = if state.starts_with(":") {
            let prefix = state.find(' ').map(|i| &state[1..i]);
            state = state.find(' ').map_or("", |i| &state[i+1..]);
            prefix
        } else {
            None
        };
        let suffix = if state.contains(" :") {
            let suffix = state.find(" :").map(|i| &state[i+2..state.len()-2]);
            state = state.find(" :").map_or("", |i| &state[..i+1]);
            suffix
        } else {
            None
        };
        let command = match state.find(' ').map(|i| &state[..i]) {
            Some(cmd) => {
                state = state.find(' ').map_or("", |i| &state[i+1..]);
                cmd
            }
            _ => return Err("Cannot parse a message without a command.")
        };
        if suffix.is_none() { state = &state[..state.len() - 2] }
        let args: Vec<_> = state.splitn(14, ' ').filter(|s| s.len() != 0).collect();
        Message::with_tags(
            tags, prefix, command, args, suffix
        ).map_err(|_| "Invalid input for Command.")
    }
}

impl<'a> From<&'a str> for Message {
    fn from(s: &'a str) -> Message {
        s.parse().unwrap()
    }
}

/// A message tag as defined by [IRCv3.2](http://ircv3.net/specs/core/message-tags-3.2.html).
#[derive(Clone, PartialEq, Debug)]
pub struct Tag(String, Option<String>);

#[cfg(test)]
mod test {
    use super::{Message, Tag};
    use client::data::Command::{PRIVMSG, Raw};

    #[test]
    fn new() {
        let message = Message {
            tags: None,
            prefix: None,
            command: PRIVMSG(format!("test"), format!("Testing!")),
        };
        assert_eq!(Message::new(None, "PRIVMSG", vec!["test"], Some("Testing!")).unwrap(), message)
    }

    #[test]
    fn source_nickname() {
        assert_eq!(Message::new(
            None, "PING", vec![], Some("data")
        ).unwrap().source_nickname(), None);

        assert_eq!(Message::new(
            Some("irc.test.net"), "PING", vec![], Some("data")
        ).unwrap().source_nickname(), None);

        assert_eq!(Message::new(
            Some("test!test@test"), "PING", vec![], Some("data")
        ).unwrap().source_nickname(), Some("test"));

        assert_eq!(Message::new(
            Some("test@test"), "PING", vec![], Some("data")
        ).unwrap().source_nickname(), Some("test"));

        assert_eq!(Message::new(
            Some("test!test@awe.did.you.know.irc.hostnames.have.dots"), "PING", vec![], Some("data")
        ).unwrap().source_nickname(), Some("test"));

        assert_eq!(Message::new(
            Some("test!test@127.0.0.1"), "PING", vec![], Some("data")
        ).unwrap().source_nickname(), Some("test"));

        assert_eq!(Message::new(
            Some("test@test.com"), "PING", vec![], Some("data")
        ).unwrap().source_nickname(), Some("test"));

        assert_eq!(Message::new(
            Some("test"), "PING", vec![], Some("data")
        ).unwrap().source_nickname(), Some("test"));
    }

    #[test]
    fn into_string() {
        let message = Message {
            tags: None,
            prefix: None,
            command: PRIVMSG(format!("test"), format!("Testing!")),
        };
        assert_eq!(&message.into_string()[..], "PRIVMSG test :Testing!\r\n");
        let message = Message {
            tags: None,
            prefix: Some(format!("test!test@test")),
            command: PRIVMSG(format!("test"), format!("Still testing!")),
        };
        assert_eq!(&message.into_string()[..], ":test!test@test PRIVMSG test :Still testing!\r\n");
    }

    #[test]
    fn from_string() {
        let message = Message {
            tags: None,
            prefix: None,
            command: PRIVMSG(format!("test"), format!("Testing!")),
        };
        assert_eq!("PRIVMSG test :Testing!\r\n".parse(), Ok(message));
        let message = Message {
            tags: None,
            prefix: Some(format!("test!test@test")),
            command: PRIVMSG(format!("test"), format!("Still testing!")),
        };
        assert_eq!(":test!test@test PRIVMSG test :Still testing!\r\n".parse(), Ok(message));
        let message = Message {
            tags: Some(vec![Tag(format!("aaa"), Some(format!("bbb"))),
                            Tag(format!("ccc"), None),
                            Tag(format!("example.com/ddd"), Some(format!("eee")))]),
            prefix: Some(format!("test!test@test")),
            command: PRIVMSG(format!("test"), format!("Testing with tags!")),
        };
        assert_eq!("@aaa=bbb;ccc;example.com/ddd=eee :test!test@test PRIVMSG test :Testing with \
                    tags!\r\n".parse(), Ok(message))
    }

    #[test]
    fn to_message() {
        let message = Message {
            tags: None,
            prefix: None,
            command: PRIVMSG(format!("test"), format!("Testing!")),
        };
        let msg: Message = "PRIVMSG test :Testing!\r\n".into();
        assert_eq!(msg, message);
        let message = Message {
            tags: None,
            prefix: Some(format!("test!test@test")),
            command: PRIVMSG(format!("test"), format!("Still testing!")),
        };
        let msg: Message = ":test!test@test PRIVMSG test :Still testing!\r\n".into();
        assert_eq!(msg, message);
    }

    #[test]
    fn to_message_with_colon_in_arg() {
        // Apparently, UnrealIRCd (and perhaps some others) send some messages that include
        // colons within individual parameters. So, let's make sure it parses correctly.
        let message = Message {
            tags: None,
            prefix: Some(format!("test!test@test")),
            command: Raw(
                format!("COMMAND"), vec![format!("ARG:test")], Some(format!("Testing!"))
            ),
        };
        let msg: Message = ":test!test@test COMMAND ARG:test :Testing!\r\n".into();
        assert_eq!(msg, message);
    }

    #[test]
    #[should_panic]
    fn to_message_invalid_format() {
        let _: Message = ":invalid :message".into();
    }
}
<commit_msg>Cleaned up new comments on source_nickname.<commit_after>//! Messages to and from the server.
use std::borrow::ToOwned;
use std::io::{Result as IoResult};
use std::str::FromStr;
use client::data::Command;

/// IRC Message data.
#[derive(Clone, PartialEq, Debug)]
pub struct Message {
    /// Message tags as defined by [IRCv3.2](http://ircv3.net/specs/core/message-tags-3.2.html).
    pub tags: Option<Vec<Tag>>,
    /// The message prefix (or source) as defined by [RFC 2812](http://tools.ietf.org/html/rfc2812).
    pub prefix: Option<String>,
    /// The IRC command.
    pub command: Command,
}

impl Message {
    /// Creates a new Message.
    pub fn new(prefix: Option<&str>, command: &str, args: Vec<&str>, suffix: Option<&str>)
        -> IoResult<Message> {
        Message::with_tags(None, prefix, command, args, suffix)
    }

    /// Creates a new Message optionally including IRCv3.2 message tags.
    pub fn with_tags(tags: Option<Vec<Tag>>, prefix: Option<&str>, command: &str,
                     args: Vec<&str>, suffix: Option<&str>) -> IoResult<Message> {
        Ok(Message {
            tags: tags,
            prefix: prefix.map(|s| s.to_owned()),
            command: try!(Command::new(command, args, suffix)),
        })
    }

    /// Gets the nickname of the message source, if it exists.
    pub fn source_nickname(&self) -> Option<&str> {
        // <prefix> ::= <servername> | <nick> [ '!' <user> ] [ '@' <host> ]
        // <servername> ::= <host>
        self.prefix.as_ref().and_then(|s|
            match (s.find('!'), s.find('@'), s.find('.')) {
                (Some(i), _, _) => Some(&s[..i]), // <nick> '!' <user> [ '@' <host> ]
                (None, Some(i), _) => Some(&s[..i]), // <nick> '@' <host>
                (None, None, None) => Some(&s), // <nick>
                _ => None // <servername>
            }
        )
    }

    /// Converts a Message into a String according to the IRC protocol.
    pub fn into_string(&self) -> String {
        // TODO: tags
        let mut ret = String::new();
        if let Some(ref prefix) = self.prefix {
            ret.push(':');
            ret.push_str(&prefix);
            ret.push(' ');
        }
        let cmd: String = From::from(&self.command);
        ret.push_str(&cmd);
        ret.push_str("\r\n");
        ret
    }
}

impl From<Command> for Message {
    fn from(cmd: Command) -> Message {
        Message { tags: None, prefix: None, command: cmd }
    }
}

impl FromStr for Message {
    type Err = &'static str;
    fn from_str(s: &str) -> Result<Message, &'static str> {
        let mut state = s.clone();
        if s.len() == 0 { return Err("Cannot parse an empty string as a message.") }
        let tags = if state.starts_with("@") {
            let tags = state.find(' ').map(|i| &state[1..i]);
            state = state.find(' ').map_or("", |i| &state[i+1..]);
            tags.map(|ts| ts.split(";").filter(|s| s.len() != 0).map(|s: &str| {
                let mut iter = s.splitn(2, "=");
                let (fst, snd) = (iter.next(), iter.next());
                Tag(fst.unwrap_or("").to_owned(), snd.map(|s| s.to_owned()))
            }).collect::<Vec<_>>())
        } else {
            None
        };
        let prefix = if state.starts_with(":") {
            let prefix = state.find(' ').map(|i| &state[1..i]);
            state = state.find(' ').map_or("", |i| &state[i+1..]);
            prefix
        } else {
            None
        };
        let suffix = if state.contains(" :") {
            let suffix = state.find(" :").map(|i| &state[i+2..state.len()-2]);
            state = state.find(" :").map_or("", |i| &state[..i+1]);
            suffix
        } else {
            None
        };
        let command = match state.find(' ').map(|i| &state[..i]) {
            Some(cmd) => {
                state = state.find(' ').map_or("", |i| &state[i+1..]);
                cmd
            }
            _ => return Err("Cannot parse a message without a command.")
        };
        if suffix.is_none() { state = &state[..state.len() - 2] }
        let args: Vec<_> = state.splitn(14, ' ').filter(|s| s.len() != 0).collect();
        Message::with_tags(
            tags, prefix, command, args, suffix
        ).map_err(|_| "Invalid input for Command.")
    }
}

impl<'a> From<&'a str> for Message {
    fn from(s: &'a str) -> Message {
        s.parse().unwrap()
    }
}

/// A message tag as defined by [IRCv3.2](http://ircv3.net/specs/core/message-tags-3.2.html).
#[derive(Clone, PartialEq, Debug)]
pub struct Tag(String, Option<String>);

#[cfg(test)]
mod test {
    use super::{Message, Tag};
    use client::data::Command::{PRIVMSG, Raw};

    #[test]
    fn new() {
        let message = Message {
            tags: None,
            prefix: None,
            command: PRIVMSG(format!("test"), format!("Testing!")),
        };
        assert_eq!(Message::new(None, "PRIVMSG", vec!["test"], Some("Testing!")).unwrap(), message)
    }

    #[test]
    fn source_nickname() {
        assert_eq!(Message::new(
            None, "PING", vec![], Some("data")
        ).unwrap().source_nickname(), None);

        assert_eq!(Message::new(
            Some("irc.test.net"), "PING", vec![], Some("data")
        ).unwrap().source_nickname(), None);

        assert_eq!(Message::new(
            Some("test!test@test"), "PING", vec![], Some("data")
        ).unwrap().source_nickname(), Some("test"));

        assert_eq!(Message::new(
            Some("test@test"), "PING", vec![], Some("data")
        ).unwrap().source_nickname(), Some("test"));

        assert_eq!(Message::new(
            Some("test!test@irc.test.com"), "PING", vec![], Some("data")
        ).unwrap().source_nickname(), Some("test"));

        assert_eq!(Message::new(
            Some("test!test@127.0.0.1"), "PING", vec![], Some("data")
        ).unwrap().source_nickname(), Some("test"));

        assert_eq!(Message::new(
            Some("test@test.com"), "PING", vec![], Some("data")
        ).unwrap().source_nickname(), Some("test"));

        assert_eq!(Message::new(
            Some("test"), "PING", vec![], Some("data")
        ).unwrap().source_nickname(), Some("test"));
    }

    #[test]
    fn into_string() {
        let message = Message {
            tags: None,
            prefix: None,
            command: PRIVMSG(format!("test"), format!("Testing!")),
        };
        assert_eq!(&message.into_string()[..], "PRIVMSG test :Testing!\r\n");
        let message = Message {
            tags: None,
            prefix: Some(format!("test!test@test")),
            command: PRIVMSG(format!("test"), format!("Still testing!")),
        };
        assert_eq!(&message.into_string()[..], ":test!test@test PRIVMSG test :Still testing!\r\n");
    }

    #[test]
    fn from_string() {
        let message = Message {
            tags: None,
            prefix: None,
            command: PRIVMSG(format!("test"), format!("Testing!")),
        };
        assert_eq!("PRIVMSG test :Testing!\r\n".parse(), Ok(message));
        let message = Message {
            tags: None,
            prefix: Some(format!("test!test@test")),
            command: PRIVMSG(format!("test"), format!("Still testing!")),
        };
        assert_eq!(":test!test@test PRIVMSG test :Still testing!\r\n".parse(), Ok(message));
        let message = Message {
            tags: Some(vec![Tag(format!("aaa"), Some(format!("bbb"))),
                            Tag(format!("ccc"), None),
                            Tag(format!("example.com/ddd"), Some(format!("eee")))]),
            prefix: Some(format!("test!test@test")),
            command: PRIVMSG(format!("test"), format!("Testing with tags!")),
        };
        assert_eq!("@aaa=bbb;ccc;example.com/ddd=eee :test!test@test PRIVMSG test :Testing with \
                    tags!\r\n".parse(), Ok(message))
    }

    #[test]
    fn to_message() {
        let message = Message {
            tags: None,
            prefix: None,
            command: PRIVMSG(format!("test"), format!("Testing!")),
        };
        let msg: Message = "PRIVMSG test :Testing!\r\n".into();
        assert_eq!(msg, message);
        let message = Message {
            tags: None,
            prefix: Some(format!("test!test@test")),
            command: PRIVMSG(format!("test"), format!("Still testing!")),
        };
        let msg: Message = ":test!test@test PRIVMSG test :Still testing!\r\n".into();
        assert_eq!(msg, message);
    }

    #[test]
    fn to_message_with_colon_in_arg() {
        // Apparently, UnrealIRCd (and perhaps some others) send some messages that include
        // colons within individual parameters. So, let's make sure it parses correctly.
        let message = Message {
            tags: None,
            prefix: Some(format!("test!test@test")),
            command: Raw(
                format!("COMMAND"), vec![format!("ARG:test")], Some(format!("Testing!"))
            ),
        };
        let msg: Message = ":test!test@test COMMAND ARG:test :Testing!\r\n".into();
        assert_eq!(msg, message);
    }

    #[test]
    #[should_panic]
    fn to_message_invalid_format() {
        let _: Message = ":invalid :message".into();
    }
}
<|endoftext|>


<commit_before>extern crate saddle_points;

use saddle_points::find_saddle_points;

// We don't care about order
fn find_sorted_saddle_points(input: &[Vec<u64>]) -> Vec<(usize, usize)> {
    let mut result = saddle_points::find_saddle_points(input);
    result.sort();
    result
}

#[test]
fn identify_single_saddle_point() {
    let input = vec![
        vec![9, 8, 7],
        vec![5, 3, 2],
        vec![6, 6, 7],
    ];
    assert_eq!(vec![(1, 0)], find_saddle_points(&input));
}

#[test]
#[ignore]
fn identify_empty_matrix() {
    let input = vec![vec![], vec![], vec![]];
    let expected: Vec<(usize, usize)> = Vec::new();
    assert_eq!(expected, find_saddle_points(&input));
}

#[test]
#[ignore]
fn identify_lack_of_saddle_point() {
    let input = vec![
        vec![1, 2, 3],
        vec![3, 1, 2],
        vec![2, 3, 1],
    ];
    let expected: Vec<(usize, usize)> = Vec::new();
    assert_eq!(expected, find_saddle_points(&input));
}

#[test]
#[ignore]
fn multiple_saddle_points_in_col() {
    let input = vec![
        vec![4, 5, 4],
        vec![3, 5, 5],
        vec![1, 5, 4],
    ];
    assert_eq!(
        vec![(0, 1), (1, 1), (2, 1)],
        find_sorted_saddle_points(&input)
    );
}

#[test]
#[ignore]
fn multiple_saddle_points_in_row() {
    let input = vec![
        vec![6, 7, 8],
        vec![5, 5, 5],
        vec![7, 5, 6],
    ];
    assert_eq!(
        vec![(1, 0), (1, 1), (1, 2)],
        find_sorted_saddle_points(&input)
    );
}

#[test]
#[ignore]
fn identify_bottom_right_saddle_point() {
    let input = vec![
        vec![8, 7, 9],
        vec![6, 7, 6],
        vec![3, 2, 5],
    ];
    assert_eq!(vec![(2, 2)], find_saddle_points(&input));
}

// track specific as of v1.3
#[test]
#[ignore]
fn non_square_matrix_high() {
    let input = vec![
        vec![1, 5],
        vec![3, 6],
        vec![2, 7],
        vec![3, 8],
    ];
    assert_eq!(vec![(0, 1)], find_saddle_points(&input));
}

#[test]
#[ignore]
fn non_square_matrix_wide() {
    let input = vec![
        vec![3, 1, 3],
        vec![3, 2, 4]
    ];
    assert_eq!(vec![(0, 0), (0, 2)], find_sorted_saddle_points(&input));
}

#[test]
#[ignore]
fn single_column_matrix() {
    let input = vec![
        vec![2],
        vec![1],
        vec![4],
        vec![1],
    ];
    assert_eq!(vec![(1, 0), (3, 0)], find_saddle_points(&input));
}

#[test]
#[ignore]
fn single_row_matrix() {
    let input = vec![
        vec![2, 5, 3, 5],
    ];
    assert_eq!(vec![(0, 1), (0, 3)], find_saddle_points(&input));
}

<commit_msg>saddle-points: Add test for all saddle points (#724)<commit_after>extern crate saddle_points;

use saddle_points::find_saddle_points;

// We don't care about order
fn find_sorted_saddle_points(input: &[Vec<u64>]) -> Vec<(usize, usize)> {
    let mut result = saddle_points::find_saddle_points(input);
    result.sort();
    result
}

#[test]
fn identify_single_saddle_point() {
    let input = vec![
        vec![9, 8, 7],
        vec![5, 3, 2],
        vec![6, 6, 7],
    ];
    assert_eq!(vec![(1, 0)], find_saddle_points(&input));
}

#[test]
#[ignore]
fn identify_empty_matrix() {
    let input = vec![vec![], vec![], vec![]];
    let expected: Vec<(usize, usize)> = Vec::new();
    assert_eq!(expected, find_saddle_points(&input));
}

#[test]
#[ignore]
fn identify_lack_of_saddle_point() {
    let input = vec![
        vec![1, 2, 3],
        vec![3, 1, 2],
        vec![2, 3, 1],
    ];
    let expected: Vec<(usize, usize)> = Vec::new();
    assert_eq!(expected, find_saddle_points(&input));
}

#[test]
#[ignore]
fn multiple_saddle_points_in_col() {
    let input = vec![
        vec![4, 5, 4],
        vec![3, 5, 5],
        vec![1, 5, 4],
    ];
    assert_eq!(
        vec![(0, 1), (1, 1), (2, 1)],
        find_sorted_saddle_points(&input)
    );
}

#[test]
#[ignore]
fn multiple_saddle_points_in_row() {
    let input = vec![
        vec![6, 7, 8],
        vec![5, 5, 5],
        vec![7, 5, 6],
    ];
    assert_eq!(
        vec![(1, 0), (1, 1), (1, 2)],
        find_sorted_saddle_points(&input)
    );
}

#[test]
#[ignore]
fn identify_bottom_right_saddle_point() {
    let input = vec![
        vec![8, 7, 9],
        vec![6, 7, 6],
        vec![3, 2, 5],
    ];
    assert_eq!(vec![(2, 2)], find_saddle_points(&input));
}

// track specific as of v1.3
#[test]
#[ignore]
fn non_square_matrix_high() {
    let input = vec![
        vec![1, 5],
        vec![3, 6],
        vec![2, 7],
        vec![3, 8],
    ];
    assert_eq!(vec![(0, 1)], find_saddle_points(&input));
}

#[test]
#[ignore]
fn non_square_matrix_wide() {
    let input = vec![
        vec![3, 1, 3],
        vec![3, 2, 4]
    ];
    assert_eq!(vec![(0, 0), (0, 2)], find_sorted_saddle_points(&input));
}

#[test]
#[ignore]
fn single_column_matrix() {
    let input = vec![
        vec![2],
        vec![1],
        vec![4],
        vec![1],
    ];
    assert_eq!(vec![(1, 0), (3, 0)], find_saddle_points(&input));
}

#[test]
#[ignore]
fn single_row_matrix() {
    let input = vec![
        vec![2, 5, 3, 5],
    ];
    assert_eq!(vec![(0, 1), (0, 3)], find_saddle_points(&input));
}

#[test]
#[ignore]
fn identify_all_saddle_points() {
    let input = vec![
        vec![5, 5, 5],
        vec![5, 5, 5],
        vec![5, 5, 5],
    ];
    assert_eq!(vec![(0, 0), (0, 1), (0, 2), (1, 0), (1, 1), (1, 2), (2, 0), (2, 1), (2, 2)], find_saddle_points(&input));
}

<|endoftext|>


<commit_before>use std::any::Any;
use std::env;
use std::fs;
use std::path::PathBuf;

use parking_lot::RwLock;

use std::rc::Rc;

use super::Mode;

use crate::core::editor::register_input_stage_action;
use crate::core::editor::InputStageActionMap;
use crate::core::Editor;
use crate::core::EditorEnv;

use crate::core::event::*;

use crate::core::event::input_map::build_input_event_map;

use crate::core::view;
use crate::core::view::View;

use crate::core::view::ViewEvent;
use crate::core::view::ViewEventDestination;
use crate::core::view::ViewEventSource;

use crate::core::view::ControllerView;

static OPEN_DOC_TRIGGER_MAP: &str = r#"
[
  {
    "events": [
     { "in": [{ "key": "ctrl+o" } ],    "action": "open-doc:start" }
    ]
  }
]"#;

static OPEN_DOC_INTERACTIVE_MAP: &str = r#"
[
  {
    "events": [
     { "in": [{ "key": "Escape" } ],    "action": "open-doc:stop" },
     { "in": [{ "key": "\n" } ],        "action": "open-doc:stop" },
     { "in": [{ "key": "BackSpace" } ], "action": "open-doc:del-char" },
     { "in": [{ "key": "Delete" } ],    "action": "open-doc:do-nothing" },
     { "default": [],                   "action": "open-doc:add-char" }
   ]
  }

]"#;

impl<'a> Mode for OpenDocMode {
    fn name(&self) -> &'static str {
        &"open-doc-mode"
    }

    fn build_action_map(&self) -> InputStageActionMap<'static> {
        let mut map = InputStageActionMap::new();
        Self::register_input_stage_actions(&mut map);
        map
    }

    fn alloc_ctx(&self) -> Box<dyn Any> {
        dbg_println!("alloc open-doc-mode ctx");
        let ctx = OpenDocModeContext::new();
        Box::new(ctx)
    }

    fn configure_view(
        &mut self,
        _editor: &mut Editor<'static>,
        _env: &mut EditorEnv<'static>,
        view: &mut View<'static>,
    ) {
        dbg_println!("configure find  {:?}", view.id);

        // setup input map for core actions
        let input_map = build_input_event_map(OPEN_DOC_TRIGGER_MAP).unwrap();
        let mut input_map_stack = view.input_ctx.input_map.as_ref().borrow_mut();
        input_map_stack.push((self.name(), input_map));
    }

    fn on_view_event(
        &self,
        editor: &mut Editor<'static>,
        env: &mut EditorEnv<'static>,
        _src: ViewEventSource,
        _dst: ViewEventDestination,
        event: &ViewEvent,
        src_view: &mut View<'static>,
        _parent: Option<&mut View<'static>>,
    ) {
        if env.status_view_id.is_none() {
            dbg_println!("open-doc-mode env.status_view_id.is_none()");
            return;
        }

        let src_view_id = src_view.id;
        let svid = env.status_view_id.clone().unwrap();
        dbg_println!("open-doc-mode svid = {:?}", svid);
        match event {
            &ViewEvent::ViewDeselected => {
                let mut gtm = src_view.mode_ctx_mut::<OpenDocModeContext>("open-doc-mode");
                dbg_println!("open-doc-mode gtm.active = {}", gtm.active);
                if gtm.active {
                    let status_view = editor.view_map.get(&svid).unwrap();
                    let mut status_view = status_view.write();
                    match &mut status_view.controller {
                        Some(ControllerView { id, mode_name }) => {
                            if *id == src_view_id && *mode_name == "open-doc-mode" {
                                clear_status_view(&mut status_view, &mut gtm);
                            }
                        }

                        _ => {}
                    }
                }
            }

            &ViewEvent::ViewSelected => {
                let src_view_id = src_view.id;
                let mut gtm = src_view.mode_ctx_mut::<OpenDocModeContext>("open-doc-mode");
                dbg_println!("open-doc-mode gtm.active = {}", gtm.active);
                if gtm.active {
                    let status_view = editor.view_map.get(&svid).unwrap();
                    let mut status_view = status_view.write();

                    status_view.controller = Some(view::ControllerView {
                        id: src_view_id,
                        mode_name: &"open-doc-mode",
                    });
                    update_status_view(&mut status_view, &mut gtm);
                }
            }

            _ => {}
        }
    }
}

pub struct OpenDocModeContext {
    pub active: bool,
    pub open_doc_str: Vec<char>,

    pub current_dir: String,
    pub current_entry: String,
}

impl OpenDocModeContext {
    pub fn new() -> Self {
        dbg_println!("OpenDocModeContext");
        OpenDocModeContext {
            active: false,
            open_doc_str: Vec::new(),
            current_dir: String::new(),
            current_entry: String::new(),
        }
    }
}
pub struct OpenDocMode {
    // add common fields
}

impl OpenDocMode {
    pub fn new() -> Self {
        dbg_println!("OpenDocMode");
        OpenDocMode {}
    }

    pub fn register_input_stage_actions<'a>(mut map: &'a mut InputStageActionMap<'a>) {
        register_input_stage_action(&mut map, "open-doc:start", open_doc_start);
        register_input_stage_action(&mut map, "open-doc:stop", open_doc_stop);
        register_input_stage_action(&mut map, "open-doc:add-char", open_doc_add_char);
        register_input_stage_action(&mut map, "open-doc:del-char", open_doc_del_char);
    }
}

pub fn open_doc_start(
    editor: &mut Editor<'static>,
    env: &mut EditorEnv<'static>,
    view: &Rc<RwLock<View<'static>>>,
) {
    {
        let status_vid = view::get_status_view(&editor, &env, view);

        if status_vid.is_none() {
            // TODO(ceg): log missing status mode
            return;
        }

        let svid = status_vid.unwrap();

        let status_view = editor.view_map.get(&svid).unwrap();

        // start/resume ?
        let already_active = {
            let mut v = view.write();
            let gtm = v.mode_ctx_mut::<OpenDocModeContext>("open-doc-mode");
            let already_active = gtm.active;
            gtm.active = true;

            status_view.write().controller = Some(view::ControllerView {
                id: v.id,
                mode_name: &"open-doc-mode",
            });
            already_active
        };

        //
        let doc = status_view.read().document().unwrap();
        let mut doc = doc.write();

        // clear status view
        doc.delete_content(None);

        // setup working directory
        {
            let mut v = view.write();
            let gtm = v.mode_ctx_mut::<OpenDocModeContext>("open-doc-mode");

            if gtm.open_doc_str.is_empty() {
                let path = env::current_dir().unwrap();
                let s = path.to_str().unwrap();
                let s = s.to_owned();
                for c in s.chars() {
                    gtm.open_doc_str.push(c);
                }
                gtm.open_doc_str.push('/');
            }
        }

        if !already_active {
            // setup new input map
            let mut v = view.write();
            v.input_ctx.stack_pos = None;
            let input_map = build_input_event_map(OPEN_DOC_INTERACTIVE_MAP).unwrap();
            let mut input_map_stack = v.input_ctx.input_map.as_ref().borrow_mut();
            input_map_stack.push(("open-doc-mode", input_map));
        }
    }

    display_open_doc_string(editor, env, &view);
}

pub fn open_doc_stop(
    editor: &mut Editor<'static>,
    env: &mut EditorEnv<'static>,
    view: &Rc<RwLock<View<'static>>>,
) {
    {
        let v = view.write();
        let mut input_map_stack = v.input_ctx.input_map.as_ref().borrow_mut();
        input_map_stack.pop();
    }

    // reset status view : TODO(ceg): view::reset_status_view(&editor, view);
    let status_vid = view::get_status_view(&editor, &env, view);
    if let Some(status_vid) = status_vid {
        let status_view = editor.view_map.get(&status_vid).unwrap();
        let doc = status_view.read().document().unwrap();
        let mut doc = doc.write();
        // clear buffer
        let sz = doc.size();
        doc.remove(0, sz, None);

        {
            let mut v = view.write();
            let gtm = v.mode_ctx_mut::<OpenDocModeContext>("open-doc-mode");

            // gtm.reset();
            gtm.open_doc_str.clear();
            gtm.active = false;
        }
    }
}

pub fn open_doc_do_completion(
    _editor: &mut Editor<'static>,
    _env: &mut EditorEnv<'static>,
    view: &Rc<RwLock<View<'static>>>,
) {
    let mut v = view.write();
    let gtm = v.mode_ctx_mut::<OpenDocModeContext>("open-doc-mode");

    dbg_println!("open file : do completion");

    let s: String = gtm.open_doc_str.iter().collect();
    let path = PathBuf::from(s);
    dbg_println!("open file : current directory is '{}'", path.display());

    // path.exist ?
    // if dir and no / at end push '/'

    match fs::read_dir(path) {
        Ok(path) => {
            for e in path {
                dbg_println!("open file: dir entry : '{}'", e.unwrap().path().display())
            }
        }
        _ => {
            /* wrong/incomplete */
            dbg_println!("open file: cannot complete");
        }
    }
}

pub fn open_doc_add_char(
    mut editor: &mut Editor<'static>,
    mut env: &mut EditorEnv<'static>,
    view: &Rc<RwLock<View<'static>>>,
) {
    let mut array = vec![];

    // filter input event
    let mut do_completion = false;
    {
        let v = view.read();

        assert!(v.input_ctx.trigger.len() > 0);
        let idx = v.input_ctx.trigger.len() - 1;

        dbg_println!("open file : env {:?}", v.input_ctx.trigger[idx]);

        match &v.input_ctx.trigger[idx] {
            InputEvent::KeyPress {
                key: Key::Unicode(c),
                mods:
                    KeyModifiers {
                        ctrl: false,
                        alt: false,
                        shift: false,
                    },
            } => {
                if *c == '\t' {
                    do_completion = true;
                } else {
                    array.push(*c);
                }
            }

            _ => {
                return;
            }
        }

        if array.is_empty() && !do_completion {
            return;
        }
    }

    if do_completion {
        open_doc_do_completion(editor, env, view);
    } else {
        let mut v = view.write();
        let gtm = v.mode_ctx_mut::<OpenDocModeContext>("open-doc-mode");
        gtm.open_doc_str.append(&mut array);
        dbg_println!("open file : {:?}", gtm.open_doc_str);
    }

    display_open_doc_string(&mut editor, &mut env, &view);
}

pub fn open_doc_del_char(
    mut editor: &mut Editor<'static>,
    mut env: &mut EditorEnv<'static>,
    view: &Rc<RwLock<View<'static>>>,
) {
    {
        let mut v = view.write();
        let gtm = v.mode_ctx_mut::<OpenDocModeContext>("open-doc-mode");
        if gtm.open_doc_str.is_empty() {
            return;
        }
        gtm.open_doc_str.pop();
    }

    display_open_doc_string(&mut editor, &mut env, &view);
}

fn clear_status_view(status_view: &mut View, _fm: &mut OpenDocModeContext) {
    // clear status
    let doc = status_view.document().unwrap();
    let mut doc = doc.write();
    // clear buffer. doc.erase_all();
    doc.delete_content(None);
}

pub fn display_open_doc_string(
    editor: &mut Editor<'static>,
    env: &mut EditorEnv<'static>,
    view: &Rc<RwLock<View<'static>>>,
) {
    //
    // reset status view : TODO(ceg): view::reset_status_view(&editor, view);
    let status_vid = view::get_status_view(&editor, &env, view);

    if let Some(status_vid) = status_vid {
        let mut v = view.write();
        let mut gtm = v.mode_ctx_mut::<OpenDocModeContext>("open-doc-mode");

        let mut status_view = editor.view_map.get(&status_vid).unwrap().write();
        update_status_view(&mut status_view, &mut gtm);
    }
}

fn update_status_view(status_view: &mut View, gtm: &mut OpenDocModeContext) {
    let doc = status_view.document().unwrap();
    let mut doc = doc.write();

    doc.delete_content(None);
    doc.append("Open: ".as_bytes());

    if !gtm.open_doc_str.is_empty() {
        let s: String = gtm.open_doc_str.iter().collect();
        let d = &s.as_bytes();
        doc.append(d);
    }
}
<commit_msg>open doc: gtm -> odm (OpenDocMode ctx)<commit_after>use std::any::Any;
use std::env;
use std::fs;
use std::path::PathBuf;

use parking_lot::RwLock;

use std::rc::Rc;

use super::Mode;

use crate::core::editor::register_input_stage_action;
use crate::core::editor::InputStageActionMap;
use crate::core::Editor;
use crate::core::EditorEnv;

use crate::core::event::*;

use crate::core::event::input_map::build_input_event_map;

use crate::core::view;
use crate::core::view::ChildView;
use crate::core::view::View;

use crate::core::view::LayoutOperation;
use crate::core::view::ViewEvent;
use crate::core::view::ViewEventDestination;
use crate::core::view::ViewEventSource;

use crate::core::view::ControllerView;

use crate::core::document::DocumentBuilder;

static OPEN_DOC_TRIGGER_MAP: &str = r#"
[
  {
    "events": [
     { "in": [{ "key": "ctrl+o" } ],    "action": "open-doc:start" }
    ]
  }
]"#;

static OPEN_DOC_INTERACTIVE_MAP: &str = r#"
[
  {
    "events": [
     { "in": [{ "key": "Escape" } ],    "action": "open-doc:stop" },
     { "in": [{ "key": "\n" } ],        "action": "open-doc:stop" },
     { "in": [{ "key": "BackSpace" } ], "action": "open-doc:del-char" },
     { "in": [{ "key": "Delete" } ],    "action": "open-doc:do-nothing" },
     { "default": [],                   "action": "open-doc:add-char" }
   ]
  }

]"#;

impl<'a> Mode for OpenDocMode {
    fn name(&self) -> &'static str {
        &"open-doc-mode"
    }

    fn build_action_map(&self) -> InputStageActionMap<'static> {
        let mut map = InputStageActionMap::new();
        Self::register_input_stage_actions(&mut map);
        map
    }

    fn alloc_ctx(&self) -> Box<dyn Any> {
        dbg_println!("alloc open-doc-mode ctx");
        let ctx = OpenDocModeContext::new();
        Box::new(ctx)
    }

    fn configure_view(
        &mut self,
        _editor: &mut Editor<'static>,
        _env: &mut EditorEnv<'static>,
        view: &mut View<'static>,
    ) {
        dbg_println!("configure find  {:?}", view.id);

        // setup input map for core actions
        let input_map = build_input_event_map(OPEN_DOC_TRIGGER_MAP).unwrap();
        let mut input_map_stack = view.input_ctx.input_map.as_ref().borrow_mut();
        input_map_stack.push((self.name(), input_map));
    }

    fn on_view_event(
        &self,
        editor: &mut Editor<'static>,
        env: &mut EditorEnv<'static>,
        _src: ViewEventSource,
        _dst: ViewEventDestination,
        event: &ViewEvent,
        src_view: &mut View<'static>,
        _parent: Option<&mut View<'static>>,
    ) {
        if env.status_view_id.is_none() {
            dbg_println!("open-doc-mode env.status_view_id.is_none()");
            return;
        }

        let src_view_id = src_view.id;
        let svid = env.status_view_id.clone().unwrap();
        dbg_println!("open-doc-mode svid = {:?}", svid);
        match event {
            &ViewEvent::ViewDeselected => {
                let mut odm = src_view.mode_ctx_mut::<OpenDocModeContext>("open-doc-mode");
                dbg_println!("open-doc-mode odm.active = {}", odm.active);
                if odm.active {
                    let status_view = editor.view_map.get(&svid).unwrap();
                    let mut status_view = status_view.write();
                    match &mut status_view.controller {
                        Some(ControllerView { id, mode_name }) => {
                            if *id == src_view_id && *mode_name == "open-doc-mode" {
                                clear_status_view(&mut status_view, &mut odm);
                            }
                        }

                        _ => {}
                    }
                }
            }

            &ViewEvent::ViewSelected => {
                let src_view_id = src_view.id;
                let mut odm = src_view.mode_ctx_mut::<OpenDocModeContext>("open-doc-mode");
                dbg_println!("open-doc-mode odm.active = {}", odm.active);
                if odm.active {
                    let status_view = editor.view_map.get(&svid).unwrap();
                    let mut status_view = status_view.write();

                    status_view.controller = Some(view::ControllerView {
                        id: src_view_id,
                        mode_name: &"open-doc-mode",
                    });
                    update_status_view(&mut status_view, &mut odm);
                }
            }

            _ => {}
        }
    }
}

pub struct OpenDocModeContext {
    pub active: bool,
    pub open_doc_str: Vec<char>,
    pub completion_str: String,
    pub current_dir: String,
    pub current_entry: String,
}

impl OpenDocModeContext {
    pub fn new() -> Self {
        dbg_println!("OpenDocModeContext");
        OpenDocModeContext {
            active: false,
            open_doc_str: Vec::new(),
            completion_str: String::new(),
            current_dir: String::new(),
            current_entry: String::new(),
        }
    }
}
pub struct OpenDocMode {
    // add common fields
}

impl OpenDocMode {
    pub fn new() -> Self {
        dbg_println!("OpenDocMode");
        OpenDocMode {}
    }

    pub fn register_input_stage_actions<'a>(mut map: &'a mut InputStageActionMap<'a>) {
        register_input_stage_action(&mut map, "open-doc:start", open_doc_start);
        register_input_stage_action(&mut map, "open-doc:stop", open_doc_stop);
        register_input_stage_action(&mut map, "open-doc:add-char", open_doc_add_char);
        register_input_stage_action(&mut map, "open-doc:del-char", open_doc_del_char);
    }
}

pub fn open_doc_start(
    editor: &mut Editor<'static>,
    env: &mut EditorEnv<'static>,
    view: &Rc<RwLock<View<'static>>>,
) {
    {
        let status_vid = view::get_status_view(&editor, &env, view);

        if status_vid.is_none() {
            // TODO(ceg): log missing status mode
            return;
        }

        let svid = status_vid.unwrap();

        let status_view = editor.view_map.get(&svid).unwrap();

        // start/resume ?
        let already_active = {
            let mut v = view.write();
            let odm = v.mode_ctx_mut::<OpenDocModeContext>("open-doc-mode");
            let already_active = odm.active;
            odm.active = true;

            status_view.write().controller = Some(view::ControllerView {
                id: v.id,
                mode_name: &"open-doc-mode",
            });
            already_active
        };

        //
        let doc = status_view.read().document().unwrap();
        let mut doc = doc.write();

        // clear status view
        doc.delete_content(None);

        // setup working directory
        {
            let mut v = view.write();
            let odm = v.mode_ctx_mut::<OpenDocModeContext>("open-doc-mode");

            if odm.open_doc_str.is_empty() {
                let path = env::current_dir().unwrap();
                let s = path.to_str().unwrap();
                let s = s.to_owned();
                for c in s.chars() {
                    odm.open_doc_str.push(c);
                }
                odm.open_doc_str.push('/');
            }
        }

        if !already_active {
            // setup new input map
            let mut v = view.write();
            v.input_ctx.stack_pos = None;
            let input_map = build_input_event_map(OPEN_DOC_INTERACTIVE_MAP).unwrap();
            let mut input_map_stack = v.input_ctx.input_map.as_ref().borrow_mut();
            input_map_stack.push(("open-doc-mode", input_map));
        }
    }

    display_open_doc_string(editor, env, &view);
}

pub fn open_doc_stop(
    editor: &mut Editor<'static>,
    env: &mut EditorEnv<'static>,
    view: &Rc<RwLock<View<'static>>>,
) {
    // destroy previous popup
    destroy_completion_popup(editor, env, view);

    //
    {
        let v = view.write();
        let mut input_map_stack = v.input_ctx.input_map.as_ref().borrow_mut();
        input_map_stack.pop();
    }

    // reset status view : TODO(ceg): view::reset_status_view(&editor, view);
    let status_vid = view::get_status_view(&editor, &env, view);
    if let Some(status_vid) = status_vid {
        let status_view = editor.view_map.get(&status_vid).unwrap();
        let doc = status_view.read().document().unwrap();
        let mut doc = doc.write();
        // clear buffer
        let sz = doc.size();
        doc.remove(0, sz, None);

        {
            let mut v = view.write();
            let odm = v.mode_ctx_mut::<OpenDocModeContext>("open-doc-mode");

            // odm.reset();
            odm.open_doc_str.clear();
            odm.active = false;
        }
    }
}

pub fn open_doc_add_char(
    mut editor: &mut Editor<'static>,
    mut env: &mut EditorEnv<'static>,
    view: &Rc<RwLock<View<'static>>>,
) {
    let mut array = vec![];

    // filter input event
    let mut do_completion = false;
    {
        let v = view.read();

        assert!(v.input_ctx.trigger.len() > 0);
        let idx = v.input_ctx.trigger.len() - 1;

        dbg_println!("open file : env {:?}", v.input_ctx.trigger[idx]);

        match &v.input_ctx.trigger[idx] {
            InputEvent::KeyPress {
                key: Key::Unicode(c),
                mods:
                    KeyModifiers {
                        ctrl: false,
                        alt: false,
                        shift: false,
                    },
            } => {
                if *c == '\t' {
                    do_completion = true;
                } else {
                    array.push(*c);
                }
            }

            _ => {
                return;
            }
        }

        if array.is_empty() && !do_completion {
            return;
        }
    }

    if do_completion {
        open_doc_do_completion(editor, env, view);
    } else {
        let mut v = view.write();
        let odm = v.mode_ctx_mut::<OpenDocModeContext>("open-doc-mode");
        odm.open_doc_str.append(&mut array);
        dbg_println!("open file : {:?}", odm.open_doc_str);
    }

    display_open_doc_string(&mut editor, &mut env, &view);
}

pub fn open_doc_del_char(
    mut editor: &mut Editor<'static>,
    mut env: &mut EditorEnv<'static>,
    view: &Rc<RwLock<View<'static>>>,
) {
    {
        let mut v = view.write();
        let odm = v.mode_ctx_mut::<OpenDocModeContext>("open-doc-mode");
        if odm.open_doc_str.is_empty() {
            return;
        }
        odm.open_doc_str.pop();
    }

    display_open_doc_string(&mut editor, &mut env, &view);
}

fn clear_status_view(status_view: &mut View, _fm: &mut OpenDocModeContext) {
    // clear status
    let doc = status_view.document().unwrap();
    let mut doc = doc.write();
    // clear buffer. doc.erase_all();
    doc.delete_content(None);
}

pub fn display_open_doc_string(
    editor: &mut Editor<'static>,
    env: &mut EditorEnv<'static>,
    view: &Rc<RwLock<View<'static>>>,
) {
    //
    // reset status view : TODO(ceg): view::reset_status_view(&editor, view);
    let status_vid = view::get_status_view(&editor, &env, view);

    if let Some(status_vid) = status_vid {
        let mut v = view.write();
        let mut odm = v.mode_ctx_mut::<OpenDocModeContext>("open-doc-mode");

        let mut status_view = editor.view_map.get(&status_vid).unwrap().write();
        update_status_view(&mut status_view, &mut odm);
    }
}

fn update_status_view(status_view: &mut View, odm: &mut OpenDocModeContext) {
    let doc = status_view.document().unwrap();
    let mut doc = doc.write();

    doc.delete_content(None);
    doc.append("Open: ".as_bytes());

    if !odm.open_doc_str.is_empty() {
        let s: String = odm.open_doc_str.iter().collect();
        let d = &s.as_bytes();
        doc.append(d);
    }
}

pub fn open_doc_do_completion(
    editor: &mut Editor<'static>,
    env: &mut EditorEnv<'static>,
    view: &Rc<RwLock<View<'static>>>,
) {
    let show = {
        let mut v = view.write();
        let odm = v.mode_ctx_mut::<OpenDocModeContext>("open-doc-mode");

        dbg_println!("open file : do completion");

        let s: String = odm.open_doc_str.iter().collect();
        let path = PathBuf::from(s.clone());
        dbg_println!("open file : current directory is '{}'", path.display());

        // path.exist ?
        // if dir and no / at end push '/'
        odm.completion_str.clear();
        match fs::read_dir(path) {
            Ok(path) => {
                for e in path {
                    let s = format!("{}\n", e.unwrap().path().display());
                    odm.completion_str.push_str(&s);

                    dbg_println!("open file: dir entry : '{}'", s);
                }
            }
            _ => {
                /* wrong/incomplete */
                let s = format!("cannot read {}\n", s);
                odm.completion_str.push_str(&s);

                dbg_println!("open file: cannot complete {:?}", s);
            }
        }

        !odm.completion_str.is_empty()
    };
    dbg_println!("show = {}", show);
    if show {
        show_completion_popup(editor, env, view);
    } else {
        destroy_completion_popup(editor, env, view);
    }
}

fn show_completion_popup(
    mut editor: &mut Editor<'static>,
    mut env: &mut EditorEnv<'static>,
    text_view: &Rc<RwLock<View>>,
) {
    let parent_id = env.root_view_id;

    let command_doc = DocumentBuilder::new()
        .document_name("completion-pop-up")
        .internal(true)
        .use_buffer_log(false)
        .finalize();

    {
        let s = text_view
            .read()
            .mode_ctx::<OpenDocModeContext>("open-doc-mode")
            .completion_str
            .clone();

        let mut d = command_doc.as_ref().unwrap().write();
        d.append(s.as_bytes());
    }

    // TODO: get view global coordinates, update on  resize
    let (x, y, pop_width, pop_height) = {
        let parent_view = editor.view_map.get(&parent_id).unwrap().read();
        let dim = parent_view.dimension();

        (8, 2, dim.0.saturating_sub(16), dim.1.saturating_sub(4))
    };

    // create view
    let popup_view = View::new(
        &mut editor,
        &mut env,
        Some(parent_id),
        (x, y),
        (pop_width, pop_height),
        command_doc,
        &vec!["status-mode".to_owned()],
        0,
    );

    {
        let mut parent_view = editor.view_map.get(&parent_id).unwrap().write();
        parent_view.floating_children.push(ChildView {
            id: popup_view.id,
            layout_op: LayoutOperation::Floating,
        });
    }

    editor.add_view(popup_view.id, Rc::new(RwLock::new(popup_view)));
}

fn destroy_completion_popup(
    editor: &mut Editor<'static>,
    env: &mut EditorEnv<'static>,
    _view: &Rc<RwLock<View<'static>>>,
) {
    // destroy previous popup
    let parent_id = env.root_view_id;
    if let Some(info) = {
        let mut p_view = editor.view_map.get(&parent_id).unwrap().write();
        p_view.floating_children.pop()
    } {
        editor.view_map.remove(&info.id);
    }
}
<|endoftext|>


<commit_before>//
//  SOS: the Stupid Operating System
//  by Hawk Weisman (hi@hawkweisman.me)
//
//  Copyright (c) 2015 Hawk Weisman
//  Released under the terms of the MIT license. See `LICENSE` in the root
//  directory of this repository for more information.
//
//! `x86_64` execution contexts.
//!
//! This is inteded to be general-purpose and composable, so that the same
//! code can be reused for interrupts and for multithreading.

use core::mem;
use core::fmt;
use super::flags::{Flags as RFlags};
use super::segment;

/// Registers pushed to the stack when handling an interrupt or context switch.
#[repr(C, packed)]
#[derive(Copy, Clone)]
pub struct Registers { pub rsi: u64
                     , pub rdi: u64
                     , pub r11: u64
                     , pub r10: u64
                     , pub r9:  u64
                     , pub r8:  u64
                     , pub rdx: u64
                     , pub rcx: u64
                     , pub rax: u64
                     }

 impl Registers {
     /// Transform this struct into an array of `u64`s
     /// (if you would ever want to do this)
     pub unsafe fn to_array(&self) -> [u64; 9] {
        //  [ self.rsi, self.rdi, self.r11
        //  , self.r10, self.r9, self.r8
        //  , self.rdx, self.rcx, self.rax
        //  ]
        // using transmute is probably faster and we're already unsafe...
        mem::transmute(*self)
     }

     /// Create a new empty set of Registers
     pub const fn empty() -> Self {
         Registers { rsi: 0, rdi: 0, r11: 0
                   , r10: 0, r9:  0, r8:  0
                   , rdx: 0, rcx: 0, rax: 0
                   }
     }

     /// Push the caller-saved registers to the stack
     /// (such as when handling a context switch or interrupt).
     ///
     /// THIS FUNCTION IS NAKED. DO NOT CALL IT NORMALLY.
     #[naked]
     #[inline(always)]
     pub unsafe fn push() {
         asm!( "push rax
                push rcx
                push rdx
                push r8
                push r9
                push r10
                push r11
                push rdi
                push rsi"
             :::: "intel"
                , "volatile");
     }

     /// Push the caller-saved registers off the stack
     /// (such as when handling a context switch or interrupt).
     ///
     /// THIS FUNCTION IS NAKED. DO NOT CALL IT NORMALLY.
     #[naked]
     #[inline(always)]
     pub unsafe fn pop() {
         asm!( "pop rsi
                pop rdi
                pop r11
                pop r10
                pop r9
                pop r8
                pop rdx
                pop rcx
                pop rax"
             :::: "intel"
                , "volatile");
     }
 }

impl fmt::Debug for Registers {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         write!( f
               , "    RSI: {:#018x} RDI: {:#018x} R11: {:#018x}\n    \
                      R10: {:#018x} R9:  {:#018x} R8:  {:#018x}\n    \
                      RDX: {:#018x} RCX: {:#018x} RAX: {:#018x}"
              , self.rsi, self.rdi, self.r11
              , self.r10, self.r9,  self.r8
              , self.rdx, self.rcx, self.rax)
     }
}

#[repr(C, packed)]
pub struct InterruptFrame {
    //  this is the actual value of the interrupt stack frame context,
    //  not the old one (which is wrong). note that the old one seems to cause
    //  stack misalignment.
    //          -- eliza, october 4th, 2016
    /// Value of the instruction pointer (`$rip`) register
    pub rip: u64
  , /// Value of the code segment (`$cs`) register
    pub cs: segment::Selector
  , __pad_1: u32
  , __pad_2: u16
  , /// Value of the CPU flags (`$rflags`) register
    pub rflags: RFlags
  , /// Value of the stack pointer (`$rsp`) register
    //  TODO: should this actually be a pointer?
    pub rsp: u64
  , /// Value of the stack segment (`$ss`) register
    pub ss: segment::Selector
  , __pad_3: u32
  , __pad_4: u16
}

#[cfg(test)]
mod test {
    #[test]
    fn test_interrupt_frame_correct_size() {
        use core::mem::size_of;
        use super::InterruptFrame;

        assert_eq!(size_of::<InterruptFrame>(), 32);
    }
}

impl fmt::Debug for InterruptFrame {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!( f
              , "Interrupt Frame: \
                \n   instruction pointer: {:#018x} \
                \n   code segment:        {} \
                \n   rflags:              {:?} \
                \n   stack pointer:       {:#018x} \
                \n   stack segment:       {}"
             , self.rip
            //  , self.__pad_1, self.__pad_2
             , self.cs
             , self.rflags
             , self.rsp
            //  , self.__pad_3, self.__pad_4
             , self.ss)
    }
}

/// Thread execution context
#[repr(C, packed)]
pub struct Context { /// Value of the stack pointer (`rsp`) register
                     pub rsp: *mut u8
                   , /// Value of the caller-saved registers
                     pub registers: Registers
                   , /// Value of the instruction pointer (`rip`) register
                     pub rip: *mut u8
                 //, pub stack: [u8] // TODO: should be box
                   }

impl Context {
    pub fn empty() -> Self {
        unsafe {
            Context { rsp: mem::transmute(0u64)
                    , registers: Registers::empty()
                    , rip: mem::transmute(0u64)
                  //, stack: [0u8; 8]
                    }
        }
    }
}
<commit_msg>[x86_64] pointers in InterruptFrame are now typed as pointers<commit_after>//
//  SOS: the Stupid Operating System
//  by Hawk Weisman (hi@hawkweisman.me)
//
//  Copyright (c) 2015 Hawk Weisman
//  Released under the terms of the MIT license. See `LICENSE` in the root
//  directory of this repository for more information.
//
//! `x86_64` execution contexts.
//!
//! This is inteded to be general-purpose and composable, so that the same
//! code can be reused for interrupts and for multithreading.

use core::mem;
use core::fmt;
use super::flags::{Flags as RFlags};
use super::segment;

/// Registers pushed to the stack when handling an interrupt or context switch.
#[repr(C, packed)]
#[derive(Copy, Clone)]
pub struct Registers { pub rsi: u64
                     , pub rdi: u64
                     , pub r11: u64
                     , pub r10: u64
                     , pub r9:  u64
                     , pub r8:  u64
                     , pub rdx: u64
                     , pub rcx: u64
                     , pub rax: u64
                     }

 impl Registers {
     /// Transform this struct into an array of `u64`s
     /// (if you would ever want to do this)
     pub unsafe fn to_array(&self) -> [u64; 9] {
        //  [ self.rsi, self.rdi, self.r11
        //  , self.r10, self.r9, self.r8
        //  , self.rdx, self.rcx, self.rax
        //  ]
        // using transmute is probably faster and we're already unsafe...
        mem::transmute(*self)
     }

     /// Create a new empty set of Registers
     pub const fn empty() -> Self {
         Registers { rsi: 0, rdi: 0, r11: 0
                   , r10: 0, r9:  0, r8:  0
                   , rdx: 0, rcx: 0, rax: 0
                   }
     }

     /// Push the caller-saved registers to the stack
     /// (such as when handling a context switch or interrupt).
     ///
     /// THIS FUNCTION IS NAKED. DO NOT CALL IT NORMALLY.
     #[naked]
     #[inline(always)]
     pub unsafe fn push() {
         asm!( "push rax
                push rcx
                push rdx
                push r8
                push r9
                push r10
                push r11
                push rdi
                push rsi"
             :::: "intel"
                , "volatile");
     }

     /// Push the caller-saved registers off the stack
     /// (such as when handling a context switch or interrupt).
     ///
     /// THIS FUNCTION IS NAKED. DO NOT CALL IT NORMALLY.
     #[naked]
     #[inline(always)]
     pub unsafe fn pop() {
         asm!( "pop rsi
                pop rdi
                pop r11
                pop r10
                pop r9
                pop r8
                pop rdx
                pop rcx
                pop rax"
             :::: "intel"
                , "volatile");
     }
 }

impl fmt::Debug for Registers {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         write!( f
               , "    RSI: {:#018x} RDI: {:#018x} R11: {:#018x}\n    \
                      R10: {:#018x} R9:  {:#018x} R8:  {:#018x}\n    \
                      RDX: {:#018x} RCX: {:#018x} RAX: {:#018x}"
              , self.rsi, self.rdi, self.r11
              , self.r10, self.r9,  self.r8
              , self.rdx, self.rcx, self.rax)
     }
}

#[repr(C, packed)]
pub struct InterruptFrame {
    //  this is the actual value of the interrupt stack frame context,
    //  not the old one (which is wrong). note that the old one seems to cause
    //  stack misalignment.
    //          -- eliza, october 4th, 2016
    /// Value of the instruction pointer (`$rip`) register
    pub rip: *const u8
  , /// Value of the code segment (`$cs`) register
    pub cs: segment::Selector
  , __pad_1: u32
  , __pad_2: u16
  , /// Value of the CPU flags (`$rflags`) register
    pub rflags: RFlags
  , /// Value of the stack pointer (`$rsp`) register
    //  TODO: should this actually be a pointer?
    pub rsp: *const u8
  , /// Value of the stack segment (`$ss`) register
    pub ss: segment::Selector
  , __pad_3: u32
  , __pad_4: u16
}

#[cfg(test)]
mod test {
    #[test]
    fn test_interrupt_frame_correct_size() {
        use core::mem::size_of;
        use super::InterruptFrame;

        assert_eq!(size_of::<InterruptFrame>(), 32);
    }
}

impl fmt::Debug for InterruptFrame {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!( f
              , "Interrupt Frame: \
                \n   instruction pointer: {:p} \
                \n   code segment:        {} \
                \n   rflags:              {:?} \
                \n   stack pointer:       {:p} \
                \n   stack segment:       {}"
             , self.rip
            //  , self.__pad_1, self.__pad_2
             , self.cs
             , self.rflags
             , self.rsp
            //  , self.__pad_3, self.__pad_4
             , self.ss)
    }
}

/// Thread execution context
#[repr(C, packed)]
pub struct Context { /// Value of the stack pointer (`rsp`) register
                     pub rsp: *mut u8
                   , /// Value of the caller-saved registers
                     pub registers: Registers
                   , /// Value of the instruction pointer (`rip`) register
                     pub rip: *mut u8
                 //, pub stack: [u8] // TODO: should be box
                   }

impl Context {
    pub fn empty() -> Self {
        unsafe {
            Context { rsp: mem::transmute(0u64)
                    , registers: Registers::empty()
                    , rip: mem::transmute(0u64)
                  //, stack: [0u8; 8]
                    }
        }
    }
}
<|endoftext|>