<commit_before>#![allow(unused_imports, unused_variables, dead_code)]
use super::error::ConfigError;
use anyhow::{anyhow, Result};

use serde::de::{Deserializer, Error, MapAccess, SeqAccess, Visitor};
use serde::Deserialize;
use std::collections::HashMap;
use std::fmt;
use std::num::ParseIntError;
use std::vec::Vec;
/*
type Tasks = Vec<Task>;
type Params = Vec<Param>;
*/
type Tasks = HashMap<String, Task>;
type Params = HashMap<String, Param>;

#[derive(Debug, Clone, PartialEq)]
pub enum Nargs {
    One,
    Zero,
    OneOrZero,
    OneOrMore,
    ZeroOrMore,
    Range(usize, usize),
}

impl fmt::Display for Nargs {
    fn fmt(&self, fmtr: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            Nargs::One => write!(fmtr, "Nargs::One[1]"),
            Nargs::Zero => write!(fmtr, "Nargs::Zero[0]"),
            Nargs::OneOrZero => write!(fmtr, "Nargs::OneOrZero[?]"),
            Nargs::OneOrMore => write!(fmtr, "Nargs::OneOrMore[+]"),
            Nargs::ZeroOrMore => write!(fmtr, "Nargs::ZeroOrMore[*]"),
            Nargs::Range(min, max) => write!(fmtr, "Nargs::Range[{}, {}]", min + 1, max),
        }
    }
}

impl Default for Nargs {
    fn default() -> Self {
        Nargs::One
    }
}

impl<'de> Deserialize<'de> for Nargs {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        let s = String::deserialize(deserializer)?;
        let result = match &s[..] {
            "1" => Nargs::One,
            "0" => Nargs::Zero,
            "?" => Nargs::OneOrZero,
            "+" => Nargs::OneOrMore,
            "*" => Nargs::ZeroOrMore,
            _ => {
                println!("s={}", s);
                if s.contains(':') {
                    let parts: Vec<&str> = s.split(':').collect();
                    let min = parts[0].parse::<usize>().map_err(Error::custom)?;
                    let max = parts[1].parse::<usize>().map_err(Error::custom)?;
                    Nargs::Range(min - 1, max)
                } else {
                    let num = s.parse::<usize>().map_err(Error::custom)?;
                    Nargs::Range(0, num)
                }
            }
        };
        Ok(result)
    }
}

#[derive(Debug, Clone, PartialEq)]
pub enum Value {
    Item(String),
    List(Vec<String>),
    Dict(HashMap<String, String>),
    Empty,
}

impl fmt::Display for Value {
    fn fmt(&self, fmtr: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            Value::Item(s) => write!(fmtr, "Values::Item({})", s),
            Value::List(vs) => write!(fmtr, "Values::List([{}])", vs.join(", ")),
            Value::Dict(ds) => write!(fmtr, "Values::Dict[NOT IMPLEMENTED]"),
            Value::Empty => write!(fmtr, "Value::Empty(\"\")"),
        }
    }
}

impl Default for Value {
    fn default() -> Self {
        Value::Empty
    }
}

fn deserialize_value<'de, D>(deserializer: D) -> Result<Value, D::Error>
where
    D: Deserializer<'de>,
{
    struct ValueEnum;
    impl<'de> Visitor<'de> for ValueEnum {
        type Value = Value;

        fn expecting(&self, fmtr: &mut fmt::Formatter) -> fmt::Result {
            fmtr.write_str("string or list of strings")
        }
        fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
        where
            E: Error,
        {
            Ok(Value::Item(value.to_owned()))
        }
        fn visit_seq<S>(self, mut visitor: S) -> Result<Self::Value, S::Error>
        where
            S: SeqAccess<'de>,
        {
            let mut vec: Vec<String> = vec![];
            while let Some(item) = visitor.next_element()? {
                vec.push(item);
            }
            Ok(Value::List(vec))
        }
    }
    deserializer.deserialize_any(ValueEnum)
}

fn default_otto() -> String {
    "otto".to_string()
}

fn default_verbosity() -> i32 {
    1
}

fn default_api() -> i32 {
    1
}

fn default_jobs() -> i32 {
    12
}
fn default_defaults() -> Defaults {
    Defaults {
        api: default_api(),
        verbosity: default_verbosity(),
        jobs: default_jobs(),
        tasks: vec![],
    }
}

#[derive(Clone, Debug, Default, PartialEq, Deserialize)]
pub struct Spec {
    #[serde(default = "default_defaults")]
    pub defaults: Defaults,

    pub otto: Otto,
}

#[derive(Clone, Debug, Default, PartialEq, Deserialize)]
pub struct Defaults {
    #[serde(default = "default_api")]
    pub api: i32,

    #[serde(default = "default_verbosity")]
    pub verbosity: i32,

    #[serde(default = "default_jobs")]
    pub jobs: i32,

    #[serde(default)]
    pub tasks: Vec<String>,
}

#[derive(Clone, Debug, Default, PartialEq, Deserialize)]
pub struct Otto {
    #[serde(skip_deserializing, default = "default_otto")]
    pub name: String,

    #[serde(default)]
    pub author: Option<String>,

    #[serde(default)]
    pub about: Option<String>,

    #[serde(default)]
    pub version: Option<String>,

    #[serde(default, deserialize_with = "deserialize_param_map")]
    pub params: Params,

    #[serde(default, deserialize_with = "deserialize_task_map")]
    pub tasks: Tasks,

    pub action: Option<String>,
}

impl Otto {
    fn get_param_key(&self, flag: &str) -> Result<&String, ConfigError> {
        for (key, param) in self.params.iter() {
            if param.flags.iter().any(|f| f == flag) {
                return Ok(key);
            }
        }
        Err(ConfigError::FlagLookupError(flag.to_string()))
    }
    pub fn get_param(&self, name: &str) -> Result<&Param, ConfigError> {
        self.params
            .get(name)
            .ok_or_else(|| ConfigError::NameLookupError(name.to_string()))
    }
    pub fn get_param_from_flag(&self, flag: &str) -> Result<&Param, ConfigError> {
        let key = self.get_param_key(flag)?;
        self.get_param(key)
    }
    pub fn set_param(&mut self, param: Param) -> Result<Param, ConfigError> {
        let name = param.name.to_owned();
        self.params
            .insert(name.to_owned(), param)
            .ok_or(ConfigError::NameLookupError(name))
    }
    pub fn get_task(&self, name: &str) -> Result<&Task, ConfigError> {
        self.tasks
            .get(name)
            .ok_or_else(|| ConfigError::NameLookupError(name.to_string()))
    }
    pub fn set_task(&mut self, task: Task) -> Result<Task, ConfigError> {
        let name = task.name.to_owned();
        self.tasks
            .insert(name.to_owned(), task)
            .ok_or(ConfigError::NameLookupError(name))
    }
    pub fn task_names(&self) -> Vec<&str> {
        self.tasks.keys().map(AsRef::as_ref).collect()
    }
}

pub enum ParamType {
    FLG,
    OPT,
    POS,
}

// FIXME: Flag, Named and Positional Args
#[derive(Clone, Debug, Default, PartialEq, Deserialize)]
pub struct Param {
    #[serde(skip_deserializing)]
    pub name: String,

    #[serde(skip_deserializing)]
    pub flags: Vec<String>,

    #[serde(skip_deserializing)]
    pub value: Value,

    #[serde(default)]
    pub dest: Option<String>,

    #[serde(default)]
    pub metavar: Option<String>,

    #[serde(default)]
    pub default: Option<String>,

    #[serde(default, deserialize_with = "deserialize_value")]
    pub constant: Value,

    #[serde(default)]
    pub choices: Vec<String>,

    #[serde(default)]
    pub nargs: Nargs,

    #[serde(default)]
    pub help: Option<String>,
}

impl Param {
    pub fn param_type(&self) -> ParamType {
        match self.name.chars().next() {
            Some('-') => match self.default.as_deref() {
                Some("true") | Some("false") => ParamType::FLG,
                Some(_) | None => ParamType::OPT,
            },
            Some(_) | None => ParamType::POS,
        }
    }
}

fn deserialize_param_map<'de, D>(deserializer: D) -> Result<Params, D::Error>
where
    D: Deserializer<'de>,
{
    struct ParamMap;

    impl<'de> Visitor<'de> for ParamMap {
        type Value = Params;

        fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
            formatter.write_str("a map of name to Param")
        }

        fn visit_map<M>(self, mut map: M) -> Result<Self::Value, M::Error>
        where
            M: MapAccess<'de>,
        {
            let mut params = Params::new();
            while let Some((name, mut param)) = map.next_entry::<String, Param>()? {
                param.flags = name.split('|').map(|f| f.to_string()).collect();
                let short: Vec<String> = param
                    .flags
                    .iter()
                    .cloned()
                    .filter(|i| i.starts_with('-') && i.len() == 2)
                    //.map(|i| i.to_string())
                    .collect();
                let long: Vec<String> = param
                    .flags
                    .iter()
                    .cloned()
                    .filter(|i| i.starts_with("--") && i.len() > 2)
                    //.map(|i| i.to_string())
                    .collect();
                if param.dest.is_none() {
                    let dest = match long.first() {
                        Some(long) => String::from(long.trim_matches('-')),
                        None => match short.first() {
                            Some(short) => String::from(short.trim_matches('-')),
                            None => param.name,
                        },
                    };
                    param.dest = Some(dest);
                }
                param.name = name.to_owned();
                params.insert(name.to_owned(), param);
            }
            Ok(params)
        }
    }
    deserializer.deserialize_map(ParamMap)
}

#[derive(Clone, Debug, Default, PartialEq, Deserialize)]
pub struct Task {
    #[serde(skip_deserializing)]
    pub name: String,

    #[serde(default)]
    pub help: Option<String>,

    #[serde(default)]
    pub after: Vec<String>,

    #[serde(default)]
    pub before: Vec<String>,

    #[serde(default, deserialize_with = "deserialize_param_map")]
    pub params: Params,

    pub action: Option<String>,

    #[serde(skip_deserializing)]
    pub selected: bool,
}

impl Task {
    pub fn new(
        name: String,
        help: Option<String>,
        after: Vec<String>,
        before: Vec<String>,
        params: Params,
        action: Option<String>,
        selected: bool,
    ) -> Self {
        Self {
            name,
            help,
            after,
            before,
            params,
            action,
            selected,
        }
    }
    fn get_param_key(&self, flag: &str) -> Result<&String, ConfigError> {
        for (key, param) in self.params.iter() {
            if param.flags.iter().any(|f| f == flag) {
                return Ok(key);
            }
        }
        Err(ConfigError::FlagLookupError(flag.to_string()))
    }
    pub fn get_param(&self, name: &str) -> Result<&Param> {
        self.params
            .get(name)
            .ok_or_else(|| anyhow!("get_param: failed to get name={}", name))
    }
    pub fn get_param_from_flag(&self, flag: &str) -> Result<&Param> {
        let key = self.get_param_key(flag)?;
        self.get_param(key)
    }
    pub fn set_param(&mut self, param: Param) -> Result<Param> {
        let name = param.name.to_owned();
        self.params
            .insert(name.to_owned(), param)
            .ok_or_else(|| anyhow!("set_param: failed to set param.name={}", name))
    }
}

