<commit_before>use std::path::PathBuf;

use rustc_data_structures::fx::FxHashMap;

use crate::externalfiles::ExternalHtml;
use crate::html::escape::Escape;
use crate::html::format::{Buffer, Print};
use crate::html::render::{ensure_trailing_slash, StylePath};

#[derive(Clone)]
crate struct Layout {
    crate logo: String,
    crate favicon: String,
    crate external_html: ExternalHtml,
    crate default_settings: FxHashMap<String, String>,
    crate krate: String,
    /// The given user css file which allow to customize the generated
    /// documentation theme.
    crate css_file_extension: Option<PathBuf>,
    /// If false, the `select` element to have search filtering by crates on rendered docs
    /// won't be generated.
    crate generate_search_filter: bool,
}

crate struct Page<'a> {
    crate title: &'a str,
    crate css_class: &'a str,
    crate root_path: &'a str,
    crate static_root_path: Option<&'a str>,
    crate description: &'a str,
    crate keywords: &'a str,
    crate resource_suffix: &'a str,
    crate extra_scripts: &'a [&'a str],
    crate static_extra_scripts: &'a [&'a str],
}

impl<'a> Page<'a> {
    crate fn get_static_root_path(&self) -> &str {
        self.static_root_path.unwrap_or(self.root_path)
    }
}

crate fn render<T: Print, S: Print>(
    layout: &Layout,
    page: &Page<'_>,
    sidebar: S,
    t: T,
    style_files: &[StylePath],
) -> String {
    let static_root_path = page.get_static_root_path();
    format!(
        "<!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=\"{static_root_path}normalize{suffix}.css\">\
    <link rel=\"stylesheet\" type=\"text/css\" href=\"{static_root_path}rustdoc{suffix}.css\" \
          id=\"mainThemeStyle\">\
    {style_files}\
    \
    \
    \
    <link rel=\"stylesheet\" href=\"{static_root_path}noscript{suffix}.css\">\
    {css_extension}\
    {favicon}\
    {in_header}\
    \
\
\
    \
    {before_content}\
    \

☰
\
        {logo}\
        {sidebar}\
    \

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

\

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

\

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

\
                <button type=\"button\" id=\"help-button\" title=\"help\">?</button>
                \
                    \
                \

\
        </form>\
    \

{content}
\

\
    {after_content}\

\
    \
    {extra_scripts}\
\
",
        css_extension = if layout.css_file_extension.is_some() {
            format!(
                "<link rel=\"stylesheet\" \
                       type=\"text/css\" \
                       href=\"{static_root_path}theme{suffix}.css\">",
                static_root_path = static_root_path,
                suffix = page.resource_suffix
            )
        } else {
            String::new()
        },
        content = Buffer::html().to_display(t),
        static_root_path = static_root_path,
        root_path = page.root_path,
        css_class = page.css_class,
        logo = {
            if layout.logo.is_empty() {
                format!(
                    "\

\

",
                    root = page.root_path,
                    path = ensure_trailing_slash(&layout.krate),
                    static_root_path = static_root_path,
                    suffix = page.resource_suffix
                )
            } else {
                format!(
                    "\

",
                    root = page.root_path,
                    path = ensure_trailing_slash(&layout.krate),
                    logo = layout.logo
                )
            }
        },
        title = page.title,
        description = page.description,
        keywords = page.keywords,
        favicon = if layout.favicon.is_empty() {
            format!(
                r##"<link rel="icon" type="image/svg+xml" href="{static_root_path}favicon{suffix}.svg">
<link rel="alternate icon" type="image/png" href="{static_root_path}favicon-16x16{suffix}.png">
<link rel="alternate icon" type="image/png" href="{static_root_path}favicon-32x32{suffix}.png">"##,
                static_root_path = static_root_path,
                suffix = page.resource_suffix
            )
        } 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 = Buffer::html().to_display(sidebar),
        krate = layout.krate,
        default_settings = layout
            .default_settings
            .iter()
            .map(|(k, v)| format!(r#" data-{}="{}""#, k.replace('-', "_"), Escape(v)))
            .collect::<String>(),
        style_files = style_files
            .iter()
            .filter_map(|t| {
                if let Some(stem) = t.path.file_stem() { Some((stem, t.disabled)) } else { None }
            })
            .filter_map(|t| {
                if let Some(path) = t.0.to_str() { Some((path, t.1)) } else { None }
            })
            .map(|t| format!(
                r#"<link rel="stylesheet" type="text/css" href="{}.css" {} {}>"#,
                Escape(&format!("{}{}{}", static_root_path, t.0, page.resource_suffix)),
                if t.1 { "disabled" } else { "" },
                if t.0 == "light" { "id=\"themeStyle\"" } else { "" }
            ))
            .collect::<String>(),
        suffix = page.resource_suffix,
        extra_scripts = page
            .static_extra_scripts
            .iter()
            .map(|e| {
                format!(
                    "",
                    static_root_path = static_root_path,
                    extra_script = e
                )
            })
            .chain(page.extra_scripts.iter().map(|e| {
                format!(
                    "",
                    root_path = page.root_path,
                    extra_script = e
                )
            }))
            .collect::<String>(),
        filter_crates = if layout.generate_search_filter {
            "<select id=\"crate-search\">\
                 <option value=\"All crates\">All crates</option>\
             </select>"
        } else {
            ""
        },
    )
}

crate fn redirect(url: &str) -> String {
    //

"##,
        url = url,
    )
}
<commit_msg>Escape <meta> content attribute value<commit_after>use std::path::PathBuf;

use rustc_data_structures::fx::FxHashMap;

use crate::externalfiles::ExternalHtml;
use crate::html::escape::Escape;
use crate::html::format::{Buffer, Print};
use crate::html::render::{ensure_trailing_slash, StylePath};

#[derive(Clone)]
crate struct Layout {
    crate logo: String,
    crate favicon: String,
    crate external_html: ExternalHtml,
    crate default_settings: FxHashMap<String, String>,
    crate krate: String,
    /// The given user css file which allow to customize the generated
    /// documentation theme.
    crate css_file_extension: Option<PathBuf>,
    /// If false, the `select` element to have search filtering by crates on rendered docs
    /// won't be generated.
    crate generate_search_filter: bool,
}

crate struct Page<'a> {
    crate title: &'a str,
    crate css_class: &'a str,
    crate root_path: &'a str,
    crate static_root_path: Option<&'a str>,
    crate description: &'a str,
    crate keywords: &'a str,
    crate resource_suffix: &'a str,
    crate extra_scripts: &'a [&'a str],
    crate static_extra_scripts: &'a [&'a str],
}

impl<'a> Page<'a> {
    crate fn get_static_root_path(&self) -> &str {
        self.static_root_path.unwrap_or(self.root_path)
    }
}

