<commit_before>// Inspired by Paul Woolcock's cargo-fmt (https://github.com/pwoolcoc/cargo-fmt/).

#![cfg(not(test))]
#![deny(warnings)]

use cargo_metadata;
use getopts;

use std::cmp::Ordering;
use std::collections::{BTreeMap, BTreeSet};
use std::env;
use std::fs;
use std::hash::{Hash, Hasher};
use std::io::{self, Write};
use std::iter::FromIterator;
use std::path::{Path, PathBuf};
use std::process::Command;
use std::str;

use getopts::{Matches, Options};

fn main() {
    let exit_status = execute();
    std::io::stdout().flush().unwrap();
    std::process::exit(exit_status);
}

const SUCCESS: i32 = 0;
const FAILURE: i32 = 1;

fn execute() -> i32 {
    let mut opts = getopts::Options::new();
    opts.optflag("h", "help", "show this message");
    opts.optflag("q", "quiet", "no output printed to stdout");
    opts.optflag("v", "verbose", "use verbose output");
    opts.optmulti(
        "p",
        "package",
        "specify package to format (only usable in workspaces)",
        "<package>",
    );
    opts.optflag("", "version", "print rustfmt version and exit");
    opts.optflag("", "all", "format all packages (only usable in workspaces)");

    // If there is any invalid argument passed to `cargo fmt`, return without formatting.
    let mut is_package_arg = false;
    for arg in env::args().skip(2).take_while(|a| a != "--") {
        if arg.starts_with('-') {
            is_package_arg = arg.starts_with("--package") | arg.starts_with("-p");
        } else if !is_package_arg {
            print_usage_to_stderr(&opts, &format!("Invalid argument: `{}`.", arg));
            return FAILURE;
        } else {
            is_package_arg = false;
        }
    }

    let matches = match opts.parse(env::args().skip(1).take_while(|a| a != "--")) {
        Ok(m) => m,
        Err(e) => {
            print_usage_to_stderr(&opts, &e.to_string());
            return FAILURE;
        }
    };

    let verbosity = match (matches.opt_present("v"), matches.opt_present("q")) {
        (false, false) => Verbosity::Normal,
        (false, true) => Verbosity::Quiet,
        (true, false) => Verbosity::Verbose,
        (true, true) => {
            print_usage_to_stderr(&opts, "quiet mode and verbose mode are not compatible");
            return FAILURE;
        }
    };

    if matches.opt_present("h") {
        print_usage_to_stdout(&opts, "");
        return SUCCESS;
    }

    if matches.opt_present("version") {
        return handle_command_status(get_version(), &opts);
    }

    let strategy = CargoFmtStrategy::from_matches(&matches);
    handle_command_status(format_crate(verbosity, &strategy), &opts)
}

macro_rules! print_usage {
    ($print:ident, $opts:ident, $reason:expr) => {{
        let msg = format!("{}\nusage: cargo fmt [options]", $reason);
        $print!(
            "{}\nThis utility formats all bin and lib files of the current crate using rustfmt. \
             Arguments after `--` are passed to rustfmt.",
            $opts.usage(&msg)
        );
    }};
}

fn print_usage_to_stdout(opts: &Options, reason: &str) {
    print_usage!(println, opts, reason);
}

fn print_usage_to_stderr(opts: &Options, reason: &str) {
    print_usage!(eprintln, opts, reason);
}

#[derive(Debug, Clone, Copy, PartialEq)]
pub enum Verbosity {
    Verbose,
    Normal,
    Quiet,
}

fn handle_command_status(status: Result<i32, io::Error>, opts: &getopts::Options) -> i32 {
    match status {
        Err(e) => {
            print_usage_to_stderr(opts, &e.to_string());
            FAILURE
        }
        Ok(status) => status,
    }
}

fn get_version() -> Result<i32, io::Error> {
    let mut status = vec![];
    let mut command = Command::new("rustfmt")
        .stdout(std::process::Stdio::inherit())
        .args(&[String::from("--version")])
        .spawn()
        .map_err(|e| match e.kind() {
            io::ErrorKind::NotFound => io::Error::new(
                io::ErrorKind::Other,
                "Could not run rustfmt, please make sure it is in your PATH.",
            ),
            _ => e,
        })?;
    status.push(command.wait()?);

    Ok(status
        .iter()
        .filter_map(|s| if s.success() { None } else { s.code() })
        .next()
        .unwrap_or(SUCCESS))
}

fn format_crate(verbosity: Verbosity, strategy: &CargoFmtStrategy) -> Result<i32, io::Error> {
    let rustfmt_args = get_fmt_args();
    let targets = if rustfmt_args
        .iter()
        .any(|s| ["--print-config", "-h", "--help", "-V", "--version"].contains(&s.as_str()))
    {
        BTreeSet::new()
    } else {
        get_targets(strategy)?
    };

    // Currently only bin and lib files get formatted.
    run_rustfmt(&targets, &rustfmt_args, verbosity)
}

fn get_fmt_args() -> Vec<String> {
    // All arguments after -- are passed to rustfmt.
    env::args().skip_while(|a| a != "--").skip(1).collect()
}

/// Target uses a `path` field for equality and hashing.
#[derive(Debug)]
pub struct Target {
    /// A path to the main source file of the target.
    path: PathBuf,
    /// A kind of target (e.g., lib, bin, example, ...).
    kind: String,
    /// Rust edition for this target.
    edition: String,
}

impl Target {
    pub fn from_target(target: &cargo_metadata::Target) -> Self {
        let path = PathBuf::from(&target.src_path);
        let canonicalized = fs::canonicalize(&path).unwrap_or(path);

        Target {
            path: canonicalized,
            kind: target.kind[0].clone(),
            edition: target.edition.clone(),
        }
    }
}

impl PartialEq for Target {
    fn eq(&self, other: &Target) -> bool {
        self.path == other.path
    }
}

impl PartialOrd for Target {
    fn partial_cmp(&self, other: &Target) -> Option<Ordering> {
        Some(self.path.cmp(&other.path))
    }
}

impl Ord for Target {
    fn cmp(&self, other: &Target) -> Ordering {
        self.path.cmp(&other.path)
    }
}

impl Eq for Target {}

impl Hash for Target {
    fn hash<H: Hasher>(&self, state: &mut H) {
        self.path.hash(state);
    }
}

#[derive(Debug, PartialEq, Eq)]
pub enum CargoFmtStrategy {
    /// Format every packages and dependencies.
    All,
    /// Format packages that are specified by the command line argument.
    Some(Vec<String>),
    /// Format the root packages only.
    Root,
}

impl CargoFmtStrategy {
    pub fn from_matches(matches: &Matches) -> CargoFmtStrategy {
        match (matches.opt_present("all"), matches.opt_present("p")) {
            (false, false) => CargoFmtStrategy::Root,
            (true, _) => CargoFmtStrategy::All,
            (false, true) => CargoFmtStrategy::Some(matches.opt_strs("p")),
        }
    }
}

/// Based on the specified `CargoFmtStrategy`, returns a set of main source files.
fn get_targets(strategy: &CargoFmtStrategy) -> Result<BTreeSet<Target>, io::Error> {
    let mut targets = BTreeSet::new();

    match *strategy {
        CargoFmtStrategy::Root => get_targets_root_only(&mut targets)?,
        CargoFmtStrategy::All => get_targets_recursive(None, &mut targets, &mut BTreeSet::new())?,
        CargoFmtStrategy::Some(ref hitlist) => get_targets_with_hitlist(hitlist, &mut targets)?,
    }

    if targets.is_empty() {
        Err(io::Error::new(
            io::ErrorKind::Other,
            "Failed to find targets".to_owned(),
        ))
    } else {
        Ok(targets)
    }
}

fn get_targets_root_only(targets: &mut BTreeSet<Target>) -> Result<(), io::Error> {
    let metadata = get_cargo_metadata(None)?;
    let current_dir = env::current_dir()?.canonicalize()?;
    let current_dir_manifest = current_dir.join("Cargo.toml");
    let workspace_root_path = PathBuf::from(&metadata.workspace_root).canonicalize()?;
    let in_workspace_root = workspace_root_path == current_dir;

    for package in metadata.packages {
        if in_workspace_root || PathBuf::from(&package.manifest_path) == current_dir_manifest {
            for target in package.targets {
                targets.insert(Target::from_target(&target));
            }
        }
    }

    Ok(())
}

fn get_targets_recursive(
    manifest_path: Option<&Path>,
    mut targets: &mut BTreeSet<Target>,
    visited: &mut BTreeSet<String>,
) -> Result<(), io::Error> {
    let metadata = get_cargo_metadata(manifest_path)?;

    for package in metadata.packages {
        add_targets(&package.targets, &mut targets);

        // Look for local dependencies.
        for dependency in package.dependencies {
            if dependency.source.is_some() || visited.contains(&dependency.name) {
                continue;
            }

            let mut manifest_path = PathBuf::from(&package.manifest_path);

            manifest_path.pop();
            manifest_path.push(&dependency.name);
            manifest_path.push("Cargo.toml");

            if manifest_path.exists() {
                visited.insert(dependency.name);
                get_targets_recursive(Some(&manifest_path), &mut targets, visited)?;
            }
        }
    }

    Ok(())
}

fn get_targets_with_hitlist(
    hitlist: &[String],
    targets: &mut BTreeSet<Target>,
) -> Result<(), io::Error> {
    let metadata = get_cargo_metadata(None)?;

    let mut workspace_hitlist: BTreeSet<&String> = BTreeSet::from_iter(hitlist);

    for package in metadata.packages {
        if workspace_hitlist.remove(&package.name) {
            for target in package.targets {
                targets.insert(Target::from_target(&target));
            }
        }
    }

    if workspace_hitlist.is_empty() {
        Ok(())
    } else {
        let package = workspace_hitlist.iter().next().unwrap();
        Err(io::Error::new(
            io::ErrorKind::InvalidInput,
            format!("package `{}` is not a member of the workspace", package),
        ))
    }
}