fn deserialize_task_map<'de, D>(deserializer: D) -> Result<Tasks, D::Error>
where
    D: Deserializer<'de>,
{
    struct TaskMap;

    impl<'de> Visitor<'de> for TaskMap {
        type Value = Tasks;

        fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
            formatter.write_str("a map of name to Task")
        }

        fn visit_map<M>(self, mut map: M) -> Result<Self::Value, M::Error>
        where
            M: MapAccess<'de>,
        {
            let mut tasks = Tasks::new();
            while let Some((name, mut task)) = map.next_entry::<String, Task>()? {
                task.name = name.to_owned();
                tasks.insert(name.to_owned(), task);
            }
            Ok(tasks)
        }
    }
    deserializer.deserialize_map(TaskMap)
}
<commit_msg>removed dead map code<commit_after>#![allow(unused_imports, unused_variables, dead_code)]
use super::error::ConfigError;
use anyhow::{anyhow, Result};

use serde::de::{Deserializer, Error, MapAccess, SeqAccess, Visitor};
use serde::Deserialize;
use std::collections::HashMap;
use std::fmt;
use std::num::ParseIntError;
use std::vec::Vec;
/*
type Tasks = Vec<Task>;
type Params = Vec<Param>;
*/
type Tasks = HashMap<String, Task>;
type Params = HashMap<String, Param>;

#[derive(Debug, Clone, PartialEq)]
pub enum Nargs {
    One,
    Zero,
    OneOrZero,
    OneOrMore,
    ZeroOrMore,
    Range(usize, usize),
}

impl fmt::Display for Nargs {
    fn fmt(&self, fmtr: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            Nargs::One => write!(fmtr, "Nargs::One[1]"),
            Nargs::Zero => write!(fmtr, "Nargs::Zero[0]"),
            Nargs::OneOrZero => write!(fmtr, "Nargs::OneOrZero[?]"),
            Nargs::OneOrMore => write!(fmtr, "Nargs::OneOrMore[+]"),
            Nargs::ZeroOrMore => write!(fmtr, "Nargs::ZeroOrMore[*]"),
            Nargs::Range(min, max) => write!(fmtr, "Nargs::Range[{}, {}]", min + 1, max),
        }
    }
}

impl Default for Nargs {
    fn default() -> Self {
        Nargs::One
    }
}

impl<'de> Deserialize<'de> for Nargs {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        let s = String::deserialize(deserializer)?;
        let result = match &s[..] {
            "1" => Nargs::One,
            "0" => Nargs::Zero,
            "?" => Nargs::OneOrZero,
            "+" => Nargs::OneOrMore,
            "*" => Nargs::ZeroOrMore,
            _ => {
                println!("s={}", s);
                if s.contains(':') {
                    let parts: Vec<&str> = s.split(':').collect();
                    let min = parts[0].parse::<usize>().map_err(Error::custom)?;
                    let max = parts[1].parse::<usize>().map_err(Error::custom)?;
                    Nargs::Range(min - 1, max)
                } else {
                    let num = s.parse::<usize>().map_err(Error::custom)?;
                    Nargs::Range(0, num)
                }
            }
        };
        Ok(result)
    }
}

#[derive(Debug, Clone, PartialEq)]
pub enum Value {
    Item(String),
    List(Vec<String>),
    Dict(HashMap<String, String>),
    Empty,
}

impl fmt::Display for Value {
    fn fmt(&self, fmtr: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            Value::Item(s) => write!(fmtr, "Values::Item({})", s),
            Value::List(vs) => write!(fmtr, "Values::List([{}])", vs.join(", ")),
            Value::Dict(ds) => write!(fmtr, "Values::Dict[NOT IMPLEMENTED]"),
            Value::Empty => write!(fmtr, "Value::Empty(\"\")"),
        }
    }
}

impl Default for Value {
    fn default() -> Self {
        Value::Empty
    }
}

fn deserialize_value<'de, D>(deserializer: D) -> Result<Value, D::Error>
where
    D: Deserializer<'de>,
{
    struct ValueEnum;
    impl<'de> Visitor<'de> for ValueEnum {
        type Value = Value;

        fn expecting(&self, fmtr: &mut fmt::Formatter) -> fmt::Result {
            fmtr.write_str("string or list of strings")
        }
        fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
        where
            E: Error,
        {
            Ok(Value::Item(value.to_owned()))
        }
        fn visit_seq<S>(self, mut visitor: S) -> Result<Self::Value, S::Error>
        where
            S: SeqAccess<'de>,
        {
            let mut vec: Vec<String> = vec![];
            while let Some(item) = visitor.next_element()? {
                vec.push(item);
            }
            Ok(Value::List(vec))
        }
    }
    deserializer.deserialize_any(ValueEnum)
}

fn default_otto() -> String {
    "otto".to_string()
}

fn default_verbosity() -> i32 {
    1
}

fn default_api() -> i32 {
    1
}

fn default_jobs() -> i32 {
    12
}
fn default_defaults() -> Defaults {
    Defaults {
        api: default_api(),
        verbosity: default_verbosity(),
        jobs: default_jobs(),
        tasks: vec![],
    }
}

#[derive(Clone, Debug, Default, PartialEq, Deserialize)]
pub struct Spec {
    #[serde(default = "default_defaults")]
    pub defaults: Defaults,

    pub otto: Otto,
}

#[derive(Clone, Debug, Default, PartialEq, Deserialize)]
pub struct Defaults {
    #[serde(default = "default_api")]
    pub api: i32,

    #[serde(default = "default_verbosity")]
    pub verbosity: i32,

    #[serde(default = "default_jobs")]
    pub jobs: i32,

    #[serde(default)]
    pub tasks: Vec<String>,
}

#[derive(Clone, Debug, Default, PartialEq, Deserialize)]
pub struct Otto {
    #[serde(skip_deserializing, default = "default_otto")]
    pub name: String,

    #[serde(default)]
    pub author: Option<String>,

    #[serde(default)]
    pub about: Option<String>,

    #[serde(default)]
    pub version: Option<String>,

    #[serde(default, deserialize_with = "deserialize_param_map")]
    pub params: Params,

    #[serde(default, deserialize_with = "deserialize_task_map")]
    pub tasks: Tasks,

    pub action: Option<String>,
}

impl Otto {
    fn get_param_key(&self, flag: &str) -> Result<&String, ConfigError> {
        for (key, param) in self.params.iter() {
            if param.flags.iter().any(|f| f == flag) {
                return Ok(key);
            }
        }
        Err(ConfigError::FlagLookupError(flag.to_string()))
    }
    pub fn get_param(&self, name: &str) -> Result<&Param, ConfigError> {
        self.params
            .get(name)
            .ok_or_else(|| ConfigError::NameLookupError(name.to_string()))
    }
    pub fn get_param_from_flag(&self, flag: &str) -> Result<&Param, ConfigError> {
        let key = self.get_param_key(flag)?;
        self.get_param(key)
    }
    pub fn set_param(&mut self, param: Param) -> Result<Param, ConfigError> {
        let name = param.name.to_owned();
        self.params
            .insert(name.to_owned(), param)
            .ok_or(ConfigError::NameLookupError(name))
    }
    pub fn get_task(&self, name: &str) -> Result<&Task, ConfigError> {
        self.tasks
            .get(name)
            .ok_or_else(|| ConfigError::NameLookupError(name.to_string()))
    }
    pub fn set_task(&mut self, task: Task) -> Result<Task, ConfigError> {
        let name = task.name.to_owned();
        self.tasks
            .insert(name.to_owned(), task)
            .ok_or(ConfigError::NameLookupError(name))
    }
    pub fn task_names(&self) -> Vec<&str> {
        self.tasks.keys().map(AsRef::as_ref).collect()
    }
}

pub enum ParamType {
    FLG,
    OPT,
    POS,
}

// FIXME: Flag, Named and Positional Args
#[derive(Clone, Debug, Default, PartialEq, Deserialize)]
pub struct Param {
    #[serde(skip_deserializing)]
    pub name: String,

    #[serde(skip_deserializing)]
    pub flags: Vec<String>,

    #[serde(skip_deserializing)]
    pub value: Value,

    #[serde(default)]
    pub dest: Option<String>,

    #[serde(default)]
    pub metavar: Option<String>,

    #[serde(default)]
    pub default: Option<String>,

    #[serde(default, deserialize_with = "deserialize_value")]
    pub constant: Value,

    #[serde(default)]
    pub choices: Vec<String>,

    #[serde(default)]
    pub nargs: Nargs,

    #[serde(default)]
    pub help: Option<String>,
}

impl Param {
    pub fn param_type(&self) -> ParamType {
        match self.name.chars().next() {
            Some('-') => match self.default.as_deref() {
                Some("true") | Some("false") => ParamType::FLG,
                Some(_) | None => ParamType::OPT,
            },
            Some(_) | None => ParamType::POS,
        }
    }
}

fn deserialize_param_map<'de, D>(deserializer: D) -> Result<Params, D::Error>
where
    D: Deserializer<'de>,
{
    struct ParamMap;

    impl<'de> Visitor<'de> for ParamMap {
        type Value = Params;

        fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
            formatter.write_str("a map of name to Param")
        }

        fn visit_map<M>(self, mut map: M) -> Result<Self::Value, M::Error>
        where
            M: MapAccess<'de>,
        {
            let mut params = Params::new();
            while let Some((name, mut param)) = map.next_entry::<String, Param>()? {
                param.flags = name.split('|').map(|f| f.to_string()).collect();
                let short: Vec<String> = param
                    .flags
                    .iter()
                    .cloned()
                    .filter(|i| i.starts_with('-') && i.len() == 2)
                    .collect();
                let long: Vec<String> = param
                    .flags
                    .iter()
                    .cloned()
                    .filter(|i| i.starts_with("--") && i.len() > 2)
                    .collect();
                if param.dest.is_none() {
                    let dest = match long.first() {
                        Some(long) => String::from(long.trim_matches('-')),
                        None => match short.first() {
                            Some(short) => String::from(short.trim_matches('-')),
                            None => param.name,
                        },
                    };
                    param.dest = Some(dest);
                }
                param.name = name.to_owned();
                params.insert(name.to_owned(), param);
            }
            Ok(params)
        }
    }
    deserializer.deserialize_map(ParamMap)
}

#[derive(Clone, Debug, Default, PartialEq, Deserialize)]
pub struct Task {
    #[serde(skip_deserializing)]
    pub name: String,

    #[serde(default)]
    pub help: Option<String>,

    #[serde(default)]
    pub after: Vec<String>,

    #[serde(default)]
    pub before: Vec<String>,

    #[serde(default, deserialize_with = "deserialize_param_map")]
    pub params: Params,

    pub action: Option<String>,

