<commit_before>use std::fmt::{Debug, Display, Formatter};
use std::fmt;

use regex::Regex;

pub mod id;
pub mod id_type;
pub mod header;
pub mod hash;

use storage::file::id::*;
use self::header::data::*;

/**
 * Internal abstract view on a file. Does not neccessarily exist on the FS and is just kept
 * internally until it is written to disk.
 */
pub struct File {
    /// The name of the module which owns this file
    pub owning_module_name  : &'static str,

    /// The header of the file
    pub header              : FileHeaderData,

    /// The content part of the file
    pub data                : String,

    /// The ID of the file
    pub id                  : FileID,
}

impl File {

    /**
     * Get the owner module name of the file
     */
    pub fn owner_name(&self) -> &'static str {
        self.owning_module_name
    }

    /**
     * Get the header of the file
     */
    pub fn header(&self) -> &FileHeaderData {
        &self.header
    }

    /**
     * Set the header of the file
     */
    pub fn set_header(&mut self, new_header: FileHeaderData) {
        self.header = new_header;
    }

    /**
     * Set the data of the file
     */
    pub fn data(&self) -> &String {
        &self.data
    }

    /**
     * Set the (header, data) of the file
     */
    pub fn contents(&self) -> (&FileHeaderData, &String) {
        (self.header(), self.data())
    }

    /**
     * Set the id of the file
     */
    pub fn id(&self) -> &FileID {
        &self.id
    }

    /**
     * Check whether the header or the data of the file match some regex
     */
    pub fn matches_with(&self, r: &Regex) -> bool {
        r.is_match(&self.data[..]) || self.header.matches_with(r)
    }

}

impl Display for File {

    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        try!(write!(fmt,
"[File] Owner : '{:?}'
        FileID: '{:?}'
        Header: '{:?}'
        Data  : '{:?}'",
               self.owning_module_name,
               self.header,
               self.data,
               self.id));
        Ok(())
    }

}

impl Debug for File {

    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        try!(write!(fmt,
"[File] Owner : '{:?}'
        FileID: '{:?}'
        Header: '{:?}'
        Data  : '{:?}'",
               self.owning_module_name,
               self.id,
               self.header,
               self.data));
        Ok(())
    }

}

#[cfg(test)]
mod test {
    // we use the JSON parser here, so we can generate FileHeaderData
    use storage::json::parser::JsonHeaderParser;
    use storage::file::header::match_header_spec;
    use storage::parser::{FileHeaderParser, ParserError};
    use storage::file::header::data::FileHeaderData as FHD;
    use storage::file::header::spec::FileHeaderSpec as FHS;

    #[test]
    fn test_spec_matching() {
        let text = String::from("{\"a\": 1, \"b\": -2}");
        let spec = FHS::Map {
            keys: vec![
                FHS::Key {
                    name: String::from("a"),
                    value_type: Box::new(FHS::UInteger)
                },
                FHS::Key {
                    name: String::from("b"),
                    value_type: Box::new(FHS::Integer)
                }
            ]
        };

        let parser  = JsonHeaderParser::new(Some(spec.clone()));
        let datares = parser.read(Some(text.clone()));
        assert!(datares.is_ok(), "Text could not be parsed: '{}'", text);
        let data = datares.unwrap();

        let matchres = match_header_spec(&spec, &data);
        assert!(matchres.is_none(), "Matching returns error: {:?}", matchres);
    }
}

<commit_msg>Add File::set_data()<commit_after>use std::fmt::{Debug, Display, Formatter};
use std::fmt;

use regex::Regex;

pub mod id;
pub mod id_type;
pub mod header;
pub mod hash;

use storage::file::id::*;
use self::header::data::*;

/**
 * Internal abstract view on a file. Does not neccessarily exist on the FS and is just kept
 * internally until it is written to disk.
 */
pub struct File {
    /// The name of the module which owns this file
    pub owning_module_name  : &'static str,

    /// The header of the file
    pub header              : FileHeaderData,

    /// The content part of the file
    pub data                : String,

    /// The ID of the file
    pub id                  : FileID,
}

impl File {

    /**
     * Get the owner module name of the file
     */
    pub fn owner_name(&self) -> &'static str {
        self.owning_module_name
    }

    /**
     * Get the header of the file
     */
    pub fn header(&self) -> &FileHeaderData {
        &self.header
    }

    /**
     * Set the header of the file
     */
    pub fn set_header(&mut self, new_header: FileHeaderData) {
        self.header = new_header;
    }

    /**
     * Set the data of the file
     */
    pub fn data(&self) -> &String {
        &self.data
    }

    /**
     * Set the data
     */
    pub fn set_data(&mut self, new_data: String) {
        self.data = new_data;
    }

    /**
     * Set the (header, data) of the file
     */
    pub fn contents(&self) -> (&FileHeaderData, &String) {
        (self.header(), self.data())
    }

    /**
     * Set the id of the file
     */
    pub fn id(&self) -> &FileID {
        &self.id
    }

    /**
     * Check whether the header or the data of the file match some regex
     */
    pub fn matches_with(&self, r: &Regex) -> bool {
        r.is_match(&self.data[..]) || self.header.matches_with(r)
    }

}

impl Display for File {

    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        try!(write!(fmt,
"[File] Owner : '{:?}'
        FileID: '{:?}'
        Header: '{:?}'
        Data  : '{:?}'",
               self.owning_module_name,
               self.header,
               self.data,
               self.id));
        Ok(())
    }

}

impl Debug for File {

    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        try!(write!(fmt,
"[File] Owner : '{:?}'
        FileID: '{:?}'
        Header: '{:?}'
        Data  : '{:?}'",
               self.owning_module_name,
               self.id,
               self.header,
               self.data));
        Ok(())
    }

}

#[cfg(test)]
mod test {
    // we use the JSON parser here, so we can generate FileHeaderData
    use storage::json::parser::JsonHeaderParser;
    use storage::file::header::match_header_spec;
    use storage::parser::{FileHeaderParser, ParserError};
    use storage::file::header::data::FileHeaderData as FHD;
    use storage::file::header::spec::FileHeaderSpec as FHS;

    #[test]
    fn test_spec_matching() {
        let text = String::from("{\"a\": 1, \"b\": -2}");
        let spec = FHS::Map {
            keys: vec![
                FHS::Key {
                    name: String::from("a"),
                    value_type: Box::new(FHS::UInteger)
                },
                FHS::Key {
                    name: String::from("b"),
                    value_type: Box::new(FHS::Integer)
                }
            ]
        };

        let parser  = JsonHeaderParser::new(Some(spec.clone()));
        let datares = parser.read(Some(text.clone()));
        assert!(datares.is_ok(), "Text could not be parsed: '{}'", text);
        let data = datares.unwrap();

        let matchres = match_header_spec(&spec, &data);
        assert!(matchres.is_none(), "Matching returns error: {:?}", matchres);
    }
}

<|endoftext|>


<commit_before>//! See https://github.com/matklad/cargo-xtask/.
//!
//! This binary defines various auxiliary build commands, which are not
//! expressible with just `cargo`. Notably, it provides `cargo xtask codegen`
//! for code generation and `cargo xtask install` for installation of
//! rust-analyzer server and client.
//!
//! This binary is integrated into the `cargo` command line by using an alias in
//! `.cargo/config`.

use std::env;

use codegen::CodegenCmd;
use pico_args::Arguments;
use xshell::pushd;
use xtask::{
    codegen::{self, Mode},
    dist::DistCmd,
    install::{InstallCmd, Malloc, ServerOpt},
    metrics::MetricsCmd,
    pre_cache::PreCacheCmd,
    pre_commit, project_root,
    release::{PromoteCmd, ReleaseCmd},
    run_clippy, run_fuzzer, run_rustfmt, Result,
};

fn main() -> Result<()> {
    if env::args().next().map(|it| it.contains("pre-commit")) == Some(true) {
        return pre_commit::run_hook();
    }

    let _d = pushd(project_root())?;

    let mut args = Arguments::from_env();
    let subcommand = args.subcommand()?.unwrap_or_default();

    match subcommand.as_str() {
        "install" => {
            if args.contains(["-h", "--help"]) {
                eprintln!(
                    "\
cargo xtask install
Install rust-analyzer server or editor plugin.

USAGE:
    cargo xtask install [FLAGS]

FLAGS:
        --client[=CLIENT] Install only VS Code plugin.
                          CLIENT is one of 'code', 'code-insiders', 'codium', or 'code-oss'
        --server          Install only the language server
        --mimalloc        Use mimalloc for server
    -h, --help            Prints help information
        "
                );
                return Ok(());
            }
            let server = args.contains("--server");
            let client_code = args.contains("--client");
            if server && client_code {
                eprintln!(
                    "error: The argument `--server` cannot be used with `--client`\n\n\
                     For more information try --help"
                );
                return Ok(());
            }

            let malloc =
                if args.contains("--mimalloc") { Malloc::Mimalloc } else { Malloc::System };

            let client_opt = args.opt_value_from_str("--client")?;

            args.finish()?;

            InstallCmd {
                client: if server { None } else { Some(client_opt.unwrap_or_default()) },
                server: if client_code { None } else { Some(ServerOpt { malloc }) },
            }
            .run()
        }
        "codegen" => {
            let features = args.contains("--features");
            args.finish()?;
            CodegenCmd { features }.run()
        }
        "format" => {
            args.finish()?;
            run_rustfmt(Mode::Overwrite)
        }
        "install-pre-commit-hook" => {
            args.finish()?;
            pre_commit::install_hook()
        }
        "lint" => {
            args.finish()?;
            run_clippy()
        }
        "fuzz-tests" => {
            args.finish()?;
            run_fuzzer()
        }
        "pre-cache" => {
            args.finish()?;
            PreCacheCmd.run()
        }
        "release" => {
            let dry_run = args.contains("--dry-run");
            args.finish()?;
            ReleaseCmd { dry_run }.run()
        }
        "promote" => {
            let dry_run = args.contains("--dry-run");
            args.finish()?;
            PromoteCmd { dry_run }.run()
        }
        "dist" => {
            let nightly = args.contains("--nightly");
            let client_version: Option<String> = args.opt_value_from_str("--client")?;
            args.finish()?;
            DistCmd { nightly, client_version }.run()
        }
        "metrics" => {
            let dry_run = args.contains("--dry-run");
            args.finish()?;
            MetricsCmd { dry_run }.run()
        }
        _ => {
            eprintln!(
                "\
cargo xtask
Run custom build command.

USAGE:
    cargo xtask <SUBCOMMAND>

SUBCOMMANDS:
    format
    install-pre-commit-hook
    fuzz-tests
    codegen
    install
    lint
    dist
    promote"
            );
            Ok(())
        }
    }
}
<commit_msg>Update usage string to include code-exploration client.<commit_after>//! See https://github.com/matklad/cargo-xtask/.
//!
//! This binary defines various auxiliary build commands, which are not
//! expressible with just `cargo`. Notably, it provides `cargo xtask codegen`
//! for code generation and `cargo xtask install` for installation of
//! rust-analyzer server and client.
//!
//! This binary is integrated into the `cargo` command line by using an alias in
//! `.cargo/config`.