crate fn render<T: Print, S: Print>(
    layout: &Layout,
    page: &Page<'_>,
    sidebar: S,
    t: T,
    style_files: &[StylePath],
) -> String {
    let static_root_path = page.get_static_root_path();
    format!(
        "<!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=\"{static_root_path}normalize{suffix}.css\">\
    <link rel=\"stylesheet\" type=\"text/css\" href=\"{static_root_path}rustdoc{suffix}.css\" \
          id=\"mainThemeStyle\">\
    {style_files}\
    \
    \
    \
    <link rel=\"stylesheet\" href=\"{static_root_path}noscript{suffix}.css\">\
    {css_extension}\
    {favicon}\
    {in_header}\
    \
\
\
    \
    {before_content}\
    \

☰
\
        {logo}\
        {sidebar}\
    \

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

\

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

\

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

\
                <button type=\"button\" id=\"help-button\" title=\"help\">?</button>
                \
                    \
                \

\
        </form>\
    \

{content}
\

\
    {after_content}\

\
    \
    {extra_scripts}\
\
",
        css_extension = if layout.css_file_extension.is_some() {
            format!(
                "<link rel=\"stylesheet\" \
                       type=\"text/css\" \
                       href=\"{static_root_path}theme{suffix}.css\">",
                static_root_path = static_root_path,
                suffix = page.resource_suffix
            )
        } else {
            String::new()
        },
        content = Buffer::html().to_display(t),
        static_root_path = static_root_path,
        root_path = page.root_path,
        css_class = page.css_class,
        logo = {
            if layout.logo.is_empty() {
                format!(
                    "\

\

",
                    root = page.root_path,
                    path = ensure_trailing_slash(&layout.krate),
                    static_root_path = static_root_path,
                    suffix = page.resource_suffix
                )
            } else {
                format!(
                    "\

",
                    root = page.root_path,
                    path = ensure_trailing_slash(&layout.krate),
                    logo = layout.logo
                )
            }
        },
        title = page.title,
        description = Escape(page.description),
        keywords = page.keywords,
        favicon = if layout.favicon.is_empty() {
            format!(
                r##"<link rel="icon" type="image/svg+xml" href="{static_root_path}favicon{suffix}.svg">
<link rel="alternate icon" type="image/png" href="{static_root_path}favicon-16x16{suffix}.png">
<link rel="alternate icon" type="image/png" href="{static_root_path}favicon-32x32{suffix}.png">"##,
                static_root_path = static_root_path,
                suffix = page.resource_suffix
            )
        } 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 = Buffer::html().to_display(sidebar),
        krate = layout.krate,
        default_settings = layout
            .default_settings
            .iter()
            .map(|(k, v)| format!(r#" data-{}="{}""#, k.replace('-', "_"), Escape(v)))
            .collect::<String>(),
        style_files = style_files
            .iter()
            .filter_map(|t| {
                if let Some(stem) = t.path.file_stem() { Some((stem, t.disabled)) } else { None }
            })
            .filter_map(|t| {
                if let Some(path) = t.0.to_str() { Some((path, t.1)) } else { None }
            })
            .map(|t| format!(
                r#"<link rel="stylesheet" type="text/css" href="{}.css" {} {}>"#,
                Escape(&format!("{}{}{}", static_root_path, t.0, page.resource_suffix)),
                if t.1 { "disabled" } else { "" },
                if t.0 == "light" { "id=\"themeStyle\"" } else { "" }
            ))
            .collect::<String>(),
        suffix = page.resource_suffix,
        extra_scripts = page
            .static_extra_scripts
            .iter()
            .map(|e| {
                format!(
                    "",
                    static_root_path = static_root_path,
                    extra_script = e
                )
            })
            .chain(page.extra_scripts.iter().map(|e| {
                format!(
                    "",
                    root_path = page.root_path,
                    extra_script = e
                )
            }))
            .collect::<String>(),
        filter_crates = if layout.generate_search_filter {
            "<select id=\"crate-search\">\
                 <option value=\"All crates\">All crates</option>\
             </select>"
        } else {
            ""
        },
    )
}

crate fn redirect(url: &str) -> String {
    //

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


<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 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 {
        "".to_owned()
    },
    content   = *t,
    root_path = page.root_path,
    css_class = page.css_class,
    logo      = if layout.logo.is_empty() {
        "".to_string()
    } else {
        format!("\
                 ",
                page.root_path, layout.krate,
                layout.logo)
    },
    title     = page.title,
    description = page.description,
    keywords = page.keywords,
    favicon   = if layout.favicon.is_empty() {
        "".to_string()
    } 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 io::Write, url: &str) -> io::Result<()> {
    //

"##,
    url = url,
    )
}
<commit_msg>fix search load page failure<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 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 {
        "".to_owned()
    },
    content   = *t,
    root_path = page.root_path,
    css_class = page.css_class,
    logo      = if layout.logo.is_empty() {
        "".to_string()
    } else {
        format!("\
                 ",
                page.root_path, layout.krate,
                layout.logo)
    },
    title     = page.title,
    description = page.description,
    keywords = page.keywords,
    favicon   = if layout.favicon.is_empty() {
        "".to_string()
    } 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 io::Write, url: &str) -> io::Result<()> {
    //

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


<commit_before>#![allow(missing_docs, nonstandard_style)]

use crate::ffi::{OsStr, OsString};
use crate::io::ErrorKind;
use crate::os::windows::ffi::{OsStrExt, OsStringExt};
use crate::path::PathBuf;
use crate::ptr;
use crate::time::Duration;

pub use self::rand::hashmap_random_keys;
pub use libc::strlen;

#[macro_use]
pub mod compat;

pub mod alloc;
pub mod args;
pub mod c;
pub mod cmath;
pub mod condvar;
pub mod env;
pub mod ext;
pub mod fast_thread_local;
pub mod fs;
pub mod handle;
pub mod io;
pub mod memchr;
pub mod mutex;
pub mod net;
pub mod os;
pub mod os_str;
pub mod path;
pub mod pipe;
pub mod process;
pub mod rand;
pub mod rwlock;
pub mod thread;
pub mod thread_local;
pub mod time;
cfg_if::cfg_if! {
    if #[cfg(not(target_vendor = "uwp"))] {
        pub mod stdio;
        pub mod stack_overflow;
    } else {
        pub mod stdio_uwp;
        pub mod stack_overflow_uwp;
        pub use self::stdio_uwp as stdio;
        pub use self::stack_overflow_uwp as stack_overflow;
    }
}

#[cfg(not(test))]
pub fn init() {}

pub fn decode_error_kind(errno: i32) -> ErrorKind {
    match errno as c::DWORD {
        c::ERROR_ACCESS_DENIED => return ErrorKind::PermissionDenied,
        c::ERROR_ALREADY_EXISTS => return ErrorKind::AlreadyExists,
        c::ERROR_FILE_EXISTS => return ErrorKind::AlreadyExists,
        c::ERROR_BROKEN_PIPE => return ErrorKind::BrokenPipe,
        c::ERROR_FILE_NOT_FOUND => return ErrorKind::NotFound,
        c::ERROR_PATH_NOT_FOUND => return ErrorKind::NotFound,
        c::ERROR_NO_DATA => return ErrorKind::BrokenPipe,
        c::ERROR_SEM_TIMEOUT |
        c::WAIT_TIMEOUT |
        c::ERROR_DRIVER_CANCEL_TIMEOUT |
        c::ERROR_OPERATION_ABORTED |
        c::ERROR_SERVICE_REQUEST_TIMEOUT |
        c::ERROR_COUNTER_TIMEOUT |
        c::ERROR_TIMEOUT |
        c::ERROR_RESOURCE_CALL_TIMED_OUT |
        c::ERROR_CTX_MODEM_RESPONSE_TIMEOUT |
        c::ERROR_CTX_CLIENT_QUERY_TIMEOUT |
        c::FRS_ERR_SYSVOL_POPULATE_TIMEOUT |
        c::ERROR_DS_TIMELIMIT_EXCEEDED |
        c::DNS_ERROR_RECORD_TIMED_OUT |
        c::ERROR_IPSEC_IKE_TIMED_OUT |
        c::ERROR_RUNLEVEL_SWITCH_TIMEOUT |
        c::ERROR_RUNLEVEL_SWITCH_AGENT_TIMEOUT => return ErrorKind::TimedOut,
        _ => {}
    }

    match errno {
        c::WSAEACCES => ErrorKind::PermissionDenied,
        c::WSAEADDRINUSE => ErrorKind::AddrInUse,
        c::WSAEADDRNOTAVAIL => ErrorKind::AddrNotAvailable,
        c::WSAECONNABORTED => ErrorKind::ConnectionAborted,
        c::WSAECONNREFUSED => ErrorKind::ConnectionRefused,
        c::WSAECONNRESET => ErrorKind::ConnectionReset,
        c::WSAEINVAL => ErrorKind::InvalidInput,
        c::WSAENOTCONN => ErrorKind::NotConnected,
        c::WSAEWOULDBLOCK => ErrorKind::WouldBlock,
        c::WSAETIMEDOUT => ErrorKind::TimedOut,

        _ => ErrorKind::Other,
    }
}

pub fn unrolled_find_u16s(needle: u16, haystack: &[u16]) -> Option<usize> {
    let ptr = haystack.as_ptr();
    let mut len = haystack.len();
    let mut start = &haystack[..];

    // For performance reasons unfold the loop eight times.
    while len >= 8 {
        if start[0] == needle {
            return Some((start.as_ptr() as usize - ptr as usize) / 2);
        }
        if start[1] == needle {
            return Some((start[1..].as_ptr() as usize - ptr as usize) / 2);
        }
        if start[2] == needle {
            return Some((start[2..].as_ptr() as usize - ptr as usize) / 2);
        }
        if start[3] == needle {
            return Some((start[3..].as_ptr() as usize - ptr as usize) / 2);
        }
        if start[4] == needle {
            return Some((start[4..].as_ptr() as usize - ptr as usize) / 2);
        }
        if start[5] == needle {
            return Some((start[5..].as_ptr() as usize - ptr as usize) / 2);
        }
        if start[6] == needle {
            return Some((start[6..].as_ptr() as usize - ptr as usize) / 2);
        }
        if start[7] == needle {
            return Some((start[7..].as_ptr() as usize - ptr as usize) / 2);
        }

        start = &start[8..];
        len -= 8;
    }

    for (i, c) in start.iter().enumerate() {
        if *c == needle {
            return Some((start.as_ptr() as usize - ptr as usize) / 2 + i);
        }
    }
    None
}

pub fn to_u16s<S: AsRef<OsStr>>(s: S) -> crate::io::Result<Vec<u16>> {
    fn inner(s: &OsStr) -> crate::io::Result<Vec<u16>> {
        let mut maybe_result: Vec<u16> = s.encode_wide().collect();
        if unrolled_find_u16s(0, &maybe_result).is_some() {
            return Err(crate::io::Error::new(
                ErrorKind::InvalidInput,
                "strings passed to WinAPI cannot contain NULs",
            ));
        }
        maybe_result.push(0);
        Ok(maybe_result)
    }
    inner(s.as_ref())
}

// Many Windows APIs follow a pattern of where we hand a buffer and then they
// will report back to us how large the buffer should be or how many bytes
// currently reside in the buffer. This function is an abstraction over these
// functions by making them easier to call.
//
// The first callback, `f1`, is yielded a (pointer, len) pair which can be
// passed to a syscall. The `ptr` is valid for `len` items (u16 in this case).
// The closure is expected to return what the syscall returns which will be
// interpreted by this function to determine if the syscall needs to be invoked
// again (with more buffer space).
//
// Once the syscall has completed (errors bail out early) the second closure is
// yielded the data which has been read from the syscall. The return value
// from this closure is then the return value of the function.
fn fill_utf16_buf<F1, F2, T>(mut f1: F1, f2: F2) -> crate::io::Result<T>
where
    F1: FnMut(*mut u16, c::DWORD) -> c::DWORD,
    F2: FnOnce(&[u16]) -> T,
{
    // Start off with a stack buf but then spill over to the heap if we end up
    // needing more space.
    let mut stack_buf = [0u16; 512];
    let mut heap_buf = Vec::new();
    unsafe {
        let mut n = stack_buf.len();
        loop {
            let buf = if n <= stack_buf.len() {
                &mut stack_buf[..]
            } else {
                let extra = n - heap_buf.len();
                heap_buf.reserve(extra);
                heap_buf.set_len(n);
                &mut heap_buf[..]
            };

            // This function is typically called on windows API functions which
            // will return the correct length of the string, but these functions
            // also return the `0` on error. In some cases, however, the
            // returned "correct length" may actually be 0!
            //
            // To handle this case we call `SetLastError` to reset it to 0 and
            // then check it again if we get the "0 error value". If the "last
            // error" is still 0 then we interpret it as a 0 length buffer and
            // not an actual error.
            c::SetLastError(0);
            let k = match f1(buf.as_mut_ptr(), n as c::DWORD) {
                0 if c::GetLastError() == 0 => 0,
                0 => return Err(crate::io::Error::last_os_error()),
                n => n,
            } as usize;
            if k == n && c::GetLastError() == c::ERROR_INSUFFICIENT_BUFFER {
                n *= 2;
            } else if k >= n {
                n = k;
            } else {
                return Ok(f2(&buf[..k]));
            }
        }
    }
}