fn add_targets(target_paths: &[cargo_metadata::Target], targets: &mut BTreeSet<Target>) {
    for target in target_paths {
        targets.insert(Target::from_target(target));
    }
}

fn run_rustfmt(
    targets: &BTreeSet<Target>,
    fmt_args: &[String],
    verbosity: Verbosity,
) -> Result<i32, io::Error> {
    let by_edition = targets
        .iter()
        .inspect(|t| {
            if verbosity == Verbosity::Verbose {
                println!("[{} ({})] {:?}", t.kind, t.edition, t.path)
            }
        })
        .fold(BTreeMap::new(), |mut h, t| {
            h.entry(&t.edition).or_insert_with(Vec::new).push(&t.path);
            h
        });

    let mut status = vec![];
    for (edition, files) in by_edition {
        let stdout = if verbosity == Verbosity::Quiet {
            std::process::Stdio::null()
        } else {
            std::process::Stdio::inherit()
        };

        if verbosity == Verbosity::Verbose {
            print!("rustfmt");
            print!(" --edition {}", edition);
            fmt_args.iter().for_each(|f| print!(" {}", f));
            files.iter().for_each(|f| print!(" {}", f.display()));
            println!();
        }

        let mut command = Command::new("rustfmt")
            .stdout(stdout)
            .args(files)
            .args(&["--edition", edition])
            .args(fmt_args)
            .spawn()
            .map_err(|e| match e.kind() {
                io::ErrorKind::NotFound => io::Error::new(
                    io::ErrorKind::Other,
                    "Could not run rustfmt, please make sure it is in your PATH.",
                ),
                _ => e,
            })?;

        status.push(command.wait()?);
    }

    Ok(status
        .iter()
        .filter_map(|s| if s.success() { None } else { s.code() })
        .next()
        .unwrap_or(SUCCESS))
}

fn get_cargo_metadata(manifest_path: Option<&Path>) -> Result<cargo_metadata::Metadata, io::Error> {
    let mut cmd = cargo_metadata::MetadataCommand::new();
    cmd.no_deps();
    if let Some(manifest_path) = manifest_path {
        cmd.manifest_path(manifest_path);
    }
    match cmd.exec() {
        Ok(metadata) => Ok(metadata),
        Err(error) => Err(io::Error::new(io::ErrorKind::Other, error.to_string())),
    }
}
<commit_msg>not to use Vec<commit_after>// Inspired by Paul Woolcock's cargo-fmt (https://github.com/pwoolcoc/cargo-fmt/).

#![cfg(not(test))]
#![deny(warnings)]

use cargo_metadata;
use getopts;

use std::cmp::Ordering;
use std::collections::{BTreeMap, BTreeSet};
use std::env;
use std::fs;
use std::hash::{Hash, Hasher};
use std::io::{self, Write};
use std::iter::FromIterator;
use std::path::{Path, PathBuf};
use std::process::Command;
use std::str;

use getopts::{Matches, Options};

fn main() {
    let exit_status = execute();
    std::io::stdout().flush().unwrap();
    std::process::exit(exit_status);
}

const SUCCESS: i32 = 0;
const FAILURE: i32 = 1;

fn execute() -> i32 {
    let mut opts = getopts::Options::new();
    opts.optflag("h", "help", "show this message");
    opts.optflag("q", "quiet", "no output printed to stdout");
    opts.optflag("v", "verbose", "use verbose output");
    opts.optmulti(
        "p",
        "package",
        "specify package to format (only usable in workspaces)",
        "<package>",
    );
    opts.optflag("", "version", "print rustfmt version and exit");
    opts.optflag("", "all", "format all packages (only usable in workspaces)");

    // If there is any invalid argument passed to `cargo fmt`, return without formatting.
    let mut is_package_arg = false;
    for arg in env::args().skip(2).take_while(|a| a != "--") {
        if arg.starts_with('-') {
            is_package_arg = arg.starts_with("--package") | arg.starts_with("-p");
        } else if !is_package_arg {
            print_usage_to_stderr(&opts, &format!("Invalid argument: `{}`.", arg));
            return FAILURE;
        } else {
            is_package_arg = false;
        }
    }

    let matches = match opts.parse(env::args().skip(1).take_while(|a| a != "--")) {
        Ok(m) => m,
        Err(e) => {
            print_usage_to_stderr(&opts, &e.to_string());
            return FAILURE;
        }
    };

    let verbosity = match (matches.opt_present("v"), matches.opt_present("q")) {
        (false, false) => Verbosity::Normal,
        (false, true) => Verbosity::Quiet,
        (true, false) => Verbosity::Verbose,
        (true, true) => {
            print_usage_to_stderr(&opts, "quiet mode and verbose mode are not compatible");
            return FAILURE;
        }
    };

    if matches.opt_present("h") {
        print_usage_to_stdout(&opts, "");
        return SUCCESS;
    }

    if matches.opt_present("version") {
        return handle_command_status(get_version(), &opts);
    }

    let strategy = CargoFmtStrategy::from_matches(&matches);
    handle_command_status(format_crate(verbosity, &strategy), &opts)
}

macro_rules! print_usage {
    ($print:ident, $opts:ident, $reason:expr) => {{
        let msg = format!("{}\nusage: cargo fmt [options]", $reason);
        $print!(
            "{}\nThis utility formats all bin and lib files of the current crate using rustfmt. \
             Arguments after `--` are passed to rustfmt.",
            $opts.usage(&msg)
        );
    }};
}

fn print_usage_to_stdout(opts: &Options, reason: &str) {
    print_usage!(println, opts, reason);
}

fn print_usage_to_stderr(opts: &Options, reason: &str) {
    print_usage!(eprintln, opts, reason);
}

#[derive(Debug, Clone, Copy, PartialEq)]
pub enum Verbosity {
    Verbose,
    Normal,
    Quiet,
}

fn handle_command_status(status: Result<i32, io::Error>, opts: &getopts::Options) -> i32 {
    match status {
        Err(e) => {
            print_usage_to_stderr(opts, &e.to_string());
            FAILURE
        }
        Ok(status) => status,
    }
}

fn get_version() -> Result<i32, io::Error> {
    let mut command = Command::new("rustfmt")
        .stdout(std::process::Stdio::inherit())
        .args(&[String::from("--version")])
        .spawn()
        .map_err(|e| match e.kind() {
            io::ErrorKind::NotFound => io::Error::new(
                io::ErrorKind::Other,
                "Could not run rustfmt, please make sure it is in your PATH.",
            ),
            _ => e,
        })?;
    let result = command.wait()?;
    if result.success() {
        Ok(SUCCESS)
    } else {
        Ok(result.code().unwrap_or(SUCCESS))
    }
}

fn format_crate(verbosity: Verbosity, strategy: &CargoFmtStrategy) -> Result<i32, io::Error> {
    let rustfmt_args = get_fmt_args();
    let targets = if rustfmt_args
        .iter()
        .any(|s| ["--print-config", "-h", "--help", "-V", "--version"].contains(&s.as_str()))
    {
        BTreeSet::new()
    } else {
        get_targets(strategy)?
    };

    // Currently only bin and lib files get formatted.
    run_rustfmt(&targets, &rustfmt_args, verbosity)
}

fn get_fmt_args() -> Vec<String> {
    // All arguments after -- are passed to rustfmt.
    env::args().skip_while(|a| a != "--").skip(1).collect()
}

/// Target uses a `path` field for equality and hashing.
#[derive(Debug)]
pub struct Target {
    /// A path to the main source file of the target.
    path: PathBuf,
    /// A kind of target (e.g., lib, bin, example, ...).
    kind: String,
    /// Rust edition for this target.
    edition: String,
}

impl Target {
    pub fn from_target(target: &cargo_metadata::Target) -> Self {
        let path = PathBuf::from(&target.src_path);
        let canonicalized = fs::canonicalize(&path).unwrap_or(path);

        Target {
            path: canonicalized,
            kind: target.kind[0].clone(),
            edition: target.edition.clone(),
        }
    }
}

impl PartialEq for Target {
    fn eq(&self, other: &Target) -> bool {
        self.path == other.path
    }
}

impl PartialOrd for Target {
    fn partial_cmp(&self, other: &Target) -> Option<Ordering> {
        Some(self.path.cmp(&other.path))
    }
}

impl Ord for Target {
    fn cmp(&self, other: &Target) -> Ordering {
        self.path.cmp(&other.path)
    }
}

impl Eq for Target {}

impl Hash for Target {
    fn hash<H: Hasher>(&self, state: &mut H) {
        self.path.hash(state);
    }
}

#[derive(Debug, PartialEq, Eq)]
pub enum CargoFmtStrategy {
    /// Format every packages and dependencies.
    All,
    /// Format packages that are specified by the command line argument.
    Some(Vec<String>),
    /// Format the root packages only.
    Root,
}

impl CargoFmtStrategy {
    pub fn from_matches(matches: &Matches) -> CargoFmtStrategy {
        match (matches.opt_present("all"), matches.opt_present("p")) {
            (false, false) => CargoFmtStrategy::Root,
            (true, _) => CargoFmtStrategy::All,
            (false, true) => CargoFmtStrategy::Some(matches.opt_strs("p")),
        }
    }
}