    #[serde(skip_deserializing)]
    pub selected: bool,
}

impl Task {
    pub fn new(
        name: String,
        help: Option<String>,
        after: Vec<String>,
        before: Vec<String>,
        params: Params,
        action: Option<String>,
        selected: bool,
    ) -> Self {
        Self {
            name,
            help,
            after,
            before,
            params,
            action,
            selected,
        }
    }
    fn get_param_key(&self, flag: &str) -> Result<&String, ConfigError> {
        for (key, param) in self.params.iter() {
            if param.flags.iter().any(|f| f == flag) {
                return Ok(key);
            }
        }
        Err(ConfigError::FlagLookupError(flag.to_string()))
    }
    pub fn get_param(&self, name: &str) -> Result<&Param> {
        self.params
            .get(name)
            .ok_or_else(|| anyhow!("get_param: failed to get name={}", name))
    }
    pub fn get_param_from_flag(&self, flag: &str) -> Result<&Param> {
        let key = self.get_param_key(flag)?;
        self.get_param(key)
    }
    pub fn set_param(&mut self, param: Param) -> Result<Param> {
        let name = param.name.to_owned();
        self.params
            .insert(name.to_owned(), param)
            .ok_or_else(|| anyhow!("set_param: failed to set param.name={}", name))
    }
}

fn deserialize_task_map<'de, D>(deserializer: D) -> Result<Tasks, D::Error>
where
    D: Deserializer<'de>,
{
    struct TaskMap;

    impl<'de> Visitor<'de> for TaskMap {
        type Value = Tasks;

        fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
            formatter.write_str("a map of name to Task")
        }

        fn visit_map<M>(self, mut map: M) -> Result<Self::Value, M::Error>
        where
            M: MapAccess<'de>,
        {
            let mut tasks = Tasks::new();
            while let Some((name, mut task)) = map.next_entry::<String, Task>()? {
                task.name = name.to_owned();
                tasks.insert(name.to_owned(), task);
            }
            Ok(tasks)
        }
    }
    deserializer.deserialize_map(TaskMap)
}
<|endoftext|>


<commit_before>/// Computes the Luhn checksum for the provided number.
///
/// # Examples
///
/// Provide the function with an identification number.
///
/// ```
/// let acct_num = 79927398713;
/// let checksum = checksum::luhn_checksum(acct_num);
/// assert_eq!(checksum, 0);
/// if checksum != 0 {
///     println!("Account number has been corrupted!");
/// }
/// ```
pub fn luhn_checksum(full_number: u64) -> u8 {
    let mut num_pre_div = full_number;
    let mut num_post_div;
    let mut sum = 0u32;
    let mut i = 0u8;
    // Scan digits from right to left
    loop {
        num_post_div = num_pre_div / 10;
        i += 1;
        let digit = num_pre_div - num_post_div * 10;
        if i % 2 == 0 {
            let mut second_digit = digit * 2;
            if second_digit > 9 {
                second_digit = second_digit - 9;
            }
            sum = sum + second_digit as u32;
        } else {
            sum = sum + digit as u32;
        }
        if num_post_div == 0 {
            break;
        }
        num_pre_div = num_post_div;
    }
    (sum % 10) as u8
}

/// Computes the Luhn check digit for the provided number.
///
/// # Examples
///
/// Provide the function with an identification number.
///
/// ```
/// let acct_num = 7992739871;
/// let checksum = checksum::luhn_calculate_check_digit(acct_num);
/// assert_eq!(checksum, 3);
/// ```
pub fn luhn_calculate_check_digit(num: u64) -> u8 {
    let mut num_pre_div = num;
    let mut num_post_div;
    let mut sum = 0u32;
    let mut i = 0u8;
    // Scan digits from right to left
    loop {
        num_post_div = num_pre_div / 10;
        i += 1;
        let digit = num_pre_div - num_post_div * 10;
        if i % 2 == 1 {
            let mut second_digit = digit * 2;
            if second_digit > 9 {
                second_digit = second_digit - 9;
            }
            sum = sum + second_digit as u32;
        } else {
            sum = sum + digit as u32;
        }
        if num_post_div == 0 {
            break;
        }
        num_pre_div = num_post_div;
    }
    (sum * 9 % 10) as u8
}

/// Verifies the check digit using the Luhn algorithm.
///
/// # Examples
///
/// Provide the function with an identification number.
///
/// ```
/// let acct_num = 79927398713;
/// let is_valid = checksum::luhn_is_valid(acct_num);
/// assert_eq!(is_valid, true);
/// if is_valid {
///     println!("Account number is valid!");
/// } else {
///     println!("Account number is NOT valid!");
/// }
/// ```
pub fn luhn_is_valid(full_number: u64) -> bool {
    luhn_checksum(full_number) == 0
}