fn os2path(s: &[u16]) -> PathBuf {
    PathBuf::from(OsString::from_wide(s))
}

#[allow(dead_code)] // Only used in backtrace::gnu::get_executable_filename()
fn wide_char_to_multi_byte(
    code_page: u32,
    flags: u32,
    s: &[u16],
    no_default_char: bool,
) -> crate::io::Result<Vec<i8>> {
    unsafe {
        let mut size = c::WideCharToMultiByte(
            code_page,
            flags,
            s.as_ptr(),
            s.len() as i32,
            ptr::null_mut(),
            0,
            ptr::null(),
            ptr::null_mut(),
        );
        if size == 0 {
            return Err(crate::io::Error::last_os_error());
        }

        let mut buf = Vec::with_capacity(size as usize);
        buf.set_len(size as usize);

        let mut used_default_char = c::FALSE;
        size = c::WideCharToMultiByte(
            code_page,
            flags,
            s.as_ptr(),
            s.len() as i32,
            buf.as_mut_ptr(),
            buf.len() as i32,
            ptr::null(),
            if no_default_char { &mut used_default_char } else { ptr::null_mut() },
        );
        if size == 0 {
            return Err(crate::io::Error::last_os_error());
        }
        if no_default_char && used_default_char == c::TRUE {
            return Err(crate::io::Error::new(
                crate::io::ErrorKind::InvalidData,
                "string cannot be converted to requested code page",
            ));
        }

        buf.set_len(size as usize);

        Ok(buf)
    }
}

pub fn truncate_utf16_at_nul(v: &[u16]) -> &[u16] {
    match unrolled_find_u16s(0, v) {
        // don't include the 0
        Some(i) => &v[..i],
        None => v,
    }
}

pub trait IsZero {
    fn is_zero(&self) -> bool;
}

macro_rules! impl_is_zero {
    ($($t:ident)*) => ($(impl IsZero for $t {
        fn is_zero(&self) -> bool {
            *self == 0
        }
    })*)
}

impl_is_zero! { i8 i16 i32 i64 isize u8 u16 u32 u64 usize }

pub fn cvt<I: IsZero>(i: I) -> crate::io::Result<I> {
    if i.is_zero() { Err(crate::io::Error::last_os_error()) } else { Ok(i) }
}

pub fn dur2timeout(dur: Duration) -> c::DWORD {
    // Note that a duration is a (u64, u32) (seconds, nanoseconds) pair, and the
    // timeouts in windows APIs are typically u32 milliseconds. To translate, we
    // have two pieces to take care of:
    //
    // * Nanosecond precision is rounded up
    // * Greater than u32::MAX milliseconds (50 days) is rounded up to INFINITE
    //   (never time out).
    dur.as_secs()
        .checked_mul(1000)
        .and_then(|ms| ms.checked_add((dur.subsec_nanos() as u64) / 1_000_000))
        .and_then(|ms| ms.checked_add(if dur.subsec_nanos() % 1_000_000 > 0 { 1 } else { 0 }))
        .map(|ms| if ms > <c::DWORD>::max_value() as u64 { c::INFINITE } else { ms as c::DWORD })
        .unwrap_or(c::INFINITE)
}

// On Windows, use the processor-specific __fastfail mechanism.  In Windows 8
// and later, this will terminate the process immediately without running any
// in-process exception handlers.  In earlier versions of Windows, this
// sequence of instructions will be treated as an access violation,
// terminating the process but without necessarily bypassing all exception
// handlers.
//
// https://docs.microsoft.com/en-us/cpp/intrinsics/fastfail
#[allow(unreachable_code)]
pub unsafe fn abort_internal() -> ! {
    #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
    {
        llvm_asm!("int $$0x29" :: "{ecx}"(7) ::: volatile); // 7 is FAST_FAIL_FATAL_APP_EXIT
        crate::intrinsics::unreachable();
    }
    crate::intrinsics::abort();
}
<commit_msg>fix formatting issues that fail tidy test<commit_after>#![allow(missing_docs, nonstandard_style)]

use crate::ffi::{OsStr, OsString};
use crate::io::ErrorKind;
use crate::os::windows::ffi::{OsStrExt, OsStringExt};
use crate::path::PathBuf;
use crate::ptr;
use crate::time::Duration;

pub use self::rand::hashmap_random_keys;
pub use libc::strlen;

#[macro_use]
pub mod compat;

pub mod alloc;
pub mod args;
pub mod c;
pub mod cmath;
pub mod condvar;
pub mod env;
pub mod ext;
pub mod fast_thread_local;
pub mod fs;
pub mod handle;
pub mod io;
pub mod memchr;
pub mod mutex;
pub mod net;
pub mod os;
pub mod os_str;
pub mod path;
pub mod pipe;
pub mod process;
pub mod rand;
pub mod rwlock;
pub mod thread;
pub mod thread_local;
pub mod time;
cfg_if::cfg_if! {
    if #[cfg(not(target_vendor = "uwp"))] {
        pub mod stdio;
        pub mod stack_overflow;
    } else {
        pub mod stdio_uwp;
        pub mod stack_overflow_uwp;
        pub use self::stdio_uwp as stdio;
        pub use self::stack_overflow_uwp as stack_overflow;
    }
}

#[cfg(not(test))]
pub fn init() {}

pub fn decode_error_kind(errno: i32) -> ErrorKind {
    match errno as c::DWORD {
        c::ERROR_ACCESS_DENIED => return ErrorKind::PermissionDenied,
        c::ERROR_ALREADY_EXISTS => return ErrorKind::AlreadyExists,
        c::ERROR_FILE_EXISTS => return ErrorKind::AlreadyExists,
        c::ERROR_BROKEN_PIPE => return ErrorKind::BrokenPipe,
        c::ERROR_FILE_NOT_FOUND => return ErrorKind::NotFound,
        c::ERROR_PATH_NOT_FOUND => return ErrorKind::NotFound,
        c::ERROR_NO_DATA => return ErrorKind::BrokenPipe,
        c::ERROR_SEM_TIMEOUT
        | c::WAIT_TIMEOUT
        | c::ERROR_DRIVER_CANCEL_TIMEOUT
        | c::ERROR_OPERATION_ABORTED
        | c::ERROR_SERVICE_REQUEST_TIMEOUT
        | c::ERROR_COUNTER_TIMEOUT
        | c::ERROR_TIMEOUT
        | c::ERROR_RESOURCE_CALL_TIMED_OUT
        | c::ERROR_CTX_MODEM_RESPONSE_TIMEOUT
        | c::ERROR_CTX_CLIENT_QUERY_TIMEOUT
        | c::FRS_ERR_SYSVOL_POPULATE_TIMEOUT
        | c::ERROR_DS_TIMELIMIT_EXCEEDED
        | c::DNS_ERROR_RECORD_TIMED_OUT
        | c::ERROR_IPSEC_IKE_TIMED_OUT
        | c::ERROR_RUNLEVEL_SWITCH_TIMEOUT
        | c::ERROR_RUNLEVEL_SWITCH_AGENT_TIMEOUT => return ErrorKind::TimedOut,
        _ => {}
    }

    match errno {
        c::WSAEACCES => ErrorKind::PermissionDenied,
        c::WSAEADDRINUSE => ErrorKind::AddrInUse,
        c::WSAEADDRNOTAVAIL => ErrorKind::AddrNotAvailable,
        c::WSAECONNABORTED => ErrorKind::ConnectionAborted,
        c::WSAECONNREFUSED => ErrorKind::ConnectionRefused,
        c::WSAECONNRESET => ErrorKind::ConnectionReset,
        c::WSAEINVAL => ErrorKind::InvalidInput,
        c::WSAENOTCONN => ErrorKind::NotConnected,
        c::WSAEWOULDBLOCK => ErrorKind::WouldBlock,
        c::WSAETIMEDOUT => ErrorKind::TimedOut,

        _ => ErrorKind::Other,
    }
}

pub fn unrolled_find_u16s(needle: u16, haystack: &[u16]) -> Option<usize> {
    let ptr = haystack.as_ptr();
    let mut len = haystack.len();
    let mut start = &haystack[..];

    // For performance reasons unfold the loop eight times.
    while len >= 8 {
        if start[0] == needle {
            return Some((start.as_ptr() as usize - ptr as usize) / 2);
        }
        if start[1] == needle {
            return Some((start[1..].as_ptr() as usize - ptr as usize) / 2);
        }
        if start[2] == needle {
            return Some((start[2..].as_ptr() as usize - ptr as usize) / 2);
        }
        if start[3] == needle {
            return Some((start[3..].as_ptr() as usize - ptr as usize) / 2);
        }
        if start[4] == needle {
            return Some((start[4..].as_ptr() as usize - ptr as usize) / 2);
        }
        if start[5] == needle {
            return Some((start[5..].as_ptr() as usize - ptr as usize) / 2);
        }
        if start[6] == needle {
            return Some((start[6..].as_ptr() as usize - ptr as usize) / 2);
        }
        if start[7] == needle {
            return Some((start[7..].as_ptr() as usize - ptr as usize) / 2);
        }

        start = &start[8..];
        len -= 8;
    }

    for (i, c) in start.iter().enumerate() {
        if *c == needle {
            return Some((start.as_ptr() as usize - ptr as usize) / 2 + i);
        }
    }
    None
}