use std::env;

use codegen::CodegenCmd;
use pico_args::Arguments;
use xshell::pushd;
use xtask::{
    codegen::{self, Mode},
    dist::DistCmd,
    install::{InstallCmd, Malloc, ServerOpt},
    metrics::MetricsCmd,
    pre_cache::PreCacheCmd,
    pre_commit, project_root,
    release::{PromoteCmd, ReleaseCmd},
    run_clippy, run_fuzzer, run_rustfmt, Result,
};

fn main() -> Result<()> {
    if env::args().next().map(|it| it.contains("pre-commit")) == Some(true) {
        return pre_commit::run_hook();
    }

    let _d = pushd(project_root())?;

    let mut args = Arguments::from_env();
    let subcommand = args.subcommand()?.unwrap_or_default();

    match subcommand.as_str() {
        "install" => {
            if args.contains(["-h", "--help"]) {
                eprintln!(
                    "\
cargo xtask install
Install rust-analyzer server or editor plugin.

USAGE:
    cargo xtask install [FLAGS]

FLAGS:
        --client[=CLIENT] Install only VS Code plugin.
                          CLIENT is one of 'code', 'code-exploration', 'code-insiders', 'codium', or 'code-oss'
        --server          Install only the language server
        --mimalloc        Use mimalloc for server
    -h, --help            Prints help information
        "
                );
                return Ok(());
            }
            let server = args.contains("--server");
            let client_code = args.contains("--client");
            if server && client_code {
                eprintln!(
                    "error: The argument `--server` cannot be used with `--client`\n\n\
                     For more information try --help"
                );
                return Ok(());
            }

            let malloc =
                if args.contains("--mimalloc") { Malloc::Mimalloc } else { Malloc::System };

            let client_opt = args.opt_value_from_str("--client")?;

            args.finish()?;

            InstallCmd {
                client: if server { None } else { Some(client_opt.unwrap_or_default()) },
                server: if client_code { None } else { Some(ServerOpt { malloc }) },
            }
            .run()
        }
        "codegen" => {
            let features = args.contains("--features");
            args.finish()?;
            CodegenCmd { features }.run()
        }
        "format" => {
            args.finish()?;
            run_rustfmt(Mode::Overwrite)
        }
        "install-pre-commit-hook" => {
            args.finish()?;
            pre_commit::install_hook()
        }
        "lint" => {
            args.finish()?;
            run_clippy()
        }
        "fuzz-tests" => {
            args.finish()?;
            run_fuzzer()
        }
        "pre-cache" => {
            args.finish()?;
            PreCacheCmd.run()
        }
        "release" => {
            let dry_run = args.contains("--dry-run");
            args.finish()?;
            ReleaseCmd { dry_run }.run()
        }
        "promote" => {
            let dry_run = args.contains("--dry-run");
            args.finish()?;
            PromoteCmd { dry_run }.run()
        }
        "dist" => {
            let nightly = args.contains("--nightly");
            let client_version: Option<String> = args.opt_value_from_str("--client")?;
            args.finish()?;
            DistCmd { nightly, client_version }.run()
        }
        "metrics" => {
            let dry_run = args.contains("--dry-run");
            args.finish()?;
            MetricsCmd { dry_run }.run()
        }
        _ => {
            eprintln!(
                "\
cargo xtask
Run custom build command.

USAGE:
    cargo xtask <SUBCOMMAND>

SUBCOMMANDS:
    format
    install-pre-commit-hook
    fuzz-tests
    codegen
    install
    lint
    dist
    promote"
            );
            Ok(())
        }
    }
}
<|endoftext|>


<commit_before>use backend::{self, Arguments, ReadDirError, ScanDir, Season, tokenizer, DRY_RUN};

use gdk::enums::key;
use gtk::prelude::*;
use gtk::{
    self, Builder, Button, Entry, FileChooserDialog, ListStore,
    SpinButton, TreeView, TreeViewColumn, Type, Window, WindowType
};
use std::fs;
use std::path::{Path, PathBuf};
use tvdb;

/// Allow drag-and-drop support in the directory entry text field by fixing the URI generated by dropped files.
#[inline]
fn parse_directory(directory: &str) -> String {
    let mut output = String::from(directory);
    if output.starts_with("file://") {
        output = output.replace("file://", "");
        output = output.replace("%20", " ");
        output = output.replace("\n", "");
        output = output.replace("\r", "");
    }
    output
}

pub fn interface() {
    gtk::init().unwrap_or_else(|_| panic!("tv-renamer: failed to initialize GTK."));

    // Open the Glade GTK UI and import key GTK objects from the UI.
    let builder = Builder::new_from_string(include_str!("gtk_interface.glade"));
    let window: Window                  = builder.get_object("main_window").unwrap();
    let preview_button: Button          = builder.get_object("preview_button").unwrap();
    let rename_button: Button           = builder.get_object("rename_button").unwrap();
    let series_name_entry: Entry        = builder.get_object("series_name_entry").unwrap();
    let series_directory_entry: Entry   = builder.get_object("series_directory_entry").unwrap();
    let template_entry: Entry           = builder.get_object("template_entry").unwrap();
    let series_directory_button: Button = builder.get_object("series_directory_button").unwrap();
    let episode_spin_button: SpinButton = builder.get_object("episode_spin_button").unwrap();
    let season_spin_button: SpinButton  = builder.get_object("season_spin_button").unwrap();
    let preview_tree: TreeView          = builder.get_object("preview_tree").unwrap();
    let info_bar: gtk::InfoBar          = builder.get_object("info_bar").unwrap();
    let info_button: Button             = builder.get_object("info_close").unwrap();
    let notification_label: gtk::Label  = builder.get_object("notification_label").unwrap();

    // TreeView's List Store
    // Link these up to the preview_tree and then start renaming
    let preview_list = ListStore::new(&[Type::String, Type::String]);

    // A simple macro for adding a column to the preview tree.
    macro_rules! add_column {
        ($preview_tree:ident, $title:expr, $id:expr) => {{
            let column   = TreeViewColumn::new();
            let renderer = gtk::CellRendererText::new();
            column.set_title($title);
            column.set_resizable(true);
            column.pack_start(&renderer, true);
            column.add_attribute(&renderer, "text", $id);
            preview_tree.append_column(&column);
        }}
    }

    // Create and append the Before column to the preview tree
    add_column!(preview_tree, "Before", 0);
    add_column!(preview_tree, "After", 1);

    // Connect the preview_list to the preview tree
    preview_tree.set_model(Some(&preview_list));
    preview_tree.set_headers_visible(true);

    // A simple macro that is shared among all widgets that trigger the action to either
    // update the preview or rename the TV series.
    macro_rules! rename_action {
        ($widget:ident, $dry_run:ident, $dialog:ident) => {{
            let $widget             = $widget.clone();
            let season_spin_button  = season_spin_button.clone();
            let episode_spin_button = episode_spin_button.clone();
            let series_entry        = series_name_entry.clone();
            let directory_entry     = series_directory_entry.clone();
            let preview_list        = preview_list.clone();
            let info_bar            = info_bar.clone();
            let notification_label  = notification_label.clone();
            let template_entry      = template_entry.clone();
            $widget.connect_clicked(move |_| {
                if $dialog {
                    // Open file chooser dialog to modify series_directory_entry.
                    let dialog = FileChooserDialog::new (
                        Some("Choose Directory"),
                        Some(&Window::new(WindowType::Popup)),
                        gtk::FileChooserAction::SelectFolder,
                    );
                    dialog.add_button("Cancel", gtk::ResponseType::Cancel.into());
                    dialog.add_button("Select", gtk::ResponseType::Ok.into());

                    if dialog.run() == gtk::ResponseType::Ok.into() {
                        dialog.get_filename().map(|path| path.to_str().map(|text| directory_entry.set_text(text)));
                    }
                    dialog.destroy();
                }
                if let Some(directory) = directory_entry.get_text() {
                    let mut program = &mut Arguments {
                        flags:          if $dry_run { DRY_RUN } else { 0 },
                        base_directory: parse_directory(&directory),
                        series_name:    series_entry.get_text().unwrap_or_default(),
                        season_index:   season_spin_button.get_value_as_int() as u8,
                        episode_index:  episode_spin_button.get_value_as_int() as u16,
                        pad_length:     2,
                        template:       tokenizer::tokenize_template(template_entry.get_text().unwrap().as_str())
                    };

                    if program.series_name.is_empty() {
                        program.series_name = String::from(Path::new(&program.base_directory)
                            .file_name().unwrap().to_str().unwrap());
                        series_entry.set_text(program.series_name.as_str());
                    }

                    if !program.base_directory.is_empty() {
                        rename_series(&program, &preview_list, &info_bar, &notification_label);
                    }
                }
            });
        }}
    }

    // All of the widgets that implement the rename action.
    rename_action!(preview_button, true, false);
    rename_action!(series_directory_button, true, true);
    rename_action!(rename_button, false, false);

    { // Hide the Info Bar when the Info Bar is closed
        let info_bar = info_bar.clone();
        info_button.connect_clicked(move |_| {
            info_bar.hide();
        });
    }

    window.show_all();
    info_bar.hide();

    // Quit the program when the program has been exited
    window.connect_delete_event(|_, _| {
        gtk::main_quit();
        Inhibit(false)
    });

    // Define custom actions on keypress
    window.connect_key_press_event(move |_, key| {
        if let key::Escape = key.get_keyval() { gtk::main_quit() }
        gtk::Inhibit(false)
    });

    gtk::main();
}