const DIHEDRAL_D5: [[u8; 10]; 10] = [[0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
                                     [1, 2, 3, 4, 0, 6, 7, 8, 9, 5],
                                     [2, 3, 4, 0, 1, 7, 8, 9, 5, 6],
                                     [3, 4, 0, 1, 2, 8, 9, 5, 6, 7],
                                     [4, 0, 1, 2, 3, 9, 5, 6, 7, 8],
                                     [5, 9, 8, 7, 6, 0, 4, 3, 2, 1],
                                     [6, 5, 9, 8, 7, 1, 0, 4, 3, 2],
                                     [7, 6, 5, 9, 8, 2, 1, 0, 4, 3],
                                     [8, 7, 6, 5, 9, 3, 2, 1, 0, 4],
                                     [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]];

const INV_DIHEDRAL_D5: [u8; 10] = [0, 4, 3, 2, 1, 5, 6, 7, 8, 9];

const VERHOEFF_P_TABLE: [[u8; 10]; 8] = [[0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
                                         [1, 5, 7, 6, 2, 8, 3, 0, 9, 4],
                                         [5, 8, 0, 3, 7, 9, 6, 1, 4, 2],
                                         [8, 9, 1, 6, 0, 4, 3, 5, 2, 7],
                                         [9, 4, 5, 3, 1, 2, 6, 8, 7, 0],
                                         [4, 2, 8, 6, 5, 7, 3, 9, 0, 1],
                                         [2, 7, 9, 3, 8, 0, 6, 4, 1, 5],
                                         [7, 0, 4, 6, 9, 1, 3, 2, 5, 8]];

/// Computes the Verhoeff checksum for the provided number.
///
/// # Examples
///
/// Generate a checksum for 236:
///
/// ```
/// let num = 2363;
/// let check_digit = checksum::verhoeff_checksum(num);
/// assert_eq!(check_digit, 0);
/// ```
pub fn verhoeff_checksum(num: u64) -> u8 {
    let mut num_pre_div = num;
    let mut num_post_div;
    let mut i = 0u8;
    let mut c = 0u8;
    loop {
        num_post_div = num_pre_div / 10;
        let digit = num_pre_div - num_post_div * 10;
        c = DIHEDRAL_D5[c as usize][VERHOEFF_P_TABLE[(i % 8) as usize][digit as usize] as usize];
        i += 1;
        if num_post_div == 0 {
            break;
        }
        num_pre_div = num_post_div;
    }
    c
}

/// Computes the Verhoeff check digit for the provided number.
///
/// # Examples
///
/// Generate a check digit for 236:
///
/// ```
/// let num = 236;
/// let check_digit = checksum::verhoeff_calculate_check_digit(num);
/// assert_eq!(check_digit, 3);
/// ```
pub fn verhoeff_calculate_check_digit(num: u64) -> u8 {
    let c = verhoeff_checksum(num * 10);
    INV_DIHEDRAL_D5[c as usize]
}

/// Uses the Verhoeff checksum formula for error detection.
///
/// # Examples
///
/// Validate the check digit 2363.
///
/// ```
/// let num = 2363;
/// let is_valid = checksum::verhoeff_is_valid(num);
/// assert_eq!(is_valid, true);
/// ```
pub fn verhoeff_is_valid(num: u64) -> bool {
    verhoeff_checksum(num) == 0
}
<commit_msg>Enforce DRY for Luhn functions<commit_after>/// Performs the summation of digits in a number as specified by the Luhn algorithm.
fn luhn_digit_sum(num: u64) -> u32 {
    let mut num_pre_div = num;
    let mut num_post_div;
    let mut sum = 0u32;
    let mut i = 0u8;
    // Scan digits from right to left
    loop {
        num_post_div = num_pre_div / 10;
        i += 1;
        let digit = num_pre_div - num_post_div * 10;
        if i % 2 == 0 {
            // Even indexed digits are doubled and adjusted if greater than 9
            let mut second_digit = digit * 2;
            if second_digit > 9 {
                second_digit = second_digit - 9;
            }
            sum += second_digit as u32;
        } else {
            // Odd indexed digits are treated as-is
            sum += digit as u32;
        }
        if num_post_div == 0 {
            break;
        }
        num_pre_div = num_post_div;
    }
    sum
}

/// Computes the Luhn checksum for the provided number.
///
/// # Examples
///
/// Provide the function with an identification number.
///
/// ```
/// let acct_num = 79927398713;
/// let checksum = checksum::luhn_checksum(acct_num);
/// assert_eq!(checksum, 0);
/// if checksum != 0 {
///     println!("Account number has been corrupted!");
/// }
/// ```
pub fn luhn_checksum(num: u64) -> u8 {
    (luhn_digit_sum(num) % 10) as u8
}

/// Computes the Luhn check digit for the provided number.
///
/// # Examples
///
/// Provide the function with an identification number.
///
/// ```
/// let acct_num = 7992739871;
/// let checksum = checksum::luhn_calculate_check_digit(acct_num);
/// assert_eq!(checksum, 3);
/// ```
pub fn luhn_calculate_check_digit(num: u64) -> u8 {
    (luhn_digit_sum(num * 10) * 9 % 10) as u8
}

/// Verifies the check digit using the Luhn algorithm.
///
/// # Examples
///
/// Provide the function with an identification number.
///
/// ```
/// let acct_num = 79927398713;
/// let is_valid = checksum::luhn_is_valid(acct_num);
/// assert_eq!(is_valid, true);
/// if is_valid {
///     println!("Account number is valid!");
/// } else {
///     println!("Account number is NOT valid!");
/// }
/// ```
pub fn luhn_is_valid(num: u64) -> bool {
    luhn_checksum(num) == 0
}

const DIHEDRAL_D5: [[u8; 10]; 10] = [[0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
                                     [1, 2, 3, 4, 0, 6, 7, 8, 9, 5],
                                     [2, 3, 4, 0, 1, 7, 8, 9, 5, 6],
                                     [3, 4, 0, 1, 2, 8, 9, 5, 6, 7],
                                     [4, 0, 1, 2, 3, 9, 5, 6, 7, 8],
                                     [5, 9, 8, 7, 6, 0, 4, 3, 2, 1],
                                     [6, 5, 9, 8, 7, 1, 0, 4, 3, 2],
                                     [7, 6, 5, 9, 8, 2, 1, 0, 4, 3],
                                     [8, 7, 6, 5, 9, 3, 2, 1, 0, 4],
                                     [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]];

const INV_DIHEDRAL_D5: [u8; 10] = [0, 4, 3, 2, 1, 5, 6, 7, 8, 9];

const VERHOEFF_P_TABLE: [[u8; 10]; 8] = [[0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
                                         [1, 5, 7, 6, 2, 8, 3, 0, 9, 4],
                                         [5, 8, 0, 3, 7, 9, 6, 1, 4, 2],
                                         [8, 9, 1, 6, 0, 4, 3, 5, 2, 7],
                                         [9, 4, 5, 3, 1, 2, 6, 8, 7, 0],
                                         [4, 2, 8, 6, 5, 7, 3, 9, 0, 1],
                                         [2, 7, 9, 3, 8, 0, 6, 4, 1, 5],
                                         [7, 0, 4, 6, 9, 1, 3, 2, 5, 8]];

/// Computes the Verhoeff checksum for the provided number.
///
/// # Examples
///
/// Generate a checksum for 236:
///
/// ```
/// let num = 2363;
/// let check_digit = checksum::verhoeff_checksum(num);
/// assert_eq!(check_digit, 0);
/// ```
pub fn verhoeff_checksum(num: u64) -> u8 {
    let mut num_pre_div = num;
    let mut num_post_div;
    let mut i = 0u8;
    let mut c = 0u8;
    loop {
        num_post_div = num_pre_div / 10;
        let digit = num_pre_div - num_post_div * 10;
        c = DIHEDRAL_D5[c as usize][VERHOEFF_P_TABLE[(i % 8) as usize][digit as usize] as usize];
        i += 1;
        if num_post_div == 0 {
            break;
        }
        num_pre_div = num_post_div;
    }
    c
}

/// Computes the Verhoeff check digit for the provided number.
///
/// # Examples
///
/// Generate a check digit for 236:
///
/// ```
/// let num = 236;
/// let check_digit = checksum::verhoeff_calculate_check_digit(num);
/// assert_eq!(check_digit, 3);
/// ```
pub fn verhoeff_calculate_check_digit(num: u64) -> u8 {
    let c = verhoeff_checksum(num * 10);
    INV_DIHEDRAL_D5[c as usize]
}

/// Uses the Verhoeff checksum formula for error detection.
///
/// # Examples
///
/// Validate the check digit 2363.
///
/// ```
/// let num = 2363;
/// let is_valid = checksum::verhoeff_is_valid(num);
/// assert_eq!(is_valid, true);
/// ```
pub fn verhoeff_is_valid(num: u64) -> bool {
    verhoeff_checksum(num) == 0
}
<|endoftext|>


<commit_before>#![allow(dead_code)]

extern crate libc;

use crate::config::Config;
use crate::layout::{Layout, LayoutMsg};
use crate::xlib_window_system::XlibWindowSystem;
use crate::state::WmState;
use crate::workspace::MoveOp;
use self::libc::execvpe;
use std::{env, iter};
use std::ptr::null;
use std::ffi::CString;
use std::process::Command;
use std::path::Path;
use std::fs::OpenOptions;
use x11::xlib::Window;
use anyhow::{bail, Context, Result};

pub enum Cmd {
    Exec(String, Vec<String>),
    SwitchWorkspace(usize),
    SwitchScreen(usize),
    MoveToWorkspace(usize),
    MoveToScreen(usize),
    SendLayoutMsg(LayoutMsg),
    NestLayout(Box<dyn Fn() -> Box<dyn Layout>>),
    Reload,
    Exit,
    KillClient,
    FocusParentUp,
    FocusParentDown,
    FocusParentMaster,
    FocusUp,
    FocusDown,
    FocusMaster,
    SwapUp,
    SwapDown,
    SwapMaster,
    SwapParentUp,
    SwapParentDown,
    SwapParentMaster,
}

impl Cmd {
    pub fn call(&self, xws: &XlibWindowSystem, state: &mut WmState, config: &Config) -> Result<()> {
        match self {
            Cmd::Exec(ref cmd, ref args) => {
                debug!("Cmd::Exec: {} {:?}", cmd, args);
                exec(cmd.clone(), args.clone());
            }
            Cmd::SwitchWorkspace(index) => {
                debug!("Cmd::SwitchWorkspace: {}", index);
                state.switch_to_ws(xws, config, index - 1, true);
            }
            Cmd::SwitchScreen(screen) => {
                debug!("Cmd::SwitchScreen: {}", screen);
                state.switch_to_screen(xws, config, screen - 1);
            }
            Cmd::MoveToWorkspace(index) => {
                debug!("Cmd::MoveToWorkspace: {}", index);
                state.move_window_to(xws, config, index - 1);
            }
            Cmd::MoveToScreen(screen) => {
                debug!("Cmd::MoveToScreen: {}", screen);
                state.move_window_to_screen(xws, config, screen - 1);
            }
            Cmd::SendLayoutMsg(ref msg) => {
                debug!("Cmd::SendLayoutMsg::{:?}", msg);
                state.current_ws_mut().send_layout_message(msg.clone());
                state.current_ws().redraw(xws, config, state.get_screens());
            }
            Cmd::NestLayout(layout_fn) => {
                let layout = layout_fn();
                debug!("Cmd::NestLayout: {}", layout.name());
                state.current_ws_mut().nest_layout(layout);
            }
            Cmd::Reload => {
                debug!("Cmd::Reload");
                reload(state)
                    .context("failed to reload xr3wm")?;
            }
            Cmd::Exit => {
                debug!("Cmd::Exit");
                xws.close();
            }
            Cmd::KillClient => {
                if let Some(window) = state.current_ws().focused_window() {
                    debug!("Cmd::KillClient: {:#x}", window);
                    xws.kill_window(window);
                }
            }
            Cmd::FocusUp | Cmd::FocusDown | Cmd::FocusMaster | Cmd::FocusParentUp | Cmd::FocusParentDown | Cmd::FocusParentMaster => {
                if let Some(window) = state.current_ws().focused_window() {
                    let workspace = state.current_ws_mut();
                    let new_focus = match self {
                        Cmd::FocusUp => {
                            debug!("Cmd::FocusUp: {:#x}", window);
                            workspace.move_focus(MoveOp::Up)
                        }
                        Cmd::FocusDown => {
                            debug!("Cmd::FocusDown: {:#x}", window);
                            workspace.move_focus(MoveOp::Down)
                        }
                        Cmd::FocusMaster => {
                            debug!("Cmd::FocusMaster: {:#x}", window);
                            workspace.move_focus(MoveOp::Swap)
                        }
                        Cmd::FocusParentUp => {
                            debug!("Cmd::FocusParentUp: {:#x}", window);
                            workspace.move_parent_focus(MoveOp::Up)
                        }
                        Cmd::FocusParentDown => {
                            debug!("Cmd::FocusParentDown: {:#x}", window);
                            workspace.move_parent_focus(MoveOp::Down)
                        }
                        Cmd::FocusParentMaster => {
                            debug!("Cmd::FocusParentMaster: {:#x}", window);
                            workspace.move_parent_focus(MoveOp::Swap)
                        }
                        _ => None
                    };

                    if let Some(window) = new_focus {
                        xws.focus_window(window);
                    }
                }
            },
            Cmd::SwapUp | Cmd::SwapDown | Cmd::SwapMaster | Cmd::SwapParentUp | Cmd::SwapParentDown | Cmd::SwapParentMaster => {
                if let Some(window) = state.current_ws().focused_window() {
                    let workspace = state.current_ws_mut();
                    let new_focus = match self {
                        Cmd::SwapUp => {
                            debug!("Cmd::SwapUp: {:#x}", window);
                            workspace.move_window(MoveOp::Up)
                        }
                        Cmd::SwapDown => {
                            debug!("Cmd::SwapDown: {:#x}", window);
                            workspace.move_window(MoveOp::Down)
                        }
                        Cmd::SwapMaster => {
                            debug!("Cmd::SwapMaster: {:#x}", window);
                            workspace.move_window(MoveOp::Swap)
                        }
                        Cmd::SwapParentUp => {
                            debug!("Cmd::SwapParentUp: {:#x}", window);
                            workspace.move_parent_window(MoveOp::Up)
                        }
                        Cmd::SwapParentDown => {
                            debug!("Cmd::SwapParentDown: {:#x}", window);
                            workspace.move_parent_window(MoveOp::Down)
                        }
                        Cmd::SwapParentMaster => {
                            debug!("Cmd::SwapParentMaster: {:#x}", window);
                            workspace.move_parent_window(MoveOp::Swap)
                        }
                        _ => false
                    };

                    if new_focus {
                        state.current_ws().redraw(xws, config, state.get_screens());
                    }
                }
            }
        }
        Ok(())
    }
}

fn reload(state: &WmState) -> Result<()> {
    info!("recompiling...");

    let cfg_dir = Config::get_dir()
        .context("failed to locate config directory")?;
    let mut cmd = Command::new("cargo");

    let output = cmd.current_dir(&format!("{}/.build", cfg_dir))
        .arg("build")
        .env("RUST_LOG", "none")
        .output()
        .context("failed to run cargo")?;

    if !output.status.success() {
        let stderr_msg = String::from_utf8(output.stderr)
            .context("failed to convert cargo stderr to UTF-8")?;
        bail!("failed to recompile: {}", stderr_msg)
    }

    debug!("Cmd::Reload: restarting xr3wm...");

    let path = Path::new(&cfg_dir).join(".state.tmp");

    // save current workspace states to restore on restart
    let file = OpenOptions::new()
        .create(true)
        .write(true)
        .truncate(true)
        .open(&path)
        .context("failed to open workspace state tmp file")?;

    serde_json::to_writer(file, state)
        .context("failed to serialize workspace states")?;

    let args: Vec<*const libc::c_char> = env::args()
        .filter_map(|x| CString::new(x).ok())
        .map(|x| x.into_raw() as *const libc::c_char)
        .chain(iter::once(null()))
        .collect();

    let envs: Vec<*const libc::c_char> = env::vars()
        .filter_map(|(k,v)| CString::new(format!("{}={}", k, v)).ok())
        .map(|x| x.into_raw() as *const libc::c_char)
        .chain(iter::once(null()))
        .collect();

    unsafe {
        execvpe(args[0] as *const libc::c_char, args.as_ptr(), envs.as_ptr());
        // execvp returns only if an error has occurred
        error!("failed to reload: {}", ::std::io::Error::last_os_error());
    }

    Ok(())
}

pub struct ManageHook {
    pub class_name: String,
    pub cmd: CmdManage,
}

pub enum CmdManage {
    Move(usize),
    Float,
    Fullscreen,
    Ignore,
}

impl CmdManage {
    pub fn call(&self,
                xws: &XlibWindowSystem,
                state: &mut WmState,
                config: &Config,
                window: Window) {
        match *self {
            CmdManage::Move(index) => {
                debug!("CmdManage::Move: {}, {}", window, index);
                state.add_window(Some(index - 1), xws, config, window);
            }
            CmdManage::Float => {
                debug!("CmdManage::Float");
                unimplemented!()
            }
            CmdManage::Fullscreen => {
                debug!("CmdManage::Fullscreen");
                unimplemented!()
            }
            CmdManage::Ignore => {
                debug!("CmdManage::Ignore");
                unimplemented!()
            }
        }
    }
}

fn exec(cmd: String, args: Vec<String>) {
    if !cmd.is_empty() {
        let mut cmd = Command::new(cmd);

        if !args.is_empty() {
            cmd.args(&args);
        }

        match cmd.envs(env::vars()).spawn() {
            Ok(_) => (),
            Err(e) => error!("failed to start \"{:?}\": {}", cmd, e),
        }
    }
}
<commit_msg>Add custom command<commit_after>#![allow(dead_code)]

extern crate libc;

use crate::config::Config;
use crate::layout::{Layout, LayoutMsg};
use crate::xlib_window_system::XlibWindowSystem;
use crate::state::WmState;
use crate::workspace::MoveOp;
use self::libc::execvpe;
use std::{env, iter};
use std::ptr::null;
use std::ffi::CString;
use std::process::Command;
use std::path::Path;
use std::fs::OpenOptions;
use x11::xlib::Window;
use anyhow::{bail, Context, Result};

pub enum Cmd {
    Custom(Box<dyn Fn(&WmState) -> Result<Option<Cmd>, String>>),
    Exec(String, Vec<String>),
    SwitchWorkspace(usize),
    SwitchScreen(usize),
    MoveToWorkspace(usize),
    MoveToScreen(usize),
    SendLayoutMsg(LayoutMsg),
    NestLayout(Box<dyn Fn() -> Box<dyn Layout>>),
    Reload,
    Exit,
    KillClient,
    FocusParentUp,
    FocusParentDown,
    FocusParentMaster,
    FocusUp,
    FocusDown,
    FocusMaster,
    SwapUp,
    SwapDown,
    SwapMaster,
    SwapParentUp,
    SwapParentDown,
    SwapParentMaster,
}

impl Cmd {
    pub fn call(&self, xws: &XlibWindowSystem, state: &mut WmState, config: &Config) -> Result<()> {
        match self {
            Cmd::Custom(func) => {
                debug!("Cmd::Custom");
                match func(state) {
                    Ok(Some(cmd)) => cmd.call(xws, state, config)?,
                    Ok(None) => (),
                    Err(e) => error!("Cmd::Custom failed: {}", e),
                }
            }
            Cmd::Exec(ref cmd, ref args) => {
                debug!("Cmd::Exec: {} {:?}", cmd, args);
                exec(cmd.clone(), args.clone());
            }
            Cmd::SwitchWorkspace(index) => {
                debug!("Cmd::SwitchWorkspace: {}", index);
                state.switch_to_ws(xws, config, index - 1, true);
            }
            Cmd::SwitchScreen(screen) => {
                debug!("Cmd::SwitchScreen: {}", screen);
                state.switch_to_screen(xws, config, screen - 1);
            }
            Cmd::MoveToWorkspace(index) => {
                debug!("Cmd::MoveToWorkspace: {}", index);
                state.move_window_to(xws, config, index - 1);
            }
            Cmd::MoveToScreen(screen) => {
                debug!("Cmd::MoveToScreen: {}", screen);
                state.move_window_to_screen(xws, config, screen - 1);
            }
            Cmd::SendLayoutMsg(ref msg) => {
                debug!("Cmd::SendLayoutMsg::{:?}", msg);
                state.current_ws_mut().send_layout_message(msg.clone());
                state.current_ws().redraw(xws, config, state.get_screens());
            }
            Cmd::NestLayout(layout_fn) => {
                let layout = layout_fn();
                debug!("Cmd::NestLayout: {}", layout.name());
                state.current_ws_mut().nest_layout(layout);
            }
            Cmd::Reload => {
                debug!("Cmd::Reload");
                reload(state)
                    .context("failed to reload xr3wm")?;
            }
            Cmd::Exit => {
                debug!("Cmd::Exit");
                xws.close();
            }
            Cmd::KillClient => {
                if let Some(window) = state.current_ws().focused_window() {
                    debug!("Cmd::KillClient: {:#x}", window);
                    xws.kill_window(window);
                }
            }
            Cmd::FocusUp | Cmd::FocusDown | Cmd::FocusMaster | Cmd::FocusParentUp | Cmd::FocusParentDown | Cmd::FocusParentMaster => {
                if let Some(window) = state.current_ws().focused_window() {
                    let workspace = state.current_ws_mut();
                    let new_focus = match self {
                        Cmd::FocusUp => {
                            debug!("Cmd::FocusUp: {:#x}", window);
                            workspace.move_focus(MoveOp::Up)
                        }
                        Cmd::FocusDown => {
                            debug!("Cmd::FocusDown: {:#x}", window);
                            workspace.move_focus(MoveOp::Down)
                        }
                        Cmd::FocusMaster => {
                            debug!("Cmd::FocusMaster: {:#x}", window);
                            workspace.move_focus(MoveOp::Swap)
                        }
                        Cmd::FocusParentUp => {
                            debug!("Cmd::FocusParentUp: {:#x}", window);
                            workspace.move_parent_focus(MoveOp::Up)
                        }
                        Cmd::FocusParentDown => {
                            debug!("Cmd::FocusParentDown: {:#x}", window);
                            workspace.move_parent_focus(MoveOp::Down)
                        }
                        Cmd::FocusParentMaster => {
                            debug!("Cmd::FocusParentMaster: {:#x}", window);
                            workspace.move_parent_focus(MoveOp::Swap)
                        }
                        _ => None
                    };

                    if let Some(window) = new_focus {
                        xws.focus_window(window);
                    }
                }
            },
            Cmd::SwapUp | Cmd::SwapDown | Cmd::SwapMaster | Cmd::SwapParentUp | Cmd::SwapParentDown | Cmd::SwapParentMaster => {
                if let Some(window) = state.current_ws().focused_window() {
                    let workspace = state.current_ws_mut();
                    let new_focus = match self {
                        Cmd::SwapUp => {
                            debug!("Cmd::SwapUp: {:#x}", window);
                            workspace.move_window(MoveOp::Up)
                        }
                        Cmd::SwapDown => {
                            debug!("Cmd::SwapDown: {:#x}", window);
                            workspace.move_window(MoveOp::Down)
                        }
                        Cmd::SwapMaster => {
                            debug!("Cmd::SwapMaster: {:#x}", window);
                            workspace.move_window(MoveOp::Swap)
                        }
                        Cmd::SwapParentUp => {
                            debug!("Cmd::SwapParentUp: {:#x}", window);
                            workspace.move_parent_window(MoveOp::Up)
                        }
                        Cmd::SwapParentDown => {
                            debug!("Cmd::SwapParentDown: {:#x}", window);
                            workspace.move_parent_window(MoveOp::Down)
                        }
                        Cmd::SwapParentMaster => {
                            debug!("Cmd::SwapParentMaster: {:#x}", window);
                            workspace.move_parent_window(MoveOp::Swap)
                        }
                        _ => false
                    };

                    if new_focus {
                        state.current_ws().redraw(xws, config, state.get_screens());
                    }
                }
            }
        }
        Ok(())
    }
}

fn reload(state: &WmState) -> Result<()> {
    info!("recompiling...");

    let cfg_dir = Config::get_dir()
        .context("failed to locate config directory")?;
    let mut cmd = Command::new("cargo");

    let output = cmd.current_dir(&format!("{}/.build", cfg_dir))
        .arg("build")
        .env("RUST_LOG", "none")
        .output()
        .context("failed to run cargo")?;

    if !output.status.success() {
        let stderr_msg = String::from_utf8(output.stderr)
            .context("failed to convert cargo stderr to UTF-8")?;
        bail!("failed to recompile: {}", stderr_msg)
    }

    debug!("Cmd::Reload: restarting xr3wm...");

    let path = Path::new(&cfg_dir).join(".state.tmp");

    // save current workspace states to restore on restart
    let file = OpenOptions::new()
        .create(true)
        .write(true)
        .truncate(true)
        .open(&path)
        .context("failed to open workspace state tmp file")?;

    serde_json::to_writer(file, state)
        .context("failed to serialize workspace states")?;

    let args: Vec<*const libc::c_char> = env::args()
        .filter_map(|x| CString::new(x).ok())
        .map(|x| x.into_raw() as *const libc::c_char)
        .chain(iter::once(null()))
        .collect();

    let envs: Vec<*const libc::c_char> = env::vars()
        .filter_map(|(k,v)| CString::new(format!("{}={}", k, v)).ok())
        .map(|x| x.into_raw() as *const libc::c_char)
        .chain(iter::once(null()))
        .collect();

    unsafe {
        execvpe(args[0] as *const libc::c_char, args.as_ptr(), envs.as_ptr());
        // execvp returns only if an error has occurred
        error!("failed to reload: {}", ::std::io::Error::last_os_error());
    }

    Ok(())
}

pub struct ManageHook {
    pub class_name: String,
    pub cmd: CmdManage,
}

pub enum CmdManage {
    Move(usize),
    Float,
    Fullscreen,
    Ignore,
}

impl CmdManage {
    pub fn call(&self,
                xws: &XlibWindowSystem,
                state: &mut WmState,
                config: &Config,
                window: Window) {
        match *self {
            CmdManage::Move(index) => {
                debug!("CmdManage::Move: {}, {}", window, index);
                state.add_window(Some(index - 1), xws, config, window);
            }
            CmdManage::Float => {
                debug!("CmdManage::Float");
                unimplemented!()
            }
            CmdManage::Fullscreen => {
                debug!("CmdManage::Fullscreen");
                unimplemented!()
            }
            CmdManage::Ignore => {
                debug!("CmdManage::Ignore");
                unimplemented!()
            }
        }
    }
}

fn exec(cmd: String, args: Vec<String>) {
    if !cmd.is_empty() {
        let mut cmd = Command::new(cmd);

        if !args.is_empty() {
            cmd.args(&args);
        }

        match cmd.envs(env::vars()).spawn() {
            Ok(_) => (),
            Err(e) => error!("failed to start \"{:?}\": {}", cmd, e),
        }
    }
}
<|endoftext|>


<commit_before>// Translation of the following Go program into Rust:
//
// ```
// func main() {
//     people := []string{"Anna", "Bob", "Cody", "Dave", "Eva"}
//     match := make(chan string, 1) // Make room for one unmatched send.
//     wg := new(sync.WaitGroup)
//     for _, name := range people {
//         wg.Add(1)
//         go Seek(name, match, wg)
//     }
//     wg.Wait()
//     select {
//     case name := <-match:
//         fmt.Printf("No one received %s’s message.\n", name)
//     default:
//         // There was no pending send operation.
//     }
// }
//
// // Seek either sends or receives, whichever possible, a name on the match
// // channel and notifies the wait group when done.
// func Seek(name string, match chan string, wg *sync.WaitGroup) {
//     select {
//     case peer := <-match:
//         fmt.Printf("%s received a message from %s.\n", name, peer)
//     case match <- name:
//         // Wait for someone to receive my message.
//     }
//     wg.Done()
// }
// ```
//
// Source: https://www.nada.kth.se/~snilsson/concurrency/#Match

extern crate crossbeam;
extern crate channel;

use channel::select;

fn main() {
    let people = vec!["Anna", "Bob", "Cody", "Dave", "Eva"];
    let (tx, rx) = channel::bounded(1); // Make room for one unmatched send.
    let (tx, rx) = (&tx, &rx);

    crossbeam::scope(|s| {
        for name in people {
            s.spawn(move || {
                loop {
                    if let Ok(peer) = rx.select() {
                        println!("{} received a message from {}.", name, peer);
                        break;
                    }
                    if let Ok(_) = tx.select(name) {
                        // Wait for someone to receive my message.
                        break;
                    }
                }
            });
        }
    });

    loop {
        if let Ok(peer) = rx.select() {
            println!("No one received {}’s message.", peer);
            break;
        }
        if select::blocked() {
            // There was no pending send operation.
            break;
        }
    }
}
<commit_msg>Factor out the seek method<commit_after>// Translation of the following Go program into Rust:
//
// ```
// func main() {
//     people := []string{"Anna", "Bob", "Cody", "Dave", "Eva"}
//     match := make(chan string, 1) // Make room for one unmatched send.
//     wg := new(sync.WaitGroup)
//     for _, name := range people {
//         wg.Add(1)
//         go Seek(name, match, wg)
//     }
//     wg.Wait()
//     select {
//     case name := <-match:
//         fmt.Printf("No one received %s’s message.\n", name)
//     default:
//         // There was no pending send operation.
//     }
// }
//
// // Seek either sends or receives, whichever possible, a name on the match
// // channel and notifies the wait group when done.
// func Seek(name string, match chan string, wg *sync.WaitGroup) {
//     select {
//     case peer := <-match:
//         fmt.Printf("%s received a message from %s.\n", name, peer)
//     case match <- name:
//         // Wait for someone to receive my message.
//     }
//     wg.Done()
// }
// ```
//
// Source: https://www.nada.kth.se/~snilsson/concurrency/#Match

extern crate crossbeam;
extern crate channel;

use channel::{select, Receiver, Sender};

fn main() {
    let people = vec!["Anna", "Bob", "Cody", "Dave", "Eva"];
    let (tx, rx) = channel::bounded(1); // Make room for one unmatched send.
    let (tx, rx) = (&tx, &rx);

    crossbeam::scope(|s| for name in people {
        s.spawn(move || seek(name, tx, rx));
    });

    loop {
        if let Ok(peer) = rx.select() {
            println!("No one received {}’s message.", peer);
            break;
        }
        if select::blocked() {
            // There was no pending send operation.
            break;
        }
    }
}

// Either sends or receives, whichever possible, a name on the channel.
fn seek<'a>(name: &'a str, tx: &Sender<&'a str>, rx: &Receiver<&'a str>) {
    loop {
        if let Ok(peer) = rx.select() {
            println!("{} received a message from {}.", name, peer);
            break;
        }
        if let Ok(_) = tx.select(name) {
            // Wait for someone to receive my message.
            break;
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2016 Joe Wilm, The Alacritty Project Contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
//! Compatibility layer for different font engines
//!
//! CoreText is used on Mac OS.
//! FreeType is used on everything that's not Mac OS.
//! Eventually, ClearType support will be available for windows
#[cfg(not(target_os = "macos"))]
extern crate fontconfig;
#[cfg(not(target_os = "macos"))]
extern crate freetype;

#[cfg(target_os = "macos")]
extern crate core_text;
#[cfg(target_os = "macos")]
extern crate core_foundation;
#[cfg(target_os = "macos")]
extern crate core_foundation_sys;
#[cfg(target_os = "macos")]
extern crate core_graphics;
#[cfg(target_os = "macos")]
extern crate euclid;

extern crate libc;

#[cfg(not(target_os = "macos"))]
#[macro_use]
extern crate foreign_types;

#[macro_use]
extern crate log;

use std::hash::{Hash, Hasher};
use std::fmt;
use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering};

// If target isn't macos, reexport everything from ft
#[cfg(not(target_os = "macos"))]
pub mod ft;
#[cfg(not(target_os = "macos"))]
pub use ft::{FreeTypeRasterizer as Rasterizer, Error};

// If target is macos, reexport everything from darwin
#[cfg(target_os = "macos")]
mod darwin;
#[cfg(target_os = "macos")]
pub use darwin::*;

/// Character used for the underline cursor
#[cfg(not(target_os = "macos"))]
// This is part of the private use area and should not conflict with any font
pub const UNDERLINE_CURSOR_CHAR: char = '􊏢';
#[cfg(target_os = "macos")]
pub const UNDERLINE_CURSOR_CHAR: char = '▁';

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct FontDesc {
    name: String,
    style: Style,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Slant {
    Normal,
    Italic,
    Oblique,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Weight {
    Normal,
    Bold
}

/// Style of font
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum Style {
    Specific(String),
    Description { slant: Slant, weight: Weight }
}

impl fmt::Display for Style {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Style::Specific(ref s) => f.write_str(&s),
            Style::Description { slant, weight } => {
                write!(f, "slant={:?}, weight={:?}", slant, weight)
            },
        }
    }
}

impl FontDesc {
    pub fn new<S>(name: S, style: Style) -> FontDesc
        where S: Into<String>
    {
        FontDesc {
            name: name.into(),
            style: style
        }
    }
}

impl fmt::Display for FontDesc {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "name '{}' and style '{}'", self.name, self.style)
    }
}

/// Identifier for a Font for use in maps/etc
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
pub struct FontKey {
    token: u16,
}

impl FontKey {
    /// Get next font key for given size
    ///
    /// The generated key will be globally unique
    pub fn next() -> FontKey {
        static TOKEN: AtomicUsize = ATOMIC_USIZE_INIT;

        FontKey {
            token: TOKEN.fetch_add(1, Ordering::SeqCst) as _,
        }
    }
}

#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub struct GlyphKey {
    pub c: char,
    pub font_key: FontKey,
    pub size: Size,
}

impl Hash for GlyphKey {
    fn hash<H: Hasher>(&self, state: &mut H) {
        unsafe {
            // This transmute is fine:
            //
            // - If GlyphKey ever becomes a different size, this will fail to compile
            // - Result is being used for hashing and has no fields (it's a u64)
            ::std::mem::transmute::<GlyphKey, u64>(*self)
        }.hash(state);
    }
}

/// Font size stored as integer
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
pub struct Size(i16);

impl Size {
    /// Scale factor between font "Size" type and point size
    #[inline]
    pub fn factor() -> f32 {
        2.0
    }

    /// Create a new `Size` from a f32 size in points
    pub fn new(size: f32) -> Size {
        Size((size * Size::factor()) as i16)
    }

    /// Get the f32 size in points
    pub fn as_f32_pts(self) -> f32 {
        self.0 as f32 / Size::factor()
    }
}

impl ::std::ops::Add for Size {
    type Output = Size;

    fn add(self, other: Size) -> Size {
        Size(self.0.saturating_add(other.0))
    }
}

pub struct RasterizedGlyph {
    pub c: char,
    pub width: i32,
    pub height: i32,
    pub top: i32,
    pub left: i32,
    pub buf: Vec<u8>,
}

impl Default for RasterizedGlyph {
    fn default() -> RasterizedGlyph {
        RasterizedGlyph {
            c: ' ',
            width: 0,
            height: 0,
            top: 0,
            left: 0,
            buf: Vec::new(),
        }
    }
}

struct BufDebugger<'a>(&'a [u8]);

impl<'a> fmt::Debug for BufDebugger<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("GlyphBuffer")
            .field("len", &self.0.len())
            .field("bytes", &self.0)
            .finish()
    }
}