pub fn to_u16s<S: AsRef<OsStr>>(s: S) -> crate::io::Result<Vec<u16>> {
    fn inner(s: &OsStr) -> crate::io::Result<Vec<u16>> {
        let mut maybe_result: Vec<u16> = s.encode_wide().collect();
        if unrolled_find_u16s(0, &maybe_result).is_some() {
            return Err(crate::io::Error::new(
                ErrorKind::InvalidInput,
                "strings passed to WinAPI cannot contain NULs",
            ));
        }
        maybe_result.push(0);
        Ok(maybe_result)
    }
    inner(s.as_ref())
}

// Many Windows APIs follow a pattern of where we hand a buffer and then they
// will report back to us how large the buffer should be or how many bytes
// currently reside in the buffer. This function is an abstraction over these
// functions by making them easier to call.
//
// The first callback, `f1`, is yielded a (pointer, len) pair which can be
// passed to a syscall. The `ptr` is valid for `len` items (u16 in this case).
// The closure is expected to return what the syscall returns which will be
// interpreted by this function to determine if the syscall needs to be invoked
// again (with more buffer space).
//
// Once the syscall has completed (errors bail out early) the second closure is
// yielded the data which has been read from the syscall. The return value
// from this closure is then the return value of the function.
fn fill_utf16_buf<F1, F2, T>(mut f1: F1, f2: F2) -> crate::io::Result<T>
where
    F1: FnMut(*mut u16, c::DWORD) -> c::DWORD,
    F2: FnOnce(&[u16]) -> T,
{
    // Start off with a stack buf but then spill over to the heap if we end up
    // needing more space.
    let mut stack_buf = [0u16; 512];
    let mut heap_buf = Vec::new();
    unsafe {
        let mut n = stack_buf.len();
        loop {
            let buf = if n <= stack_buf.len() {
                &mut stack_buf[..]
            } else {
                let extra = n - heap_buf.len();
                heap_buf.reserve(extra);
                heap_buf.set_len(n);
                &mut heap_buf[..]
            };

            // This function is typically called on windows API functions which
            // will return the correct length of the string, but these functions
            // also return the `0` on error. In some cases, however, the
            // returned "correct length" may actually be 0!
            //
            // To handle this case we call `SetLastError` to reset it to 0 and
            // then check it again if we get the "0 error value". If the "last
            // error" is still 0 then we interpret it as a 0 length buffer and
            // not an actual error.
            c::SetLastError(0);
            let k = match f1(buf.as_mut_ptr(), n as c::DWORD) {
                0 if c::GetLastError() == 0 => 0,
                0 => return Err(crate::io::Error::last_os_error()),
                n => n,
            } as usize;
            if k == n && c::GetLastError() == c::ERROR_INSUFFICIENT_BUFFER {
                n *= 2;
            } else if k >= n {
                n = k;
            } else {
                return Ok(f2(&buf[..k]));
            }
        }
    }
}

fn os2path(s: &[u16]) -> PathBuf {
    PathBuf::from(OsString::from_wide(s))
}

#[allow(dead_code)] // Only used in backtrace::gnu::get_executable_filename()
fn wide_char_to_multi_byte(
    code_page: u32,
    flags: u32,
    s: &[u16],
    no_default_char: bool,
) -> crate::io::Result<Vec<i8>> {
    unsafe {
        let mut size = c::WideCharToMultiByte(
            code_page,
            flags,
            s.as_ptr(),
            s.len() as i32,
            ptr::null_mut(),
            0,
            ptr::null(),
            ptr::null_mut(),
        );
        if size == 0 {
            return Err(crate::io::Error::last_os_error());
        }

        let mut buf = Vec::with_capacity(size as usize);
        buf.set_len(size as usize);

        let mut used_default_char = c::FALSE;
        size = c::WideCharToMultiByte(
            code_page,
            flags,
            s.as_ptr(),
            s.len() as i32,
            buf.as_mut_ptr(),
            buf.len() as i32,
            ptr::null(),
            if no_default_char { &mut used_default_char } else { ptr::null_mut() },
        );
        if size == 0 {
            return Err(crate::io::Error::last_os_error());
        }
        if no_default_char && used_default_char == c::TRUE {
            return Err(crate::io::Error::new(
                crate::io::ErrorKind::InvalidData,
                "string cannot be converted to requested code page",
            ));
        }

        buf.set_len(size as usize);

        Ok(buf)
    }
}

pub fn truncate_utf16_at_nul(v: &[u16]) -> &[u16] {
    match unrolled_find_u16s(0, v) {
        // don't include the 0
        Some(i) => &v[..i],
        None => v,
    }
}

pub trait IsZero {
    fn is_zero(&self) -> bool;
}

macro_rules! impl_is_zero {
    ($($t:ident)*) => ($(impl IsZero for $t {
        fn is_zero(&self) -> bool {
            *self == 0
        }
    })*)
}

impl_is_zero! { i8 i16 i32 i64 isize u8 u16 u32 u64 usize }

pub fn cvt<I: IsZero>(i: I) -> crate::io::Result<I> {
    if i.is_zero() { Err(crate::io::Error::last_os_error()) } else { Ok(i) }
}

pub fn dur2timeout(dur: Duration) -> c::DWORD {
    // Note that a duration is a (u64, u32) (seconds, nanoseconds) pair, and the
    // timeouts in windows APIs are typically u32 milliseconds. To translate, we
    // have two pieces to take care of:
    //
    // * Nanosecond precision is rounded up
    // * Greater than u32::MAX milliseconds (50 days) is rounded up to INFINITE
    //   (never time out).
    dur.as_secs()
        .checked_mul(1000)
        .and_then(|ms| ms.checked_add((dur.subsec_nanos() as u64) / 1_000_000))
        .and_then(|ms| ms.checked_add(if dur.subsec_nanos() % 1_000_000 > 0 { 1 } else { 0 }))
        .map(|ms| if ms > <c::DWORD>::max_value() as u64 { c::INFINITE } else { ms as c::DWORD })
        .unwrap_or(c::INFINITE)
}

// On Windows, use the processor-specific __fastfail mechanism.  In Windows 8
// and later, this will terminate the process immediately without running any
// in-process exception handlers.  In earlier versions of Windows, this
// sequence of instructions will be treated as an access violation,
// terminating the process but without necessarily bypassing all exception
// handlers.
//
// https://docs.microsoft.com/en-us/cpp/intrinsics/fastfail
#[allow(unreachable_code)]
pub unsafe fn abort_internal() -> ! {
    #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
    {
        llvm_asm!("int $$0x29" :: "{ecx}"(7) ::: volatile); // 7 is FAST_FAIL_FATAL_APP_EXIT
        crate::intrinsics::unreachable();
    }
    crate::intrinsics::abort();
}
<|endoftext|>


<commit_before><commit_msg>Use fill_rect() instead of rect(); fill();<commit_after><|endoftext|>


<commit_before>/*!
Playing field.
*/

use ::std::{fmt, ops};
use ::std::str::{FromStr};

use ::{Player, Point};

pub const MAX_HEIGHT: usize = 22;
pub const MAX_WIDTH: usize = 16;

pub type Line = u16;

#[derive(Clone, Debug)]
pub struct Well {
	width: i16,
	height: i16,
	field: [Line; MAX_HEIGHT],
}

const MINOS_STR: &'static str = "□";