/// Attempt to rename all of the seasons within a given series
fn rename_series(args: &Arguments, preview_list: &ListStore, info_bar: &gtk::InfoBar, notification_label: &gtk::Label) {
    preview_list.clear();
    match backend::scan_directory(&args.base_directory, args.season_index) {
        Ok(ScanDir::Episodes(season)) => {
            match rename_season(&season, args.episode_index, args, preview_list) {
                Ok(_) => {
                    if args.flags & DRY_RUN != 0 { return }
                    info_bar.set_message_type(gtk::MessageType::Info);
                    notification_label.set_text("Rename Success");
                },
                Err(why) => match_rename_error(info_bar, notification_label, why, args)
            }
        },
        Ok(ScanDir::Seasons(seasons))  => {
            for season in seasons {
                match rename_season(&season, 1, args, preview_list) {
                    Ok(_) => {
                        if args.flags & DRY_RUN != 0 { return }
                        info_bar.set_message_type(gtk::MessageType::Info);
                        notification_label.set_text("Rename Success");
                    },
                    Err(why) => {
                        match_rename_error(info_bar, notification_label, why, args);
                        break
                    }
                }
            }
        },
        Err(why) => {
            info_bar.set_message_type(gtk::MessageType::Error);
            notification_label.set_text(match why {
                ReadDirError::UnableToReadDir => "Unable to read directory",
                ReadDirError::InvalidDirEntry => "Directory entry is invalid",
                ReadDirError::MimeFileErr     => "Unable to open /etc/mime.types",
                ReadDirError::MimeStringErr   => "Unable to read /etc/mime.types to string"
            });
        }
    }
    info_bar.show();
}

/// If a rename error occurs, write the message to the `InfoBar`.
fn match_rename_error(info_bar: &gtk::InfoBar, notification_label: &gtk::Label, why: RenameErr, args: &Arguments) {
    info_bar.set_message_type(gtk::MessageType::Error);
    let message = match why {
        RenameErr::RenameFailed(source, target) => format!("Could not rename {:?} to {:?}", source, target),
        RenameErr::TargetExists(path)           => format!("{:?} already exists", path),
        RenameErr::EpisodeDoesNotExist(episode) => format!("Episode {} could not be found on TheTVDB", episode),
        RenameErr::SeriesLookupFailed           => format!("{} could not be found on TheTVDB", &args.series_name)
    };
    notification_label.set_text(message.as_str());
}

enum RenameErr {
    TargetExists(PathBuf),
    RenameFailed(PathBuf, PathBuf),
    EpisodeDoesNotExist(u16),
    SeriesLookupFailed
}

/// Renames a given season and updates the preview for each episode renamed.
/// If executed with `arguments.dry_run` set to true, the preview will be updated but the files will not be renamed.
fn rename_season(season: &Season, episode_no: u16, arguments: &Arguments, preview_list: &ListStore)
    -> Result<(), RenameErr>
{
    let mut episode_no = episode_no;

    // TVDB
    let api = tvdb::Tvdb::new("0629B785CE550C8D");
    let series_id = api.search(&arguments.series_name, "en").map_err(|_| RenameErr::SeriesLookupFailed)?[0].seriesid;

    for source in &season.episodes {
        let target = backend::collect_target(source, season.season_no, episode_no, arguments, &api, series_id)
            .map_err(|_| RenameErr::EpisodeDoesNotExist(episode_no))?;
        if target.exists() { return Err(RenameErr::TargetExists(source.clone())); }
        update_preview(preview_list, source, &target);
        if arguments.flags & DRY_RUN == 0 {
            fs::rename(&source, &target).map_err(|_| RenameErr::RenameFailed(source.clone(), target))?;
        }
        episode_no += 1;
    }
    Ok(()) // Rename success
}

#[inline]
/// Appends an episode to the preview list
fn update_preview(preview_list: &ListStore, source: &Path, target: &Path) {
    let src = source.components().last().unwrap().as_os_str().to_str().unwrap().to_string();
    let trg = target.components().last().unwrap().as_os_str().to_str().unwrap().to_string();
    preview_list.insert_with_values(None, &[0, 1], &[&src, &trg]);
}
<commit_msg>Fix missing WM_CLASS<commit_after>use backend::{self, Arguments, ReadDirError, ScanDir, Season, tokenizer, DRY_RUN};

use gdk::enums::key;
use gtk::prelude::*;
use gtk::{
    self, Builder, Button, Entry, FileChooserDialog, ListStore,
    SpinButton, TreeView, TreeViewColumn, Type, Window, WindowType
};
use std::fs;
use std::path::{Path, PathBuf};
use tvdb;

/// Allow drag-and-drop support in the directory entry text field by fixing the URI generated by dropped files.
#[inline]
fn parse_directory(directory: &str) -> String {
    let mut output = String::from(directory);
    if output.starts_with("file://") {
        output = output.replace("file://", "");
        output = output.replace("%20", " ");
        output = output.replace("\n", "");
        output = output.replace("\r", "");
    }
    output
}

pub fn interface() {
    gtk::init().unwrap_or_else(|_| panic!("tv-renamer: failed to initialize GTK."));

    // Open the Glade GTK UI and import key GTK objects from the UI.
    let builder = Builder::new_from_string(include_str!("gtk_interface.glade"));
    let window: Window                  = builder.get_object("main_window").unwrap();
    let preview_button: Button          = builder.get_object("preview_button").unwrap();
    let rename_button: Button           = builder.get_object("rename_button").unwrap();
    let series_name_entry: Entry        = builder.get_object("series_name_entry").unwrap();
    let series_directory_entry: Entry   = builder.get_object("series_directory_entry").unwrap();
    let template_entry: Entry           = builder.get_object("template_entry").unwrap();
    let series_directory_button: Button = builder.get_object("series_directory_button").unwrap();
    let episode_spin_button: SpinButton = builder.get_object("episode_spin_button").unwrap();
    let season_spin_button: SpinButton  = builder.get_object("season_spin_button").unwrap();
    let preview_tree: TreeView          = builder.get_object("preview_tree").unwrap();
    let info_bar: gtk::InfoBar          = builder.get_object("info_bar").unwrap();
    let info_button: Button             = builder.get_object("info_close").unwrap();
    let notification_label: gtk::Label  = builder.get_object("notification_label").unwrap();

    // TreeView's List Store
    // Link these up to the preview_tree and then start renaming
    let preview_list = ListStore::new(&[Type::String, Type::String]);

    // A simple macro for adding a column to the preview tree.
    macro_rules! add_column {
        ($preview_tree:ident, $title:expr, $id:expr) => {{
            let column   = TreeViewColumn::new();
            let renderer = gtk::CellRendererText::new();
            column.set_title($title);
            column.set_resizable(true);
            column.pack_start(&renderer, true);
            column.add_attribute(&renderer, "text", $id);
            preview_tree.append_column(&column);
        }}
    }

    // Create and append the Before column to the preview tree
    add_column!(preview_tree, "Before", 0);
    add_column!(preview_tree, "After", 1);

    // Connect the preview_list to the preview tree
    preview_tree.set_model(Some(&preview_list));
    preview_tree.set_headers_visible(true);

    // A simple macro that is shared among all widgets that trigger the action to either
    // update the preview or rename the TV series.
    macro_rules! rename_action {
        ($widget:ident, $dry_run:ident, $dialog:ident) => {{
            let $widget             = $widget.clone();
            let season_spin_button  = season_spin_button.clone();
            let episode_spin_button = episode_spin_button.clone();
            let series_entry        = series_name_entry.clone();
            let directory_entry     = series_directory_entry.clone();
            let preview_list        = preview_list.clone();
            let info_bar            = info_bar.clone();
            let notification_label  = notification_label.clone();
            let template_entry      = template_entry.clone();
            $widget.connect_clicked(move |_| {
                if $dialog {
                    // Open file chooser dialog to modify series_directory_entry.
                    let dialog = FileChooserDialog::new (
                        Some("Choose Directory"),
                        Some(&Window::new(WindowType::Popup)),
                        gtk::FileChooserAction::SelectFolder,
                    );
                    dialog.add_button("Cancel", gtk::ResponseType::Cancel.into());
                    dialog.add_button("Select", gtk::ResponseType::Ok.into());

                    if dialog.run() == gtk::ResponseType::Ok.into() {
                        dialog.get_filename().map(|path| path.to_str().map(|text| directory_entry.set_text(text)));
                    }
                    dialog.destroy();
                }
                if let Some(directory) = directory_entry.get_text() {
                    let mut program = &mut Arguments {
                        flags:          if $dry_run { DRY_RUN } else { 0 },
                        base_directory: parse_directory(&directory),
                        series_name:    series_entry.get_text().unwrap_or_default(),
                        season_index:   season_spin_button.get_value_as_int() as u8,
                        episode_index:  episode_spin_button.get_value_as_int() as u16,
                        pad_length:     2,
                        template:       tokenizer::tokenize_template(template_entry.get_text().unwrap().as_str())
                    };

                    if program.series_name.is_empty() {
                        program.series_name = String::from(Path::new(&program.base_directory)
                            .file_name().unwrap().to_str().unwrap());
                        series_entry.set_text(program.series_name.as_str());
                    }

                    if !program.base_directory.is_empty() {
                        rename_series(&program, &preview_list, &info_bar, &notification_label);
                    }
                }
            });
        }}
    }

    // All of the widgets that implement the rename action.
    rename_action!(preview_button, true, false);
    rename_action!(series_directory_button, true, true);
    rename_action!(rename_button, false, false);

    { // Hide the Info Bar when the Info Bar is closed
        let info_bar = info_bar.clone();
        info_button.connect_clicked(move |_| {
            info_bar.hide();
        });
    }

    // Fix WM_CLASS
    window.set_wmclass ("tv-renamer", "Tv-renamer");

    window.show_all();
    info_bar.hide();

    // Quit the program when the program has been exited
    window.connect_delete_event(|_, _| {
        gtk::main_quit();
        Inhibit(false)
    });

    // Define custom actions on keypress
    window.connect_key_press_event(move |_, key| {
        if let key::Escape = key.get_keyval() { gtk::main_quit() }
        gtk::Inhibit(false)
    });

    gtk::main();
}

/// Attempt to rename all of the seasons within a given series
fn rename_series(args: &Arguments, preview_list: &ListStore, info_bar: &gtk::InfoBar, notification_label: &gtk::Label) {
    preview_list.clear();
    match backend::scan_directory(&args.base_directory, args.season_index) {
        Ok(ScanDir::Episodes(season)) => {
            match rename_season(&season, args.episode_index, args, preview_list) {
                Ok(_) => {
                    if args.flags & DRY_RUN != 0 { return }
                    info_bar.set_message_type(gtk::MessageType::Info);
                    notification_label.set_text("Rename Success");
                },
                Err(why) => match_rename_error(info_bar, notification_label, why, args)
            }
        },
        Ok(ScanDir::Seasons(seasons))  => {
            for season in seasons {
                match rename_season(&season, 1, args, preview_list) {
                    Ok(_) => {
                        if args.flags & DRY_RUN != 0 { return }
                        info_bar.set_message_type(gtk::MessageType::Info);
                        notification_label.set_text("Rename Success");
                    },
                    Err(why) => {
                        match_rename_error(info_bar, notification_label, why, args);
                        break
                    }
                }
            }
        },
        Err(why) => {
            info_bar.set_message_type(gtk::MessageType::Error);
            notification_label.set_text(match why {
                ReadDirError::UnableToReadDir => "Unable to read directory",
                ReadDirError::InvalidDirEntry => "Directory entry is invalid",
                ReadDirError::MimeFileErr     => "Unable to open /etc/mime.types",
                ReadDirError::MimeStringErr   => "Unable to read /etc/mime.types to string"
            });
        }
    }
    info_bar.show();
}