/// Based on the specified `CargoFmtStrategy`, returns a set of main source files.
fn get_targets(strategy: &CargoFmtStrategy) -> Result<BTreeSet<Target>, io::Error> {
    let mut targets = BTreeSet::new();

    match *strategy {
        CargoFmtStrategy::Root => get_targets_root_only(&mut targets)?,
        CargoFmtStrategy::All => get_targets_recursive(None, &mut targets, &mut BTreeSet::new())?,
        CargoFmtStrategy::Some(ref hitlist) => get_targets_with_hitlist(hitlist, &mut targets)?,
    }

    if targets.is_empty() {
        Err(io::Error::new(
            io::ErrorKind::Other,
            "Failed to find targets".to_owned(),
        ))
    } else {
        Ok(targets)
    }
}

fn get_targets_root_only(targets: &mut BTreeSet<Target>) -> Result<(), io::Error> {
    let metadata = get_cargo_metadata(None)?;
    let current_dir = env::current_dir()?.canonicalize()?;
    let current_dir_manifest = current_dir.join("Cargo.toml");
    let workspace_root_path = PathBuf::from(&metadata.workspace_root).canonicalize()?;
    let in_workspace_root = workspace_root_path == current_dir;

    for package in metadata.packages {
        if in_workspace_root || PathBuf::from(&package.manifest_path) == current_dir_manifest {
            for target in package.targets {
                targets.insert(Target::from_target(&target));
            }
        }
    }

    Ok(())
}

fn get_targets_recursive(
    manifest_path: Option<&Path>,
    mut targets: &mut BTreeSet<Target>,
    visited: &mut BTreeSet<String>,
) -> Result<(), io::Error> {
    let metadata = get_cargo_metadata(manifest_path)?;

    for package in metadata.packages {
        add_targets(&package.targets, &mut targets);

        // Look for local dependencies.
        for dependency in package.dependencies {
            if dependency.source.is_some() || visited.contains(&dependency.name) {
                continue;
            }

            let mut manifest_path = PathBuf::from(&package.manifest_path);

            manifest_path.pop();
            manifest_path.push(&dependency.name);
            manifest_path.push("Cargo.toml");

            if manifest_path.exists() {
                visited.insert(dependency.name);
                get_targets_recursive(Some(&manifest_path), &mut targets, visited)?;
            }
        }
    }

    Ok(())
}

fn get_targets_with_hitlist(
    hitlist: &[String],
    targets: &mut BTreeSet<Target>,
) -> Result<(), io::Error> {
    let metadata = get_cargo_metadata(None)?;

    let mut workspace_hitlist: BTreeSet<&String> = BTreeSet::from_iter(hitlist);

    for package in metadata.packages {
        if workspace_hitlist.remove(&package.name) {
            for target in package.targets {
                targets.insert(Target::from_target(&target));
            }
        }
    }

    if workspace_hitlist.is_empty() {
        Ok(())
    } else {
        let package = workspace_hitlist.iter().next().unwrap();
        Err(io::Error::new(
            io::ErrorKind::InvalidInput,
            format!("package `{}` is not a member of the workspace", package),
        ))
    }
}

fn add_targets(target_paths: &[cargo_metadata::Target], targets: &mut BTreeSet<Target>) {
    for target in target_paths {
        targets.insert(Target::from_target(target));
    }
}

fn run_rustfmt(
    targets: &BTreeSet<Target>,
    fmt_args: &[String],
    verbosity: Verbosity,
) -> Result<i32, io::Error> {
    let by_edition = targets
        .iter()
        .inspect(|t| {
            if verbosity == Verbosity::Verbose {
                println!("[{} ({})] {:?}", t.kind, t.edition, t.path)
            }
        })
        .fold(BTreeMap::new(), |mut h, t| {
            h.entry(&t.edition).or_insert_with(Vec::new).push(&t.path);
            h
        });

    let mut status = vec![];
    for (edition, files) in by_edition {
        let stdout = if verbosity == Verbosity::Quiet {
            std::process::Stdio::null()
        } else {
            std::process::Stdio::inherit()
        };

        if verbosity == Verbosity::Verbose {
            print!("rustfmt");
            print!(" --edition {}", edition);
            fmt_args.iter().for_each(|f| print!(" {}", f));
            files.iter().for_each(|f| print!(" {}", f.display()));
            println!();
        }

        let mut command = Command::new("rustfmt")
            .stdout(stdout)
            .args(files)
            .args(&["--edition", edition])
            .args(fmt_args)
            .spawn()
            .map_err(|e| match e.kind() {
                io::ErrorKind::NotFound => io::Error::new(
                    io::ErrorKind::Other,
                    "Could not run rustfmt, please make sure it is in your PATH.",
                ),
                _ => e,
            })?;

        status.push(command.wait()?);
    }

    Ok(status
        .iter()
        .filter_map(|s| if s.success() { None } else { s.code() })
        .next()
        .unwrap_or(SUCCESS))
}

fn get_cargo_metadata(manifest_path: Option<&Path>) -> Result<cargo_metadata::Metadata, io::Error> {
    let mut cmd = cargo_metadata::MetadataCommand::new();
    cmd.no_deps();
    if let Some(manifest_path) = manifest_path {
        cmd.manifest_path(manifest_path);
    }
    match cmd.exec() {
        Ok(metadata) => Ok(metadata),
        Err(error) => Err(io::Error::new(io::ErrorKind::Other, error.to_string())),
    }
}
<|endoftext|>


<commit_before>use crate::types::ShortString;
use parking_lot::RwLock;
use std::sync::Arc;

#[derive(Clone, Debug, Default)]
pub struct ChannelStatus {
    inner: Arc<RwLock<Inner>>,
}

impl ChannelStatus {
    pub fn is_initializing(&self) -> bool {
        self.inner.read().state == ChannelState::Initial
    }

    pub fn is_closing(&self) -> bool {
        self.inner.read().state == ChannelState::Closing
    }

    pub fn is_connected(&self) -> bool {
        !&[
            ChannelState::Initial,
            ChannelState::Closing,
            ChannelState::Closed,
            ChannelState::Error,
        ]
        .contains(&self.inner.read().state)
    }

    pub fn confirm(&self) -> bool {
        self.inner.read().confirm
    }

    pub(crate) fn set_confirm(&self) {
        self.inner.write().confirm = true
    }

    pub fn state(&self) -> ChannelState {
        self.inner.read().state.clone()
    }

    pub(crate) fn set_state(&self, state: ChannelState) {
        self.inner.write().state = state
    }

    pub(crate) fn set_send_flow(&self, flow: bool) {
        self.inner.write().send_flow = flow;
    }

    pub(crate) fn flow(&self) -> bool {
        self.inner.read().send_flow
    }
}

#[derive(Clone, Debug, PartialEq, Eq)]
pub enum ChannelState {
    Initial,
    Connected,
    Closing,
    Closed,
    Error,
    SendingContent(usize),
    WillReceiveContent(Option<ShortString>, Option<ShortString>),
    ReceivingContent(Option<ShortString>, Option<ShortString>, usize),
}

impl Default for ChannelState {
    fn default() -> Self {
        ChannelState::Initial
    }
}

#[derive(Debug)]
struct Inner {
    confirm: bool,
    send_flow: bool,
    state: ChannelState,
}

impl Default for Inner {
    fn default() -> Self {
        Self {
            confirm: false,
            send_flow: true,
            state: ChannelState::default(),
        }
    }
}
<commit_msg>channel: log when activating publisher confirms<commit_after>use crate::types::ShortString;
use parking_lot::RwLock;
use std::sync::Arc;

#[derive(Clone, Debug, Default)]
pub struct ChannelStatus {
    inner: Arc<RwLock<Inner>>,
}

impl ChannelStatus {
    pub fn is_initializing(&self) -> bool {
        self.inner.read().state == ChannelState::Initial
    }

    pub fn is_closing(&self) -> bool {
        self.inner.read().state == ChannelState::Closing
    }

    pub fn is_connected(&self) -> bool {
        !&[
            ChannelState::Initial,
            ChannelState::Closing,
            ChannelState::Closed,
            ChannelState::Error,
        ]
        .contains(&self.inner.read().state)
    }

    pub fn confirm(&self) -> bool {
        self.inner.read().confirm
    }

    pub(crate) fn set_confirm(&self) {
        self.inner.write().confirm = true
        trace!("Publisher confirms activated");
    }

    pub fn state(&self) -> ChannelState {
        self.inner.read().state.clone()
    }

    pub(crate) fn set_state(&self, state: ChannelState) {
        self.inner.write().state = state
    }

    pub(crate) fn set_send_flow(&self, flow: bool) {
        self.inner.write().send_flow = flow;
    }

    pub(crate) fn flow(&self) -> bool {
        self.inner.read().send_flow
    }
}

#[derive(Clone, Debug, PartialEq, Eq)]
pub enum ChannelState {
    Initial,
    Connected,
    Closing,
    Closed,
    Error,
    SendingContent(usize),
    WillReceiveContent(Option<ShortString>, Option<ShortString>),
    ReceivingContent(Option<ShortString>, Option<ShortString>, usize),
}

impl Default for ChannelState {
    fn default() -> Self {
        ChannelState::Initial
    }
}

#[derive(Debug)]
struct Inner {
    confirm: bool,
    send_flow: bool,
    state: ChannelState,
}

impl Default for Inner {
    fn default() -> Self {
        Self {
            confirm: false,
            send_flow: true,
            state: ChannelState::default(),
        }
    }
}
<|endoftext|>


<commit_before>//! # yeild
//!
//! generator yield implmentation
//!

use std::any::Any;
use generator::Generator;
use rt::{Error, Context, ContextStack};
use reg_context::Context as RegContext;