impl Well {
	/// Creates an empty well with the given dimensions.
	///
	/// # Panics
	///
	/// The width must be ∈ [4, 16] and the height must be ∈ [4, 22].
	pub fn new(width: i32, height: i32) -> Well {
		assert!(width >= 4 && width <= MAX_WIDTH as i32, "width must be ∈ [4, {}]", MAX_WIDTH);
		assert!(height >= 4 && height <= MAX_HEIGHT as i32, "height must be ∈ [4, {}]", MAX_HEIGHT);
		Well {
			width: width as i16,
			height: height as i16,
			field: [0; MAX_HEIGHT],
		}
	}
	/// Creates a new well with the given data.
	///
	///# Panics
	///
	/// No minos may be found outside the well's width.
	///
	///# Examples
	///
	/// ```
	///# use tetrs_core::Well;
	///let well = Well::from_data(10, &[
	///	0b0000110000,
	///	0b0111111001,
	///	0b0110111111,
	///	0b1111111111,
	///	0b1110111111,
	///	0b1111111111,
	///]);
	///assert_eq!(format!("{}", well), "\
	///	|    □□    |\n\
	///	| □□□□□□  □|\n\
	///	| □□ □□□□□□|\n\
	///	|□□□□□□□□□□|\n\
	///	|□□□ □□□□□□|\n\
	///	|□□□□□□□□□□|\n\
	///	+----------+");
	/// ```
	pub fn from_data(width: i32, lines: &[Line]) -> Well {
		let mut well = Well::new(width, lines.len() as i32);
		for (lhs, &rhs) in Iterator::zip(well.field[..lines.len()].iter_mut(), lines.iter().rev()) {
			let mut rhs = rhs;
			let mut line = 0;
			for _ in 0..width {
				line = (line << 1) | (rhs & 1);
				rhs >>= 1;
			}
			assert_eq!(0, rhs, "found minos outside the well's width");
			*lhs = line;
		}
		well
	}
	/// Returns the width of the well.
	pub fn width(&self) -> i32 {
		self.width as i32
	}
	/// Returns the height of the well.
	pub fn height(&self) -> i32 {
		self.height as i32
	}
	/// Returns the field as lines.
	pub fn lines(&self) -> &[Line] {
		&self.field[..self.height as usize]
	}
	pub fn lines_mut(&mut self) -> &mut [Line] {
		&mut self.field[..self.height as usize]
	}
	/// Hit tests the player against the field.
	///
	/// Returns `true` if the player is out of bounds left, right or below the well or if the piece overlaps with an occupied cell; `false` otheriwse.
	pub fn test(&self, player: &Player) -> bool {
		// Early reject out of bounds
		if player.pt.x < (0 - 4) || player.pt.x >= self.width() || player.pt.y < 0 {
			return true;
		}
		if player.pt.y >= self.height() + 4 {
			return false;
		}

		// Get the unperturbed mesh
		let mesh = player.piece.mesh().data[player.rot as u8 as usize];

		// For clipping left/right walls
		let line_mask = if player.pt.x < 0 { self.line_mask() << (-player.pt.x) as usize } else { self.line_mask() >> player.pt.x as usize };

		for y in 0..4 {
			// Check if part is sticking out of a wall
			if (mesh[y as usize] as Line) & !line_mask != 0 {
				return true;
			}
			let row = player.pt.y - y;
			// If this row is below the floor
			if row < 0 {
				if mesh[y as usize] != 0 {
					return true;
				}
			}
			// If this row is below the ceiling
			else if row < self.height() {
				// Render the mesh for this line
				let cg_line = if player.pt.x < 0 {
					(mesh[y as usize] as Line) >> (-player.pt.x) as usize
				}
				else {
					(mesh[y as usize] as Line) << player.pt.x as usize
				};
				if cg_line & self.field[row as usize] != 0 {
					return true;
				}
			}
		}
		return false;
	}
	/// Etch the player into the field.
	pub fn etch(&mut self, player: &Player) {
		// Grab the mesh for this rotation
		let mesh = player.piece.mesh().data[player.rot as u8 as usize];
		// Etch the 4x4 mask into the field
		for y in 0..4 {
			// Clip the affected row to the field
			let row = player.pt.y - y;
			if row >= 0 && row < self.height() {
				// Render the mesh for this line
				let cg_line = if player.pt.x < 0 {
					(mesh[y as usize] as Line) >> (-player.pt.x) as usize
				}
				else {
					(mesh[y as usize] as Line) << player.pt.x as usize
				};
				self.field[row as usize] |= cg_line;
			}
		}
	}
	/// Gets a line with all columns set.
	pub fn line_mask(&self) -> Line {
		(1 << self.width() as usize) - 1
	}
	/// Gets a line.
	pub fn line(&self, row: i32) -> Line {
		self.field[row as usize]
	}
	/// Sets a line.
	///
	/// Returns the erased line.
	pub fn set_line(&mut self, row: i32, line: Line) -> Line {
		let old = self.field[row as usize];
		self.field[row as usize] = line;
		old
	}
	/// Removes a line.
	///
	/// Returns the removed line.
	///
	/// The lines above the removed line are shifted down and an empty line is inserted at the top.
	pub fn remove_line(&mut self, row: i32) -> Line {
		let line = self.field[row as usize];
		for i in row as usize..MAX_HEIGHT - 1 {
			self.field[i] = self.field[i + 1];
		}
		line
	}
	/// Inserts a line.
	///
	/// The existing lines are shifted up and the top line that got bumped out is returned.
	pub fn insert_line(&mut self, row: i32, line: Line) -> Line {
		let old = self.field[self.height() as usize - 1];
		for i in (row as usize..self.height() as usize - 1).rev() {
			self.field[i + 1] = self.field[i];
		}
		self.field[row as usize] = line;
		old
	}
}

/// Set all the blocks in lhs that aren't set in rhs.
impl ops::Sub for Well {
	type Output = Well;
	fn sub(self, rhs: Well) -> Well {
		assert_eq!(self.width(), rhs.width());
		assert_eq!(self.height(), rhs.height());
		let mut result = Well::new(self.width(), self.height());
		for (result, (&lhs, &rhs)) in Iterator::zip(result.lines_mut().iter_mut(), Iterator::zip(self.lines().iter(), rhs.lines().iter())) {
			*result = lhs & !rhs;
		}
		result
	}
}

pub enum ParseWellError {
	/// The string is empty.
	Empty,
	/// The well has no walls.
	BadWalls,
	/// The well has inconsistent width.
	InWidth,
	/// The well is too wide.
	OutWidth,
	/// The well is too high.
	OutHeight,
}
impl FromStr for Well {
	type Err = ParseWellError;
	fn from_str(s: &str) -> Result<Well, ParseWellError> {
		let mut width = None;
		let mut height = 0;
		let mut field = [0; MAX_HEIGHT];

		for line in s.lines() {
			let line = line.trim_right();
			if line.len() < 3 {
				return Err(ParseWellError::BadWalls);
			}
			let bline = line.as_bytes();
			if bline[0] != b'|' || bline[bline.len() - 1] != b'|' {
				return Err(ParseWellError::BadWalls);
			}
			let mut w = 0;
			let mut row = 0;
			let line = &line[1..line.len() - 1];
			for c in line.chars() {
				let bit = if c == ' ' { 0 } else { 1 };
				row |= bit << w;
				w += 1;
				if w >= MAX_WIDTH {
					return Err(ParseWellError::OutWidth);
				}
			}

			if let Some(prev_width) = width {
				if prev_width != w {
					return Err(ParseWellError::InWidth);
				}
			}
			else {
				width = Some(w);
			}

			field[height] = row;

			height += 1;
			if height >= MAX_HEIGHT {
				return Err(ParseWellError::OutHeight);
			}
		}

		if let Some(width) = width {
			Ok(Well {
				width: width as i16,
				height: height as i16,
				field: field,
			})
		}
		else {
			return Err(ParseWellError::Empty);
		}
	}
}

impl fmt::Display for Well {
	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
		let mut bg = " ";
		for &row in self.field[0..self.height() as usize].iter().rev() {
			f.write_str("|")?;
			let mut mask = 0x1;
			for _ in 0..self.width() {
				let graphic = if (row & mask) != 0 { MINOS_STR } else { bg };
				f.write_str(graphic)?;
				mask <<= 1;
			}
			f.write_str("|\n")?;
			// if bg == " " {
			// 	bg = "_";
			// }
			// else if bg == "_" {
			// 	bg = ".";
			// }
		}
		f.write_str("+")?;
		for _ in 0..self.width() {
			f.write_str("-")?;
		}
		f.write_str("+")
	}
}

//----------------------------------------------------------------

#[cfg(test)]
mod tests {
	use super::*;
	use ::{Piece, Rot, Point};

	fn well() -> Well {
		let mut well = Well::new(10, 4);

		let p1 = Player::new(Piece::L, Rot::Zero, Point::new(2, 1));
		let p2 = Player::new(Piece::O, Rot::Zero, Point::new(-1, 2));
		let p3 = Player::new(Piece::I, Rot::One, Point::new(7, 3));

		well.etch(&p1);
		well.etch(&p2);
		well.etch(&p3);
		println!("\n{}", well);

		well
	}

	#[test]
	fn etch() {
		let well = well();
		assert_eq!("|         □|\n\
		            |         □|\n\
		            |□□   □   □|\n\
		            |□□ □□□   □|\n\
		            +----------+", format!("{}", well));
	}

	#[test]
	fn hit_test() {
		let well = well();
		// Within the field bounds
		assert!(!well.test(&Player::new(Piece::S, Rot::Zero, Point::new(-1, 3))));
		assert!(!well.test(&Player::new(Piece::J, Rot::Three, Point::new(5, 2))));
		// Clip left wall
		assert!(well.test(&Player::new(Piece::S, Rot::Zero, Point::new(-2, 3))));
		// Clip with existing pieces
		assert!(well.test(&Player::new(Piece::I, Rot::Two, Point::new(2, 3))));
		// Clip right wall
		assert!(well.test(&Player::new(Piece::O, Rot::One, Point::new(9, 1))));
		// Clip the bottom
		assert!(well.test(&Player::new(Piece::J, Rot::Three, Point::new(5, 1))));
	}

	#[test]
	fn remove_line() {
		let mut well = well();

		let removed1 = well.remove_line(3);
		assert_eq!(0b1000000000, removed1);
		assert_eq!("|          |\n\
		            |         □|\n\
		            |□□   □   □|\n\
		            |□□ □□□   □|\n\
		            +----------+", format!("{}", well));

		let removed2 = well.remove_line(0);
		assert_eq!(0b1000111011, removed2);
		assert_eq!("|          |\n\
		            |          |\n\
		            |         □|\n\
		            |□□   □   □|\n\
		            +----------+", format!("{}", well));
	}
}
<commit_msg>Try to document and test the `Well` code.<commit_after>/*!
Playing field.
*/

use ::std::{fmt, ops};
use ::std::str::{FromStr};

use ::{Player, Point};

pub const MAX_HEIGHT: usize = 22;
pub const MAX_WIDTH: usize = 16;

pub type Line = u16;

#[derive(Clone, Debug)]
pub struct Well {
	width: i16,
	height: i16,
	field: [Line; MAX_HEIGHT],
}

const MINOS_STR: &'static str = "□";