impl fmt::Debug for RasterizedGlyph {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("RasterizedGlyph")
            .field("c", &self.c)
            .field("width", &self.width)
            .field("height", &self.height)
            .field("top", &self.top)
            .field("left", &self.left)
            .field("buf", &BufDebugger(&self.buf[..]))
            .finish()
    }
}

pub struct Metrics {
    pub average_advance: f64,
    pub line_height: f64,
    pub descent: f32,
}

pub trait Rasterize {
    /// Errors occurring in Rasterize methods
    type Err: ::std::error::Error + Send + Sync + 'static;

    /// Create a new Rasterize
    fn new(device_pixel_ratio: f32, use_thin_strokes: bool) -> Result<Self, Self::Err>
        where Self: Sized;

    /// Get `Metrics` for the given `FontKey`
    fn metrics(&self, FontKey) -> Result<Metrics, Self::Err>;

    /// Load the font described by `FontDesc` and `Size`
    fn load_font(&mut self, &FontDesc, Size) -> Result<FontKey, Self::Err>;

    /// Rasterize the glyph described by `GlyphKey`.
    fn get_glyph(&mut self, &GlyphKey) -> Result<RasterizedGlyph, Self::Err>;
}
<commit_msg>Specify unicode code point explicitly<commit_after>// Copyright 2016 Joe Wilm, The Alacritty Project Contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
//! Compatibility layer for different font engines
//!
//! CoreText is used on Mac OS.
//! FreeType is used on everything that's not Mac OS.
//! Eventually, ClearType support will be available for windows
#[cfg(not(target_os = "macos"))]
extern crate fontconfig;
#[cfg(not(target_os = "macos"))]
extern crate freetype;