/// switch back to parent context
#[inline]
pub fn yield_now() {
    let env = ContextStack::current();
    let mut cur = env.top();
    let sp = &cur.stack;
    // judge if this is root context
    if sp.size() > 0 {
        env.pop();
        let parent = env.top();
        RegContext::swap(&mut cur.regs, &parent.regs);
    }
}

/// raw yiled without catch passed in para
#[inline]
fn raw_yield<T: Any>(context: &mut Context, v: T) {
    // check the context
    if !context.is_generator() {
        info!("yield from none generator context");
        // do nothing, just return
        return;
        // panic!(Error::ContextErr);
    }

    context.set_ret(v);
    context._ref -= 1;
    yield_now();

    // here we just panic to exit the func
    if context._ref != 1 {
        panic!(Error::Cancel);
    }
}

/// yiled something without catch passed in para
#[inline]
pub fn yield_with<T: Any>(v: T) {
    raw_yield(ContextStack::current().top(), v);
}

/// get the passed in para
#[inline]
pub fn get_yield<A: Any>() -> Option<A> {
    let context = ContextStack::current().top();
    raw_get_yield(context)
}

/// get the passed in para from context
#[inline]
fn raw_get_yield<A: Any>(context: &mut Context) -> Option<A> {
    // check the context
    if !context.is_generator() {
        error!("get yield from none generator context");
        panic!(Error::ContextErr);
    }

    context.get_para()
}

/// yiled and get the send para
#[inline]
pub fn yield_<A: Any, T: Any>(v: T) -> Option<A> {
    let context = ContextStack::current().top();
    let p = raw_get_yield(context);
    raw_yield(context, v);
    p
}

/// `yiled_from`
pub fn yield_from<A: Any, T: Any>(mut g: Box<Generator<A, Output = T>>) {
    let context = ContextStack::current().top();
    while !g.is_done() {
        let p = context.get_para();
        let r = g.raw_send(p).unwrap();
        raw_yield(context, r);
    }
}
<commit_msg>reduce TLS access for raw_yield_now<commit_after>//! # yeild
//!
//! generator yield implmentation
//!

use std::any::Any;
use generator::Generator;
use rt::{Error, Context, ContextStack};
use reg_context::Context as RegContext;

/// switch back to parent context
#[inline]
pub fn yield_now() {
    let env = ContextStack::current();
    let mut cur = env.top();
    let sp = &cur.stack;
    // judge if this is root context
    if sp.size() > 0 {
        env.pop();
        let parent = env.top();
        RegContext::swap(&mut cur.regs, &parent.regs);
    }
}

#[inline]
fn raw_yield_now(env: &mut ContextStack, cur: &mut Context) {
    let sp = &cur.stack;
    // judge if this is root context
    if sp.size() > 0 {
        env.pop();
        let parent = env.top();
        RegContext::swap(&mut cur.regs, &parent.regs);
    }
}

/// raw yiled without catch passed in para
#[inline]
fn raw_yield<T: Any>(env: &mut ContextStack, context: &mut Context, v: T) {
    // check the context
    if !context.is_generator() {
        info!("yield from none generator context");
        // do nothing, just return
        return;
        // panic!(Error::ContextErr);
    }

    context.set_ret(v);
    context._ref -= 1;
    raw_yield_now(env, context);

    // here we just panic to exit the func
    if context._ref != 1 {
        panic!(Error::Cancel);
    }
}

/// yiled something without catch passed in para
#[inline]
pub fn yield_with<T: Any>(v: T) {
    let env = ContextStack::current();
    let context = env.top();
    raw_yield(env, context, v);
}

/// get the passed in para
#[inline]
pub fn get_yield<A: Any>() -> Option<A> {
    let context = ContextStack::current().top();
    raw_get_yield(context)
}

/// get the passed in para from context
#[inline]
fn raw_get_yield<A: Any>(context: &mut Context) -> Option<A> {
    // check the context
    if !context.is_generator() {
        error!("get yield from none generator context");
        panic!(Error::ContextErr);
    }

    context.get_para()
}

/// yiled and get the send para
#[inline]
pub fn yield_<A: Any, T: Any>(v: T) -> Option<A> {
    let env = ContextStack::current();
    let context = env.top();
    let p = raw_get_yield(context);
    raw_yield(env, context, v);
    p
}

/// `yiled_from`
pub fn yield_from<A: Any, T: Any>(mut g: Box<Generator<A, Output = T>>) {
    let env = ContextStack::current();
    let context = env.top();
    while !g.is_done() {
        let p = context.get_para();
        let r = g.raw_send(p).unwrap();
        raw_yield(env, context, r);
    }
}
<|endoftext|>


<commit_before>use state::{Named, Editable, Undoable, Selectable};
use termion::event::{Event, Key, MouseEvent};
use view::View;
use std::cmp;
use clipboard::ClipboardContext;
use super::{State, treat_insert_event};

pub fn treat_selected_event<T>(content: &mut T, view: &mut View, event: Event, state: &mut State)
    where T: Selectable + Editable + Named + Undoable
{
    match event {
        Event::Key(Key::Ctrl('c')) => {
            let (beg, end) = content.sel().unwrap();

            let selection: String = content.iter().skip(beg).take(end - beg + 1).collect();
            let mut ctx = ClipboardContext::new().unwrap();
            ctx.set_contents(selection).unwrap();

            content.reset_sel();
            *state = State::Insert;
        }
        Event::Key(Key::Ctrl('x')) => {
            let (beg, end) = content.sel().unwrap();

            let selection: String = content.iter().skip(beg).take(end - beg + 1).collect();
            let mut ctx = ClipboardContext::new().unwrap();
            ctx.set_contents(selection).unwrap();

            delete_sel(content);
            view.adjust_view(content.line());

            content.reset_sel();
            *state = State::Insert;
        }
        Event::Key(Key::Backspace) => {
            delete_sel(content);
            view.adjust_view(content.line());
            content.reset_sel();
            *state = State::Insert;
        }
        _ => {
            content.reset_sel();
            *state = State::Insert;

            treat_insert_event(content, view, event, state)
        }
    }
}

fn delete_sel<T>(content: &mut T)
    where T: Selectable + Editable
{
    let (beg, end) = content.sel().unwrap();
    let end = cmp::min(end + 1, content.len() - 1);
    content.move_to(end);
    for _ in beg..end {
        content.delete();
    }
}

pub fn treat_select_event<T>(content: &mut T, view: &mut View, event: Event, state: &mut State)
    where T: Editable + Selectable
{
    match event {
        Event::Mouse(MouseEvent::Hold(x, y)) => {
            let (line, col) = view.translate_coordinates(content, x, y);
            content.move_at(line, col);
            if let State::Select(origin) = *state {
                let sel = (cmp::min(origin, content.pos()), cmp::max(origin, content.pos()));
                content.set_sel(sel);
            } else {
                panic!("Treating select event when event is not a Select");
            }
        }
        Event::Mouse(MouseEvent::Release(x, y)) => {
            let (line, col) = view.translate_coordinates(content, x, y);
            content.move_at(line, col);
            if let State::Select(origin) = *state {
                if origin != content.pos() {
                    let sel = (cmp::min(origin, content.pos() - 1),
                               cmp::max(origin, content.pos() - 1));
                    content.set_sel(sel);
                    *state = State::Selected;
                } else {
                    *state = State::Insert;
                }
            } else {
                panic!("Treating select event when event is not a Select");
            }

        }
        _ => {}
    }
}
<commit_msg>removed useless offsetting<commit_after>use state::{Named, Editable, Undoable, Selectable};
use termion::event::{Event, Key, MouseEvent};
use view::View;
use std::cmp;
use clipboard::ClipboardContext;
use super::{State, treat_insert_event};

pub fn treat_selected_event<T>(content: &mut T, view: &mut View, event: Event, state: &mut State)
    where T: Selectable + Editable + Named + Undoable
{
    match event {
        Event::Key(Key::Ctrl('c')) => {
            let (beg, end) = content.sel().unwrap();

            let selection: String = content.iter().skip(beg).take(end - beg + 1).collect();
            let mut ctx = ClipboardContext::new().unwrap();
            ctx.set_contents(selection).unwrap();

            content.reset_sel();
            *state = State::Insert;
        }
        Event::Key(Key::Ctrl('x')) => {
            let (beg, end) = content.sel().unwrap();

            let selection: String = content.iter().skip(beg).take(end - beg + 1).collect();
            let mut ctx = ClipboardContext::new().unwrap();
            ctx.set_contents(selection).unwrap();

            delete_sel(content);
            view.adjust_view(content.line());

            content.reset_sel();
            *state = State::Insert;
        }
        Event::Key(Key::Backspace) => {
            delete_sel(content);
            view.adjust_view(content.line());
            content.reset_sel();
            *state = State::Insert;
        }
        _ => {
            content.reset_sel();
            *state = State::Insert;

            treat_insert_event(content, view, event, state)
        }
    }
}

fn delete_sel<T>(content: &mut T)
    where T: Selectable + Editable
{
    let (beg, end) = content.sel().unwrap();
    let end = cmp::min(end + 1, content.len() - 1);
    content.move_to(end);
    for _ in beg..end {
        content.delete();
    }
}

pub fn treat_select_event<T>(content: &mut T, view: &mut View, event: Event, state: &mut State)
    where T: Editable + Selectable
{
    match event {
        Event::Mouse(MouseEvent::Hold(x, y)) => {
            let (line, col) = view.translate_coordinates(content, x, y);
            content.move_at(line, col);
            if let State::Select(origin) = *state {
                let sel = (cmp::min(origin, content.pos()), cmp::max(origin, content.pos()));
                content.set_sel(sel);
            } else {
                panic!("Treating select event when event is not a Select");
            }
        }
        Event::Mouse(MouseEvent::Release(x, y)) => {
            let (line, col) = view.translate_coordinates(content, x, y);
            content.move_at(line, col);
            if let State::Select(origin) = *state {
                if origin != content.pos() {
                    let sel = (cmp::min(origin, content.pos()),
                               cmp::max(origin, content.pos()));
                    content.set_sel(sel);
                    *state = State::Selected;
                } else {
                    *state = State::Insert;
                }
            } else {
                panic!("Treating select event when event is not a Select");
            }

        }
        _ => {}
    }
}
<|endoftext|>