impl Well {
	/// Creates an empty well with the given dimensions.
	///
	/// # Panics
	///
	/// The width must be ∈ [4, 16] and the height must be ∈ [4, 22].
	pub fn new(width: i32, height: i32) -> Well {
		assert!(width >= 4 && width <= MAX_WIDTH as i32, "width must be ∈ [4, {}]", MAX_WIDTH);
		assert!(height >= 4 && height <= MAX_HEIGHT as i32, "height must be ∈ [4, {}]", MAX_HEIGHT);
		Well {
			width: width as i16,
			height: height as i16,
			field: [0; MAX_HEIGHT],
		}
	}
	/// Creates a new well with the given data.
	///
	/// # Panics
	///
	/// No minos may be found outside the well's width.
	///
	/// # Examples
	///
	/// ```
	/// # use tetrs_core::Well;
	/// let well = Well::from_data(10, &[
	/// 	0b0000110000,
	/// 	0b0111111001,
	/// 	0b0110111111,
	/// 	0b1111111111,
	/// 	0b1110111111,
	/// 	0b1111111111,
	/// ]);
	/// assert_eq!(format!("{}", well), "\
	/// 	|    □□    |\n\
	/// 	| □□□□□□  □|\n\
	/// 	| □□ □□□□□□|\n\
	/// 	|□□□□□□□□□□|\n\
	/// 	|□□□ □□□□□□|\n\
	/// 	|□□□□□□□□□□|\n\
	/// 	+----------+");
	/// ```
	pub fn from_data(width: i32, lines: &[Line]) -> Well {
		let mut well = Well::new(width, lines.len() as i32);
		for (lhs, &rhs) in Iterator::zip(well.field[..lines.len()].iter_mut(), lines.iter().rev()) {
			let mut rhs = rhs;
			let mut line = 0;
			for _ in 0..width {
				line = (line << 1) | (rhs & 1);
				rhs >>= 1;
			}
			assert_eq!(0, rhs, "found minos outside the well's width");
			*lhs = line;
		}
		well
	}
	/// Returns the width of the well.
	pub fn width(&self) -> i32 {
		self.width as i32
	}
	/// Returns the height of the well.
	pub fn height(&self) -> i32 {
		self.height as i32
	}
	/// Returns the field as lines.
	pub fn lines(&self) -> &[Line] {
		&self.field[..self.height as usize]
	}
	pub fn lines_mut(&mut self) -> &mut [Line] {
		&mut self.field[..self.height as usize]
	}
	/// Hit tests the player against the field.
	///
	/// Returns `true` if the player is out of bounds left, right or below the well or if the piece overlaps with an occupied cell; `false` otheriwse.
	pub fn test(&self, player: &Player) -> bool {
		// Early reject out of bounds
		if player.pt.x < (0 - 4) || player.pt.x >= self.width() || player.pt.y < 0 {
			return true;
		}
		if player.pt.y >= self.height() + 4 {
			return false;
		}

		// Get the unperturbed mesh
		let mesh = player.piece.mesh().data[player.rot as u8 as usize];

		// For clipping left/right walls
		let line_mask = if player.pt.x < 0 {
			self.line_mask() << (-player.pt.x) as usize
		}
		else {
			self.line_mask() >> player.pt.x as usize
		};

		for y in 0..4 {
			// Check if part is sticking out of a wall
			if (mesh[y as usize] as Line) & !line_mask != 0 {
				return true;
			}
			let row = player.pt.y - y;
			// If this row is below the floor
			if row < 0 {
				if mesh[y as usize] != 0 {
					return true;
				}
			}
			// If this row is below the ceiling
			else if row < self.height() {
				// Render the mesh for this line
				let cg_line = if player.pt.x < 0 {
					(mesh[y as usize] as Line) >> (-player.pt.x) as usize
				}
				else {
					(mesh[y as usize] as Line) << player.pt.x as usize
				};
				if cg_line & self.field[row as usize] != 0 {
					return true;
				}
			}
		}
		return false;
	}
	/// Etch the player into the field.
	pub fn etch(&mut self, player: &Player) {
		// Grab the mesh for this rotation
		let mesh = player.piece.mesh().data[player.rot as u8 as usize];
		// Etch the 4x4 mask into the field
		for y in 0..4 {
			// Clip the affected row to the field
			let row = player.pt.y - y;
			if row >= 0 && row < self.height() {
				// Render the mesh for this line
				let cg_line = if player.pt.x < 0 {
					(mesh[y as usize] as Line) >> (-player.pt.x) as usize
				}
				else {
					(mesh[y as usize] as Line) << player.pt.x as usize
				};
				self.field[row as usize] |= cg_line;
			}
		}
	}
	/// Gets a line with all columns set.
	pub fn line_mask(&self) -> Line {
		(1 << self.width() as usize) - 1
	}
	/// Gets a line.
	pub fn line(&self, row: i32) -> Line {
		self.field[row as usize]
	}
	/// Sets a line.
	///
	/// Returns the erased line.
	pub fn set_line(&mut self, row: i32, line: Line) -> Line {
		let old = self.field[row as usize];
		self.field[row as usize] = line;
		old
	}
	/// Removes a line.
	///
	/// Returns the removed line.
	///
	/// The lines above the removed line are shifted down and an empty line is inserted at the top.
	pub fn remove_line(&mut self, row: i32) -> Line {
		let line = self.field[row as usize];
		for i in row as usize..MAX_HEIGHT - 1 {
			self.field[i] = self.field[i + 1];
		}
		line
	}
	/// Inserts a line.
	///
	/// The existing lines are shifted up and the top line that got bumped out is returned.
	/*
	///
	/// # Examples
	///
	/// ```
	/// # use tetrs_core::Well;
	///
	/// let mut well = Well::from_data(10, &[
	/// 	0b0000100000,
	/// 	0b0110110001,
	/// 	0b1100100001,
	/// 	0b1111100011,
	/// ]);
	///
	/// assert_eq!(0b0000100000, well.insert_line(1, 0b1111000011));
	///
	/// assert_eq!(well.lines(), &[
	/// 	0b0110110001,
	/// 	0b1100100001,
	/// 	0b1111000011,
	/// 	0b1111100011,
	/// ]);
	/// ```
	*/
	pub fn insert_line(&mut self, row: i32, line: Line) -> Line {
		let old = self.field[self.height() as usize - 1];
		for i in (row as usize..self.height() as usize - 1).rev() {
			self.field[i + 1] = self.field[i];
		}
		self.field[row as usize] = line;
		old
	}
}

pub enum ParseWellError {
	/// The string is empty.
	Empty,
	/// The well has no walls.
	BadWalls,
	/// The well has inconsistent width.
	InWidth,
	/// The well is too wide.
	OutWidth,
	/// The well is too high.
	OutHeight,
}
impl FromStr for Well {
	type Err = ParseWellError;
	fn from_str(s: &str) -> Result<Well, ParseWellError> {
		let mut width = None;
		let mut height = 0;
		let mut field = [0; MAX_HEIGHT];

		for line in s.lines() {
			let line = line.trim_right();
			if line.len() < 3 {
				return Err(ParseWellError::BadWalls);
			}
			let bline = line.as_bytes();
			if bline[0] != b'|' || bline[bline.len() - 1] != b'|' {
				return Err(ParseWellError::BadWalls);
			}
			let mut w = 0;
			let mut row = 0;
			let line = &line[1..line.len() - 1];
			for c in line.chars() {
				let bit = if c == ' ' { 0 } else { 1 };
				row |= bit << w;
				w += 1;
				if w >= MAX_WIDTH {
					return Err(ParseWellError::OutWidth);
				}
			}

			if let Some(prev_width) = width {
				if prev_width != w {
					return Err(ParseWellError::InWidth);
				}
			}
			else {
				width = Some(w);
			}

			field[height] = row;

			height += 1;
			if height >= MAX_HEIGHT {
				return Err(ParseWellError::OutHeight);
			}
		}

		if let Some(width) = width {
			Ok(Well {
				width: width as i16,
				height: height as i16,
				field: field,
			})
		}
		else {
			return Err(ParseWellError::Empty);
		}
	}
}

impl fmt::Display for Well {
	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
		let mut bg = " ";
		for &row in self.field[0..self.height() as usize].iter().rev() {
			f.write_str("|")?;
			let mut mask = 0x1;
			for _ in 0..self.width() {
				let graphic = if (row & mask) != 0 { MINOS_STR } else { bg };
				f.write_str(graphic)?;
				mask <<= 1;
			}
			f.write_str("|\n")?;
			// if bg == " " {
			// 	bg = "_";
			// }
			// else if bg == "_" {
			// 	bg = ".";
			// }
		}
		f.write_str("+")?;
		for _ in 0..self.width() {
			f.write_str("-")?;
		}
		f.write_str("+")
	}
}

//----------------------------------------------------------------

#[cfg(test)]
mod tests {
	use super::*;
	use ::{Piece, Rot, Point};

	fn well() -> Well {
		let mut well = Well::new(10, 4);

		let p1 = Player::new(Piece::L, Rot::Zero, Point::new(2, 1));
		let p2 = Player::new(Piece::O, Rot::Zero, Point::new(-1, 2));
		let p3 = Player::new(Piece::I, Rot::One, Point::new(7, 3));

		well.etch(&p1);
		well.etch(&p2);
		well.etch(&p3);
		println!("\n{}", well);

		well
	}

	#[test]
	fn etch() {
		let well = well();
		assert_eq!("|         □|\n\
		            |         □|\n\
		            |□□   □   □|\n\
		            |□□ □□□   □|\n\
		            +----------+", format!("{}", well));
	}

	#[test]
	fn hit_test() {
		let well = well();
		// Within the field bounds
		assert!(!well.test(&Player::new(Piece::S, Rot::Zero, Point::new(-1, 3))));
		assert!(!well.test(&Player::new(Piece::J, Rot::Three, Point::new(5, 2))));
		// Clip left wall
		assert!(well.test(&Player::new(Piece::S, Rot::Zero, Point::new(-2, 3))));
		// Clip with existing pieces
		assert!(well.test(&Player::new(Piece::I, Rot::Two, Point::new(2, 3))));
		// Clip right wall
		assert!(well.test(&Player::new(Piece::O, Rot::One, Point::new(9, 1))));
		// Clip the bottom
		assert!(well.test(&Player::new(Piece::J, Rot::Three, Point::new(5, 1))));
	}

	#[test]
	fn remove_line() {
		let mut well = well();

		let removed1 = well.remove_line(3);
		assert_eq!(0b1000000000, removed1);
		assert_eq!("|          |\n\
		            |         □|\n\
		            |□□   □   □|\n\
		            |□□ □□□   □|\n\
		            +----------+", format!("{}", well));

		let removed2 = well.remove_line(0);
		assert_eq!(0b1000111011, removed2);
		assert_eq!("|          |\n\
		            |          |\n\
		            |         □|\n\
		            |□□   □   □|\n\
		            +----------+", format!("{}", well));
	}
}
<|endoftext|>