/// If a rename error occurs, write the message to the `InfoBar`.
fn match_rename_error(info_bar: &gtk::InfoBar, notification_label: &gtk::Label, why: RenameErr, args: &Arguments) {
    info_bar.set_message_type(gtk::MessageType::Error);
    let message = match why {
        RenameErr::RenameFailed(source, target) => format!("Could not rename {:?} to {:?}", source, target),
        RenameErr::TargetExists(path)           => format!("{:?} already exists", path),
        RenameErr::EpisodeDoesNotExist(episode) => format!("Episode {} could not be found on TheTVDB", episode),
        RenameErr::SeriesLookupFailed           => format!("{} could not be found on TheTVDB", &args.series_name)
    };
    notification_label.set_text(message.as_str());
}

enum RenameErr {
    TargetExists(PathBuf),
    RenameFailed(PathBuf, PathBuf),
    EpisodeDoesNotExist(u16),
    SeriesLookupFailed
}

/// Renames a given season and updates the preview for each episode renamed.
/// If executed with `arguments.dry_run` set to true, the preview will be updated but the files will not be renamed.
fn rename_season(season: &Season, episode_no: u16, arguments: &Arguments, preview_list: &ListStore)
    -> Result<(), RenameErr>
{
    let mut episode_no = episode_no;

    // TVDB
    let api = tvdb::Tvdb::new("0629B785CE550C8D");
    let series_id = api.search(&arguments.series_name, "en").map_err(|_| RenameErr::SeriesLookupFailed)?[0].seriesid;

    for source in &season.episodes {
        let target = backend::collect_target(source, season.season_no, episode_no, arguments, &api, series_id)
            .map_err(|_| RenameErr::EpisodeDoesNotExist(episode_no))?;
        if target.exists() { return Err(RenameErr::TargetExists(source.clone())); }
        update_preview(preview_list, source, &target);
        if arguments.flags & DRY_RUN == 0 {
            fs::rename(&source, &target).map_err(|_| RenameErr::RenameFailed(source.clone(), target))?;
        }
        episode_no += 1;
    }
    Ok(()) // Rename success
}

#[inline]
/// Appends an episode to the preview list
fn update_preview(preview_list: &ListStore, source: &Path, target: &Path) {
    let src = source.components().last().unwrap().as_os_str().to_str().unwrap().to_string();
    let trg = target.components().last().unwrap().as_os_str().to_str().unwrap().to_string();
    preview_list.insert_with_values(None, &[0, 1], &[&src, &trg]);
}
<|endoftext|>


<commit_before>
#![allow(non_snake_case)]

use game::entity::{Entity, UID, EEntityType, EntityController};
use cgmath::Vector3;
use game::world::World;
use graphics::renderer::RenderFrame;
use graphics::square_renderer::SquareRenderData;
use rand;
use rand::distributions::{IndependentSample, Range};

type Vec2 = (i8, i8);

#[derive(Copy, Clone)]
pub enum TetrominoType {
    Line,
    Sqaure,
    Tee,
    El,
    S,
    Z
}

impl TetrominoType {
    pub fn offsets(&self) -> Vec<Vec2> {
        match *self {
            TetrominoType::Line => {
                return vec![
                    (0, 0),
                    (0, 1),
                    (0, 2),
                    (0, 3)
                ];
            },
            TetrominoType::Sqaure => {
                return vec![
                    (0, 0),
                    (1, 0),
                    (0, 1),
                    (1, 1)
                ];
            },
            TetrominoType::Tee => {
                return vec![
                    (0, 0),
                    (1, 0),
                    (-1, 0),
                    (0, 1)
                ];
            },
            TetrominoType::El => {
                return vec![
                    (0, 0),
                    (1, 0),
                    (1, 1),
                    (1, 2)
                ];
            },
            TetrominoType::S => {
                return vec![
                    (0, 0),
                    (-1, 0),
                    (0, 1),
                    (1, 1)
                ];
            },
            TetrominoType::Z => {
                return vec![
                    (0, 0),
                    (1, 0),
                    (0, 1),
                    (-1, 1)
                ];
            }
        }
    }

    pub fn from_usize(index: usize) -> Option<TetrominoType> {

        if index >= 6 {
            return None;
        }
        else {
            match index {
                0 => {
                    Some(TetrominoType::Line)
                },
                1 => {
                    Some(TetrominoType::Sqaure)
                },
                2 => {
                    Some(TetrominoType::Tee)
                },
                3 => {
                    Some(TetrominoType::El)
                },
                4 => {
                    Some(TetrominoType::S)
                },
                5 => {
                    Some(TetrominoType::Z)
                },
                _ => {
                    None
                }
            }
        }
    }
}

pub struct TetrisBlockController {
    pub uid: UID,
    pub current_cluster: Vec<UID>,
    pub frame_count: u16,
    pub tetris_frame: [[Option<UID>; 10]; 20],
    pub rng_pool: rand::ThreadRng,
    pub current_cluster_pos: Vec<Vec2>,
    pub spawn_pos: Vec2
}

impl<'a>TetrisBlockController {

    pub fn new(uid: UID) -> TetrisBlockController {
        TetrisBlockController {
            uid,
            current_cluster: vec![],
            frame_count: 0u16,
            tetris_frame: [[None; 10]; 20],
            rng_pool: rand::thread_rng(),
            current_cluster_pos: vec![],
            spawn_pos: (5, 0)
        }
    }

    pub fn genererate_and_place_next_tetris_block(&mut self, inner_world: &mut World){

        let color_v = Range::new(0.0f32, 1.0f32);
        let index = Range::new(0usize, 6usize);
        let index = index.ind_sample(&mut self.rng_pool);
        let offsets = TetrominoType::from_usize(index).unwrap().offsets();

        let color : [f32; 4] = [color_v.ind_sample(&mut self.rng_pool),//r
                                color_v.ind_sample(&mut self.rng_pool),//g
                                color_v.ind_sample(&mut self.rng_pool), //b
                                255.0f32];//a

        for offset in offsets {
            let pos = Vector3::new(100.0f32 * (offset.0 as f32), 550f32 - (100f32 * -offset.1 as f32), 250f32);
            let tbm = TetrisBlockModel::new(pos, color, 0u64);
            let new_uid = inner_world.set_uid_for_entity(Box::new(tbm));
            self.tetris_frame[(self.spawn_pos.1 + offset.1) as usize][(self.spawn_pos.0 + offset.0) as usize] = Some(new_uid);
            self.current_cluster_pos.push((self.spawn_pos.0 + offset.0, self.spawn_pos.1 + offset.1));
        }
  }

    pub fn generate_next_positions_for_cluster(&self) -> Option<Vec<Vec2>> {
        let mut new_pos : Vec<Vec2> = vec![];
        for pos in &self.current_cluster_pos {
            let new_y = pos.1 + 1;
            if new_y < 0 || new_y > 19{
                return None;
            }

            new_pos.push((pos.0, new_y));
        }
        return Some(new_pos);
    }

    pub fn finish_with_current_cluster(&mut self) {
        self.current_cluster_pos.truncate(0);
    }

    pub fn are_unoccupied_and_not_me(&self, posistions: Vec<Vec2>) -> bool {

        for pos in posistions {
            if self.tetris_frame[pos.1 as usize][pos.0 as usize] != None {
                if !self.current_cluster_pos.contains(&pos) {
                    return false;
                }
            }
        }

        return true;
    }

}

impl EntityController for TetrisBlockController {

    fn get_uid(&self) -> UID {
        self.uid
    }

    fn update(&self, _world: &World) ->  Option<Box<Fn(&mut World, &mut EntityController)>> {

         let return_closure = move |inner_world: &mut World, controller: &mut EntityController| {

            let tbc =  unsafe { &mut *(controller as *mut EntityController as *mut TetrisBlockController) };

            if tbc.current_cluster_pos.len() == 0 {
                //if we have no current cluster, create and place a new one
                tbc.genererate_and_place_next_tetris_block(inner_world);
            }
            else {

                tbc.frame_count = tbc.frame_count + 1u16;

                if tbc.frame_count == 60u16 {

                    let next_pos = tbc.generate_next_positions_for_cluster();

                    match next_pos {
                        Some(next_pos) => {

                            let are_clear = tbc.are_unoccupied_and_not_me(next_pos);

                            if are_clear {

                                let old_poses = tbc.current_cluster_pos.clone();
                                tbc.current_cluster_pos.truncate(0);

                                let old_frame = tbc.tetris_frame.clone();
                                let mut use_uids = vec![];

                                for pos in &old_poses {
                                    let uid = old_frame[pos.1 as usize][pos.0 as usize].unwrap();
                                    tbc.tetris_frame[pos.1 as usize][pos.0 as usize] = None;
                                    use_uids.push((uid, pos));
                                }

                                for k in use_uids.iter() {
                                    let tetris_piece = inner_world.get_mut_entity(k.0).unwrap();
                                    let tetris_piece = unsafe {&mut *(tetris_piece as *mut &Entity as *mut  &mut TetrisBlockModel)};
                                    tetris_piece.pos = Vector3::new(tetris_piece.pos.x, tetris_piece.pos.y - 100f32, tetris_piece.pos.z);
                      //              tbc.tetris_frame[(k.1).1 as usize][(k.1).0 as usize] = None;
                                    tbc.tetris_frame[(k.1).1 as usize + 1][(k.1).0 as usize] = Some(k.0);
                                    tbc.current_cluster_pos.push(((k.1).0, (k.1).1 + 1));
                                }

                            }
                            else {
                                tbc.finish_with_current_cluster();
                            }

                            tbc.frame_count = 016;
                        }
                        None => {
                            //in this case we can assume that a generated position is out of bounds, so we just stop the movmenet
                            tbc.finish_with_current_cluster();
                        }
                    }

                }
            }
        };

        return Some(Box::new(return_closure));
    }

    fn get_entity_type(&self) -> EEntityType {
        EEntityType::TetrisBlock
    }

}

#[derive(Copy, Clone)]
pub struct TetrisBlockModel {
    pub pos: Vector3<f32>,
    pub color: [f32;4],
    pub uid: UID,

}

impl TetrisBlockModel {
    pub fn new(pos: Vector3<f32>, color: [f32;4], uid: UID) -> TetrisBlockModel {
        TetrisBlockModel {
            pos,
            color,
            uid
        }
    }
}