<commit_before>use annotation::*;
use error::Cause;
use image::ImageFormat;
use config::resource::Resource;
use std::borrow::Cow;
use std::error;
use std::fmt;
use std::path::{Path, PathBuf};

// How the hell do you make a path buffer from command line input if command line input is a
// string but a path buffer itself is technically not because it isn't validated UTF8?

pub struct Options {
    pub base_image: Resource,
    pub annotations: AnnotationCollection,
    pub output_path: PathBuf,
    pub output_format: OutputFormat,
    pub scale_mult: f32,
    pub font_path: PathBuf,
    pub debug: bool,
}

#[derive(Copy, Clone)]
pub enum OutputFormat {
    Jpg,
    Png,
}

impl Into<ImageFormat> for OutputFormat {
    fn into(self) -> ImageFormat {
        match self {
            OutputFormat::Jpg => ImageFormat::JPEG,
            OutputFormat::Png => ImageFormat::PNG,
        }
    }
}

impl Options {
    pub fn from_args() -> Result<Self, BuildOptionsError> {
        read_command()
    }
}

pub struct OptionsBuilder {
    base_image: Option<String>,
    annotations: Vec<Annotation>,
    output_path: Option<String>,
    output_format: OutputFormat,
    scale_mult: f32,
    font_path: Cow<'static, str>,
    debug: bool,
}

impl OptionsBuilder {
    fn new() -> OptionsBuilder {
        OptionsBuilder {
            base_image: None,
            annotations: Vec::new(),
            output_path: None,
            output_format: OutputFormat::Jpg,
            scale_mult: 1.0,
            font_path: default_font(),
            debug: false,
        }
    }
}

impl OptionsBuilder {
    fn build(self) -> Result<Options, BuildOptionsError> {
        let input_path: PathBuf = self.base_image.as_ref().unwrap().into();
        if input_path.file_name().is_none() {
            return Err(BuildOptionsError {
                kind: BuildOptionsErrorKind::ImagePath,
                description: Cow::from("The provided image path does not appear to have a filename"),
                cause: None,
            });
        }

        let output_format = self.output_format;
        let output_path = self.output_path
            .map(|s| s.into())
            .unwrap_or_else(|| create_output_file_path(&input_path, output_format));

        Ok(Options {
            base_image: Resource::new(self.base_image.unwrap()),
            annotations: AnnotationCollection::new(self.annotations),
            output_path,
            output_format,
            scale_mult: self.scale_mult,
            font_path: self.font_path.to_string().into(),
            debug: self.debug,
        })
    }
}

#[derive(Debug)]
pub struct BuildOptionsError {
    kind: BuildOptionsErrorKind,
    description: Cow<'static, str>,
    cause: Cause,
}

#[derive(Debug)]
enum BuildOptionsErrorKind {
    ImagePath,
    ScalingMultiplier,
}

impl fmt::Display for BuildOptionsError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.write_str(&self.description)
    }
}

impl error::Error for BuildOptionsError {
    fn description(&self) -> &str {
        &self.description
    }

    fn cause(&self) -> Option<&error::Error> {
        match self.cause {
            Some(ref error) => Some(error.as_ref()),
            None => None,
        }
    }
}

fn read_command() -> Result<Options, BuildOptionsError> {
    use clap::ArgGroup;

    let text_group = ArgGroup::with_name("text_group")
        .args(&["caption", "bottom", "top", "middle"])
        .required(true)
        .multiple(true);

    let encoding_group = ArgGroup::with_name("enc_group")
        .args(&["encoding", "jpg", "png"]);

    let app = clap_app!(annatar =>
        (version: crate_version!())
        (author: crate_authors!())
        (about: crate_description!())
        (@arg image: +required "Path to an image to be annotated")
        (@arg caption: "A message to be added to the bottom of the image")
        (@arg bottom: -b --bottom +takes_value "A message to be added to the bottom of the image")
        (@arg top: -t --top +takes_value "A message to be added to the top of the image")
        (@arg middle: -m --middle +takes_value "A message to be added to the middle of the image")
        (@arg output: -o --output +takes_value "Sets an output path for the new image (default: <image path>/<image name>.ann.<ext>)")
        (@arg scale: -s --scale +takes_value "Sets the scale multiplier for annotations")
        (@arg font: -f --font +takes_value "Sets the path of the font to be used (default: Impact)")
        (@arg debug: -d --debug "Save edge detection ... thing to disk")
        (@arg encoding: -e --encoding +takes_value "Set JPG or PNG")
        (@arg jpg: --jpg "Set JPG mode (default)")
        (@arg png: --png "Set PNG mode")
    );

    // Much easier to set up argument groups outside macro.
    let app = app
        .group(text_group)
        .group(encoding_group);

    let matches = app.get_matches();
    let mut options = OptionsBuilder::new();

    options.base_image = Some(matches.value_of("image").unwrap().to_string());
    options.output_path = matches.value_of("output").map(|s| s.to_string());

    if let Some(scale_multiplier) = matches.value_of("scale") {
        let multiplier = scale_multiplier.parse::<f32>()
            .map_err(|e| BuildOptionsError {
                kind: BuildOptionsErrorKind::ScalingMultiplier,
                description: Cow::from("Scaling multiplier must be a decimal value"),
                cause: Some(Box::new(e)),
            })?;
        options.scale_mult = multiplier;
    }

    if let Some(font_path) = matches.value_of("font") {
        options.font_path = Cow::from(font_path.to_string());
    }

    if let Some(caption) = matches.value_of("caption") {
        options.annotations.push(Annotation::Bottom(caption.into()));
    }

    if let Some(caption) = matches.value_of("top") {
        options.annotations.push(Annotation::Top(caption.into()));
    }

    if let Some(caption) = matches.value_of("middle") {
        options.annotations.push(Annotation::Middle(caption.into()));
    }

    if let Some(caption) = matches.value_of("bottom") {
        options.annotations.push(Annotation::Bottom(caption.into()));
    }

    if matches.is_present("png") {
        options.output_format = OutputFormat::Png;
    } else if let Some(format) = matches.value_of("encoding") {
        options.output_format = match &*format {
            "png" | "PNG" => OutputFormat::Png,
            _ => OutputFormat::Jpg,
        };
    }

    options.debug = matches.is_present("debug");

    options.build()
}

#[cfg(target_os = "windows")]
fn default_font() -> Cow<'static, str> {
    Cow::from("C:/Windows/Fonts/Impact.ttf")
}

#[cfg(target_os = "macos")]
fn default_font() -> Cow<'static, str> {
    Cow::from("/Library/Fonts/Impact.ttf")
}

#[cfg(not(any(target_os = "windows", target_os = "macos")))]
fn default_font() -> Cow<'static, str> {
    panic!("Honestly, getting a font on Linux is going to be an adventure.");
}

fn create_output_file_path(input_path: &Path, output_format: OutputFormat) -> PathBuf {
    // I unwrap this because clap already converted it to a string, implying it's valid utf-8.
    let mut file_name = input_path.file_name().unwrap().to_str().unwrap().to_string();
    if let Some(last_segment_idx) = file_name.rfind('.') {
        file_name.truncate(last_segment_idx);
    }

    match output_format {
        OutputFormat::Png => file_name.push_str("-annotated.png"),
        _ => file_name.push_str("-annotated.jpg"),
    }

    file_name.into()
}
<commit_msg>Allow alternate annotation sources<commit_after>use annotation::*;
use error::Cause;
use image::ImageFormat;
use config::resource::Resource;
use std::borrow::Cow;
use std::error;
use std::fmt;
use std::path::{Path, PathBuf};

// How the hell do you make a path buffer from command line input if command line input is a
// string but a path buffer itself is technically not because it isn't validated UTF8?

pub struct Options {
    pub base_image: Resource,
    pub annotations: AnnotationCollection,
    pub output_path: PathBuf,
    pub output_format: OutputFormat,
    pub scale_mult: f32,
    pub font_path: PathBuf,
    pub debug: bool,
}

#[derive(Copy, Clone)]
pub enum OutputFormat {
    Jpg,
    Png,
}

impl Into<ImageFormat> for OutputFormat {
    fn into(self) -> ImageFormat {
        match self {
            OutputFormat::Jpg => ImageFormat::JPEG,
            OutputFormat::Png => ImageFormat::PNG,
        }
    }
}

impl Options {
    pub fn from_args() -> Result<Self, BuildOptionsError> {
        read_command()
    }
}

pub struct OptionsBuilder {
    base_image: Option<String>,
    annotations: Vec<Annotation>,
    output_path: Option<String>,
    output_format: OutputFormat,
    scale_mult: f32,
    font_path: Cow<'static, str>,
    debug: bool,
}

impl OptionsBuilder {
    fn new() -> OptionsBuilder {
        OptionsBuilder {
            base_image: None,
            annotations: Vec::new(),
            output_path: None,
            output_format: OutputFormat::Jpg,
            scale_mult: 1.0,
            font_path: default_font(),
            debug: false,
        }
    }
}