#[cfg(target_os = "macos")]
extern crate core_text;
#[cfg(target_os = "macos")]
extern crate core_foundation;
#[cfg(target_os = "macos")]
extern crate core_foundation_sys;
#[cfg(target_os = "macos")]
extern crate core_graphics;
#[cfg(target_os = "macos")]
extern crate euclid;

extern crate libc;

#[cfg(not(target_os = "macos"))]
#[macro_use]
extern crate foreign_types;

#[macro_use]
extern crate log;

use std::hash::{Hash, Hasher};
use std::fmt;
use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering};

// If target isn't macos, reexport everything from ft
#[cfg(not(target_os = "macos"))]
pub mod ft;
#[cfg(not(target_os = "macos"))]
pub use ft::{FreeTypeRasterizer as Rasterizer, Error};

// If target is macos, reexport everything from darwin
#[cfg(target_os = "macos")]
mod darwin;
#[cfg(target_os = "macos")]
pub use darwin::*;

/// Character used for the underline cursor
#[cfg(not(target_os = "macos"))]
// This is part of the private use area and should not conflict with any font
pub const UNDERLINE_CURSOR_CHAR: char = '\u{10a3e2}';
#[cfg(target_os = "macos")]
pub const UNDERLINE_CURSOR_CHAR: char = '▁';

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct FontDesc {
    name: String,
    style: Style,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Slant {
    Normal,
    Italic,
    Oblique,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Weight {
    Normal,
    Bold
}

/// Style of font
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum Style {
    Specific(String),
    Description { slant: Slant, weight: Weight }
}

impl fmt::Display for Style {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Style::Specific(ref s) => f.write_str(&s),
            Style::Description { slant, weight } => {
                write!(f, "slant={:?}, weight={:?}", slant, weight)
            },
        }
    }
}