impl Entity for TetrisBlockModel {
    fn get_entity_type(&self) -> EEntityType {
        EEntityType::TetrisBlock
    }

    fn set_uid(&mut self, uid: UID) {
        self.uid = uid;
    }

    fn get_uid(&self) -> UID {
        self.uid
    }

    fn add_to_render_frame(&self, render_frame: &mut RenderFrame) {
        if render_frame.sqaures.is_none() {
            render_frame.sqaures = Some(vec![]);
        }

        let sqd = SquareRenderData{
            pos: [self.pos.x, self.pos.y],
            height: 100.0f32,
            width: 100.0f32,
            color: [self.color[0], self.color[1], self.color[2]]
        };

        render_frame.sqaures.as_mut().unwrap().push(sqd);
    }
} <commit_msg>Move computers<commit_after>
#![allow(non_snake_case)]

use game::entity::{Entity, UID, EEntityType, EntityController};
use cgmath::Vector3;
use game::world::World;
use graphics::renderer::RenderFrame;
use graphics::square_renderer::SquareRenderData;
use rand;
use rand::distributions::{IndependentSample, Range};

type Vec2 = (i8, i8);

#[derive(Copy, Clone)]
pub enum TetrominoType {
    Line,
    Sqaure,
    Tee,
    El,
    S,
    Z
}

impl TetrominoType {
    pub fn offsets(&self) -> Vec<Vec2> {
        match *self {
            TetrominoType::Line => {
                return vec![
                    (0, 0),
                    (0, 1),
                    (0, 2),
                    (0, 3)
                ];
            },
            TetrominoType::Sqaure => {
                return vec![
                    (0, 0),
                    (1, 0),
                    (0, 1),
                    (1, 1)
                ];
            },
            TetrominoType::Tee => {
                return vec![
                    (0, 0),
                    (1, 0),
                    (-1, 0),
                    (0, 1)
                ];
            },
            TetrominoType::El => {
                return vec![
                    (0, 0),
                    (1, 0),
                    (1, 1),
                    (1, 2)
                ];
            },
            TetrominoType::S => {
                return vec![
                    (0, 0),
                    (-1, 0),
                    (0, 1),
                    (1, 1)
                ];
            },
            TetrominoType::Z => {
                return vec![
                    (0, 0),
                    (1, 0),
                    (0, 1),
                    (-1, 1)
                ];
            }
        }
    }

    pub fn from_usize(index: usize) -> Option<TetrominoType> {

        if index >= 6 {
            return None;
        }
        else {
            match index {
                0 => {
                    Some(TetrominoType::Line)
                },
                1 => {
                    Some(TetrominoType::Sqaure)
                },
                2 => {
                    Some(TetrominoType::Tee)
                },
                3 => {
                    Some(TetrominoType::El)
                },
                4 => {
                    Some(TetrominoType::S)
                },
                5 => {
                    Some(TetrominoType::Z)
                },
                _ => {
                    None
                }
            }
        }
    }
}

pub struct TetrisBlockController {
    pub uid: UID,
    pub current_cluster: Vec<UID>,
    pub frame_count: u16,
    pub tetris_frame: [[Option<UID>; 10]; 20],
    pub rng_pool: rand::ThreadRng,
    pub current_cluster_pos: Vec<Vec2>,
    pub spawn_pos: Vec2
}

impl<'a>TetrisBlockController {

    pub fn new(uid: UID) -> TetrisBlockController {
        TetrisBlockController {
            uid,
            current_cluster: vec![],
            frame_count: 0u16,
            tetris_frame: [[None; 10]; 20],
            rng_pool: rand::thread_rng(),
            current_cluster_pos: vec![],
            spawn_pos: (5, 0)
        }
    }

    pub fn genererate_and_place_next_tetris_block(&mut self, inner_world: &mut World){

        let color_v = Range::new(0.0f32, 1.0f32);
        let index = Range::new(0usize, 6usize);
        let index = index.ind_sample(&mut self.rng_pool);
        let offsets = TetrominoType::from_usize(index).unwrap().offsets();

        let color : [f32; 4] = [color_v.ind_sample(&mut self.rng_pool),//r
                                color_v.ind_sample(&mut self.rng_pool),//g
                                color_v.ind_sample(&mut self.rng_pool), //b
                                255.0f32];//a

        for offset in offsets {
            let pos = Vector3::new(100.0f32 * (offset.0 as f32), 550f32 - (100f32 * -offset.1 as f32), 250f32);
            let tbm = TetrisBlockModel::new(pos, color, 0u64);
            let new_uid = inner_world.set_uid_for_entity(Box::new(tbm));
            self.tetris_frame[(self.spawn_pos.1 + offset.1) as usize][(self.spawn_pos.0 + offset.0) as usize] = Some(new_uid);
            self.current_cluster_pos.push((self.spawn_pos.0 + offset.0, self.spawn_pos.1 + offset.1));
        }
  }

    pub fn generate_next_positions_for_cluster(&self) -> Option<Vec<Vec2>> {
        let mut new_pos : Vec<Vec2> = vec![];
        for pos in &self.current_cluster_pos {
            let new_y = pos.1 + 1;
            if new_y < 0 || new_y > 19{
                return None;
            }

            new_pos.push((pos.0, new_y));
        }
        return Some(new_pos);
    }

    pub fn finish_with_current_cluster(&mut self) {
        self.current_cluster_pos.truncate(0);
    }

    pub fn are_unoccupied_and_not_me(&self, posistions: Vec<Vec2>) -> bool {

        for pos in posistions {
            if self.tetris_frame[pos.1 as usize][pos.0 as usize] != None {
                if !self.current_cluster_pos.contains(&pos) {
                    return false;
                }
            }
        }

        return true;
    }

}

impl EntityController for TetrisBlockController {

    fn get_uid(&self) -> UID {
        self.uid
    }

    fn update(&self, _world: &World) ->  Option<Box<Fn(&mut World, &mut EntityController)>> {

         let return_closure = move |inner_world: &mut World, controller: &mut EntityController| {

            let tbc =  unsafe { &mut *(controller as *mut EntityController as *mut TetrisBlockController) };

            if tbc.current_cluster_pos.len() == 0 {
                //if we have no current cluster, create and place a new one
                tbc.genererate_and_place_next_tetris_block(inner_world);
            }
            else {

                tbc.frame_count = tbc.frame_count + 1u16;

                if tbc.frame_count == 60u16 {

                    let next_pos = tbc.generate_next_positions_for_cluster();

                    match next_pos {
                        Some(next_pos) => {

                            let are_clear = tbc.are_unoccupied_and_not_me(next_pos);

                            if are_clear {

                                let old_poses = tbc.current_cluster_pos.clone();
                                tbc.current_cluster_pos.truncate(0);

                                let old_frame = tbc.tetris_frame.clone();
                                let mut use_uids = vec![];

                                for pos in &old_poses {
                                    let uid = old_frame[pos.1 as usize][pos.0 as usize].unwrap();
                                    tbc.tetris_frame[pos.1 as usize][pos.0 as usize] = None;
                                    use_uids.push((uid, pos));
                                }

                                for k in use_uids.iter() {
                                    let tetris_piece = inner_world.get_mut_entity(k.0).unwrap();
                                    let tetris_piece = unsafe {&mut *(tetris_piece as *mut &Entity as *mut  &mut TetrisBlockModel)};
                                    tetris_piece.pos = Vector3::new(tetris_piece.pos.x, tetris_piece.pos.y - 100f32, tetris_piece.pos.z);
                                    tbc.tetris_frame[(k.1).1 as usize + 1][(k.1).0 as usize] = Some(k.0);
                                    tbc.current_cluster_pos.push(((k.1).0, (k.1).1 + 1));
                                }
                            }
                            else {
                                tbc.finish_with_current_cluster();
                            }

                            tbc.frame_count = 016;
                        }
                        None => {
                            //in this case we can assume that a generated position is out of bounds, so we just stop the movmenet
                            tbc.finish_with_current_cluster();
                        }
                    }

                }
            }
        };

        return Some(Box::new(return_closure));
    }

    fn get_entity_type(&self) -> EEntityType {
        EEntityType::TetrisBlock
    }

}

#[derive(Copy, Clone)]
pub struct TetrisBlockModel {
    pub pos: Vector3<f32>,
    pub color: [f32;4],
    pub uid: UID,

}

impl TetrisBlockModel {
    pub fn new(pos: Vector3<f32>, color: [f32;4], uid: UID) -> TetrisBlockModel {
        TetrisBlockModel {
            pos,
            color,
            uid
        }
    }
}

impl Entity for TetrisBlockModel {
    fn get_entity_type(&self) -> EEntityType {
        EEntityType::TetrisBlock
    }

    fn set_uid(&mut self, uid: UID) {
        self.uid = uid;
    }

    fn get_uid(&self) -> UID {
        self.uid
    }

    fn add_to_render_frame(&self, render_frame: &mut RenderFrame) {
        if render_frame.sqaures.is_none() {
            render_frame.sqaures = Some(vec![]);
        }

        let sqd = SquareRenderData{
            pos: [self.pos.x, self.pos.y],
            height: 100.0f32,
            width: 100.0f32,
            color: [self.color[0], self.color[1], self.color[2]]
        };

        render_frame.sqaures.as_mut().unwrap().push(sqd);
    }
} <|endoftext|>


<commit_before>extern crate piston_window;

use piston_window::Transformed;

use piston_window as pw;

struct Game {
    rotation: f64,
	x: f64,
	y: f64,
	up: bool,
	down: bool,
	left: bool,
	right: bool,
}

impl Game {
    fn new() -> Game {
        Game { rotation: 0.0, x: 0., y: 0., up: false, down: false, left: false, right: false }
    }

    fn on_update(&mut self, args: &pw::UpdateArgs) {
        self.rotation += 3.0 * args.dt;

		if self.up {
			self.y += -50.0 * args.dt;
		}
		if self.down {
			self.y += 50.0 * args.dt;
		}
		if self.left {
			self.x += -50.0 * args.dt;
		}
		if self.right {
			self.x += 50.0 * args.dt;
		}
    }

    fn on_draw(&mut self, args: &pw::RenderArgs, window: &pw::PistonWindow) {
        window.draw_2d(|context, graphics| {
            pw::clear([0.0, 0.0, 0.0, 1.0], graphics);

            let red = [1.0, 0.0, 0.0, 1.0];
            let square = pw::rectangle::square(0.0, 0.0, 100.0);
            let center = context.transform.trans((args.width / 2) as f64, (args.height / 2) as f64);
            pw::rectangle(red, square, center.rot_rad(self.rotation).trans(-50.0, -50.0), graphics);
        });
    }