<commit_before>// Copyright 2016 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.

//! Check license of third-party deps by inspecting src/vendor

use std::fs::File;
use std::io::Read;
use std::path::Path;

static LICENSES: &'static [&'static str] = &[
    "MIT/Apache-2.0",
    "MIT / Apache-2.0",
    "Apache-2.0/MIT",
    "Apache-2.0 / MIT",
    "MIT OR Apache-2.0",
    "MIT",
    "Unlicense/MIT",
];

// These are exceptions to Rust's permissive licensing policy, and
// should be considered bugs. Exceptions are only allowed in Rust
// tooling. It is _crucial_ that no exception crates be dependencies
// of the Rust runtime (std / test).
static EXCEPTIONS: &'static [&'static str] = &[
    "mdbook", // MPL2, mdbook
    "openssl", // BSD+advertising clause, cargo, mdbook
    "pest", // MPL2, mdbook via handlebars
    "thread-id", // Apache-2.0, mdbook
];

pub fn check(path: &Path, bad: &mut bool) {
    let path = path.join("vendor");
    assert!(path.exists(), "vendor directory missing");
    let mut saw_dir = false;
    'next_path: for dir in t!(path.read_dir()) {
        saw_dir = true;
        let dir = t!(dir);

        // skip our exceptions
        for exception in EXCEPTIONS {
            if dir.path()
                .to_str()
                .unwrap()
                .contains(&format!("src/vendor/{}", exception)) {
                continue 'next_path;
            }
        }

        let toml = dir.path().join("Cargo.toml");
        if !check_license(&toml) {
            *bad = true;
        }
    }
    assert!(saw_dir, "no vendored source");
}

fn check_license(path: &Path) -> bool {
    if !path.exists() {
        panic!("{} does not exist", path.display());
    }
    let mut contents = String::new();
    t!(t!(File::open(path)).read_to_string(&mut contents));

    let mut found_license = false;
    for line in contents.lines() {
        if !line.starts_with("license") {
            continue;
        }
        let license = extract_license(line);
        if !LICENSES.contains(&&*license) {
            println!("invalid license {} in {}", license, path.display());
            return false;
        }
        found_license = true;
        break;
    }
    if !found_license {
        println!("no license in {}", path.display());
        return false;
    }

    true
}

fn extract_license(line: &str) -> String {
    let first_quote = line.find('"');
    let last_quote = line.rfind('"');
    if let (Some(f), Some(l)) = (first_quote, last_quote) {
        let license = &line[f + 1 .. l];
        license.into()
    } else {
        "bad-license-parse".into()
    }
}
<commit_msg>Add license exceptions<commit_after>// Copyright 2016 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.

//! Check license of third-party deps by inspecting src/vendor

use std::fs::File;
use std::io::Read;
use std::path::Path;

static LICENSES: &'static [&'static str] = &[
    "MIT/Apache-2.0",
    "MIT / Apache-2.0",
    "Apache-2.0/MIT",
    "Apache-2.0 / MIT",
    "MIT OR Apache-2.0",
    "MIT",
    "Unlicense/MIT",
];

// These are exceptions to Rust's permissive licensing policy, and
// should be considered bugs. Exceptions are only allowed in Rust
// tooling. It is _crucial_ that no exception crates be dependencies
// of the Rust runtime (std / test).
static EXCEPTIONS: &'static [&'static str] = &[
    "mdbook", // MPL2, mdbook
    "openssl", // BSD+advertising clause, cargo, mdbook
    "pest", // MPL2, mdbook via handlebars
    "thread-id", // Apache-2.0, mdbook
    "cssparser", // MPL-2.0, rustdoc
    "smallvec", // MPL-2.0, rustdoc
    "magenta-sys", // BSD-3-Clause, rustdoc
    "magenta", // BSD-3-Clause, rustdoc
    "cssparser-macros", // MPL-2.0, rustdoc
    "selectors", // MPL-2.0, rustdoc
];

pub fn check(path: &Path, bad: &mut bool) {
    let path = path.join("vendor");
    assert!(path.exists(), "vendor directory missing");
    let mut saw_dir = false;
    'next_path: for dir in t!(path.read_dir()) {
        saw_dir = true;
        let dir = t!(dir);

        // skip our exceptions
        for exception in EXCEPTIONS {
            if dir.path()
                .to_str()
                .unwrap()
                .contains(&format!("src/vendor/{}", exception)) {
                continue 'next_path;
            }
        }

        let toml = dir.path().join("Cargo.toml");
        if !check_license(&toml) {
            *bad = true;
        }
    }
    assert!(saw_dir, "no vendored source");
}

fn check_license(path: &Path) -> bool {
    if !path.exists() {
        panic!("{} does not exist", path.display());
    }
    let mut contents = String::new();
    t!(t!(File::open(path)).read_to_string(&mut contents));

    let mut found_license = false;
    for line in contents.lines() {
        if !line.starts_with("license") {
            continue;
        }
        let license = extract_license(line);
        if !LICENSES.contains(&&*license) {
            println!("invalid license {} in {}", license, path.display());
            return false;
        }
        found_license = true;
        break;
    }
    if !found_license {
        println!("no license in {}", path.display());
        return false;
    }

    true
}

fn extract_license(line: &str) -> String {
    let first_quote = line.find('"');
    let last_quote = line.rfind('"');
    if let (Some(f), Some(l)) = (first_quote, last_quote) {
        let license = &line[f + 1 .. l];
        license.into()
    } else {
        "bad-license-parse".into()
    }
}
<|endoftext|>


<commit_before>use std::rc::*;
use super::treenode::*;

///
/// Trait implemented by types that can work as a tree node index
///
pub trait TreeNodeIndex : Sized {
    ///
    /// Finds the tree node corresponding to the specified index in the tree
    ///
    fn lookup_index<'a, T: TreeNode>(&'a self, parent_node: &'a T) -> Option<&Rc<TreeNode>>;
}

impl TreeNodeIndex for usize {
    ///
    /// Finds the tree node corresponding to the specified index in the tree
    ///
    fn lookup_index<'a, T: TreeNode>(&'a self, parent_node: &'a T) -> Option<&Rc<TreeNode>> {
        let mut pos = *self;
        let mut current_child = parent_node.get_child_ref().to_owned();

        loop {
            match current_child {
                None        => return None,
                Some(child) => {
                    if pos == 0 { return current_child; }

                    pos = pos-1;
                    current_child = child.get_sibling_ref().to_owned();
                }
            }
        }
    }
}

///
/// Provides the ability to reference the children of a tree node by looking up a particular index
///
pub trait TreeNodeLookup : TreeNode {
    ///
    /// Looks up a child node at a particular index (panics if the child does not exist)
    ///
    fn get_child_at<TIndex: TreeNodeIndex>(&self, index: TIndex) -> &TreeNode;
}

impl<T: TreeNode> TreeNodeLookup for T {
    ///
    /// Looks up a child node at a particular index (panics if the child does not exist)
    ///
    fn get_child_at<TIndex: TreeNodeIndex>(&self, index: TIndex) -> &TreeNode {
        let opt_node = index.lookup_index(self);
        let node_ref = opt_node.unwrap();

        &**node_ref
    }
}

/*
impl<TIndex: TreeNodeIndex> Index<TIndex> for TreeNode {
    type Output = TreeNode;

    fn index<'a>(&'a self, index: TIndex) -> &'a TreeNode {
        let opt_node = index.lookup_index(self);
        let node_ref = opt_node.unwrap();

        &**node_ref
    }
}
*/

#[cfg(test)]
mod treenode_index_tests {
    use super::super::values::*;
    use super::super::treenode::*;
    use super::super::basictree::*;
    use std::rc::*;

    #[test]
    fn can_get_first_child() {
        let mut tree = BasicTree::new("test", ());
        let first_child = Rc::new(BasicTree::new("first_child", ()));

        tree.set_child_ref(first_child);

        assert!(tree.get_child_at(0).is_some());
        assert!((tree.get_child_at(0).unwrap().get_tag()) == "child");
        assert!(tree.get_sibling_ref().is_none());
    }
}
<commit_msg>Try the static lifetime? Rust determined to continue to be incomprehensible.<commit_after>use std::rc::*;
use super::treenode::*;

///
/// Trait implemented by types that can work as a tree node index
///
pub trait TreeNodeIndex {
    ///
    /// Finds the tree node corresponding to the specified index in the tree
    ///
    fn lookup_index<T: TreeNode>(&'static self, parent_node: &'static T) -> Option<&Rc<TreeNode>>;
}

impl TreeNodeIndex for usize {
    ///
    /// Finds the tree node corresponding to the specified index in the tree
    ///
    fn lookup_index<T: TreeNode>(&'static self, parent_node: &'static T) -> Option<&Rc<TreeNode>> {
        let mut pos = *self;
        let mut current_child = parent_node.get_child_ref().to_owned();

        loop {
            match current_child {
                None        => return None,
                Some(child) => {
                    if pos == 0 { return current_child; }

                    pos = pos-1;
                    current_child = child.get_sibling_ref().to_owned();
                }
            }
        }
    }
}

///
/// Provides the ability to reference the children of a tree node by looking up a particular index
///
pub trait TreeNodeLookup : TreeNode {
    ///
    /// Looks up a child node at a particular index (panics if the child does not exist)
    ///
    fn get_child_at<TIndex: TreeNodeIndex>(&'static self, index: TIndex) -> &TreeNode where TIndex: 'static;
}

impl<T: TreeNode> TreeNodeLookup for T {
    ///
    /// Looks up a child node at a particular index (panics if the child does not exist)
    ///
    fn get_child_at<TIndex: TreeNodeIndex>(&'static self, index: TIndex) -> &TreeNode where TIndex: 'static {
        let opt_node = index.lookup_index(self);
        let node_ref = opt_node.unwrap();

        &**node_ref
    }
}

/*
impl<TIndex: TreeNodeIndex> Index<TIndex> for TreeNode {
    type Output = TreeNode;

    fn index<'a>(&'a self, index: TIndex) -> &'a TreeNode {
        let opt_node = index.lookup_index(self);
        let node_ref = opt_node.unwrap();

        &**node_ref
    }
}
*/

#[cfg(test)]
mod treenode_index_tests {
    use super::super::values::*;
    use super::super::treenode::*;
    use super::super::basictree::*;
    use std::rc::*;