impl OptionsBuilder {
    fn build(self) -> Result<Options, BuildOptionsError> {
        let input_path: PathBuf = self.base_image.as_ref().unwrap().into();
        if input_path.file_name().is_none() {
            return Err(BuildOptionsError {
                kind: BuildOptionsErrorKind::ImagePath,
                description: Cow::from("The provided image path does not appear to have a filename"),
                cause: None,
            });
        }

        let output_format = self.output_format;
        let output_path = self.output_path
            .map(|s| s.into())
            .unwrap_or_else(|| create_output_file_path(&input_path, output_format));

        let annotations = if self.annotations.is_empty() {
            return Err(BuildOptionsError {
                kind: BuildOptionsErrorKind::Annotations,
                description: Cow::from("No annotations provided"),
                cause: None,
            })
        } else {
            AnnotationCollection::new(self.annotations)
        };

        Ok(Options {
            base_image: Resource::new(self.base_image.unwrap()),
            annotations,
            output_path,
            output_format,
            scale_mult: self.scale_mult,
            font_path: self.font_path.to_string().into(),
            debug: self.debug,
        })
    }
}

#[derive(Debug)]
pub struct BuildOptionsError {
    kind: BuildOptionsErrorKind,
    description: Cow<'static, str>,
    cause: Cause,
}

#[derive(Debug)]
enum BuildOptionsErrorKind {
    Annotations,
    ImagePath,
    ScalingMultiplier,
}

impl fmt::Display for BuildOptionsError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.write_str(&self.description)
    }
}

impl error::Error for BuildOptionsError {
    fn description(&self) -> &str {
        &self.description
    }

    fn cause(&self) -> Option<&error::Error> {
        match self.cause {
            Some(ref error) => Some(error.as_ref()),
            None => None,
        }
    }
}

fn read_command() -> Result<Options, BuildOptionsError> {
    use clap::ArgGroup;

    let text_group = ArgGroup::with_name("text_group")
        .args(&["caption", "bottom", "top", "middle"])
        .multiple(true);

    let encoding_group = ArgGroup::with_name("enc_group")
        .args(&["encoding", "jpg", "png"]);

    let app = clap_app!(annatar =>
        (version: crate_version!())
        (author: crate_authors!())
        (about: crate_description!())
        (@arg image: +required "Path to an image to be annotated")
        (@arg caption: "A message to be added to the bottom of the image")
        (@arg bottom: -b --bottom +takes_value "A message to be added to the bottom of the image")
        (@arg top: -t --top +takes_value "A message to be added to the top of the image")
        (@arg middle: -m --middle +takes_value "A message to be added to the middle of the image")
        (@arg output: -o --output +takes_value "Sets an output path for the new image (default: <image path>/<image name>.ann.<ext>)")
        (@arg scale: -s --scale +takes_value "Sets the scale multiplier for annotations")
        (@arg font: -f --font +takes_value "Sets the path of the font to be used (default: Impact)")
        (@arg debug: -d --debug "Save edge detection ... thing to disk")
        (@arg encoding: -e --encoding +takes_value "Set JPG or PNG")
        (@arg jpg: --jpg "Set JPG mode (default)")
        (@arg png: --png "Set PNG mode")
    );

    // Much easier to set up argument groups outside macro.
    let app = app
        .group(text_group)
        .group(encoding_group);

    let matches = app.get_matches();
    let mut options = OptionsBuilder::new();

    options.base_image = Some(matches.value_of("image").unwrap().to_string());
    options.output_path = matches.value_of("output").map(|s| s.to_string());

    if let Some(scale_multiplier) = matches.value_of("scale") {
        let multiplier = scale_multiplier.parse::<f32>()
            .map_err(|e| BuildOptionsError {
                kind: BuildOptionsErrorKind::ScalingMultiplier,
                description: Cow::from("Scaling multiplier must be a decimal value"),
                cause: Some(Box::new(e)),
            })?;
        options.scale_mult = multiplier;
    }

    if let Some(font_path) = matches.value_of("font") {
        options.font_path = Cow::from(font_path.to_string());
    }

    if let Some(caption) = matches.value_of("caption") {
        options.annotations.push(Annotation::Bottom(caption.into()));
    }

    if let Some(caption) = matches.value_of("top") {
        options.annotations.push(Annotation::Top(caption.into()));
    }

    if let Some(caption) = matches.value_of("middle") {
        options.annotations.push(Annotation::Middle(caption.into()));
    }

    if let Some(caption) = matches.value_of("bottom") {
        options.annotations.push(Annotation::Bottom(caption.into()));
    }

    if matches.is_present("png") {
        options.output_format = OutputFormat::Png;
    } else if let Some(format) = matches.value_of("encoding") {
        options.output_format = match &*format {
            "png" | "PNG" => OutputFormat::Png,
            _ => OutputFormat::Jpg,
        };
    }

    options.debug = matches.is_present("debug");

    options.build()
}

#[cfg(target_os = "windows")]
fn default_font() -> Cow<'static, str> {
    Cow::from("C:/Windows/Fonts/Impact.ttf")
}

#[cfg(target_os = "macos")]
fn default_font() -> Cow<'static, str> {
    Cow::from("/Library/Fonts/Impact.ttf")
}

#[cfg(not(any(target_os = "windows", target_os = "macos")))]
fn default_font() -> Cow<'static, str> {
    panic!("Honestly, getting a font on Linux is going to be an adventure.");
}

fn create_output_file_path(input_path: &Path, output_format: OutputFormat) -> PathBuf {
    // I unwrap this because clap already converted it to a string, implying it's valid utf-8.
    let mut file_name = input_path.file_name().unwrap().to_str().unwrap().to_string();
    if let Some(last_segment_idx) = file_name.rfind('.') {
        file_name.truncate(last_segment_idx);
    }

    match output_format {
        OutputFormat::Png => file_name.push_str("-annotated.png"),
        _ => file_name.push_str("-annotated.jpg"),
    }

    file_name.into()
}
<|endoftext|>


<commit_before>/* diosix debug console output code
 *
 * (c) Chris Williams, 2019-2021.
 *
 * See LICENSE for usage and copying.
 */

/* to avoid warnings about super::hardware when qemuprint is active */
#![allow(unused_imports)]

use super::error::Cause;
use core::fmt;
use super::lock::Mutex;
use alloc::vec::Vec;
use alloc::string::String;
use super::hardware;
use super::service;
use super::message;

/* here's the logic for the hypervisor's debug queues
    * all the hvprint macros feed into DEBUG_QUEUE
    * the hypervisor will select a physical CPU core in between workloads to drain DEBUG_QUEUE
    * DEBUG_QUEUE will be drained into two channels: DEBUG_LOG, and the system debug output port
      (typically a serial port) if a user interface capsule isn't running
    * the user interface capsule will drain DEBUG_LOG
    * DEBUG_LOG will have a fixed limit to avoid it chewing up too much RAM
    * if the qemuprint feature is active, the system debug output port will always be the
      Qemu virt serial port regardless of what's in the host hardware's device tree
*/

const DEBUG_LOG_MAX_LEN: usize = 64 * 1024; /* 64KB max length for debug log buffer */

lazy_static!
{
    pub static ref DEBUG_LOCK: Mutex<bool> = Mutex::new("primary debug lock", false);
    static ref DEBUG_QUEUE: Mutex<String> = Mutex::new("debug output queue", String::new());
    static ref DEBUG_LOG: Mutex<Vec<char>> = Mutex::new("debug log buffer", Vec::new());
}

/* top level debug macros */
/* bad news: bug detection, failures, etc. */
#[macro_export]
macro_rules! hvalert
{
    ($fmt:expr) => (hvprintln!("[!] CPU {}: {}", $crate::pcore::PhysicalCore::get_id(), $fmt));
    ($fmt:expr, $($arg:tt)*) => (hvprintln!(concat!("[!] CPU {}: ", $fmt), $crate::pcore::PhysicalCore::get_id(), $($arg)*));
}

/* only output if debug build is enabled */
#[macro_export]
#[cfg(debug_assertions)]
macro_rules! hvdebug
{
    ($fmt:expr) => (hvprintln!("[?] CPU {}: {}", $crate::pcore::PhysicalCore::get_id(), $fmt));
    ($fmt:expr, $($arg:tt)*) => (hvprintln!(concat!("[?] CPU {}: ", $fmt), $crate::pcore::PhysicalCore::get_id(), $($arg)*));
}

/* silence debug if disabled */
#[macro_export]
#[cfg(not(debug_assertions))]
macro_rules! hvdebug
{
    ($fmt:expr) => ({});
    ($fmt:expr, $($arg:tt)*) => ({});
}

/* don't include any metadata nor add a newline */
#[macro_export]
#[cfg(debug_assertions)]
macro_rules! hvdebugraw
{
    ($fmt:expr) => (hvprint!("{}", $fmt));
    ($fmt:expr, $($arg:tt)*) => (hvprint!(concat!($fmt), $($arg)*));
}

/* silence debug if disabled */
#[macro_export]
#[cfg(not(debug_assertions))]
macro_rules! hvdebugraw
{
    ($fmt:expr) => ({});
    ($fmt:expr, $($arg:tt)*) => ({});
}

/* low-level macros for hypervisor-only hvprintln and hvprint debug output routines */
macro_rules! hvprintln
{
    ($fmt:expr) => (hvprint!(concat!($fmt, "\r\n")));
    ($fmt:expr, $($arg:tt)*) => (hvprint!(concat!($fmt, "\r\n"), $($arg)*));
}

macro_rules! hvprint
{
    ($($arg:tt)*) =>
    ({
        use core::fmt::Write;
        {
            let mut hvprint_lock = $crate::debug::DEBUG_LOCK.lock();
            *hvprint_lock = true;

            unsafe { $crate::debug::CONSOLE.write_fmt(format_args!($($arg)*)).unwrap(); }
        }
    });
}