	fn on_input(&mut self, input: &pw::Input) {
		match input {
			&pw::Input::Press(button) => {
				match button {
					pw::Button::Keyboard(pw::Key::Up) => { self.up = true; }
					pw::Button::Keyboard(pw::Key::Down) => { self.down = true; }
					pw::Button::Keyboard(pw::Key::Left) => { self.left = true; }
					pw::Button::Keyboard(pw::Key::Right) => { self.right = true; }
					_ => {}
				}
			}
			&pw::Input::Release(button) => {
				match button {
					pw::Button::Keyboard(pw::Key::Up) => { self.up = false; }
					pw::Button::Keyboard(pw::Key::Down) => { self.down = false; }
					pw::Button::Keyboard(pw::Key::Left) => { self.left = false; }
					pw::Button::Keyboard(pw::Key::Right) => { self.right = false; }
					_ => {}
				}
			}
			_ => {}
		}
	}
}

fn main() {
    let window: pw::PistonWindow = pw::WindowSettings::new("rrthozopsi", [600, 600])
        .exit_on_esc(true)
        .build()
        .unwrap();

	let mut game = Game::new();

    for w in window {
		match w.event {
			Some(pw::Event::Update(args)) => { game.on_update(&args); }
			Some(pw::Event::Render(args)) => { game.on_draw(&args, &w); }
			Some(pw::Event::Input(input)) => { game.on_input(&input); }
			_ => {}
		}
    }
}
<commit_msg>on_draw - current position<commit_after>extern crate piston_window;

use piston_window::Transformed;

use piston_window as pw;

struct Game {
    rotation: f64,
	x: f64,
	y: f64,
	up: bool,
	down: bool,
	left: bool,
	right: bool,
}

impl Game {
    fn new() -> Game {
        Game { rotation: 0.0, x: 0., y: 0., up: false, down: false, left: false, right: false }
    }

    fn on_update(&mut self, args: &pw::UpdateArgs) {
        self.rotation += 3.0 * args.dt;

		if self.up {
			self.y += -50.0 * args.dt;
		}
		if self.down {
			self.y += 50.0 * args.dt;
		}
		if self.left {
			self.x += -50.0 * args.dt;
		}
		if self.right {
			self.x += 50.0 * args.dt;
		}
    }

    fn on_draw(&mut self, args: &pw::RenderArgs, window: &pw::PistonWindow) {
        window.draw_2d(|context, graphics| {
            pw::clear([0.0, 0.0, 0.0, 1.0], graphics);

            let red = [1.0, 0.0, 0.0, 1.0];
            let square = pw::rectangle::square(0.0, 0.0, 100.0);
            let center = context.transform.trans((args.width / 2) as f64, (args.height / 2) as f64);
            pw::rectangle(red, square, center.trans(self.x, self.y).rot_rad(self.rotation).trans(-50.0, -50.0), graphics);
        });
    }

	fn on_input(&mut self, input: &pw::Input) {
		match input {
			&pw::Input::Press(button) => {
				match button {
					pw::Button::Keyboard(pw::Key::Up) => { self.up = true; }
					pw::Button::Keyboard(pw::Key::Down) => { self.down = true; }
					pw::Button::Keyboard(pw::Key::Left) => { self.left = true; }
					pw::Button::Keyboard(pw::Key::Right) => { self.right = true; }
					_ => {}
				}
			}
			&pw::Input::Release(button) => {
				match button {
					pw::Button::Keyboard(pw::Key::Up) => { self.up = false; }
					pw::Button::Keyboard(pw::Key::Down) => { self.down = false; }
					pw::Button::Keyboard(pw::Key::Left) => { self.left = false; }
					pw::Button::Keyboard(pw::Key::Right) => { self.right = false; }
					_ => {}
				}
			}
			_ => {}
		}
	}
}

fn main() {
    let window: pw::PistonWindow = pw::WindowSettings::new("rrthozopsi", [600, 600])
        .exit_on_esc(true)
        .build()
        .unwrap();

	let mut game = Game::new();

    for w in window {
		match w.event {
			Some(pw::Event::Update(args)) => { game.on_update(&args); }
			Some(pw::Event::Render(args)) => { game.on_draw(&args, &w); }
			Some(pw::Event::Input(input)) => { game.on_input(&input); }
			_ => {}
		}
    }
}
<|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.

use super::OverlapError;

use hir::def_id::DefId;
use ich::{self, StableHashingContext};
use rustc_data_structures::stable_hasher::{HashStable, StableHasher,
                                           StableHasherResult};
use traits;
use ty::{self, TyCtxt, TypeFoldable};
use ty::fast_reject::{self, SimplifiedType};
use rustc_data_structures::sync::Lrc;
use syntax::ast::Ident;
use util::captures::Captures;
use util::nodemap::{DefIdMap, FxHashMap};

/// A per-trait graph of impls in specialization order. At the moment, this
/// graph forms a tree rooted with the trait itself, with all other nodes
/// representing impls, and parent-child relationships representing
/// specializations.
///
/// The graph provides two key services:
///
/// - Construction, which implicitly checks for overlapping impls (i.e., impls
///   that overlap but where neither specializes the other -- an artifact of the
///   simple "chain" rule.
///
/// - Parent extraction. In particular, the graph can give you the *immediate*
///   parents of a given specializing impl, which is needed for extracting
///   default items amongst other things. In the simple "chain" rule, every impl
///   has at most one parent.
#[derive(RustcEncodable, RustcDecodable)]
pub struct Graph {
    // all impls have a parent; the "root" impls have as their parent the def_id
    // of the trait
    parent: DefIdMap<DefId>,

    // the "root" impls are found by looking up the trait's def_id.
    children: DefIdMap<Children>,
}

/// Children of a given impl, grouped into blanket/non-blanket varieties as is
/// done in `TraitDef`.
#[derive(RustcEncodable, RustcDecodable)]
struct Children {
    // Impls of a trait (or specializations of a given impl). To allow for
    // quicker lookup, the impls are indexed by a simplified version of their
    // `Self` type: impls with a simplifiable `Self` are stored in
    // `nonblanket_impls` keyed by it, while all other impls are stored in
    // `blanket_impls`.
    //
    // A similar division is used within `TraitDef`, but the lists there collect
    // together *all* the impls for a trait, and are populated prior to building
    // the specialization graph.

    /// Impls of the trait.
    nonblanket_impls: FxHashMap<fast_reject::SimplifiedType, Vec<DefId>>,

    /// Blanket impls associated with the trait.
    blanket_impls: Vec<DefId>,
}

/// The result of attempting to insert an impl into a group of children.
enum Inserted {
    /// The impl was inserted as a new child in this group of children.
    BecameNewSibling(Option<OverlapError>),

    /// The impl replaced an existing impl that specializes it.
    Replaced(DefId),

    /// The impl is a specialization of an existing child.
    ShouldRecurseOn(DefId),
}

impl<'a, 'gcx, 'tcx> Children {
    fn new() -> Children {
        Children {
            nonblanket_impls: FxHashMap(),
            blanket_impls: vec![],
        }
    }

    /// Insert an impl into this set of children without comparing to any existing impls
    fn insert_blindly(&mut self,
                      tcx: TyCtxt<'a, 'gcx, 'tcx>,
                      impl_def_id: DefId) {
        let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap();
        if let Some(sty) = fast_reject::simplify_type(tcx, trait_ref.self_ty(), false) {
            self.nonblanket_impls.entry(sty).or_insert(vec![]).push(impl_def_id)
        } else {
            self.blanket_impls.push(impl_def_id)
        }
    }

    /// Attempt to insert an impl into this set of children, while comparing for
    /// specialization relationships.
    fn insert(&mut self,
              tcx: TyCtxt<'a, 'gcx, 'tcx>,
              impl_def_id: DefId,
              simplified_self: Option<SimplifiedType>)
              -> Result<Inserted, OverlapError>
    {
        let mut last_lint = None;

        for slot in match simplified_self {
            Some(sty) => self.filtered_mut(sty),
            None => self.iter_mut(),
        } {
            let possible_sibling = *slot;

            let overlap_error = |overlap: traits::coherence::OverlapResult| {
                // overlap, but no specialization; error out
                let trait_ref = overlap.impl_header.trait_ref.unwrap();
                let self_ty = trait_ref.self_ty();
                OverlapError {
                    with_impl: possible_sibling,
                    trait_desc: trait_ref.to_string(),
                    // only report the Self type if it has at least
                    // some outer concrete shell; otherwise, it's
                    // not adding much information.
                    self_desc: if self_ty.has_concrete_skeleton() {
                        Some(self_ty.to_string())
                    } else {
                        None
                    },
                    intercrate_ambiguity_causes: overlap.intercrate_ambiguity_causes,
                }
            };

            let tcx = tcx.global_tcx();
            let (le, ge) = traits::overlapping_impls(
                tcx,
                possible_sibling,
                impl_def_id,
                traits::IntercrateMode::Issue43355,
                |overlap| {
                    if tcx.impls_are_allowed_to_overlap(impl_def_id, possible_sibling) {
                        return Ok((false, false));
                    }

                    let le = tcx.specializes((impl_def_id, possible_sibling));
                    let ge = tcx.specializes((possible_sibling, impl_def_id));

                    if le == ge {
                        Err(overlap_error(overlap))
                    } else {
                        Ok((le, ge))
                    }
                },
                || Ok((false, false)),
            )?;

            if le && !ge {
                debug!("descending as child of TraitRef {:?}",
                       tcx.impl_trait_ref(possible_sibling).unwrap());

                // the impl specializes possible_sibling
                return Ok(Inserted::ShouldRecurseOn(possible_sibling));
            } else if ge && !le {
                debug!("placing as parent of TraitRef {:?}",
                       tcx.impl_trait_ref(possible_sibling).unwrap());

                    // possible_sibling specializes the impl
                    *slot = impl_def_id;
                return Ok(Inserted::Replaced(possible_sibling));
            } else {
                if !tcx.impls_are_allowed_to_overlap(impl_def_id, possible_sibling) {
                    traits::overlapping_impls(
                        tcx,
                        possible_sibling,
                        impl_def_id,
                        traits::IntercrateMode::Fixed,
                        |overlap| last_lint = Some(overlap_error(overlap)),
                        || (),
                    );
                }

                // no overlap (error bailed already via ?)
            }
        }

        // no overlap with any potential siblings, so add as a new sibling
        debug!("placing as new sibling");
        self.insert_blindly(tcx, impl_def_id);
        Ok(Inserted::BecameNewSibling(last_lint))
    }

    fn iter_mut(&'a mut self) -> Box<dyn Iterator<Item = &'a mut DefId> + 'a> {
        let nonblanket = self.nonblanket_impls.iter_mut().flat_map(|(_, v)| v.iter_mut());
        Box::new(self.blanket_impls.iter_mut().chain(nonblanket))
    }

    fn filtered_mut(&'a mut self, sty: SimplifiedType)
                    -> Box<dyn Iterator<Item = &'a mut DefId> + 'a> {
        let nonblanket = self.nonblanket_impls.entry(sty).or_insert(vec![]).iter_mut();
        Box::new(self.blanket_impls.iter_mut().chain(nonblanket))
    }
}