    #[test]
    fn can_get_first_child() {
        let mut tree = BasicTree::new("test", ());
        let first_child = Rc::new(BasicTree::new("first_child", ()));

        tree.set_child_ref(first_child);

        assert!(tree.get_child_at(0).is_some());
        assert!((tree.get_child_at(0).unwrap().get_tag()) == "child");
        assert!(tree.get_sibling_ref().is_none());
    }
}
<|endoftext|>


<commit_before>extern crate thread_id;

mod html;

use std::cell::{RefCell};
use std::rc::Rc;
use std::time::{Instant};
use std::collections::BTreeMap;
use std::marker::PhantomData;

pub type SpanPtr = RefCell<Span>;
thread_local!(static THREAD_FRAME: RefCell<ThreadFrame> = RefCell::new(ThreadFrame::new()));

struct ThreadFrame {
    epoch: Instant,
    root: Rc<SpanPtr>,
    events: Vec<Event>,
}

struct Event {
    name: &'static str,
    start_ns: u64,
    span: Rc<SpanPtr>,
}

pub struct Span {
    value: u64,
    count: u64,
    children: BTreeMap<&'static str, Rc<SpanPtr>>
}

impl Event {
    fn new(name:&'static str, timestamp: u64, span: Rc<SpanPtr>) -> Event {
        Event {
            name: name,
            start_ns: timestamp,
            span: span
        }
    }
}

impl ThreadFrame {

    fn new() -> ThreadFrame {
        let root = Span::new();
        let epoch = Instant::now();
        ThreadFrame {
            epoch: epoch,
            root: root.clone(),
            events: vec![Event::new("Self", ns_since_epoch(epoch), root)],
        }
    }

    fn start_span(&mut self, name: &'static str) {
        let timestamp = ns_since_epoch(self.epoch);
        let span = Span::sub_span(&self.events[self.events.len()-1].span, name);
        self.events.push(Event::new(name, timestamp, span));
    }

    fn end_span(&mut self) {
        let timestamp = ns_since_epoch(self.epoch);
        let event = self.events.pop().expect("ThreadFrame::end_span() called events.pop() without a currently running span!");
        let current = event.span;
        // dump self span
        {
            let mut aspan = current.borrow_mut();
            aspan.value += timestamp - event.start_ns;
            aspan.count += 1;
        }
    }

}

fn ns_since_epoch(epoch: Instant) -> u64 {
    let elapsed = epoch.elapsed();
    elapsed.as_secs() * 1000_000_000 + elapsed.subsec_nanos() as u64
}

impl Span {

    fn new() -> Rc<SpanPtr> {
        Rc::new(RefCell::new(Span {
            value: 0,
            count: 0,
            children: BTreeMap::new()
        }))
    }

    fn sub_span(this: &Rc<SpanPtr>, name: &'static str) -> Rc<SpanPtr> {
        let mut parent = this.borrow_mut();
        let  aspan = parent.children.entry(name)
                                     .or_insert_with(|| Span::new());
        aspan.clone()
    }
}

#[cfg(not(feature="nomock"))]
fn start(name: &'static str) {

}

#[cfg(not(feature="nomock"))]
fn end() {

}

#[cfg(feature="nomock")]
fn start(name: &'static str) {
    THREAD_FRAME.with(|thread| thread.borrow_mut().start_span(name));
}

#[cfg(feature="nomock")]
fn end() {
    THREAD_FRAME.with(|thread| thread.borrow_mut().end_span());
}

fn spans() -> Rc<SpanPtr> {
    THREAD_FRAME.with(|library| {
        let library = library.borrow();

        let root = library.root.clone();
        root.borrow_mut().value = ns_since_epoch(library.epoch) - library.events[0].start_ns;
        root
    })
}

#[macro_export]
macro_rules! profiler_span{
    ($name:expr, $val:expr) => {
        {
            let _p = $crate::ProfilerSpan::new($name);
            let r = $val;
            drop(_p);
            r
        }
    }
}

#[macro_export]
macro_rules! profiler_next_span{
    ($name:expr) => {
            $crate::end();
            $crate::start($name);
    }
}

pub struct ProfilerSpan<'a> {
    name: &'static str,
    _phantom: PhantomData<&'a ()>
}

impl<'a> Drop for ProfilerSpan<'a> {
    fn drop(&mut self) {
        end();
    }
}

impl<'scope> ProfilerSpan<'scope> {

    pub fn new(name: &'static str) -> ProfilerSpan<'static> {
        start(name);
        ProfilerSpan {
            name: name,
            _phantom:PhantomData
        }
    }

    pub fn next_span(& mut self, name: &'static str) {
        end();
        self.name = name;
        start(self.name);
    }

    pub fn sub_span<'smaller>(&'smaller mut self, name: &'static str) -> ProfilerSpan<'smaller>
    where 'scope: 'smaller {
        ProfilerSpan::new(name)
    }
}

pub use html::dump_html;<commit_msg>fix warnings in profiler<commit_after>#![allow(dead_code)]
#![allow(unused_variables)]
extern crate thread_id;

mod html;

use std::cell::{RefCell};
use std::rc::Rc;
use std::time::{Instant};
use std::collections::BTreeMap;
use std::marker::PhantomData;

pub type SpanPtr = RefCell<Span>;
thread_local!(static THREAD_FRAME: RefCell<ThreadFrame> = RefCell::new(ThreadFrame::new()));

struct ThreadFrame {
    epoch: Instant,
    root: Rc<SpanPtr>,
    events: Vec<Event>,
}

struct Event {
    name: &'static str,
    start_ns: u64,
    span: Rc<SpanPtr>,
}

pub struct Span {
    value: u64,
    count: u64,
    children: BTreeMap<&'static str, Rc<SpanPtr>>
}

impl Event {
    fn new(name:&'static str, timestamp: u64, span: Rc<SpanPtr>) -> Event {
        Event {
            name: name,
            start_ns: timestamp,
            span: span
        }
    }
}

impl ThreadFrame {

    fn new() -> ThreadFrame {
        let root = Span::new();
        let epoch = Instant::now();
        ThreadFrame {
            epoch: epoch,
            root: root.clone(),
            events: vec![Event::new("Self", ns_since_epoch(epoch), root)],
        }
    }

    fn start_span(&mut self, name: &'static str) {
        let timestamp = ns_since_epoch(self.epoch);
        let span = Span::sub_span(&self.events[self.events.len()-1].span, name);
        self.events.push(Event::new(name, timestamp, span));
    }

    fn end_span(&mut self) {
        let timestamp = ns_since_epoch(self.epoch);
        let event = self.events.pop().expect("ThreadFrame::end_span() called events.pop() without a currently running span!");
        let current = event.span;
        // dump self span
        {
            let mut aspan = current.borrow_mut();
            aspan.value += timestamp - event.start_ns;
            aspan.count += 1;
        }
    }

}

fn ns_since_epoch(epoch: Instant) -> u64 {
    let elapsed = epoch.elapsed();
    elapsed.as_secs() * 1000_000_000 + elapsed.subsec_nanos() as u64
}

impl Span {

    fn new() -> Rc<SpanPtr> {
        Rc::new(RefCell::new(Span {
            value: 0,
            count: 0,
            children: BTreeMap::new()
        }))
    }

    fn sub_span(this: &Rc<SpanPtr>, name: &'static str) -> Rc<SpanPtr> {
        let mut parent = this.borrow_mut();
        let  aspan = parent.children.entry(name)
                                     .or_insert_with(|| Span::new());
        aspan.clone()
    }
}

#[cfg(not(feature="nomock"))]
fn start(name: &'static str) {

}

#[cfg(not(feature="nomock"))]
fn end() {

}

#[cfg(feature="nomock")]
fn start(name: &'static str) {
    THREAD_FRAME.with(|thread| thread.borrow_mut().start_span(name));
}

#[cfg(feature="nomock")]
fn end() {
    THREAD_FRAME.with(|thread| thread.borrow_mut().end_span());
}

fn spans() -> Rc<SpanPtr> {
    THREAD_FRAME.with(|library| {
        let library = library.borrow();

        let root = library.root.clone();
        root.borrow_mut().value = ns_since_epoch(library.epoch) - library.events[0].start_ns;
        root
    })
}

#[macro_export]
macro_rules! profiler_span{
    ($name:expr, $val:expr) => {
        {
            let _p = $crate::ProfilerSpan::new($name);
            let r = $val;
            drop(_p);
            r
        }
    }
}

#[macro_export]
macro_rules! profiler_next_span{
    ($name:expr) => {
            $crate::end();
            $crate::start($name);
    }
}

pub struct ProfilerSpan<'a> {
    name: &'static str,
    _phantom: PhantomData<&'a ()>
}

impl<'a> Drop for ProfilerSpan<'a> {
    fn drop(&mut self) {
        end();
    }
}

impl<'scope> ProfilerSpan<'scope> {

    pub fn new(name: &'static str) -> ProfilerSpan<'static> {
        start(name);
        ProfilerSpan {
            name: name,
            _phantom:PhantomData
        }
    }

    pub fn next_span(& mut self, name: &'static str) {
        end();
        self.name = name;
        start(self.name);
    }

    pub fn sub_span<'smaller>(&'smaller mut self, name: &'static str) -> ProfilerSpan<'smaller>
    where 'scope: 'smaller {
        ProfilerSpan::new(name)
    }
}

pub use html::dump_html;<|endoftext|>