macro_rules! debughousekeeper
{
    () => ($crate::debug::drain_queue());
}

/* create a generic debug console writer */
pub struct ConsoleWriter;
pub static mut CONSOLE: ConsoleWriter = ConsoleWriter {};

impl fmt::Write for ConsoleWriter
{
    fn write_str(&mut self, s: &str) -> core::fmt::Result
    {
        DEBUG_QUEUE.lock().push_str(s);
        Ok(())
    }
}

/* drain the debug queue into the debug logging buffer, and if no user interface
   is available yet, drain the queue into the system debug output port */
pub fn drain_queue()
{
    /* avoid blocking if we can't write at this time */
    if DEBUG_LOCK.is_locked() == false
    {
        let mut debug_lock = DEBUG_LOCK.lock();
        *debug_lock = true;
        let mut debug_queue = DEBUG_QUEUE.lock();
        let mut debug_log = DEBUG_LOG.lock();

        /* copy the debug queue out to the system debug output port ourselves if there's
           no user interface yet */
        if service::is_registered(service::ServiceType::ConsoleInterface) == false
        {
            if cfg!(feature = "qemuprint")
            {
                /* force debug output to Qemu's serial port. useful for early debugging */
                for c in debug_queue.as_bytes()
                {
                    /* this is the serial port address in qemu's RISC-V virt emulation */
                    if cfg!(target_arch = "riscv64")
                    {
                        let tx_register = 0x10000000; /* qemu's standard UART location in memory */
                        unsafe { *(tx_register as *mut u8) = *c };
                    }
                }
            }
            else if cfg!(feature = "sifiveprint")
            {
                let tx_register = 0x10010000; /* sifive's standard UART tx register location in memory */

                /* force debug output to SiFive's standard serial port. useful for early debugging */
                for c in debug_queue.as_bytes()
                {
                    /* when reading the word-length tx write register,
                       it's zero if we're OK to write to it */
                    while unsafe { *(tx_register as *mut u32) } != 0 {}
                    unsafe { *(tx_register as *mut u32) = *c as u32 };
                }
            }
            else
            {
                /* write out the debug info to the registered output interface.
                   bail out now if this failed */
                if hardware::write_debug_string(&debug_queue) == false
                {
                    return;
                }
            }
        }

        /* drain the debug queue to the log buffer so it can be fetched later by the
           user interface service */
        for c in debug_queue.as_str().chars()
        {
            debug_log.push(c);
        }
        debug_queue.clear();

        /* truncate the log buffer if it's too long */
        if debug_log.len() > DEBUG_LOG_MAX_LEN
        {
            let to_truncate = debug_log.len() - DEBUG_LOG_MAX_LEN;
            debug_log.drain(0..to_truncate);
        }
    }
}

/* pick off the next character in the hypervisor log output buffer,
   or None if the buffer is empty */
pub fn get_log_char() -> Option<char>
{
    let mut debug_log = DEBUG_LOG.lock();
    if debug_log.len() > 0
    {
        return Some(debug_log.remove(0));
    }
    None
}<commit_msg>Make early debug more useful * If qemuprint or sifiveprint is enabled, print direct to those interfaces<commit_after>/* diosix debug console output code
 *
 * (c) Chris Williams, 2019-2021.
 *
 * See LICENSE for usage and copying.
 */

/* to avoid warnings about super::hardware when qemuprint is active */
#![allow(unused_imports)]

use super::error::Cause;
use core::fmt;
use super::lock::Mutex;
use alloc::vec::Vec;
use alloc::string::String;
use super::hardware;
use super::service;
use super::message;

/* here's the logic for the hypervisor's debug queues
    * all the hvprint macros feed into DEBUG_QUEUE
    * the hypervisor will select a physical CPU core in between workloads to drain DEBUG_QUEUE
    * DEBUG_QUEUE will be drained into two channels: DEBUG_LOG, and the system debug output port
      (typically a serial port) if a user interface capsule isn't running
    * the user interface capsule will drain DEBUG_LOG
    * DEBUG_LOG will have a fixed limit to avoid it chewing up too much RAM
    * if the qemuprint feature is active, the system debug output port will always be the
      Qemu virt serial port regardless of what's in the host hardware's device tree
*/

const DEBUG_LOG_MAX_LEN: usize = 64 * 1024; /* 64KB max length for debug log buffer */

lazy_static!
{
    pub static ref DEBUG_LOCK: Mutex<bool> = Mutex::new("primary debug lock", false);
    static ref DEBUG_QUEUE: Mutex<String> = Mutex::new("debug output queue", String::new());
    static ref DEBUG_LOG: Mutex<Vec<char>> = Mutex::new("debug log buffer", Vec::new());
}

/* top level debug macros */
/* bad news: bug detection, failures, etc. */
#[macro_export]
macro_rules! hvalert
{
    ($fmt:expr) => (hvprintln!("[!] CPU {}: {}", $crate::pcore::PhysicalCore::get_id(), $fmt));
    ($fmt:expr, $($arg:tt)*) => (hvprintln!(concat!("[!] CPU {}: ", $fmt), $crate::pcore::PhysicalCore::get_id(), $($arg)*));
}

/* only output if debug build is enabled */
#[macro_export]
#[cfg(debug_assertions)]
macro_rules! hvdebug
{
    ($fmt:expr) => (hvprintln!("[?] CPU {}: {}", $crate::pcore::PhysicalCore::get_id(), $fmt));
    ($fmt:expr, $($arg:tt)*) => (hvprintln!(concat!("[?] CPU {}: ", $fmt), $crate::pcore::PhysicalCore::get_id(), $($arg)*));
}

/* silence debug if disabled */
#[macro_export]
#[cfg(not(debug_assertions))]
macro_rules! hvdebug
{
    ($fmt:expr) => ({});
    ($fmt:expr, $($arg:tt)*) => ({});
}

/* don't include any metadata nor add a newline */
#[macro_export]
#[cfg(debug_assertions)]
macro_rules! hvdebugraw
{
    ($fmt:expr) => (hvprint!("{}", $fmt));
    ($fmt:expr, $($arg:tt)*) => (hvprint!(concat!($fmt), $($arg)*));
}

/* silence debug if disabled */
#[macro_export]
#[cfg(not(debug_assertions))]
macro_rules! hvdebugraw
{
    ($fmt:expr) => ({});
    ($fmt:expr, $($arg:tt)*) => ({});
}

/* low-level macros for hypervisor-only hvprintln and hvprint debug output routines */
macro_rules! hvprintln
{
    ($fmt:expr) => (hvprint!(concat!($fmt, "\r\n")));
    ($fmt:expr, $($arg:tt)*) => (hvprint!(concat!($fmt, "\r\n"), $($arg)*));
}

macro_rules! hvprint
{
    ($($arg:tt)*) =>
    ({
        use core::fmt::Write;
        {
            let mut hvprint_lock = $crate::debug::DEBUG_LOCK.lock();
            *hvprint_lock = true;

            unsafe { $crate::debug::CONSOLE.write_fmt(format_args!($($arg)*)).unwrap(); }
        }
    });
}

macro_rules! debughousekeeper
{
    () => ($crate::debug::drain_queue());
}

/* create a generic debug console writer */
pub struct ConsoleWriter;
pub static mut CONSOLE: ConsoleWriter = ConsoleWriter {};

impl fmt::Write for ConsoleWriter
{
    /* write the given string either to the debug queue, which will
       be outputted as normal by the hypervisor or the user interface service,
       or force output through a build-time-selected interface */
    fn write_str(&mut self, s: &str) -> core::fmt::Result
    {
        /* check if we're forcing output to a particular hardware port */
        if cfg!(feature = "qemuprint")
        {
            for c in s.as_bytes()
            {
                if cfg!(target_arch = "riscv64")
                {
                    let tx_register = 0x10000000; /* qemu's RV64 virt UART data register in memory */
                    unsafe { *(tx_register as *mut u8) = *c };
                }
            }
        }
        else if cfg!(feature = "sifiveprint")
        {
            let tx_register = 0x10010000; /* sifive's UART tx register in memory */
            for c in s.as_bytes()
            {
                /* when reading the word-length tx write register, it's zero if we're OK to write to it */
                while unsafe { *(tx_register as *mut u32) } != 0 {}
                unsafe { *(tx_register as *mut u32) = *c as u32 };
            }
        }
        else
        {
            /* queue the output for printing out later when ready */
            DEBUG_QUEUE.lock().push_str(s);
        }
        Ok(())
    }
}

/* if no user interface is available yet, copy the queue into the system debug output port.
   then regardless of the UI service, drain the debug queue into the debug logging buffer.

   if output is being forced to a particular port (eg, using qemuprint or sifiveprint)
   then this function shouldn't have anything to do. a side effect of this is that
   the UI service is then disconnected from the hypervisor's debug output, which means
   there may be conflicts. forcing hypervisor output to a particular interface should
   be used for early debugging, before any capsules are started */
pub fn drain_queue()
{
    /* avoid blocking if we can't write at this time */
    if DEBUG_LOCK.is_locked() == false
    {
        /* acquire main debug lock and pretend to do something to it
           to keep the toolchain happy */
        let mut debug_lock = DEBUG_LOCK.lock();
        *debug_lock = true;

        let mut debug_queue = DEBUG_QUEUE.lock();
        let mut debug_log = DEBUG_LOG.lock();

        /* copy the debug queue out to the system debug output port ourselves if there's no user interface yet */
        if service::is_registered(service::ServiceType::ConsoleInterface) == false
        {
            if hardware::write_debug_string(&debug_queue) == false
            {
                /* we may not even know what hardware is available yet,
                   so bail out and try again later */
                return;
            }
        }

        /* drain the debug queue to the log buffer so it can be fetched later by the
           user interface service */
        for c in debug_queue.as_str().chars()
        {
            debug_log.push(c);
        }
        debug_queue.clear();

        /* truncate the log buffer if it's too long */
        if debug_log.len() > DEBUG_LOG_MAX_LEN
        {
            let to_truncate = debug_log.len() - DEBUG_LOG_MAX_LEN;
            debug_log.drain(0..to_truncate);
        }
    }
}