impl FontDesc {
    pub fn new<S>(name: S, style: Style) -> FontDesc
        where S: Into<String>
    {
        FontDesc {
            name: name.into(),
            style: style
        }
    }
}

impl fmt::Display for FontDesc {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "name '{}' and style '{}'", self.name, self.style)
    }
}

/// Identifier for a Font for use in maps/etc
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
pub struct FontKey {
    token: u16,
}

impl FontKey {
    /// Get next font key for given size
    ///
    /// The generated key will be globally unique
    pub fn next() -> FontKey {
        static TOKEN: AtomicUsize = ATOMIC_USIZE_INIT;

        FontKey {
            token: TOKEN.fetch_add(1, Ordering::SeqCst) as _,
        }
    }
}

#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub struct GlyphKey {
    pub c: char,
    pub font_key: FontKey,
    pub size: Size,
}

impl Hash for GlyphKey {
    fn hash<H: Hasher>(&self, state: &mut H) {
        unsafe {
            // This transmute is fine:
            //
            // - If GlyphKey ever becomes a different size, this will fail to compile
            // - Result is being used for hashing and has no fields (it's a u64)
            ::std::mem::transmute::<GlyphKey, u64>(*self)
        }.hash(state);
    }
}

/// Font size stored as integer
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
pub struct Size(i16);

impl Size {
    /// Scale factor between font "Size" type and point size
    #[inline]
    pub fn factor() -> f32 {
        2.0
    }

    /// Create a new `Size` from a f32 size in points
    pub fn new(size: f32) -> Size {
        Size((size * Size::factor()) as i16)
    }

    /// Get the f32 size in points
    pub fn as_f32_pts(self) -> f32 {
        self.0 as f32 / Size::factor()
    }
}

impl ::std::ops::Add for Size {
    type Output = Size;

    fn add(self, other: Size) -> Size {
        Size(self.0.saturating_add(other.0))
    }
}

pub struct RasterizedGlyph {
    pub c: char,
    pub width: i32,
    pub height: i32,
    pub top: i32,
    pub left: i32,
    pub buf: Vec<u8>,
}

impl Default for RasterizedGlyph {
    fn default() -> RasterizedGlyph {
        RasterizedGlyph {
            c: ' ',
            width: 0,
            height: 0,
            top: 0,
            left: 0,
            buf: Vec::new(),
        }
    }
}

struct BufDebugger<'a>(&'a [u8]);

impl<'a> fmt::Debug for BufDebugger<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("GlyphBuffer")
            .field("len", &self.0.len())
            .field("bytes", &self.0)
            .finish()
    }
}

impl fmt::Debug for RasterizedGlyph {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("RasterizedGlyph")
            .field("c", &self.c)
            .field("width", &self.width)
            .field("height", &self.height)
            .field("top", &self.top)
            .field("left", &self.left)
            .field("buf", &BufDebugger(&self.buf[..]))
            .finish()
    }
}

pub struct Metrics {
    pub average_advance: f64,
    pub line_height: f64,
    pub descent: f32,
}

pub trait Rasterize {
    /// Errors occurring in Rasterize methods
    type Err: ::std::error::Error + Send + Sync + 'static;

    /// Create a new Rasterize
    fn new(device_pixel_ratio: f32, use_thin_strokes: bool) -> Result<Self, Self::Err>
        where Self: Sized;

    /// Get `Metrics` for the given `FontKey`
    fn metrics(&self, FontKey) -> Result<Metrics, Self::Err>;

    /// Load the font described by `FontDesc` and `Size`
    fn load_font(&mut self, &FontDesc, Size) -> Result<FontKey, Self::Err>;

    /// Rasterize the glyph described by `GlyphKey`.
    fn get_glyph(&mut self, &GlyphKey) -> Result<RasterizedGlyph, Self::Err>;
}
<|endoftext|>


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

#[derive(Debug, PartialEq)]
pub enum Type {
    CoffeeScript,
    JavaScript,
    JSON,
    XML,
    Ruby,
    Rust,
    ERB
}

pub fn from_path(path: &Path) -> Option<Type> {
    match path.to_str() {
        Some(filename) => {
            let extension = filename.split('.').last();
            match extension {
                Some("coffee") => Some(Type::CoffeeScript),
                Some("js") => Some(Type::JavaScript),
                Some("json") => Some(Type::JSON),
                Some("xml") => Some(Type::XML),
                Some("rb") => Some(Type::Ruby),
                Some("rs") => Some(Type::Rust),
                Some("erb") => Some(Type::ERB),
                _ => None,
            }
        },
        None => return None,
    }
}

#[cfg(test)]
mod tests {
    use std::path::Path;
    use super::from_path;
    use super::Type;

    #[test]
    fn from_path_works() {
        let buffer_type = from_path(&Path::new("file.json")).unwrap();
        assert_eq!(buffer_type, Type::JSON);
    }
}
<commit_msg>Treat rake files as Ruby, from a type detection standpoint.<commit_after>use std::path::Path;

#[derive(Debug, PartialEq)]
pub enum Type {
    CoffeeScript,
    JavaScript,
    JSON,
    XML,
    Ruby,
    Rust,
    ERB
}

pub fn from_path(path: &Path) -> Option<Type> {
    match path.to_str() {
        Some(filename) => {
            let extension = filename.split('.').last();
            match extension {
                Some("coffee") => Some(Type::CoffeeScript),
                Some("js") => Some(Type::JavaScript),
                Some("json") => Some(Type::JSON),
                Some("xml") => Some(Type::XML),
                Some("rake") => Some(Type::Ruby),
                Some("rb") => Some(Type::Ruby),
                Some("rs") => Some(Type::Rust),
                Some("erb") => Some(Type::ERB),
                _ => None,
            }
        },
        None => return None,
    }
}

#[cfg(test)]
mod tests {
    use std::path::Path;
    use super::from_path;
    use super::Type;

    #[test]
    fn from_path_works() {
        let buffer_type = from_path(&Path::new("file.json")).unwrap();
        assert_eq!(buffer_type, Type::JSON);
    }
}
<|endoftext|>


<commit_before>use semver::VersionReq;
use rustc_serialize::{Encoder, Encodable};

use core::{SourceId, Summary, PackageId};
use std::rc::Rc;
use util::CargoResult;

/// The data underlying a Dependency.
#[derive(PartialEq,Clone,Debug)]
pub struct DependencyInner {
    name: String,
    source_id: SourceId,
    req: VersionReq,
    specified_req: Option<String>,
    kind: Kind,
    only_match_name: bool,

    optional: bool,
    default_features: bool,
    features: Vec<String>,

    // This dependency should be used only for this platform.
    // `None` means *all platforms*.
    only_for_platform: Option<String>,
}

/// Information about a dependency requested by a Cargo manifest.
/// Cheap to copy.
#[derive(PartialEq,Clone,Debug)]
pub struct Dependency {
    inner: Rc<DependencyInner>,
}

#[derive(RustcEncodable)]
struct SerializedDependency {
    name: String,
    req: String
}

impl Encodable for Dependency {
    fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
        SerializedDependency {
            name: self.name().to_string(),
            req: self.version_req().to_string()
        }.encode(s)
    }
}

#[derive(PartialEq, Clone, Debug, Copy)]
pub enum Kind {
    Normal,
    Development,
    Build,
}

impl DependencyInner {
    /// Attempt to create a `Dependency` from an entry in the manifest.
    pub fn parse(name: &str,
                 version: Option<&str>,
                 source_id: &SourceId) -> CargoResult<DependencyInner> {
        let version_req = match version {
            Some(v) => try!(VersionReq::parse(v)),
            None => VersionReq::any()
        };

        Ok(DependencyInner {
            only_match_name: false,
            req: version_req,
            specified_req: version.map(|s| s.to_string()),
            .. DependencyInner::new_override(name, source_id)
        })
    }

    pub fn new_override(name: &str, source_id: &SourceId) -> DependencyInner {
        DependencyInner {
            name: name.to_string(),
            source_id: source_id.clone(),
            req: VersionReq::any(),
            kind: Kind::Normal,
            only_match_name: true,
            optional: false,
            features: Vec::new(),
            default_features: true,
            specified_req: None,
            only_for_platform: None,
        }
    }

    pub fn version_req(&self) -> &VersionReq { &self.req }
    pub fn name(&self) -> &str { &self.name }
    pub fn source_id(&self) -> &SourceId { &self.source_id }
    pub fn kind(&self) -> Kind { self.kind }
    pub fn specified_req(&self) -> Option<&str> {
        self.specified_req.as_ref().map(|s| &s[..])
    }

    /// If none, this dependencies must be built for all platforms.
    /// If some, it must only be built for the specified platform.
    pub fn only_for_platform(&self) -> Option<&str> {
        self.only_for_platform.as_ref().map(|s| &s[..])
    }

    pub fn set_kind(mut self, kind: Kind) -> DependencyInner {
        self.kind = kind;
        self
    }

    /// Sets the list of features requested for the package.
    pub fn set_features(mut self, features: Vec<String>) -> DependencyInner {
        self.features = features;
        self
    }

    /// Sets whether the dependency requests default features of the package.
    pub fn set_default_features(mut self, default_features: bool) -> DependencyInner {
        self.default_features = default_features;
        self
    }

    /// Sets whether the dependency is optional.
    pub fn set_optional(mut self, optional: bool) -> DependencyInner {
        self.optional = optional;
        self
    }

    /// Set the source id for this dependency
    pub fn set_source_id(mut self, id: SourceId) -> DependencyInner {
        self.source_id = id;
        self
    }

    /// Set the version requirement for this dependency
    pub fn set_version_req(mut self, req: VersionReq) -> DependencyInner {
        self.req = req;
        self
    }

    pub fn set_only_for_platform(mut self, platform: Option<String>)
                                 -> DependencyInner {
        self.only_for_platform = platform;
        self
    }

    /// Lock this dependency to depending on the specified package id
    pub fn lock_to(self, id: &PackageId) -> DependencyInner {
        assert_eq!(self.source_id, *id.source_id());
        assert!(self.req.matches(id.version()));
        self.set_version_req(VersionReq::exact(id.version()))
            .set_source_id(id.source_id().clone())
    }

    /// Returns false if the dependency is only used to build the local package.
    pub fn is_transitive(&self) -> bool {
        match self.kind {
            Kind::Normal | Kind::Build => true,
            Kind::Development => false,
        }
    }
    pub fn is_build(&self) -> bool {
        match self.kind { Kind::Build => true, _ => false }
    }
    pub fn is_optional(&self) -> bool { self.optional }
    /// Returns true if the default features of the dependency are requested.
    pub fn uses_default_features(&self) -> bool { self.default_features }
    /// Returns the list of features that are requested by the dependency.
    pub fn features(&self) -> &[String] { &self.features }