impl<'a, 'gcx, 'tcx> Graph {
    pub fn new() -> Graph {
        Graph {
            parent: Default::default(),
            children: Default::default(),
        }
    }

    /// Insert a local impl into the specialization graph. If an existing impl
    /// conflicts with it (has overlap, but neither specializes the other),
    /// information about the area of overlap is returned in the `Err`.
    pub fn insert(&mut self,
                  tcx: TyCtxt<'a, 'gcx, 'tcx>,
                  impl_def_id: DefId)
                  -> Result<Option<OverlapError>, OverlapError> {
        assert!(impl_def_id.is_local());

        let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap();
        let trait_def_id = trait_ref.def_id;

        debug!("insert({:?}): inserting TraitRef {:?} into specialization graph",
               impl_def_id, trait_ref);

        // if the reference itself contains an earlier error (e.g., due to a
        // resolution failure), then we just insert the impl at the top level of
        // the graph and claim that there's no overlap (in order to suppress
        // bogus errors).
        if trait_ref.references_error() {
            debug!("insert: inserting dummy node for erroneous TraitRef {:?}, \
                    impl_def_id={:?}, trait_def_id={:?}",
                   trait_ref, impl_def_id, trait_def_id);

            self.parent.insert(impl_def_id, trait_def_id);
            self.children.entry(trait_def_id).or_insert(Children::new())
                .insert_blindly(tcx, impl_def_id);
            return Ok(None);
        }

        let mut parent = trait_def_id;
        let mut last_lint = None;
        let simplified = fast_reject::simplify_type(tcx, trait_ref.self_ty(), false);

        // Descend the specialization tree, where `parent` is the current parent node
        loop {
            use self::Inserted::*;

            let insert_result = self.children.entry(parent).or_insert(Children::new())
                .insert(tcx, impl_def_id, simplified)?;

            match insert_result {
                BecameNewSibling(opt_lint) => {
                    last_lint = opt_lint;
                    break;
                }
                Replaced(new_child) => {
                    self.parent.insert(new_child, impl_def_id);
                    let mut new_children = Children::new();
                    new_children.insert_blindly(tcx, new_child);
                    self.children.insert(impl_def_id, new_children);
                    break;
                }
                ShouldRecurseOn(new_parent) => {
                    parent = new_parent;
                }
            }
        }

        self.parent.insert(impl_def_id, parent);
        Ok(last_lint)
    }

    /// Insert cached metadata mapping from a child impl back to its parent.
    pub fn record_impl_from_cstore(&mut self,
                                   tcx: TyCtxt<'a, 'gcx, 'tcx>,
                                   parent: DefId,
                                   child: DefId) {
        if self.parent.insert(child, parent).is_some() {
            bug!("When recording an impl from the crate store, information about its parent \
                  was already present.");
        }

        self.children.entry(parent).or_insert(Children::new()).insert_blindly(tcx, child);
    }

    /// The parent of a given impl, which is the def id of the trait when the
    /// impl is a "specialization root".
    pub fn parent(&self, child: DefId) -> DefId {
        *self.parent.get(&child).unwrap()
    }
}

/// A node in the specialization graph is either an impl or a trait
/// definition; either can serve as a source of item definitions.
/// There is always exactly one trait definition node: the root.
#[derive(Debug, Copy, Clone)]
pub enum Node {
    Impl(DefId),
    Trait(DefId),
}

impl<'a, 'gcx, 'tcx> Node {
    pub fn is_from_trait(&self) -> bool {
        match *self {
            Node::Trait(..) => true,
            _ => false,
        }
    }

    /// Iterate over the items defined directly by the given (impl or trait) node.
    pub fn items(
        &self,
        tcx: TyCtxt<'a, 'gcx, 'tcx>,
    ) -> impl Iterator<Item = ty::AssociatedItem> + 'a {
        tcx.associated_items(self.def_id())
    }

    pub fn def_id(&self) -> DefId {
        match *self {
            Node::Impl(did) => did,
            Node::Trait(did) => did,
        }
    }
}

pub struct Ancestors {
    trait_def_id: DefId,
    specialization_graph: Lrc<Graph>,
    current_source: Option<Node>,
}

impl Iterator for Ancestors {
    type Item = Node;
    fn next(&mut self) -> Option<Node> {
        let cur = self.current_source.take();
        if let Some(Node::Impl(cur_impl)) = cur {
            let parent = self.specialization_graph.parent(cur_impl);
            if parent == self.trait_def_id {
                self.current_source = Some(Node::Trait(parent));
            } else {
                self.current_source = Some(Node::Impl(parent));
            }
        }
        cur
    }
}

pub struct NodeItem<T> {
    pub node: Node,
    pub item: T,
}

impl<T> NodeItem<T> {
    pub fn map<U, F: FnOnce(T) -> U>(self, f: F) -> NodeItem<U> {
        NodeItem {
            node: self.node,
            item: f(self.item),
        }
    }
}

impl<'a, 'gcx, 'tcx> Ancestors {
    /// Search the items from the given ancestors, returning each definition
    /// with the given name and the given kind.
    #[inline] // FIXME(#35870) Avoid closures being unexported due to impl Trait.
    pub fn defs(
        self,
        tcx: TyCtxt<'a, 'gcx, 'tcx>,
        trait_item_name: Ident,
        trait_item_kind: ty::AssociatedKind,
        trait_def_id: DefId,
    ) -> impl Iterator<Item = NodeItem<ty::AssociatedItem>> + Captures<'gcx> + Captures<'tcx> + 'a {
        self.flat_map(move |node| {
            use ty::AssociatedKind::*;
            node.items(tcx).filter(move |impl_item| match (trait_item_kind, impl_item.kind) {
                | (Const, Const)
                | (Method, Method)
                | (Type, Type)
                | (Type, Existential)
                => tcx.hygienic_eq(impl_item.ident, trait_item_name, trait_def_id),

                _ => false,
            }).map(move |item| NodeItem { node: node, item: item })
        })
    }
}

/// Walk up the specialization ancestors of a given impl, starting with that
/// impl itself.
pub fn ancestors(tcx: TyCtxt,
                 trait_def_id: DefId,
                 start_from_impl: DefId)
                 -> Ancestors {
    let specialization_graph = tcx.specialization_graph_of(trait_def_id);
    Ancestors {
        trait_def_id,
        specialization_graph,
        current_source: Some(Node::Impl(start_from_impl)),
    }
}

impl<'a> HashStable<StableHashingContext<'a>> for Children {
    fn hash_stable<W: StableHasherResult>(&self,
                                          hcx: &mut StableHashingContext<'a>,
                                          hasher: &mut StableHasher<W>) {
        let Children {
            ref nonblanket_impls,
            ref blanket_impls,
        } = *self;

        ich::hash_stable_trait_impls(hcx, hasher, blanket_impls, nonblanket_impls);
    }
}

impl_stable_hash_for!(struct self::Graph {
    parent,
    children
});
<commit_msg>Add type system canaries for potential future bugs<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.

use super::OverlapError;

use hir::def_id::DefId;
use ich::{self, StableHashingContext};
use rustc_data_structures::stable_hasher::{HashStable, StableHasher,
                                           StableHasherResult};
use traits;
use ty::{self, TyCtxt, TypeFoldable};
use ty::fast_reject::{self, SimplifiedType};
use rustc_data_structures::sync::Lrc;
use syntax::ast::Ident;
use util::captures::Captures;
use util::nodemap::{DefIdMap, FxHashMap};

/// A per-trait graph of impls in specialization order. At the moment, this
/// graph forms a tree rooted with the trait itself, with all other nodes
/// representing impls, and parent-child relationships representing
/// specializations.
///
/// The graph provides two key services:
///
/// - Construction, which implicitly checks for overlapping impls (i.e., impls
///   that overlap but where neither specializes the other -- an artifact of the
///   simple "chain" rule.
///
/// - Parent extraction. In particular, the graph can give you the *immediate*
///   parents of a given specializing impl, which is needed for extracting
///   default items amongst other things. In the simple "chain" rule, every impl
///   has at most one parent.
#[derive(RustcEncodable, RustcDecodable)]
pub struct Graph {
    // all impls have a parent; the "root" impls have as their parent the def_id
    // of the trait
    parent: DefIdMap<DefId>,

    // the "root" impls are found by looking up the trait's def_id.
    children: DefIdMap<Children>,
}

/// Children of a given impl, grouped into blanket/non-blanket varieties as is
/// done in `TraitDef`.
#[derive(RustcEncodable, RustcDecodable)]
struct Children {
    // Impls of a trait (or specializations of a given impl). To allow for
    // quicker lookup, the impls are indexed by a simplified version of their
    // `Self` type: impls with a simplifiable `Self` are stored in
    // `nonblanket_impls` keyed by it, while all other impls are stored in
    // `blanket_impls`.
    //
    // A similar division is used within `TraitDef`, but the lists there collect
    // together *all* the impls for a trait, and are populated prior to building
    // the specialization graph.

    /// Impls of the trait.
    nonblanket_impls: FxHashMap<fast_reject::SimplifiedType, Vec<DefId>>,

    /// Blanket impls associated with the trait.
    blanket_impls: Vec<DefId>,
}

/// The result of attempting to insert an impl into a group of children.
enum Inserted {
    /// The impl was inserted as a new child in this group of children.
    BecameNewSibling(Option<OverlapError>),

    /// The impl replaced an existing impl that specializes it.
    Replaced(DefId),

    /// The impl is a specialization of an existing child.
    ShouldRecurseOn(DefId),
}