/* pick off the next character in the hypervisor log output buffer,
   or None if the buffer is empty */
pub fn get_log_char() -> Option<char>
{
    let mut debug_log = DEBUG_LOG.lock();
    if debug_log.len() > 0
    {
        return Some(debug_log.remove(0));
    }
    None
}<|endoftext|>


<commit_before>extern crate libc;

use std::boxed::Box;
use super::layout;
use super::Window;
use super::super::libx;
use super::super::libx::Context;

pub struct Workspace {
    pub screen_num: libc::c_int,
    focus: Option<Window>,
    pub clean: bool,                // if workspace is not clean, it needs to be reconfig before map
    pub visible: bool,
    windows: Vec<Window>,
    layout: Box<layout::Layout>
}

impl Workspace {
    pub fn new(screen_num: libc::c_int) -> Workspace {
        Workspace {
            screen_num: screen_num,
            focus: None,
            clean: true,
            visible: false,
            windows: Vec::new(),
            layout: Box::new(layout::TilingLayout::new(layout::Direction::Horizontal))
        }
    }

    pub fn p(&self) {
        for w in self.windows.iter() {
            println!("{}", w.id);
        }
    }

    pub fn add(&mut self, window: Window, context: Context) -> bool {
        let mut added = false;

        // should not add root window
        let root = Window::root(context, self.screen_num);
        if window == root {
            return added;
        }

        let index = self.contain(window);
        match index {
            Some(i) => {
                // already there, do nothing
            }
            None => {
                self.windows.push(window);
                self.focus = Some(window);
                if self.visible {
                    window.map();
                    self.config(context);
                    window.focus();
                }
                added = true;
                // self.clean = false;
            }
        }
        added
    }

    pub fn remove(&mut self, window: Window, context: Context) -> bool {
        let mut removed = false;
        let index = self.contain(window);
        match index {
            Some(i) => {
                // if the window focused, change to next
                if self.focus.unwrap() == window {
                    let next = self.next_window(window);
                    if next == window {
                        // removing the last one
                        self.set_focus(None, context);
                    }
                    else{
                        self.set_focus(Some(next), context);
                    }
                }

                self.windows.remove(i);
                if self.visible {
                    window.unmap();
                    self.config(context);
                }
                removed = true;
            }
            None => {}
        };
        removed
    }

    pub fn get(&self, index: usize) -> Window{
        self.windows[index]
    }

    pub fn size(&self) -> usize {
        self.windows.len()
    }

    pub fn hide(&mut self, context: Context) {
        for w in self.windows.iter() {
            w.unmap();
        }
        self.visible = false;
    }

    pub fn show(&mut self, context: Context) {
        for w in self.windows.iter() {
            w.map();
        }
        self.visible = true;

        match self.focus {
            Some(w) => {
                w.focus();
            }
            None => {
                let root = libx::root_window(context, self.screen_num);
                libx::set_input_focus(context, root);
            }
        }
    }

    pub fn set_focus(&mut self, window: Option<Window>, context: Context) {
        match window {
            Some(w) => {
                match self.contain(w) {
                    Some(i) => {
                        self.focus = window;
                        if self.visible {
                            w.focus();
                        }
                    }
                    None => {}
                }
            }
            None => {
                // set to root
                self.focus = window;
                if self.visible {
                    let root = libx::root_window(context, self.screen_num);
                    libx::set_input_focus(context, root);
                }
            }
        }
    }

    pub fn get_focus(&self) -> Option<Window>{
        self.focus
    }

    pub fn last_window(&mut self, window: Window) -> Window{
        match self.contain(window) {
            Some(i) => {
                let mut last = i-1;
                if last < 0 {
                    last = self.size() - 1
                }
                self.get(last)
            }
            None => {
                window
            }
        }
    }

    pub fn next_window(&self, window: Window) -> Window{
        match self.contain(window) {
            Some(i) => {
                let mut next = i+1;
                if next == self.size() {
                    next = 0;
                }
                self.get(next)
            }
            None => {
                window
            }
        }
    }

    pub fn contain(&self, window: Window) -> Option<usize>{
        self.windows.iter().position(|x| *x == window)
    }

    pub fn change_layout(&mut self, layout_type: layout::Type) {
        let t = self.layout.get_type();
        if t == layout_type {
            self.layout.toggle();
        }
        else{
            match layout_type {
                layout::Type::Tiling => {
                    let tmp = layout::TilingLayout::new(layout::Direction::Horizontal);
                    self.layout = Box::new(tmp);
                }
                layout::Type::Tab => {
                    let tmp = layout::TabLayout::new();
                    self.layout = Box::new(tmp);
                }
            }
        }
    }

    pub fn config(&mut self, context: Context) {
        self.layout.configure(&self.windows, context, self.screen_num);
        self.clean = true;
    }
}
<commit_msg>compare self or self.client<commit_after>extern crate libc;

use std::boxed::Box;
use super::layout;
use super::Window;
use super::super::libx;
use super::super::libx::Context;

pub struct Workspace {
    pub screen_num: libc::c_int,
    focus: Option<Window>,
    pub clean: bool,                // if workspace is not clean, it needs to be reconfig before map
    pub visible: bool,
    windows: Vec<Window>,
    layout: Box<layout::Layout>
}

impl Workspace {
    pub fn new(screen_num: libc::c_int) -> Workspace {
        Workspace {
            screen_num: screen_num,
            focus: None,
            clean: true,
            visible: false,
            windows: Vec::new(),
            layout: Box::new(layout::TilingLayout::new(layout::Direction::Horizontal))
        }
    }

    pub fn p(&self) {
        for w in self.windows.iter() {
            println!("{}", w.id);
        }
    }

    pub fn add(&mut self, window: Window, context: Context) -> bool {
        let mut added = false;

        // should not add root window
        let root = Window::root(context, self.screen_num);
        if window == root {
            return added;
        }

        let index = self.contain(window);
        match index {
            Some(i) => {
                // already there, do nothing
            }
            None => {
                self.windows.push(window);
                self.focus = Some(window);
                if self.visible {
                    window.map();
                    self.config(context);
                    window.focus();
                }
                added = true;
                // self.clean = false;
            }
        }
        added
    }

    pub fn remove(&mut self, window: Window, context: Context) -> bool {
        let mut removed = false;
        let index = self.contain(window);
        match index {
            Some(i) => {
                // if the window focused, change to next
                if self.focus.unwrap() == window {
                    let next = self.next_window(window);
                    if next == window {
                        // removing the last one
                        self.set_focus(None, context);
                    }
                    else{
                        self.set_focus(Some(next), context);
                    }
                }

                self.windows.remove(i);
                if self.visible {
                    window.unmap();
                    self.config(context);
                }
                removed = true;
            }
            None => {}
        };
        removed
    }

    pub fn get(&self, index: usize) -> Window{
        self.windows[index]
    }

    pub fn size(&self) -> usize {
        self.windows.len()
    }

    pub fn hide(&mut self, context: Context) {
        for w in self.windows.iter() {
            w.unmap();
        }
        self.visible = false;
    }

    pub fn show(&mut self, context: Context) {
        for w in self.windows.iter() {
            w.map();
        }
        self.visible = true;

        match self.focus {
            Some(w) => {
                w.focus();
            }
            None => {
                let root = libx::root_window(context, self.screen_num);
                libx::set_input_focus(context, root);
            }
        }
    }

    pub fn set_focus(&mut self, window: Option<Window>, context: Context) {
        match window {
            Some(w) => {
                match self.contain(w) {
                    Some(i) => {
                        self.focus = window;
                        if self.visible {
                            w.focus();
                        }
                    }
                    None => {}
                }
            }
            None => {
                // set to root
                self.focus = window;
                if self.visible {
                    let root = libx::root_window(context, self.screen_num);
                    libx::set_input_focus(context, root);
                }
            }
        }
    }

    pub fn get_focus(&self) -> Option<Window>{
        self.focus
    }

    pub fn last_window(&mut self, window: Window) -> Window{
        match self.contain(window) {
            Some(i) => {
                let mut last = i-1;
                if last < 0 {
                    last = self.size() - 1
                }
                self.get(last)
            }
            None => {
                window
            }
        }
    }

    pub fn next_window(&self, window: Window) -> Window{
        match self.contain(window) {
            Some(i) => {
                let mut next = i+1;
                if next == self.size() {
                    next = 0;
                }
                self.get(next)
            }
            None => {
                window
            }
        }
    }

    pub fn contain(&self, window: Window) -> Option<usize>{
        self.windows.iter().position(|x| (*x) == window || ((*x).client.is_some() && (*x).client.unwrap() == window.id))
    }

    pub fn change_layout(&mut self, layout_type: layout::Type) {
        let t = self.layout.get_type();
        if t == layout_type {
            self.layout.toggle();
        }
        else{
            match layout_type {
                layout::Type::Tiling => {
                    let tmp = layout::TilingLayout::new(layout::Direction::Horizontal);
                    self.layout = Box::new(tmp);
                }
                layout::Type::Tab => {
                    let tmp = layout::TabLayout::new();
                    self.layout = Box::new(tmp);
                }
            }
        }
    }

    pub fn config(&mut self, context: Context) {
        self.layout.configure(&self.windows, context, self.screen_num);
        self.clean = true;
    }
}
<|endoftext|>