    /// Returns true if the package (`sum`) can fulfill this dependency request.
    pub fn matches(&self, sum: &Summary) -> bool {
        self.matches_id(sum.package_id())
    }

    /// Returns true if the package (`id`) can fulfill this dependency request.
    pub fn matches_id(&self, id: &PackageId) -> bool {
        self.name == id.name() &&
            (self.only_match_name || (self.req.matches(id.version()) &&
                                      &self.source_id == id.source_id()))
    }

    pub fn into_dependency(self) -> Dependency {
        Dependency {inner: Rc::new(self)}
    }
}

impl Dependency {
    /// Attempt to create a `Dependency` from an entry in the manifest.
    pub fn parse(name: &str,
                 version: Option<&str>,
                 source_id: &SourceId) -> CargoResult<Dependency> {
        DependencyInner::parse(name, version, source_id).map(|di| {
            di.into_dependency()
        })
    }

    pub fn new_override(name: &str, source_id: &SourceId) -> Dependency {
        DependencyInner::new_override(name, source_id).into_dependency()
    }

    pub fn clone_inner(&self) -> DependencyInner { (*self.inner).clone() }

    pub fn version_req(&self) -> &VersionReq { self.inner.version_req() }
    pub fn name(&self) -> &str { self.inner.name() }
    pub fn source_id(&self) -> &SourceId { self.inner.source_id() }
    pub fn kind(&self) -> Kind { self.inner.kind() }
    pub fn specified_req(&self) -> Option<&str> { self.inner.specified_req() }

    /// If none, this dependencies must be built for all platforms.
    /// If some, it must only be built for the specified platform.
    pub fn only_for_platform(&self) -> Option<&str> {
        self.inner.only_for_platform()
    }

    /// Lock this dependency to depending on the specified package id
    pub fn lock_to(self, id: &PackageId) -> Dependency {
        self.clone_inner().lock_to(id).into_dependency()
    }

    /// Returns false if the dependency is only used to build the local package.
    pub fn is_transitive(&self) -> bool { self.inner.is_transitive() }
    pub fn is_build(&self) -> bool { self.inner.is_build() }
    pub fn is_optional(&self) -> bool { self.inner.is_optional() }
    /// Returns true if the default features of the dependency are requested.
    pub fn uses_default_features(&self) -> bool {
        self.inner.uses_default_features()
    }
    /// Returns the list of features that are requested by the dependency.
    pub fn features(&self) -> &[String] { self.inner.features() }

    /// Returns true if the package (`sum`) can fulfill this dependency request.
    pub fn matches(&self, sum: &Summary) -> bool { self.inner.matches(sum) }

    /// Returns true if the package (`id`) can fulfill this dependency request.
    pub fn matches_id(&self, id: &PackageId) -> bool {
        self.inner.matches_id(id)
    }
}

<commit_msg>add more fields to SerializedDependency<commit_after>use semver::VersionReq;
use rustc_serialize::{Encoder, Encodable};

use core::{SourceId, Summary, PackageId};
use std::rc::Rc;
use util::CargoResult;

/// The data underlying a Dependency.
#[derive(PartialEq,Clone,Debug)]
pub struct DependencyInner {
    name: String,
    source_id: SourceId,
    req: VersionReq,
    specified_req: Option<String>,
    kind: Kind,
    only_match_name: bool,

    optional: bool,
    default_features: bool,
    features: Vec<String>,

    // This dependency should be used only for this platform.
    // `None` means *all platforms*.
    only_for_platform: Option<String>,
}

/// Information about a dependency requested by a Cargo manifest.
/// Cheap to copy.
#[derive(PartialEq,Clone,Debug)]
pub struct Dependency {
    inner: Rc<DependencyInner>,
}

#[derive(RustcEncodable)]
struct SerializedDependency<'a> {
    name: &'a str,
    source: &'a SourceId,
    req: String,
    kind: Kind,

    optional: bool,
    uses_default_features: bool,
    features: &'a [String],
    target: &'a Option<&'a str>,
}

impl Encodable for Dependency {
    fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
        SerializedDependency {
            name: self.name(),
            source: &self.source_id(),
            req: self.version_req().to_string(),
            kind: self.kind(),
            optional: self.is_optional(),
            uses_default_features: self.uses_default_features(),
            features: self.features(),
            target: &self.only_for_platform(),
        }.encode(s)
    }
}

#[derive(PartialEq, Clone, Debug, Copy)]
pub enum Kind {
    Normal,
    Development,
    Build,
}

impl Encodable for Kind {
    fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
        match *self {
            Kind::Normal => None,
            Kind::Development => Some("dev"),
            Kind::Build => Some("build"),
        }.encode(s)
    }
}

impl DependencyInner {
    /// Attempt to create a `Dependency` from an entry in the manifest.
    pub fn parse(name: &str,
                 version: Option<&str>,
                 source_id: &SourceId) -> CargoResult<DependencyInner> {
        let version_req = match version {
            Some(v) => try!(VersionReq::parse(v)),
            None => VersionReq::any()
        };

        Ok(DependencyInner {
            only_match_name: false,
            req: version_req,
            specified_req: version.map(|s| s.to_string()),
            .. DependencyInner::new_override(name, source_id)
        })
    }

    pub fn new_override(name: &str, source_id: &SourceId) -> DependencyInner {
        DependencyInner {
            name: name.to_string(),
            source_id: source_id.clone(),
            req: VersionReq::any(),
            kind: Kind::Normal,
            only_match_name: true,
            optional: false,
            features: Vec::new(),
            default_features: true,
            specified_req: None,
            only_for_platform: None,
        }
    }

    pub fn version_req(&self) -> &VersionReq { &self.req }
    pub fn name(&self) -> &str { &self.name }
    pub fn source_id(&self) -> &SourceId { &self.source_id }
    pub fn kind(&self) -> Kind { self.kind }
    pub fn specified_req(&self) -> Option<&str> {
        self.specified_req.as_ref().map(|s| &s[..])
    }

    /// If none, this dependencies must be built for all platforms.
    /// If some, it must only be built for the specified platform.
    pub fn only_for_platform(&self) -> Option<&str> {
        self.only_for_platform.as_ref().map(|s| &s[..])
    }

    pub fn set_kind(mut self, kind: Kind) -> DependencyInner {
        self.kind = kind;
        self
    }

    /// Sets the list of features requested for the package.
    pub fn set_features(mut self, features: Vec<String>) -> DependencyInner {
        self.features = features;
        self
    }

    /// Sets whether the dependency requests default features of the package.
    pub fn set_default_features(mut self, default_features: bool) -> DependencyInner {
        self.default_features = default_features;
        self
    }

    /// Sets whether the dependency is optional.
    pub fn set_optional(mut self, optional: bool) -> DependencyInner {
        self.optional = optional;
        self
    }

    /// Set the source id for this dependency
    pub fn set_source_id(mut self, id: SourceId) -> DependencyInner {
        self.source_id = id;
        self
    }

    /// Set the version requirement for this dependency
    pub fn set_version_req(mut self, req: VersionReq) -> DependencyInner {
        self.req = req;
        self
    }

    pub fn set_only_for_platform(mut self, platform: Option<String>)
                                 -> DependencyInner {
        self.only_for_platform = platform;
        self
    }

    /// Lock this dependency to depending on the specified package id
    pub fn lock_to(self, id: &PackageId) -> DependencyInner {
        assert_eq!(self.source_id, *id.source_id());
        assert!(self.req.matches(id.version()));
        self.set_version_req(VersionReq::exact(id.version()))
            .set_source_id(id.source_id().clone())
    }

    /// Returns false if the dependency is only used to build the local package.
    pub fn is_transitive(&self) -> bool {
        match self.kind {
            Kind::Normal | Kind::Build => true,
            Kind::Development => false,
        }
    }
    pub fn is_build(&self) -> bool {
        match self.kind { Kind::Build => true, _ => false }
    }
    pub fn is_optional(&self) -> bool { self.optional }
    /// Returns true if the default features of the dependency are requested.
    pub fn uses_default_features(&self) -> bool { self.default_features }
    /// Returns the list of features that are requested by the dependency.
    pub fn features(&self) -> &[String] { &self.features }

    /// Returns true if the package (`sum`) can fulfill this dependency request.
    pub fn matches(&self, sum: &Summary) -> bool {
        self.matches_id(sum.package_id())
    }

    /// Returns true if the package (`id`) can fulfill this dependency request.
    pub fn matches_id(&self, id: &PackageId) -> bool {
        self.name == id.name() &&
            (self.only_match_name || (self.req.matches(id.version()) &&
                                      &self.source_id == id.source_id()))
    }

    pub fn into_dependency(self) -> Dependency {
        Dependency {inner: Rc::new(self)}
    }
}

impl Dependency {
    /// Attempt to create a `Dependency` from an entry in the manifest.
    pub fn parse(name: &str,
                 version: Option<&str>,
                 source_id: &SourceId) -> CargoResult<Dependency> {
        DependencyInner::parse(name, version, source_id).map(|di| {
            di.into_dependency()
        })
    }

    pub fn new_override(name: &str, source_id: &SourceId) -> Dependency {
        DependencyInner::new_override(name, source_id).into_dependency()
    }

    pub fn clone_inner(&self) -> DependencyInner { (*self.inner).clone() }

    pub fn version_req(&self) -> &VersionReq { self.inner.version_req() }
    pub fn name(&self) -> &str { self.inner.name() }
    pub fn source_id(&self) -> &SourceId { self.inner.source_id() }
    pub fn kind(&self) -> Kind { self.inner.kind() }
    pub fn specified_req(&self) -> Option<&str> { self.inner.specified_req() }

    /// If none, this dependencies must be built for all platforms.
    /// If some, it must only be built for the specified platform.
    pub fn only_for_platform(&self) -> Option<&str> {
        self.inner.only_for_platform()
    }

    /// Lock this dependency to depending on the specified package id
    pub fn lock_to(self, id: &PackageId) -> Dependency {
        self.clone_inner().lock_to(id).into_dependency()
    }

    /// Returns false if the dependency is only used to build the local package.
    pub fn is_transitive(&self) -> bool { self.inner.is_transitive() }
    pub fn is_build(&self) -> bool { self.inner.is_build() }
    pub fn is_optional(&self) -> bool { self.inner.is_optional() }
    /// Returns true if the default features of the dependency are requested.
    pub fn uses_default_features(&self) -> bool {
        self.inner.uses_default_features()
    }
    /// Returns the list of features that are requested by the dependency.
    pub fn features(&self) -> &[String] { self.inner.features() }

    /// Returns true if the package (`sum`) can fulfill this dependency request.
    pub fn matches(&self, sum: &Summary) -> bool { self.inner.matches(sum) }

    /// Returns true if the package (`id`) can fulfill this dependency request.
    pub fn matches_id(&self, id: &PackageId) -> bool {
        self.inner.matches_id(id)
    }
}
<|endoftext|>