impl<'a, 'gcx, 'tcx> Children {
    fn new() -> Children {
        Children {
            nonblanket_impls: FxHashMap(),
            blanket_impls: vec![],
        }
    }

    /// Insert an impl into this set of children without comparing to any existing impls
    fn insert_blindly(&mut self,
                      tcx: TyCtxt<'a, 'gcx, 'tcx>,
                      impl_def_id: DefId) {
        let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap();
        if let Some(sty) = fast_reject::simplify_type(tcx, trait_ref.self_ty(), false) {
            self.nonblanket_impls.entry(sty).or_insert(vec![]).push(impl_def_id)
        } else {
            self.blanket_impls.push(impl_def_id)
        }
    }

    /// Attempt to insert an impl into this set of children, while comparing for
    /// specialization relationships.
    fn insert(&mut self,
              tcx: TyCtxt<'a, 'gcx, 'tcx>,
              impl_def_id: DefId,
              simplified_self: Option<SimplifiedType>)
              -> Result<Inserted, OverlapError>
    {
        let mut last_lint = None;

        for slot in match simplified_self {
            Some(sty) => self.filtered_mut(sty),
            None => self.iter_mut(),
        } {
            let possible_sibling = *slot;

            let overlap_error = |overlap: traits::coherence::OverlapResult| {
                // overlap, but no specialization; error out
                let trait_ref = overlap.impl_header.trait_ref.unwrap();
                let self_ty = trait_ref.self_ty();
                OverlapError {
                    with_impl: possible_sibling,
                    trait_desc: trait_ref.to_string(),
                    // only report the Self type if it has at least
                    // some outer concrete shell; otherwise, it's
                    // not adding much information.
                    self_desc: if self_ty.has_concrete_skeleton() {
                        Some(self_ty.to_string())
                    } else {
                        None
                    },
                    intercrate_ambiguity_causes: overlap.intercrate_ambiguity_causes,
                }
            };

            let tcx = tcx.global_tcx();
            let (le, ge) = traits::overlapping_impls(
                tcx,
                possible_sibling,
                impl_def_id,
                traits::IntercrateMode::Issue43355,
                |overlap| {
                    if tcx.impls_are_allowed_to_overlap(impl_def_id, possible_sibling) {
                        return Ok((false, false));
                    }

                    let le = tcx.specializes((impl_def_id, possible_sibling));
                    let ge = tcx.specializes((possible_sibling, impl_def_id));

                    if le == ge {
                        Err(overlap_error(overlap))
                    } else {
                        Ok((le, ge))
                    }
                },
                || Ok((false, false)),
            )?;

            if le && !ge {
                debug!("descending as child of TraitRef {:?}",
                       tcx.impl_trait_ref(possible_sibling).unwrap());

                // the impl specializes possible_sibling
                return Ok(Inserted::ShouldRecurseOn(possible_sibling));
            } else if ge && !le {
                debug!("placing as parent of TraitRef {:?}",
                       tcx.impl_trait_ref(possible_sibling).unwrap());

                    // possible_sibling specializes the impl
                    *slot = impl_def_id;
                return Ok(Inserted::Replaced(possible_sibling));
            } else {
                if !tcx.impls_are_allowed_to_overlap(impl_def_id, possible_sibling) {
                    traits::overlapping_impls(
                        tcx,
                        possible_sibling,
                        impl_def_id,
                        traits::IntercrateMode::Fixed,
                        |overlap| last_lint = Some(overlap_error(overlap)),
                        || (),
                    );
                }

                // no overlap (error bailed already via ?)
            }
        }

        // no overlap with any potential siblings, so add as a new sibling
        debug!("placing as new sibling");
        self.insert_blindly(tcx, impl_def_id);
        Ok(Inserted::BecameNewSibling(last_lint))
    }

    fn iter_mut(&'a mut self) -> Box<dyn Iterator<Item = &'a mut DefId> + 'a> {
        let nonblanket = self.nonblanket_impls.iter_mut().flat_map(|(_, v)| v.iter_mut());
        Box::new(self.blanket_impls.iter_mut().chain(nonblanket))
    }

    fn filtered_mut(&'a mut self, sty: SimplifiedType)
                    -> Box<dyn Iterator<Item = &'a mut DefId> + 'a> {
        let nonblanket = self.nonblanket_impls.entry(sty).or_insert(vec![]).iter_mut();
        Box::new(self.blanket_impls.iter_mut().chain(nonblanket))
    }
}

impl<'a, 'gcx, 'tcx> Graph {
    pub fn new() -> Graph {
        Graph {
            parent: Default::default(),
            children: Default::default(),
        }
    }

    /// Insert a local impl into the specialization graph. If an existing impl
    /// conflicts with it (has overlap, but neither specializes the other),
    /// information about the area of overlap is returned in the `Err`.
    pub fn insert(&mut self,
                  tcx: TyCtxt<'a, 'gcx, 'tcx>,
                  impl_def_id: DefId)
                  -> Result<Option<OverlapError>, OverlapError> {
        assert!(impl_def_id.is_local());

        let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap();
        let trait_def_id = trait_ref.def_id;

        debug!("insert({:?}): inserting TraitRef {:?} into specialization graph",
               impl_def_id, trait_ref);

        // if the reference itself contains an earlier error (e.g., due to a
        // resolution failure), then we just insert the impl at the top level of
        // the graph and claim that there's no overlap (in order to suppress
        // bogus errors).
        if trait_ref.references_error() {
            debug!("insert: inserting dummy node for erroneous TraitRef {:?}, \
                    impl_def_id={:?}, trait_def_id={:?}",
                   trait_ref, impl_def_id, trait_def_id);

            self.parent.insert(impl_def_id, trait_def_id);
            self.children.entry(trait_def_id).or_insert(Children::new())
                .insert_blindly(tcx, impl_def_id);
            return Ok(None);
        }

        let mut parent = trait_def_id;
        let mut last_lint = None;
        let simplified = fast_reject::simplify_type(tcx, trait_ref.self_ty(), false);

        // Descend the specialization tree, where `parent` is the current parent node
        loop {
            use self::Inserted::*;

            let insert_result = self.children.entry(parent).or_insert(Children::new())
                .insert(tcx, impl_def_id, simplified)?;

            match insert_result {
                BecameNewSibling(opt_lint) => {
                    last_lint = opt_lint;
                    break;
                }
                Replaced(new_child) => {
                    self.parent.insert(new_child, impl_def_id);
                    let mut new_children = Children::new();
                    new_children.insert_blindly(tcx, new_child);
                    self.children.insert(impl_def_id, new_children);
                    break;
                }
                ShouldRecurseOn(new_parent) => {
                    parent = new_parent;
                }
            }
        }

        self.parent.insert(impl_def_id, parent);
        Ok(last_lint)
    }

    /// Insert cached metadata mapping from a child impl back to its parent.
    pub fn record_impl_from_cstore(&mut self,
                                   tcx: TyCtxt<'a, 'gcx, 'tcx>,
                                   parent: DefId,
                                   child: DefId) {
        if self.parent.insert(child, parent).is_some() {
            bug!("When recording an impl from the crate store, information about its parent \
                  was already present.");
        }

        self.children.entry(parent).or_insert(Children::new()).insert_blindly(tcx, child);
    }

    /// The parent of a given impl, which is the def id of the trait when the
    /// impl is a "specialization root".
    pub fn parent(&self, child: DefId) -> DefId {
        *self.parent.get(&child).unwrap()
    }
}

/// A node in the specialization graph is either an impl or a trait
/// definition; either can serve as a source of item definitions.
/// There is always exactly one trait definition node: the root.
#[derive(Debug, Copy, Clone)]
pub enum Node {
    Impl(DefId),
    Trait(DefId),
}

impl<'a, 'gcx, 'tcx> Node {
    pub fn is_from_trait(&self) -> bool {
        match *self {
            Node::Trait(..) => true,
            _ => false,
        }
    }

    /// Iterate over the items defined directly by the given (impl or trait) node.
    pub fn items(
        &self,
        tcx: TyCtxt<'a, 'gcx, 'tcx>,
    ) -> impl Iterator<Item = ty::AssociatedItem> + 'a {
        tcx.associated_items(self.def_id())
    }

    pub fn def_id(&self) -> DefId {
        match *self {
            Node::Impl(did) => did,
            Node::Trait(did) => did,
        }
    }
}

pub struct Ancestors {
    trait_def_id: DefId,
    specialization_graph: Lrc<Graph>,
    current_source: Option<Node>,
}

impl Iterator for Ancestors {
    type Item = Node;
    fn next(&mut self) -> Option<Node> {
        let cur = self.current_source.take();
        if let Some(Node::Impl(cur_impl)) = cur {
            let parent = self.specialization_graph.parent(cur_impl);
            if parent == self.trait_def_id {
                self.current_source = Some(Node::Trait(parent));
            } else {
                self.current_source = Some(Node::Impl(parent));
            }
        }
        cur
    }
}

pub struct NodeItem<T> {
    pub node: Node,
    pub item: T,
}

impl<T> NodeItem<T> {
    pub fn map<U, F: FnOnce(T) -> U>(self, f: F) -> NodeItem<U> {
        NodeItem {
            node: self.node,
            item: f(self.item),
        }
    }
}

impl<'a, 'gcx, 'tcx> Ancestors {
    /// Search the items from the given ancestors, returning each definition
    /// with the given name and the given kind.
    #[inline] // FIXME(#35870) Avoid closures being unexported due to impl Trait.
    pub fn defs(
        self,
        tcx: TyCtxt<'a, 'gcx, 'tcx>,
        trait_item_name: Ident,
        trait_item_kind: ty::AssociatedKind,
        trait_def_id: DefId,
    ) -> impl Iterator<Item = NodeItem<ty::AssociatedItem>> + Captures<'gcx> + Captures<'tcx> + 'a {
        self.flat_map(move |node| {
            use ty::AssociatedKind::*;
            node.items(tcx).filter(move |impl_item| match (trait_item_kind, impl_item.kind) {
                | (Const, Const)
                | (Method, Method)
                | (Type, Type)
                | (Type, Existential)
                => tcx.hygienic_eq(impl_item.ident, trait_item_name, trait_def_id),

                | (Const, _)
                | (Method, _)
                | (Type, _)
                | (Existential, _)
                => false,
            }).map(move |item| NodeItem { node: node, item: item })
        })
    }
}

/// Walk up the specialization ancestors of a given impl, starting with that
/// impl itself.
pub fn ancestors(tcx: TyCtxt,
                 trait_def_id: DefId,
                 start_from_impl: DefId)
                 -> Ancestors {
    let specialization_graph = tcx.specialization_graph_of(trait_def_id);
    Ancestors {
        trait_def_id,
        specialization_graph,
        current_source: Some(Node::Impl(start_from_impl)),
    }
}

impl<'a> HashStable<StableHashingContext<'a>> for Children {
    fn hash_stable<W: StableHasherResult>(&self,
                                          hcx: &mut StableHashingContext<'a>,
                                          hasher: &mut StableHasher<W>) {
        let Children {
            ref nonblanket_impls,
            ref blanket_impls,
        } = *self;

        ich::hash_stable_trait_impls(hcx, hasher, blanket_impls, nonblanket_impls);
    }
}

impl_stable_hash_for!(struct self::Graph {
    parent,
    children
});
<|endoftext|>