<commit_before>use std::sync::atomic::{AtomicBool, AtomicU64, Ordering};
use std::sync::Arc;
use std::time::{Duration, Instant};

use crate::{
    config::ServerConfig, context::SharedContext, relay::loadbalancing::server::LoadBalancer, relay::socks5::Address,
    relay::tcprelay::client::ServerClient,
};

use futures::{Future, Stream};
use log::{debug, error, trace};
use rand;
use tokio;
use tokio::timer::{Interval, Timeout};

struct Server {
    config: Arc<ServerConfig>,
    elapsed: AtomicU64,
    available: AtomicBool,
}

impl Server {
    fn new(config: ServerConfig) -> Server {
        Server {
            config: Arc::new(config),
            elapsed: AtomicU64::new(0),
            available: AtomicBool::new(true),
        }
    }
}

#[derive(Clone)]
pub struct PingBalancer {
    servers: Vec<Arc<Server>>,
}

impl PingBalancer {
    pub fn new(context: SharedContext) -> PingBalancer {
        let config = context.config();

        if config.server.is_empty() {
            panic!("no servers");
        }

        let check_required = config.server.len() > 1;

        let mut servers = Vec::new();
        for svr in &config.server {
            let sc = Arc::new(Server::new(svr.clone()));
            servers.push(sc.clone());

            if !check_required {
                continue;
            }

            let addr = Address::DomainNameAddress("www.example.com".to_owned(), 80);
            let context = context.clone();

            tokio::spawn(
                // Check every 60 seconds
                Interval::new_interval(Duration::from_secs(3))
                    .for_each(move |_| {
                        let sc = sc.clone();
                        let start = Instant::now();
                        let fut = ServerClient::connect(context.clone(), addr.clone(), sc.config.clone());
                        Timeout::new(fut, Duration::from_secs(2)).then(move |res| {
                            let elapsed = Instant::now() - start;
                            let elapsed = elapsed.as_secs() * 1000 + u64::from(elapsed.subsec_millis()); // Converted to ms
                            match res {
                                Ok(..) => {
                                    // Connected ... record its time
                                    trace!(
                                        "checked remote server {} connected with {} ms",
                                        sc.config.addr(),
                                        elapsed
                                    );
                                    sc.available.store(true, Ordering::Release);
                                }
                                Err(err) => {
                                    match err.into_inner() {
                                        Some(err) => {
                                            error!("failed to check server {}, error: {}", sc.config.addr(), err);
                                        }
                                        None => {
                                            // Timeout
                                            error!("checked remote server {} connect timeout", sc.config.addr());
                                        }
                                    }
                                    sc.available.store(false, Ordering::Release);
                                }
                            }
                            // Set elapsed anyway
                            sc.elapsed.store(elapsed, Ordering::Release);

                            Ok(())
                        })
                    })
                    .map_err(|_| ()),
            );
        }

        PingBalancer { servers }
    }
}

impl LoadBalancer for PingBalancer {
    fn pick_server(&mut self) -> Arc<ServerConfig> {
        if self.servers.is_empty() {
            panic!("No server");
        }

        let mut total = 0u64;
        for svr in &self.servers {
            if svr.available.load(Ordering::Acquire) {
                total += svr.elapsed.load(Ordering::Acquire);
            } else {
                debug!("server {} is blocked for unavailable", svr.config.addr());
            }
        }

        if total != 0 {
            let ridx = rand::random::<u64>() % total;
            let mut acc = 0u64;
            for svr in &self.servers {
                if svr.available.load(Ordering::Acquire) {
                    acc += svr.elapsed.load(Ordering::Acquire);
                    if acc >= ridx {
                        return svr.config.clone();
                    }
                } else {
                    debug!("server {} is blocked for unavailable", svr.config.addr());
                }
            }
        }

        // FALLBACK! Choose nothing
        for svr in &self.servers {
            if svr.available.load(Ordering::Acquire) {
                return svr.config.clone();
            }
        }

        // ALL UNAVAILABLE!
        error!("all servers are unavailable!");
        self.servers[0].config.clone()
    }

    fn total(&self) -> usize {
        self.servers.len()
    }
}
<commit_msg>Pick the best server instead of choosing by weight<commit_after>use std::sync::atomic::{AtomicBool, AtomicU64, Ordering};
use std::sync::Arc;
use std::time::{Duration, Instant};

use crate::{
    config::ServerConfig, context::SharedContext, relay::loadbalancing::server::LoadBalancer, relay::socks5::Address,
    relay::tcprelay::client::ServerClient,
};

use futures::{Future, Stream};
use log::{debug, error};
use tokio;
use tokio::timer::{Interval, Timeout};

struct Server {
    config: Arc<ServerConfig>,
    elapsed: AtomicU64,
    available: AtomicBool,
}

impl Server {
    fn new(config: ServerConfig) -> Server {
        Server {
            config: Arc::new(config),
            elapsed: AtomicU64::new(0),
            available: AtomicBool::new(true),
        }
    }
}

#[derive(Clone)]
pub struct PingBalancer {
    servers: Vec<Arc<Server>>,
}

impl PingBalancer {
    pub fn new(context: SharedContext) -> PingBalancer {
        let config = context.config();

        if config.server.is_empty() {
            panic!("no servers");
        }

        let check_required = config.server.len() > 1;

        let mut servers = Vec::new();
        for svr in &config.server {
            let sc = Arc::new(Server::new(svr.clone()));
            servers.push(sc.clone());

            if !check_required {
                continue;
            }

            let addr = Address::DomainNameAddress("www.example.com".to_owned(), 80);
            let context = context.clone();

            tokio::spawn(
                // Check every 10 seconds
                Interval::new(Instant::now() + Duration::from_secs(1), Duration::from_secs(10))
                    .for_each(move |_| {
                        let sc = sc.clone();
                        let start = Instant::now();
                        let fut = ServerClient::connect(context.clone(), addr.clone(), sc.config.clone());
                        Timeout::new(fut, Duration::from_secs(5)).then(move |res| {
                            let elapsed = Instant::now() - start;
                            let elapsed = elapsed.as_secs() * 1000 + u64::from(elapsed.subsec_millis()); // Converted to ms
                            match res {
                                Ok(..) => {
                                    // Connected ... record its time
                                    debug!(
                                        "checked remote server {} connected with {} ms",
                                        sc.config.addr(),
                                        elapsed
                                    );
                                    sc.available.store(true, Ordering::Release);
                                }
                                Err(err) => {
                                    match err.into_inner() {
                                        Some(err) => {
                                            error!("failed to check server {}, error: {}", sc.config.addr(), err);

                                            // NOTE: connection / handshake error, server is down
                                            sc.available.store(false, Ordering::Release);
                                        }
                                        None => {
                                            // Timeout
                                            error!("checked remote server {} connect timeout", sc.config.addr());

                                            // NOTE: timeout is still available, but server is too slow
                                            sc.available.store(true, Ordering::Release);
                                        }
                                    }
                                }
                            }
                            // Set elapsed anyway
                            sc.elapsed.store(elapsed, Ordering::Release);

                            Ok(())
                        })
                    })
                    .map_err(|_| ()),
            );
        }

        PingBalancer { servers }
    }
}

impl LoadBalancer for PingBalancer {
    fn pick_server(&mut self) -> Arc<ServerConfig> {
        if self.servers.is_empty() {
            panic!("No server");
        }

        // Choose the best one
        let mut choosen_svr = &self.servers[0];
        let mut found_one = false;

        for svr in &self.servers {
            if svr.available.load(Ordering::Acquire)
                && (!choosen_svr.available.load(Ordering::Acquire)
                    || svr.elapsed.load(Ordering::Acquire) < choosen_svr.elapsed.load(Ordering::Acquire))
            {
                found_one = true;
                choosen_svr = svr;
            }
        }

        if !found_one && !choosen_svr.available.load(Ordering::Acquire) {
            // Just choose one available
            for svr in &self.servers {
                if svr.available.load(Ordering::Acquire) {
                    choosen_svr = svr;
                }
            }

            debug!(
                "cannot find any available servers, picked {} delay {} ms",
                choosen_svr.config.addr(),
                choosen_svr.elapsed.load(Ordering::Acquire)
            );
        } else {
            debug!(
                "choosen the best server {} delay {} ms",
                choosen_svr.config.addr(),
                choosen_svr.elapsed.load(Ordering::Acquire)
            );
        }

        choosen_svr.config.clone()
    }

    fn total(&self) -> usize {
        self.servers.len()
    }
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use command::Query;
use util;
use selectable::fragmentable::Fragmentable;
use selectable::fragmentable::QueryFragment;

#[derive(Clone, PartialEq, Eq, Debug)]
pub struct Drilldown {
    arguments: HashMap<String, String>,
}

impl Default for Drilldown {
    fn default() -> Drilldown {
        Drilldown {
            arguments: HashMap::new(),
        }
    }
}

impl Drilldown {
    pub fn new() -> Drilldown {
        let default: Drilldown = Default::default();
        default
    }

    pub fn drilldown(mut self, target: String) -> Drilldown {
        self.arguments.insert("drilldown".to_string(), target.clone());
        self
    }

    pub fn sortby(mut self, target: String) -> Drilldown {
        self.arguments.insert("drilldown_sortby".to_string(), target.clone());
        self
    }

    pub fn output_columns(mut self, columns: Vec<String>) -> Drilldown {
        let string = util::split_values_vec(columns);
        self.arguments.insert("drilldown_output_columns".to_string(),
                              string.clone());
        self
    }

    pub fn offset(mut self, offset: u64) -> Drilldown {
        let offset = format!("{}", offset);
        self.arguments.insert("drilldown_offset".to_string(), offset.clone());
        self
    }

    pub fn limit(mut self, limit: u64) -> Drilldown {
        let limit = format!("{}", limit);
        self.arguments.insert("drilldown_limit".to_string(), limit.clone());
        self
    }

    pub fn build(self) -> Query {
        let mut query: Query = vec![];
        for (key, value) in self.arguments.iter() {
            query.push((key.to_owned(), value.to_owned()));
        }
        query
    }
}

impl Fragmentable for Drilldown {
    fn to_fragment(self) -> QueryFragment {
        self.arguments.clone()
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use std::collections::HashMap;
    use command::Query;

    #[test]
    fn test_new() {
        let vanilla_drilldown = Drilldown::new();
        let expected = Drilldown {
            arguments: HashMap::new(),
        };
        assert_eq!(expected, vanilla_drilldown);
    }

    #[test]
    fn test_drilldown() {
        let drilldown = Drilldown::new().drilldown("tag".to_string());
        let mut arg: HashMap<String, String> = HashMap::new();
        arg.insert("drilldown".to_string(), "tag".to_string());
        let expected = Drilldown {
            arguments: arg,
        };
        assert_eq!(expected, drilldown);
    }

    #[test]
    fn test_sortby() {
        let drilldown = Drilldown::new().sortby("tag".to_string());
        let mut arg: HashMap<String, String> = HashMap::new();
        arg.insert("drilldown_sortby".to_string(), "tag".to_string());
        let expected = Drilldown {
            arguments: arg,
        };
        assert_eq!(expected, drilldown);
    }

    #[test]
    fn test_output_columns() {
        let drilldown = Drilldown::new()
            .output_columns(vec![("tag".to_string()),
                                 ("category".to_string())]);
        let mut arg: HashMap<String, String> = HashMap::new();
        arg.insert("drilldown_output_columns".to_string(),
                   "tag,category".to_string());
        let expected = Drilldown {
            arguments: arg,
        };
        assert_eq!(expected, drilldown);
    }

    #[test]
    fn test_offset() {
        let drilldown = Drilldown::new().offset(10);
        let mut arg: HashMap<String, String> = HashMap::new();
        arg.insert("drilldown_offset".to_string(), "10".to_string());
        let expected = Drilldown {
            arguments: arg,
        };
        assert_eq!(expected, drilldown);
    }

    #[test]
    fn test_limit() {
        let drilldown = Drilldown::new().limit(30);
        let mut arg: HashMap<String, String> = HashMap::new();
        arg.insert("drilldown_limit".to_string(), "30".to_string());
        let expected = Drilldown {
            arguments: arg,
        };
        assert_eq!(expected, drilldown);
    }

    #[test]
    fn test_build() {
        let drilldown = Drilldown::new().limit(30).build();
        let expected: Query = vec![("drilldown_limit".to_string(),
                                    "30".to_string())];
        assert_eq!(expected, drilldown);
    }
}
<commit_msg>rustfmt<commit_after>use std::collections::HashMap;
use command::Query;
use util;
use selectable::fragmentable::Fragmentable;
use selectable::fragmentable::QueryFragment;

#[derive(Clone, PartialEq, Eq, Debug)]
pub struct Drilldown {
    arguments: HashMap<String, String>,
}

impl Default for Drilldown {
    fn default() -> Drilldown {
        Drilldown { arguments: HashMap::new() }
    }
}

impl Drilldown {
    pub fn new() -> Drilldown {
        let default: Drilldown = Default::default();
        default
    }

    pub fn drilldown(mut self, target: String) -> Drilldown {
        self.arguments.insert("drilldown".to_string(), target.clone());
        self
    }

    pub fn sortby(mut self, target: String) -> Drilldown {
        self.arguments.insert("drilldown_sortby".to_string(), target.clone());
        self
    }

    pub fn output_columns(mut self, columns: Vec<String>) -> Drilldown {
        let string = util::split_values_vec(columns);
        self.arguments.insert("drilldown_output_columns".to_string(), string.clone());
        self
    }

    pub fn offset(mut self, offset: u64) -> Drilldown {
        let offset = format!("{}", offset);
        self.arguments.insert("drilldown_offset".to_string(), offset.clone());
        self
    }

    pub fn limit(mut self, limit: u64) -> Drilldown {
        let limit = format!("{}", limit);
        self.arguments.insert("drilldown_limit".to_string(), limit.clone());
        self
    }

    pub fn build(self) -> Query {
        let mut query: Query = vec![];
        for (key, value) in self.arguments.iter() {
            query.push((key.to_owned(), value.to_owned()));
        }
        query
    }
}

impl Fragmentable for Drilldown {
    fn to_fragment(self) -> QueryFragment {
        self.arguments.clone()
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use std::collections::HashMap;
    use command::Query;

    #[test]
    fn test_new() {
        let vanilla_drilldown = Drilldown::new();
        let expected = Drilldown { arguments: HashMap::new() };
        assert_eq!(expected, vanilla_drilldown);
    }

    #[test]
    fn test_drilldown() {
        let drilldown = Drilldown::new().drilldown("tag".to_string());
        let mut arg: HashMap<String, String> = HashMap::new();
        arg.insert("drilldown".to_string(), "tag".to_string());
        let expected = Drilldown { arguments: arg };
        assert_eq!(expected, drilldown);
    }

    #[test]
    fn test_sortby() {
        let drilldown = Drilldown::new().sortby("tag".to_string());
        let mut arg: HashMap<String, String> = HashMap::new();
        arg.insert("drilldown_sortby".to_string(), "tag".to_string());
        let expected = Drilldown { arguments: arg };
        assert_eq!(expected, drilldown);
    }

    #[test]
    fn test_output_columns() {
        let drilldown = Drilldown::new()
                            .output_columns(vec![("tag".to_string()), ("category".to_string())]);
        let mut arg: HashMap<String, String> = HashMap::new();
        arg.insert("drilldown_output_columns".to_string(),
                   "tag,category".to_string());
        let expected = Drilldown { arguments: arg };
        assert_eq!(expected, drilldown);
    }

    #[test]
    fn test_offset() {
        let drilldown = Drilldown::new().offset(10);
        let mut arg: HashMap<String, String> = HashMap::new();
        arg.insert("drilldown_offset".to_string(), "10".to_string());
        let expected = Drilldown { arguments: arg };
        assert_eq!(expected, drilldown);
    }

    #[test]
    fn test_limit() {
        let drilldown = Drilldown::new().limit(30);
        let mut arg: HashMap<String, String> = HashMap::new();
        arg.insert("drilldown_limit".to_string(), "30".to_string());
        let expected = Drilldown { arguments: arg };
        assert_eq!(expected, drilldown);
    }

    #[test]
    fn test_build() {
        let drilldown = Drilldown::new().limit(30).build();
        let expected: Query = vec![("drilldown_limit".to_string(), "30".to_string())];
        assert_eq!(expected, drilldown);
    }
}
<|endoftext|>


<commit_before>use std::collections::{BTreeMap, HashMap};

use chrono::prelude::*;
use serde_derive::{Deserialize, Serialize};
use strum_macros::{Display, EnumString};

use crate::state::{GroupStatus, State};
use crate::task::Task;

/// This is the main message enum. \
/// Everything that's communicated in Pueue can be serialized as this enum.
#[derive(PartialEq, Clone, Debug, Deserialize, Serialize)]
pub enum Message {
    Add(AddMessage),
    Remove(Vec<usize>),
    Switch(SwitchMessage),
    Stash(Vec<usize>),
    Enqueue(EnqueueMessage),

    Start(StartMessage),
    Restart(RestartMessage),
    Pause(PauseMessage),
    Kill(KillMessage),

    Send(SendMessage),
    EditRequest(usize),
    EditResponse(EditResponseMessage),
    Edit(EditMessage),
    Group(GroupMessage),
    GroupResponse(GroupResponseMessage),

    Status,
    StatusResponse(Box<State>),
    Log(LogRequestMessage),
    LogResponse(BTreeMap<usize, TaskLogMessage>),
    Stream(String),
    StreamRequest(StreamRequestMessage),
    /// The boolean decides, whether the children should be get a SIGTERM as well.
    Reset(ResetMessage),
    Clean(CleanMessage),
    DaemonShutdown(Shutdown),

    Success(String),
    Failure(String),

    Parallel(ParallelMessage),
}

/// This enum is used to express a selection of tasks.
/// As commands can be executed on various sets of tasks, we need some kind of datastructure to
/// explicitly and unambiguously specify the selection.
#[derive(PartialEq, Clone, Debug, Deserialize, Serialize)]
pub enum TaskSelection {
    TaskIds(Vec<usize>),
    Group(String),
    All,
}

#[derive(PartialEq, Clone, Debug, Deserialize, Serialize)]
pub struct AddMessage {
    pub command: String,
    pub path: String,
    pub envs: HashMap<String, String>,
    pub start_immediately: bool,
    pub stashed: bool,
    pub group: String,
    pub enqueue_at: Option<DateTime<Local>>,
    pub dependencies: Vec<usize>,
    pub label: Option<String>,
    pub print_task_id: bool,
}

#[derive(PartialEq, Clone, Debug, Deserialize, Serialize)]
pub struct SwitchMessage {
    pub task_id_1: usize,
    pub task_id_2: usize,
}

#[derive(PartialEq, Clone, Debug, Deserialize, Serialize)]
pub struct EnqueueMessage {
    pub task_ids: Vec<usize>,
    pub enqueue_at: Option<DateTime<Local>>,
}

#[derive(PartialEq, Clone, Debug, Deserialize, Serialize)]
pub struct StartMessage {
    pub tasks: TaskSelection,
    pub children: bool,
}

#[derive(PartialEq, Clone, Debug, Deserialize, Serialize)]
pub struct RestartMessage {
    pub tasks: Vec<TasksToRestart>,
    pub start_immediately: bool,
    pub stashed: bool,
}

#[derive(PartialEq, Clone, Debug, Deserialize, Serialize)]
pub struct TasksToRestart {
    pub task_id: usize,
    pub command: String,
    pub path: String,
}

#[derive(PartialEq, Clone, Debug, Deserialize, Serialize)]
pub struct PauseMessage {
    pub tasks: TaskSelection,
    pub wait: bool,
    pub children: bool,
}

/// This is a small custom Enum for all currently supported unix signals.
/// Supporting all unix signals would be a mess, since there is a LOT of them.
///
/// This is also needed for usage in clap, since nix's Signal doesn't implement [Display] and
/// [std::str::FromStr].
#[derive(PartialEq, Clone, Debug, Deserialize, Serialize, Display, EnumString)]
pub enum Signal {
    #[strum(serialize = "SigInt", serialize = "sigint", serialize = "2")]
    SigInt,
    #[strum(serialize = "SigKill", serialize = "sigkill", serialize = "9")]
    SigKill,
    #[strum(serialize = "SigTerm", serialize = "sigterm", serialize = "15")]
    SigTerm,
    #[strum(serialize = "SigCont", serialize = "sigcont", serialize = "18")]
    SigCont,
    #[strum(serialize = "SigStop", serialize = "sigstop", serialize = "19")]
    SigStop,
}

#[derive(PartialEq, Clone, Debug, Deserialize, Serialize)]
pub struct KillMessage {
    pub task_ids: Vec<usize>,
    pub group: String,
    pub all: bool,
    pub children: bool,
    pub signal: Option<Signal>,
}

#[derive(PartialEq, Clone, Debug, Deserialize, Serialize)]
pub struct SendMessage {
    pub task_id: usize,
    pub input: String,
}

#[derive(PartialEq, Clone, Debug, Deserialize, Serialize)]
pub struct EditMessage {
    pub task_id: usize,
    pub command: String,
    pub path: String,
}

#[derive(PartialEq, Clone, Debug, Deserialize, Serialize)]
pub struct EditResponseMessage {
    pub task_id: usize,
    pub command: String,
    pub path: String,
}

#[derive(PartialEq, Clone, Debug, Deserialize, Serialize)]
pub enum GroupMessage {
    Add(String),
    Remove(String),
    List,
}

#[derive(PartialEq, Clone, Debug, Deserialize, Serialize)]
pub struct GroupResponseMessage {
    pub groups: BTreeMap<String, GroupStatus>,
    pub settings: BTreeMap<String, usize>,
}

#[derive(PartialEq, Clone, Debug, Deserialize, Serialize)]
pub struct ResetMessage {
    pub children: bool,
}

#[derive(PartialEq, Clone, Debug, Deserialize, Serialize)]
pub struct CleanMessage {
    #[serde(default = "false_default")]
    pub successful_only: bool,
}
fn false_default() -> bool {
    false
}

/// Determines which type of shutdown we're dealing with.
#[derive(PartialEq, Clone, Debug, Deserialize, Serialize)]
pub enum Shutdown {
    /// Emergency is most likely a system unix signal or a CTRL+C in a terminal.
    Emergency,
    /// Graceful is user initiated and expected.
    Graceful,
}

/// `err` decides, whether you should stream stderr or stdout.
#[derive(PartialEq, Clone, Debug, Deserialize, Serialize)]
pub struct StreamRequestMessage {
    pub task_id: Option<usize>,
    pub err: bool,
}

/// Request logs for specific tasks.
///
/// `task_ids` specifies the requested tasks. If none are given, all tasks are selected.
/// `send_logs` Determines whether tasks should be sent at all.
/// `lines` Determines whether only a few lines of log should be returned.
#[derive(PartialEq, Clone, Debug, Deserialize, Serialize)]
pub struct LogRequestMessage {
    pub task_ids: Vec<usize>,
    pub send_logs: bool,
    pub lines: Option<usize>,
}

/// Helper struct for sending tasks and their log output to the client.
#[derive(PartialEq, Clone, Debug, Deserialize, Serialize)]
pub struct TaskLogMessage {
    pub task: Task,
    pub stdout: Option<Vec<u8>>,
    pub stderr: Option<Vec<u8>>,
}

#[derive(PartialEq, Clone, Debug, Deserialize, Serialize)]
pub struct ParallelMessage {
    pub parallel_tasks: usize,
    pub group: String,
}

pub fn create_success_message<T: ToString>(text: T) -> Message {
    Message::Success(text.to_string())
}

pub fn create_failure_message<T: ToString>(text: T) -> Message {
    Message::Failure(text.to_string())
}
<commit_msg>refactor: Use TaskSelection in KillMessage<commit_after>use std::collections::{BTreeMap, HashMap};

use chrono::prelude::*;
use serde_derive::{Deserialize, Serialize};
use strum_macros::{Display, EnumString};

use crate::state::{GroupStatus, State};
use crate::task::Task;

/// This is the main message enum. \
/// Everything that's communicated in Pueue can be serialized as this enum.
#[derive(PartialEq, Clone, Debug, Deserialize, Serialize)]
pub enum Message {
    Add(AddMessage),
    Remove(Vec<usize>),
    Switch(SwitchMessage),
    Stash(Vec<usize>),
    Enqueue(EnqueueMessage),

    Start(StartMessage),
    Restart(RestartMessage),
    Pause(PauseMessage),
    Kill(KillMessage),

    Send(SendMessage),
    EditRequest(usize),
    EditResponse(EditResponseMessage),
    Edit(EditMessage),
    Group(GroupMessage),
    GroupResponse(GroupResponseMessage),

    Status,
    StatusResponse(Box<State>),
    Log(LogRequestMessage),
    LogResponse(BTreeMap<usize, TaskLogMessage>),
    Stream(String),
    StreamRequest(StreamRequestMessage),
    /// The boolean decides, whether the children should be get a SIGTERM as well.
    Reset(ResetMessage),
    Clean(CleanMessage),
    DaemonShutdown(Shutdown),

    Success(String),
    Failure(String),

    Parallel(ParallelMessage),
}

/// This enum is used to express a selection of tasks.
/// As commands can be executed on various sets of tasks, we need some kind of datastructure to
/// explicitly and unambiguously specify the selection.
#[derive(PartialEq, Clone, Debug, Deserialize, Serialize)]
pub enum TaskSelection {
    TaskIds(Vec<usize>),
    Group(String),
    All,
}

#[derive(PartialEq, Clone, Debug, Deserialize, Serialize)]
pub struct AddMessage {
    pub command: String,
    pub path: String,
    pub envs: HashMap<String, String>,
    pub start_immediately: bool,
    pub stashed: bool,
    pub group: String,
    pub enqueue_at: Option<DateTime<Local>>,
    pub dependencies: Vec<usize>,
    pub label: Option<String>,
    pub print_task_id: bool,
}

#[derive(PartialEq, Clone, Debug, Deserialize, Serialize)]
pub struct SwitchMessage {
    pub task_id_1: usize,
    pub task_id_2: usize,
}

#[derive(PartialEq, Clone, Debug, Deserialize, Serialize)]
pub struct EnqueueMessage {
    pub task_ids: Vec<usize>,
    pub enqueue_at: Option<DateTime<Local>>,
}

#[derive(PartialEq, Clone, Debug, Deserialize, Serialize)]
pub struct StartMessage {
    pub tasks: TaskSelection,
    pub children: bool,
}

#[derive(PartialEq, Clone, Debug, Deserialize, Serialize)]
pub struct RestartMessage {
    pub tasks: Vec<TasksToRestart>,
    pub start_immediately: bool,
    pub stashed: bool,
}

#[derive(PartialEq, Clone, Debug, Deserialize, Serialize)]
pub struct TasksToRestart {
    pub task_id: usize,
    pub command: String,
    pub path: String,
}

#[derive(PartialEq, Clone, Debug, Deserialize, Serialize)]
pub struct PauseMessage {
    pub tasks: TaskSelection,
    pub wait: bool,
    pub children: bool,
}

/// This is a small custom Enum for all currently supported unix signals.
/// Supporting all unix signals would be a mess, since there is a LOT of them.
///
/// This is also needed for usage in clap, since nix's Signal doesn't implement [Display] and
/// [std::str::FromStr].
#[derive(PartialEq, Clone, Debug, Deserialize, Serialize, Display, EnumString)]
pub enum Signal {
    #[strum(serialize = "SigInt", serialize = "sigint", serialize = "2")]
    SigInt,
    #[strum(serialize = "SigKill", serialize = "sigkill", serialize = "9")]
    SigKill,
    #[strum(serialize = "SigTerm", serialize = "sigterm", serialize = "15")]
    SigTerm,
    #[strum(serialize = "SigCont", serialize = "sigcont", serialize = "18")]
    SigCont,
    #[strum(serialize = "SigStop", serialize = "sigstop", serialize = "19")]
    SigStop,
}

#[derive(PartialEq, Clone, Debug, Deserialize, Serialize)]
pub struct KillMessage {
    pub tasks: TaskSelection,
    pub children: bool,
    pub signal: Option<Signal>,
}

#[derive(PartialEq, Clone, Debug, Deserialize, Serialize)]
pub struct SendMessage {
    pub task_id: usize,
    pub input: String,
}

#[derive(PartialEq, Clone, Debug, Deserialize, Serialize)]
pub struct EditMessage {
    pub task_id: usize,
    pub command: String,
    pub path: String,
}

#[derive(PartialEq, Clone, Debug, Deserialize, Serialize)]
pub struct EditResponseMessage {
    pub task_id: usize,
    pub command: String,
    pub path: String,
}

#[derive(PartialEq, Clone, Debug, Deserialize, Serialize)]
pub enum GroupMessage {
    Add(String),
    Remove(String),
    List,
}

#[derive(PartialEq, Clone, Debug, Deserialize, Serialize)]
pub struct GroupResponseMessage {
    pub groups: BTreeMap<String, GroupStatus>,
    pub settings: BTreeMap<String, usize>,
}

#[derive(PartialEq, Clone, Debug, Deserialize, Serialize)]
pub struct ResetMessage {
    pub children: bool,
}

#[derive(PartialEq, Clone, Debug, Deserialize, Serialize)]
pub struct CleanMessage {
    #[serde(default = "false_default")]
    pub successful_only: bool,
}
fn false_default() -> bool {
    false
}

/// Determines which type of shutdown we're dealing with.
#[derive(PartialEq, Clone, Debug, Deserialize, Serialize)]
pub enum Shutdown {
    /// Emergency is most likely a system unix signal or a CTRL+C in a terminal.
    Emergency,
    /// Graceful is user initiated and expected.
    Graceful,
}

/// `err` decides, whether you should stream stderr or stdout.
#[derive(PartialEq, Clone, Debug, Deserialize, Serialize)]
pub struct StreamRequestMessage {
    pub task_id: Option<usize>,
    pub err: bool,
}

/// Request logs for specific tasks.
///
/// `task_ids` specifies the requested tasks. If none are given, all tasks are selected.
/// `send_logs` Determines whether tasks should be sent at all.
/// `lines` Determines whether only a few lines of log should be returned.
#[derive(PartialEq, Clone, Debug, Deserialize, Serialize)]
pub struct LogRequestMessage {
    pub task_ids: Vec<usize>,
    pub send_logs: bool,
    pub lines: Option<usize>,
}

/// Helper struct for sending tasks and their log output to the client.
#[derive(PartialEq, Clone, Debug, Deserialize, Serialize)]
pub struct TaskLogMessage {
    pub task: Task,
    pub stdout: Option<Vec<u8>>,
    pub stderr: Option<Vec<u8>>,
}

#[derive(PartialEq, Clone, Debug, Deserialize, Serialize)]
pub struct ParallelMessage {
    pub parallel_tasks: usize,
    pub group: String,
}

pub fn create_success_message<T: ToString>(text: T) -> Message {
    Message::Success(text.to_string())
}

pub fn create_failure_message<T: ToString>(text: T) -> Message {
    Message::Failure(text.to_string())
}
<|endoftext|>


<commit_before>use fool::BoolExt;
use std::ops::{Deref, DerefMut};

use crate::network::borrow::{Reborrow, ReborrowMut};
use crate::network::storage::{AsStorage, AsStorageMut, OpaqueKey};
use crate::network::Entity;

pub trait ClosedView: Deref<Target = <Self as ClosedView>::Entity> {
    type Key: OpaqueKey;
    type Entity: Entity<Key = Self::Key>;

    fn key(&self) -> Self::Key;
}

pub trait Rebind<T>: ClosedView
where
    T: ClosedView,
{
    fn rebind(self, key: T::Key) -> Option<T>;
}

pub struct View<B, E>
where
    B: Reborrow,
    B::Target: AsStorage<E>,
    E: Entity,
{
    storage: B,
    key: E::Key,
}

impl<B, E> View<B, E>
where
    B: Reborrow,
    B::Target: AsStorage<E>,
    E: Entity,
{
    pub fn bind(storage: B, key: E::Key) -> Option<Self> {
        storage
            .reborrow()
            .as_storage()
            .contains_key(&key)
            .some(View::bind_unchecked(storage, key))
    }

    pub fn bind_unchecked(storage: B, key: E::Key) -> Self {
        View { storage, key }
    }

    pub fn bind_into<T>(storage: B, key: E::Key) -> Option<T>
    where
        T: From<Self>,
    {
        View::bind(storage, key).map(T::from)
    }

    pub fn unbind(self) -> (B, E::Key) {
        let View { storage, key, .. } = self;
        (storage, key)
    }

    pub fn rebind<T>(self, key: T::Key) -> Option<View<B, T>>
    where
        B::Target: AsStorage<T>,
        T: Entity,
    {
        let (storage, _) = self.unbind();
        View::bind(storage, key)
    }

    pub fn rebind_into<T, U>(self, key: U::Key) -> Option<T>
    where
        B::Target: AsStorage<U>,
        T: From<View<B, U>>,
        U: Entity,
    {
        self.rebind(key).map(T::from)
    }

    pub fn key(&self) -> E::Key {
        self.key
    }

    pub fn interior_reborrow(&self) -> View<&B::Target, E> {
        View::bind_unchecked(self.storage.reborrow(), self.key)
    }
}

impl<B, E> View<B, E>
where
    B: ReborrowMut,
    B::Target: AsStorage<E>,
    E: Entity,
{
    pub fn interior_reborrow_mut(&mut self) -> View<&mut B::Target, E> {
        View::bind_unchecked(self.storage.reborrow_mut(), self.key)
    }
}

impl<'a, M, E> View<&'a mut M, E>
where
    M: 'a + AsStorageMut<E>,
    E: 'a + Entity,
{
    pub fn to_ref(&self) -> View<&M, E> {
        View::bind(&*self.storage, self.key).unwrap()
    }

    pub fn into_ref(self) -> View<&'a M, E> {
        let (storage, key) = self.unbind();
        View::bind(&*storage, key).unwrap()
    }
}

impl<B, E> Clone for View<B, E>
where
    B: Clone + Reborrow,
    B::Target: AsStorage<E>,
    E: Entity,
{
    fn clone(&self) -> Self {
        View {
            storage: self.storage.clone(),
            key: self.key,
        }
    }
}

impl<B, E> ClosedView for View<B, E>
where
    B: Reborrow,
    B::Target: AsStorage<E>,
    E: Entity,
{
    type Key = E::Key;
    type Entity = E;

    fn key(&self) -> Self::Key {
        self.key
    }
}

impl<B, E> Copy for View<B, E>
where
    B: Copy + Reborrow,
    B::Target: AsStorage<E>,
    E: Entity,
{
}

impl<B, E> Deref for View<B, E>
where
    B: Reborrow,
    B::Target: AsStorage<E>,
    E: Entity,
{
    type Target = E;

    fn deref(&self) -> &Self::Target {
        self.storage
            .reborrow()
            .as_storage()
            .get(&self.key)
            .expect("view key invalidated")
    }
}

impl<B, E> DerefMut for View<B, E>
where
    B: ReborrowMut,
    B::Target: AsStorageMut<E>,
    E: Entity,
{
    fn deref_mut(&mut self) -> &mut Self::Target {
        self.storage
            .reborrow_mut()
            .as_storage_mut()
            .get_mut(&self.key)
            .expect("view key invalidated")
    }
}

// TODO: Consider implementing `Eq` for views.
impl<B, E> PartialEq for View<B, E>
where
    B: Reborrow,
    B::Target: AsStorage<E>,
    E: Entity,
{
    fn eq(&self, other: &Self) -> bool {
        self.key == other.key
    }
}

impl<B, E, T> Rebind<T> for View<B, E>
where
    B: Reborrow,
    B::Target: AsStorage<E> + AsStorage<T::Entity>,
    E: Entity,
    T: ClosedView + From<View<B, <T as ClosedView>::Entity>>,
{
    fn rebind(self, key: T::Key) -> Option<T> {
        self.rebind(key).map(T::from)
    }
}

pub struct Orphan<'a, E>
where
    E: Entity,
{
    entity: &'a mut E,
    key: E::Key,
}

impl<'a, E> Orphan<'a, E>
where
    E: 'a + Entity,
{
    pub fn bind<M>(storage: &'a mut M, key: E::Key) -> Option<Self>
    where
        M: AsStorageMut<E>,
    {
        View::bind(storage, key).map(Orphan::from)
    }

    pub fn bind_unchecked(entity: &'a mut E, key: E::Key) -> Self {
        Orphan { entity, key }
    }

    pub fn bind_into<T, M>(storage: &'a mut M, key: E::Key) -> Option<T>
    where
        T: From<Self>,
        M: AsStorageMut<E>,
    {
        Orphan::bind(storage, key).map(T::from)
    }

    pub fn key(&self) -> E::Key {
        self.key
    }
}

impl<'a, E> ClosedView for Orphan<'a, E>
where
    E: 'a + Entity,
{
    type Key = E::Key;
    type Entity = E;

    fn key(&self) -> Self::Key {
        self.key
    }
}

impl<'a, E> Deref for Orphan<'a, E>
where
    E: 'a + Entity,
{
    type Target = E;

    fn deref(&self) -> &Self::Target {
        &*self.entity
    }
}

impl<'a, E> DerefMut for Orphan<'a, E>
where
    E: 'a + Entity,
{
    fn deref_mut(&mut self) -> &mut Self::Target {
        self.entity
    }
}

impl<'a, E, M> From<View<&'a mut M, E>> for Orphan<'a, E>
where
    E: 'a + Entity,
    M: AsStorageMut<E>,
{
    fn from(view: View<&'a mut M, E>) -> Self {
        let (storage, key) = view.unbind();
        let entity = storage
            .as_storage_mut()
            .get_mut(&key)
            .expect("view key invalidated");
        Orphan::bind_unchecked(entity, key)
    }
}
<commit_msg>Do not check keys when converting views into refs.<commit_after>use fool::BoolExt;
use std::ops::{Deref, DerefMut};

use crate::network::borrow::{Reborrow, ReborrowMut};
use crate::network::storage::{AsStorage, AsStorageMut, OpaqueKey};
use crate::network::Entity;

pub trait ClosedView: Deref<Target = <Self as ClosedView>::Entity> {
    type Key: OpaqueKey;
    type Entity: Entity<Key = Self::Key>;

    fn key(&self) -> Self::Key;
}

pub trait Rebind<T>: ClosedView
where
    T: ClosedView,
{
    fn rebind(self, key: T::Key) -> Option<T>;
}

pub struct View<B, E>
where
    B: Reborrow,
    B::Target: AsStorage<E>,
    E: Entity,
{
    storage: B,
    key: E::Key,
}

impl<B, E> View<B, E>
where
    B: Reborrow,
    B::Target: AsStorage<E>,
    E: Entity,
{
    pub fn bind(storage: B, key: E::Key) -> Option<Self> {
        storage
            .reborrow()
            .as_storage()
            .contains_key(&key)
            .some(View::bind_unchecked(storage, key))
    }

    pub fn bind_unchecked(storage: B, key: E::Key) -> Self {
        View { storage, key }
    }

    pub fn bind_into<T>(storage: B, key: E::Key) -> Option<T>
    where
        T: From<Self>,
    {
        View::bind(storage, key).map(T::from)
    }

    pub fn unbind(self) -> (B, E::Key) {
        let View { storage, key, .. } = self;
        (storage, key)
    }

    pub fn rebind<T>(self, key: T::Key) -> Option<View<B, T>>
    where
        B::Target: AsStorage<T>,
        T: Entity,
    {
        let (storage, _) = self.unbind();
        View::bind(storage, key)
    }

    pub fn rebind_into<T, U>(self, key: U::Key) -> Option<T>
    where
        B::Target: AsStorage<U>,
        T: From<View<B, U>>,
        U: Entity,
    {
        self.rebind(key).map(T::from)
    }

    pub fn key(&self) -> E::Key {
        self.key
    }

    pub fn interior_reborrow(&self) -> View<&B::Target, E> {
        View::bind_unchecked(self.storage.reborrow(), self.key)
    }
}

impl<B, E> View<B, E>
where
    B: ReborrowMut,
    B::Target: AsStorage<E>,
    E: Entity,
{
    pub fn interior_reborrow_mut(&mut self) -> View<&mut B::Target, E> {
        View::bind_unchecked(self.storage.reborrow_mut(), self.key)
    }
}

impl<'a, M, E> View<&'a mut M, E>
where
    M: 'a + AsStorageMut<E>,
    E: 'a + Entity,
{
    pub fn to_ref(&self) -> View<&M, E> {
        self.interior_reborrow()
    }

    pub fn into_ref(self) -> View<&'a M, E> {
        let (storage, key) = self.unbind();
        View::bind_unchecked(&*storage, key)
    }
}

impl<B, E> Clone for View<B, E>
where
    B: Clone + Reborrow,
    B::Target: AsStorage<E>,
    E: Entity,
{
    fn clone(&self) -> Self {
        View {
            storage: self.storage.clone(),
            key: self.key,
        }
    }
}

impl<B, E> ClosedView for View<B, E>
where
    B: Reborrow,
    B::Target: AsStorage<E>,
    E: Entity,
{
    type Key = E::Key;
    type Entity = E;

    fn key(&self) -> Self::Key {
        self.key
    }
}

impl<B, E> Copy for View<B, E>
where
    B: Copy + Reborrow,
    B::Target: AsStorage<E>,
    E: Entity,
{
}

impl<B, E> Deref for View<B, E>
where
    B: Reborrow,
    B::Target: AsStorage<E>,
    E: Entity,
{
    type Target = E;

    fn deref(&self) -> &Self::Target {
        self.storage
            .reborrow()
            .as_storage()
            .get(&self.key)
            .expect("view key invalidated")
    }
}

impl<B, E> DerefMut for View<B, E>
where
    B: ReborrowMut,
    B::Target: AsStorageMut<E>,
    E: Entity,
{
    fn deref_mut(&mut self) -> &mut Self::Target {
        self.storage
            .reborrow_mut()
            .as_storage_mut()
            .get_mut(&self.key)
            .expect("view key invalidated")
    }
}

// TODO: Consider implementing `Eq` for views.
impl<B, E> PartialEq for View<B, E>
where
    B: Reborrow,
    B::Target: AsStorage<E>,
    E: Entity,
{
    fn eq(&self, other: &Self) -> bool {
        self.key == other.key
    }
}

impl<B, E, T> Rebind<T> for View<B, E>
where
    B: Reborrow,
    B::Target: AsStorage<E> + AsStorage<T::Entity>,
    E: Entity,
    T: ClosedView + From<View<B, <T as ClosedView>::Entity>>,
{
    fn rebind(self, key: T::Key) -> Option<T> {
        self.rebind(key).map(T::from)
    }
}

pub struct Orphan<'a, E>
where
    E: Entity,
{
    entity: &'a mut E,
    key: E::Key,
}

impl<'a, E> Orphan<'a, E>
where
    E: 'a + Entity,
{
    pub fn bind<M>(storage: &'a mut M, key: E::Key) -> Option<Self>
    where
        M: AsStorageMut<E>,
    {
        View::bind(storage, key).map(Orphan::from)
    }

    pub fn bind_unchecked(entity: &'a mut E, key: E::Key) -> Self {
        Orphan { entity, key }
    }

    pub fn bind_into<T, M>(storage: &'a mut M, key: E::Key) -> Option<T>
    where
        T: From<Self>,
        M: AsStorageMut<E>,
    {
        Orphan::bind(storage, key).map(T::from)
    }

    pub fn key(&self) -> E::Key {
        self.key
    }
}

impl<'a, E> ClosedView for Orphan<'a, E>
where
    E: 'a + Entity,
{
    type Key = E::Key;
    type Entity = E;

    fn key(&self) -> Self::Key {
        self.key
    }
}

impl<'a, E> Deref for Orphan<'a, E>
where
    E: 'a + Entity,
{
    type Target = E;

    fn deref(&self) -> &Self::Target {
        &*self.entity
    }
}

impl<'a, E> DerefMut for Orphan<'a, E>
where
    E: 'a + Entity,
{
    fn deref_mut(&mut self) -> &mut Self::Target {
        self.entity
    }
}

impl<'a, E, M> From<View<&'a mut M, E>> for Orphan<'a, E>
where
    E: 'a + Entity,
    M: AsStorageMut<E>,
{
    fn from(view: View<&'a mut M, E>) -> Self {
        let (storage, key) = view.unbind();
        let entity = storage
            .as_storage_mut()
            .get_mut(&key)
            .expect("view key invalidated");
        Orphan::bind_unchecked(entity, key)
    }
}
<|endoftext|>


<commit_before>#![allow(dead_code)]

// spell-checker:ignore (change!) each's
// spell-checker:ignore (ToDO) LONGHELP FORMATSTRING templating parameterizing formatstr

extern crate itertools;
extern crate uucore;

mod cli;
mod memo;
mod tokenize;

static NAME: &str = "printf";
static VERSION: &str = "0.0.1";
static SHORT_USAGE: &str = "printf: usage: printf [-v var] format [arguments]";
static LONGHELP_LEAD: &str = "printf

 USAGE: printf FORMATSTRING [ARGUMENT]...

 basic anonymous string templating:

 prints format string at least once, repeating as long as there are remaining arguments
 output prints escaped literals in the format string as character literals
 output replaces anonymous fields with the next unused argument, formatted according to the field.

Options:
    --help              display this help and exit
    --version           output version information and exit

";
static LONGHELP_BODY: &str = "
  Prints the , replacing escaped character sequences with character literals
    and substitution field sequences with passed arguments

 literally, with the exception of the below
    escaped character sequences, and the substitution sequences described further down.

  ESCAPE SEQUENCES

  The following escape sequences, organized here in alphabetical order,
  will print the corresponding character literal:

  \"   double quote

  \\\\    backslash

  \\a  alert (BEL)

  \\b  backspace

  \\c  End-of-Input

  \\e  escape

  \\f  form feed

  \\n  new line

  \\r  carriage return

  \\t  horizontal tab

  \\v  vertical tab

  \\NNN byte with value expressed in octal value NNN (1 to 3 digits)
        values greater than 256 will be treated

  \\xHH byte with value expressed in hexadecimal value NN (1 to 2 digits)

  \\uHHHH Unicode (IEC 10646) character with value expressed in hexadecimal value HHHH (4 digits)

  \\uHHHH Unicode character with value expressed in hexadecimal value HHHH (8 digits)

  %% a single %

  SUBSTITUTIONS

  SUBSTITUTION QUICK REFERENCE

  Fields

  %s - string
  %b - string parsed for literals
    second parameter is max length

  %c - char
    no second parameter

  %i or %d - 64-bit integer
  %u - 64 bit unsigned integer
  %x or %X - 64-bit unsigned integer as hex
  %o - 64-bit unsigned integer as octal
    second parameter is min-width, integer
     output below that width is padded with leading zeroes

  %f or %F - decimal floating point value
  %e or %E - scientific notation floating point value
  %g or %G - shorter of specially interpreted decimal or SciNote floating point value.
    second parameter is
      -max places after decimal point for floating point output
      -max number of significant digits for scientific notation output

  parameterizing fields

  examples:

  printf '%4.3i' 7
  has a first parameter of 4
     and a second parameter of 3
  will result in ' 007'

  printf '%.1s' abcde
  has no first parameter
     and a second parameter of 1
  will result in 'a'

  printf '%4c' q
  has a first parameter of 4
     and no second parameter
  will result in  '   q'

  The first parameter of a field is the minimum width to pad the output to
   if the output is less than this absolute value of this width,
   it will be padded with leading spaces, or, if the argument is negative,
   with trailing spaces. the default is zero.

  The second parameter of a field is particular to the output field type.
   defaults can be found in the full substitution help below

  special prefixes to numeric arguments
    0 (e.g. 010) - interpret argument as octal (integer output fields only)
    0x (e.g. 0xABC) - interpret argument as hex (numeric output fields only)
    \' (e.g. \'a) - interpret argument as a character constant

  HOW TO USE SUBSTITUTIONS

  Substitutions are used to pass additional argument(s) into the FORMAT string, to be formatted a
  particular way. E.g.

      printf 'the letter %X comes before the letter %X' 10 11

  will print

     'the letter A comes before the letter B'

  because the substitution field %X means
  'take an integer argument and write it as a hexadecimal number'

  Passing more arguments than are in the format string will cause the format string to be
   repeated for the remaining substitutions

     printf 'it is %i F in %s \n' 22 Portland 25 Boston 27 New York

  will print

     'it is 22 F in Portland
      it is 25 F in Boston
      it is 27 F in Boston
     '
  If a format string is printed but there are less arguments remaining
   than there are substitution fields, substitution fields without
   an argument will default to empty strings, or for numeric fields
   the value 0

  AVAILABLE SUBSTITUTIONS

  This program, like GNU coreutils printf,
  interprets a modified subset of the POSIX C printf spec,
  a quick reference to substitutions is below.

   STRING SUBSTITUTIONS
    All string fields have a 'max width' parameter
    %.3s means 'print no more than three characters of the original input'

   %s - string

   %b - escaped string - the string will be checked for any escaped literals from
         the escaped literal list above, and translate them to literal characters.
         e.g. \\n will be transformed into a newline character.

        One special rule about %b mode is that octal literals are interpreted differently
        In arguments passed by %b, pass octal-interpreted literals must be in the form of \\0NNN
        instead of \\NNN. (Although, for legacy reasons, octal literals in the form of \\NNN will
        still be interpreted and not throw a warning, you will have problems if you use this for a
        literal whose code begins with zero, as it will be viewed as in \\0NNN form.)

   CHAR SUBSTITUTIONS
    The character field does not have a secondary parameter.

   %c - a single character

   INTEGER SUBSTITUTIONS
    All integer fields have a 'pad with zero' parameter
    %.4i means an integer which if it is less than 4 digits in length,
    is padded with leading zeros until it is 4 digits in length.

   %d or %i - 64-bit integer

   %u - 64 bit unsigned integer

   %x or %X - 64 bit unsigned integer printed in Hexadecimal (base 16)
            %X instead of %x means to use uppercase letters for 'a' through 'f'

   %o - 64 bit unsigned integer printed in octal (base 8)

   FLOATING POINT SUBSTITUTIONS

    All floating point fields have a 'max decimal places / max significant digits' parameter
    %.10f means a decimal floating point with 7 decimal places past 0
    %.10e means a scientific notation number with 10 significant digits
    %.10g means the same behavior for decimal and Sci. Note, respectively, and provides the shorter
          of each's output.

    Like with GNU coreutils, the value after the decimal point is these outputs is parsed as a
    double first before being rendered to text. For both implementations do not expect meaningful
    precision past the 18th decimal place. When using a number of decimal places that is 18 or
    higher, you can expect variation in output between GNU coreutils printf and this printf at the
    18th decimal place of +/- 1

   %f - floating point value presented in decimal, truncated and displayed to 6 decimal places by
        default. There is not past-double behavior parity with Coreutils printf, values are not
        estimated or adjusted beyond input values.

   %e or %E - floating point value presented in scientific notation
            7 significant digits by default
            %E means use to use uppercase E for the mantissa.

   %g or %G - floating point value presented in the shorter of decimal and scientific notation
            behaves differently from %f and %E, please see posix printf spec for full details,
            some examples of different behavior:

            Sci Note has 6 significant digits by default
            Trailing zeroes are removed
            Instead of being truncated, digit after last is rounded

   Like other behavior in this utility, the design choices of floating point
    behavior in this utility is selected to reproduce in exact
    the behavior of GNU coreutils' printf from an inputs and outputs standpoint.

  USING PARAMETERS
   Most substitution fields can be parameterized using up to 2 numbers that can
   be passed to the field, between the % sign and the field letter.

   The 1st parameter always indicates the minimum width of output, it is useful for creating
     columnar output. Any output that would be less than this minimum width is padded with
     leading spaces
   The 2nd parameter is proceeded by a dot.
   You do not have to use parameters

  SPECIAL FORMS OF INPUT
   For numeric input, the following additional forms of input are accepted besides decimal:

    Octal (only with integer): if the argument begins with a 0 the proceeding characters
      will be interpreted as octal (base 8) for integer fields

    Hexadecimal: if the argument begins with 0x the proceeding characters will be interpreted
      will be interpreted as hex (base 16) for any numeric fields
      for float fields, hexadecimal input results in a precision
      limit (in converting input past the decimal point) of 10^-15

    Character Constant: if the argument begins with a single quote character, the first byte
      of the next character will be interpreted as an 8-bit unsigned integer. If there are
      additional bytes, they will throw an error (unless the environment variable POSIXLY_CORRECT
      is set)

WRITTEN BY :
  Nathan E. Ross, et al. for the uutils project

MORE INFO :
  https://github.com/uutils/coreutils

COPYRIGHT :
  Copyright 2015 uutils project.
  Licensed under the MIT License, please see LICENSE file for details

";

pub fn uumain(args: impl uucore::Args) -> i32 {
    let args = args.collect_str();

    let location = &args[0];
    if args.len() <= 1 {
        println!(
            "{0}: missing operand\nTry '{0} --help' for more information.",
            location
        );
        return 1;
    }
    let formatstr = &args[1];

    if formatstr == "--help" {
        print!("{} {}", LONGHELP_LEAD, LONGHELP_BODY);
    } else if formatstr == "--version" {
        println!("{} {}", NAME, VERSION);
    } else {
        let printf_args = &args[2..];
        memo::Memo::run_all(formatstr, printf_args);
    }
    0
}
<commit_msg>fix/printf ~ use calculated VERSION<commit_after>#![allow(dead_code)]

// spell-checker:ignore (change!) each's
// spell-checker:ignore (ToDO) LONGHELP FORMATSTRING templating parameterizing formatstr

extern crate itertools;
extern crate uucore;

mod cli;
mod memo;
mod tokenize;

static NAME: &str = "printf";
static VERSION: &str = env!("CARGO_PKG_VERSION");
static SHORT_USAGE: &str = "printf: usage: printf [-v var] format [arguments]";
static LONGHELP_LEAD: &str = "printf

 USAGE: printf FORMATSTRING [ARGUMENT]...

 basic anonymous string templating:

 prints format string at least once, repeating as long as there are remaining arguments
 output prints escaped literals in the format string as character literals
 output replaces anonymous fields with the next unused argument, formatted according to the field.

Options:
    --help              display this help and exit
    --version           output version information and exit

";
static LONGHELP_BODY: &str = "
  Prints the , replacing escaped character sequences with character literals
    and substitution field sequences with passed arguments

 literally, with the exception of the below
    escaped character sequences, and the substitution sequences described further down.

  ESCAPE SEQUENCES

  The following escape sequences, organized here in alphabetical order,
  will print the corresponding character literal:

  \"   double quote

  \\\\    backslash

  \\a  alert (BEL)

  \\b  backspace

  \\c  End-of-Input

  \\e  escape

  \\f  form feed

  \\n  new line

  \\r  carriage return

  \\t  horizontal tab

  \\v  vertical tab

  \\NNN byte with value expressed in octal value NNN (1 to 3 digits)
        values greater than 256 will be treated

  \\xHH byte with value expressed in hexadecimal value NN (1 to 2 digits)

  \\uHHHH Unicode (IEC 10646) character with value expressed in hexadecimal value HHHH (4 digits)

  \\uHHHH Unicode character with value expressed in hexadecimal value HHHH (8 digits)

  %% a single %

  SUBSTITUTIONS

  SUBSTITUTION QUICK REFERENCE

  Fields

  %s - string
  %b - string parsed for literals
    second parameter is max length

  %c - char
    no second parameter

  %i or %d - 64-bit integer
  %u - 64 bit unsigned integer
  %x or %X - 64-bit unsigned integer as hex
  %o - 64-bit unsigned integer as octal
    second parameter is min-width, integer
     output below that width is padded with leading zeroes

  %f or %F - decimal floating point value
  %e or %E - scientific notation floating point value
  %g or %G - shorter of specially interpreted decimal or SciNote floating point value.
    second parameter is
      -max places after decimal point for floating point output
      -max number of significant digits for scientific notation output

  parameterizing fields

  examples:

  printf '%4.3i' 7
  has a first parameter of 4
     and a second parameter of 3
  will result in ' 007'

  printf '%.1s' abcde
  has no first parameter
     and a second parameter of 1
  will result in 'a'

  printf '%4c' q
  has a first parameter of 4
     and no second parameter
  will result in  '   q'

  The first parameter of a field is the minimum width to pad the output to
   if the output is less than this absolute value of this width,
   it will be padded with leading spaces, or, if the argument is negative,
   with trailing spaces. the default is zero.

  The second parameter of a field is particular to the output field type.
   defaults can be found in the full substitution help below

  special prefixes to numeric arguments
    0 (e.g. 010) - interpret argument as octal (integer output fields only)
    0x (e.g. 0xABC) - interpret argument as hex (numeric output fields only)
    \' (e.g. \'a) - interpret argument as a character constant

  HOW TO USE SUBSTITUTIONS

  Substitutions are used to pass additional argument(s) into the FORMAT string, to be formatted a
  particular way. E.g.

      printf 'the letter %X comes before the letter %X' 10 11

  will print

     'the letter A comes before the letter B'

  because the substitution field %X means
  'take an integer argument and write it as a hexadecimal number'

  Passing more arguments than are in the format string will cause the format string to be
   repeated for the remaining substitutions

     printf 'it is %i F in %s \n' 22 Portland 25 Boston 27 New York

  will print

     'it is 22 F in Portland
      it is 25 F in Boston
      it is 27 F in Boston
     '
  If a format string is printed but there are less arguments remaining
   than there are substitution fields, substitution fields without
   an argument will default to empty strings, or for numeric fields
   the value 0

  AVAILABLE SUBSTITUTIONS

  This program, like GNU coreutils printf,
  interprets a modified subset of the POSIX C printf spec,
  a quick reference to substitutions is below.

   STRING SUBSTITUTIONS
    All string fields have a 'max width' parameter
    %.3s means 'print no more than three characters of the original input'

   %s - string

   %b - escaped string - the string will be checked for any escaped literals from
         the escaped literal list above, and translate them to literal characters.
         e.g. \\n will be transformed into a newline character.

        One special rule about %b mode is that octal literals are interpreted differently
        In arguments passed by %b, pass octal-interpreted literals must be in the form of \\0NNN
        instead of \\NNN. (Although, for legacy reasons, octal literals in the form of \\NNN will
        still be interpreted and not throw a warning, you will have problems if you use this for a
        literal whose code begins with zero, as it will be viewed as in \\0NNN form.)

   CHAR SUBSTITUTIONS
    The character field does not have a secondary parameter.

   %c - a single character

   INTEGER SUBSTITUTIONS
    All integer fields have a 'pad with zero' parameter
    %.4i means an integer which if it is less than 4 digits in length,
    is padded with leading zeros until it is 4 digits in length.

   %d or %i - 64-bit integer

   %u - 64 bit unsigned integer

   %x or %X - 64 bit unsigned integer printed in Hexadecimal (base 16)
            %X instead of %x means to use uppercase letters for 'a' through 'f'

   %o - 64 bit unsigned integer printed in octal (base 8)

   FLOATING POINT SUBSTITUTIONS

    All floating point fields have a 'max decimal places / max significant digits' parameter
    %.10f means a decimal floating point with 7 decimal places past 0
    %.10e means a scientific notation number with 10 significant digits
    %.10g means the same behavior for decimal and Sci. Note, respectively, and provides the shorter
          of each's output.

    Like with GNU coreutils, the value after the decimal point is these outputs is parsed as a
    double first before being rendered to text. For both implementations do not expect meaningful
    precision past the 18th decimal place. When using a number of decimal places that is 18 or
    higher, you can expect variation in output between GNU coreutils printf and this printf at the
    18th decimal place of +/- 1

   %f - floating point value presented in decimal, truncated and displayed to 6 decimal places by
        default. There is not past-double behavior parity with Coreutils printf, values are not
        estimated or adjusted beyond input values.

   %e or %E - floating point value presented in scientific notation
            7 significant digits by default
            %E means use to use uppercase E for the mantissa.

   %g or %G - floating point value presented in the shorter of decimal and scientific notation
            behaves differently from %f and %E, please see posix printf spec for full details,
            some examples of different behavior:

            Sci Note has 6 significant digits by default
            Trailing zeroes are removed
            Instead of being truncated, digit after last is rounded

   Like other behavior in this utility, the design choices of floating point
    behavior in this utility is selected to reproduce in exact
    the behavior of GNU coreutils' printf from an inputs and outputs standpoint.

  USING PARAMETERS
   Most substitution fields can be parameterized using up to 2 numbers that can
   be passed to the field, between the % sign and the field letter.

   The 1st parameter always indicates the minimum width of output, it is useful for creating
     columnar output. Any output that would be less than this minimum width is padded with
     leading spaces
   The 2nd parameter is proceeded by a dot.
   You do not have to use parameters

  SPECIAL FORMS OF INPUT
   For numeric input, the following additional forms of input are accepted besides decimal:

    Octal (only with integer): if the argument begins with a 0 the proceeding characters
      will be interpreted as octal (base 8) for integer fields

    Hexadecimal: if the argument begins with 0x the proceeding characters will be interpreted
      will be interpreted as hex (base 16) for any numeric fields
      for float fields, hexadecimal input results in a precision
      limit (in converting input past the decimal point) of 10^-15

    Character Constant: if the argument begins with a single quote character, the first byte
      of the next character will be interpreted as an 8-bit unsigned integer. If there are
      additional bytes, they will throw an error (unless the environment variable POSIXLY_CORRECT
      is set)

WRITTEN BY :
  Nathan E. Ross, et al. for the uutils project

MORE INFO :
  https://github.com/uutils/coreutils

COPYRIGHT :
  Copyright 2015 uutils project.
  Licensed under the MIT License, please see LICENSE file for details

";

pub fn uumain(args: impl uucore::Args) -> i32 {
    let args = args.collect_str();

    let location = &args[0];
    if args.len() <= 1 {
        println!(
            "{0}: missing operand\nTry '{0} --help' for more information.",
            location
        );
        return 1;
    }
    let formatstr = &args[1];

    if formatstr == "--help" {
        print!("{} {}", LONGHELP_LEAD, LONGHELP_BODY);
    } else if formatstr == "--version" {
        println!("{} {}", NAME, VERSION);
    } else {
        let printf_args = &args[2..];
        memo::Memo::run_all(formatstr, printf_args);
    }
    0
}
<|endoftext|>


<commit_before>
use scope::*;

// pub enum MapWalkReturn<'a, T> {
//     NoMatch,
//     InterimMatch(&'a T),
//     FinalMatch(&'a T)
// }

pub enum MapWalkState<'a, K: 'a, T: 'a> {
    NoMatch,
    InterimMatch(&'a K, Option<&'a T>),
    FinalMatch(&'a T)
}

#[allow(dead_code)]
// pub struct MapWalkIter<'a, 'k, K: 'k, T: 'a, F>
pub struct MapWalkIter<'a, K>
{
    ctx: &'a mut Context,
    scope_id: String,
    key: K,
    next_key: Option<K>,
    func: FnMut(&Symbols, &K) -> Option<String>
}

impl<'a, K> Iterator for MapWalkIter<'a, K>
    // where F: FnMut(&Symbols, &K) -> Self::Item
{
    // type Item = MapWalkState<'a, 'k, K, T>;
    type Item = Option<String>;

    fn next(&mut self) -> Option<Self::Item> {
        let (map_id, parent_id) = {
            let scope = self.ctx.get_scope(&self.scope_id);
            if scope.is_none() { return None; }
            let scope = scope.unwrap();
            (scope.map_id().to_owned(), scope.parent_id().map(|parent_id| parent_id.to_owned()))
        };

        let map_ref = self.ctx.get_map(&map_id).expect("Map must exist for scope");
        let state = (self.func)(map_ref, &self.key);

        // match state {
        //     Some(MapWalkState::InterimMatch(ref next_key, ref v)) => {
        //         self.next_key = Some(next_key);
        //         return state;
        //     }

        //     Some(MapWalkState::FinalMatch(ref v)) => { return state; }

        //     _ => {}
        // };

        // // Prepare next iteration
        // if parent_id.is_none() { return None; }
        // self.next_scope_id = parent_id.map(|s| s.to_owned());

        // Some(MapWalkState::NoMatch)
        None
    }
}
<commit_msg>Lifetimes in `MapWalkIter` (WIP)<commit_after>
use scope::*;

// pub enum MapWalkReturn<'a, T> {
//     NoMatch,
//     InterimMatch(&'a T),
//     FinalMatch(&'a T)
// }

pub enum MapWalkState<'a, K: 'a, T: 'a> {
    NoMatch,
    InterimMatch(&'a K, Option<&'a T>),
    FinalMatch(&'a T)
}

#[allow(dead_code)]
pub struct MapWalkIter<'a, K: 'a, T: 'a>
{
    ctx: &'a mut Context,
    scope_id: String,
    key: K,
    next_key: Option<K>,
    func: FnMut(&Symbols, &K) -> MapWalkState<'a, K, T>
}

impl<'a, K, T> Iterator for MapWalkIter<'a, K, T>
{
    type Item = MapWalkState<'a, K, T>;

    fn next(&mut self) -> Option<Self::Item> {
        let (map_id, parent_id) = {
            let scope = self.ctx.get_scope(&self.scope_id);
            if scope.is_none() { return None; }
            let scope = scope.unwrap();
            (scope.map_id().to_owned(), scope.parent_id().map(|parent_id| parent_id.to_owned()))
        };

        let map_ref = self.ctx.get_map(&map_id).expect("Map must exist for scope");
        let state = (self.func)(map_ref, &self.key);

        // match state {
        //     Some(MapWalkState::InterimMatch(ref next_key, ref v)) => {
        //         self.next_key = Some(next_key);
        //         return state;
        //     }

        //     Some(MapWalkState::FinalMatch(ref v)) => { return state; }

        //     _ => {}
        // };

        // // Prepare next iteration
        // if parent_id.is_none() { return None; }
        // self.next_scope_id = parent_id.map(|s| s.to_owned());

        // Some(MapWalkState::NoMatch)
        None
    }
}
<|endoftext|>


<commit_before>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

use std::collections::BTreeMap;
use std::vec::Vec;

use engine::EngineResult;
use engine::Pool;

use super::blockdev::SimDev;

#[derive(Debug, Clone)]
pub struct SimFilesystem {
    pub name: String,
}

#[derive(Debug)]
pub struct SimPool {
    pub name: String,
    pub block_devs: Vec<Box<SimDev>>,
    pub filesystems: BTreeMap<String, Box<SimFilesystem>>,
    pub raid_level: u16,
    pub online: bool,
    pub checking: bool,
}

impl SimPool {
    pub fn new_pool(name: &str, blockdevs: &[Box<SimDev>], raid_level: u16) -> Box<Pool> {

        let mut vec = Vec::new();
        vec.extend_from_slice(blockdevs);
        let new_pool = SimPool {
            name: name.to_owned(),
            block_devs: vec,
            filesystems: BTreeMap::new(),
            raid_level: raid_level,
            online: true,
            checking: false,
        };

        Box::new(new_pool)
    }
}

impl Pool for SimPool {
    fn add_blockdev(&mut self, _path: &str) -> EngineResult<()> {
        println!("sim: pool::add_blockdev");
        Ok(())
    }

    fn add_cachedev(&mut self, _path: &str) -> EngineResult<()> {
        println!("sim: pool::add_cachedev");
        Ok(())
    }

    fn destroy(&mut self) -> EngineResult<()> {
        println!("sim: pool::destroy");
        Ok(())
    }

    fn get_name(&mut self) -> String {
        self.name.clone()
    }

    fn copy(&self) -> Box<Pool> {
        let pool_copy = SimPool {
            name: self.name.clone(),
            block_devs: self.block_devs.clone(),
            filesystems: self.filesystems.clone(),
            raid_level: self.raid_level.clone(),
            online: true,
            checking: false,
        };
        Box::new(pool_copy)
    }

    fn create_filesystem(&mut self,
                         _filesystem_name: &str,
                         _mount_point: &str,
                         _size: u64)
                         -> EngineResult<()> {
        Ok(())
    }
}
<commit_msg>Put a tiny implementation for SimFilesystem in.<commit_after>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

use std::collections::BTreeMap;
use std::vec::Vec;

use engine::EngineResult;
use engine::Pool;

use super::blockdev::SimDev;

#[derive(Debug, Clone)]
pub struct SimFilesystem {
}

impl SimFilesystem {
    pub fn new_filesystem() -> Box<SimFilesystem> {
        Box::new(SimFilesystem {})
    }
}

#[derive(Debug)]
pub struct SimPool {
    pub name: String,
    pub block_devs: Vec<Box<SimDev>>,
    pub filesystems: BTreeMap<String, Box<SimFilesystem>>,
    pub raid_level: u16,
    pub online: bool,
    pub checking: bool,
}

impl SimPool {
    pub fn new_pool(name: &str, blockdevs: &[Box<SimDev>], raid_level: u16) -> Box<Pool> {

        let mut vec = Vec::new();
        vec.extend_from_slice(blockdevs);
        let new_pool = SimPool {
            name: name.to_owned(),
            block_devs: vec,
            filesystems: BTreeMap::new(),
            raid_level: raid_level,
            online: true,
            checking: false,
        };

        Box::new(new_pool)
    }
}

impl Pool for SimPool {
    fn add_blockdev(&mut self, _path: &str) -> EngineResult<()> {
        println!("sim: pool::add_blockdev");
        Ok(())
    }

    fn add_cachedev(&mut self, _path: &str) -> EngineResult<()> {
        println!("sim: pool::add_cachedev");
        Ok(())
    }

    fn destroy(&mut self) -> EngineResult<()> {
        println!("sim: pool::destroy");
        Ok(())
    }

    fn get_name(&mut self) -> String {
        self.name.clone()
    }

    fn copy(&self) -> Box<Pool> {
        let pool_copy = SimPool {
            name: self.name.clone(),
            block_devs: self.block_devs.clone(),
            filesystems: self.filesystems.clone(),
            raid_level: self.raid_level.clone(),
            online: true,
            checking: false,
        };
        Box::new(pool_copy)
    }

    fn create_filesystem(&mut self,
                         _filesystem_name: &str,
                         _mount_point: &str,
                         _size: u64)
                         -> EngineResult<()> {
        Ok(())
    }
}
<|endoftext|>


<commit_before>use std::error::Error;
use std::fmt::{Debug, Display, Formatter};
use std::fmt;
use std::result::Result;
use std::path::{Path, PathBuf};
use std::convert::From;
use std::convert::Into;

use regex::Regex;

#[derive(Debug)]
#[derive(Clone)]
#[derive(PartialEq)]
#[derive(Eq)]
// #[derive(Display)]
pub enum FileIDType {
    NONE,
    UUID,
}

impl Into<String> for FileIDType {

    fn into(self) -> String {
        let s = match self {
            FileIDType::UUID => "UUID",
            FileIDType::NONE => "",
        };

        String::from(s)
    }

}

impl<'a> From<&'a str> for FileIDType {

    fn from(s: &'a str) -> FileIDType {
        match s {
            "UUID"  => FileIDType::UUID,
            _       => FileIDType::NONE,
        }
    }

}

impl From<String> for FileIDType {

    fn from(s: String) -> FileIDType {
        FileIDType::from(&s[..])
    }

}

#[derive(Clone)]
pub struct FileID {
    id: Option<String>,
    id_type: FileIDType,
}

impl FileID {

    pub fn new(id_type: FileIDType, id: String) -> FileID {
        FileID {
            id: Some(id),
            id_type: id_type,
        }
    }

    pub fn is_valid(&self) -> bool {
        self.id.is_some()
    }

    pub fn get_type(&self) -> FileIDType {
        self.id_type.clone()
    }

}

impl Debug for FileID {

    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        write!(fmt, "FileID[{:?}]: {:?}",
               self.id_type,
               self.id);
        Ok(())
    }

}

impl Display for FileID {

    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        write!(fmt, "FileID[{:?}]: {:?}",
               self.id_type,
               self.id);
        Ok(())
    }

}

impl Into<String> for FileID {

    fn into(self) -> String {
        if let Some(id) = self.id {
            id.clone()
        } else {
            String::from("INVALID")
        }
    }

}

impl Into<FileIDType> for FileID {

    fn into(self) -> FileIDType {
        self.id_type.clone()
    }
}

impl From<String> for FileID {

    fn from(s: String) -> FileID {
        FileID::from(&s)
    }

}

impl<'a> From<&'a String> for FileID {

    fn from(string: &'a String) -> FileID {
        // we assume that it is an path
        let regex = Regex::new(r"([:alnum:]*)-([:upper:]*)-([A-Za-z0-9-_]*)\.(.*)").unwrap();
        let s = string.split("/").last().unwrap_or("");

        debug!("Regex build: {:?}", regex);
        debug!("Matching string: '{}'", s);
        regex.captures(s).and_then(|capts| {
            // first one is the whole string, index 1-N are the matches.
            if capts.len() != 5 {
                debug!("Matches, but not expected number of groups");
                return None;
            }
            debug!("Matches: {}", capts.len());

            let modname     = capts.at(1).unwrap();
            let hashname    = capts.at(2).unwrap();
            let mut hash    = capts.at(3).unwrap();

            debug!("Destructure FilePath to ID:");
            debug!("                  FilePath: {:?}", s);
            debug!("               Module Name: {:?}", modname);
            debug!("                 Hash Name: {:?}", hashname);
            debug!("                      Hash: {:?}", hash);

            let idtype = FileIDType::from(hashname);
            match idtype {
                FileIDType::NONE => hash = "INVALID",
                _ => {},
            }

            Some(FileID::new(idtype, String::from(hash)))
        }).unwrap_or({
            debug!("Did not match");
            debug!("It is no path, actually. So we assume it is an ID already");
            FileID {
                id_type: FileIDType::NONE,
                id: Some(string.clone()),
            }
        })
    }

}

impl From<PathBuf> for FileID {

    fn from(s: PathBuf) -> FileID {
        unimplemented!()
    }

}

impl<'a> From<&'a PathBuf> for FileID {

    fn from(pb: &'a PathBuf) -> FileID {
        let s = pb.to_str().unwrap_or("");
        FileID::from(String::from(s))
    }

}

pub struct FileIDError {
    summary: String,
    descrip: String,
}

impl FileIDError {

    pub fn new(s: String, d: String) -> FileIDError {
        FileIDError {
            summary: s,
            descrip: d,
        }
    }

}

impl<'a> Error for FileIDError {

    fn description(&self) -> &str {
        &self.summary[..]
    }

    fn cause(&self) -> Option<&Error> {
        None
    }

}

impl<'a> Debug for FileIDError {

    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        write!(fmt, "FileIDError: '{}'\n{}", self.summary, self.descrip);
        Ok(())
    }

}

impl<'a> Display for FileIDError {

    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        write!(fmt, "FileIDError: '{}'", self.summary);
        Ok(())
    }

}

pub type FileIDResult = Result<FileID, FileIDError>;

#[cfg(test)]
mod test {

    use super::{FileID, FileIDType};

    #[test]
    fn file_id_from_string() {
        setup_logger();

        let s1 = String::from("/home/user/testmodule-UUID-some-id.imag");
        let s2 = String::from("/home/user/testmodule-UUID-some-id.extension.imag");
        let s3 = String::from("/home/user/testmodule-NOHASH-some-id.imag");

        let id1 = FileID::from(s1);
        let id2 = FileID::from(s2);
        let id3 = FileID::from(s3);

        println!("Id 1 : {:?}", id1);
        println!("Id 2 : {:?}", id2);
        println!("Id 3 : {:?}", id3);

        assert_eq!(FileIDType::UUID, id1.get_type());
        assert_eq!(FileIDType::UUID, id2.get_type());
        assert_eq!(FileIDType::NONE, id3.get_type());

        let f1 : String = id1.into();
        let f2 : String = id2.into();
        let f3 : String = id3.into();

        assert_eq!(String::from("some-id"), f1);
        assert_eq!(String::from("some-id"), f2);
        assert_eq!(String::from("INVALID"), f3);
    }

    fn setup_logger() {
        extern crate log;
        use log::{LogLevelFilter, set_logger};
        use runtime::ImagLogger;

        log::set_logger(|max_log_lvl| {
            let lvl = LogLevelFilter::Debug;
            max_log_lvl.set(lvl);
            Box::new(ImagLogger::new(lvl.to_log_level().unwrap()))
        });
        debug!("Init logger for test");
    }

}

<commit_msg>Add id getter for FileID<commit_after>use std::error::Error;
use std::fmt::{Debug, Display, Formatter};
use std::fmt;
use std::result::Result;
use std::path::{Path, PathBuf};
use std::convert::From;
use std::convert::Into;

use regex::Regex;

#[derive(Debug)]
#[derive(Clone)]
#[derive(PartialEq)]
#[derive(Eq)]
// #[derive(Display)]
pub enum FileIDType {
    NONE,
    UUID,
}

impl Into<String> for FileIDType {

    fn into(self) -> String {
        let s = match self {
            FileIDType::UUID => "UUID",
            FileIDType::NONE => "",
        };

        String::from(s)
    }

}

impl<'a> From<&'a str> for FileIDType {

    fn from(s: &'a str) -> FileIDType {
        match s {
            "UUID"  => FileIDType::UUID,
            _       => FileIDType::NONE,
        }
    }

}

impl From<String> for FileIDType {

    fn from(s: String) -> FileIDType {
        FileIDType::from(&s[..])
    }

}

#[derive(Clone)]
pub struct FileID {
    id: Option<String>,
    id_type: FileIDType,
}

impl FileID {

    pub fn new(id_type: FileIDType, id: String) -> FileID {
        FileID {
            id: Some(id),
            id_type: id_type,
        }
    }

    pub fn is_valid(&self) -> bool {
        self.id.is_some()
    }

    pub fn get_type(&self) -> FileIDType {
        self.id_type.clone()
    }

    pub fn get_id(&self) -> Option<String> {
        self.id.clone()
    }

}

impl Debug for FileID {

    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        write!(fmt, "FileID[{:?}]: {:?}",
               self.id_type,
               self.id);
        Ok(())
    }

}

impl Display for FileID {

    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        write!(fmt, "FileID[{:?}]: {:?}",
               self.id_type,
               self.id);
        Ok(())
    }

}

impl Into<String> for FileID {

    fn into(self) -> String {
        if let Some(id) = self.id {
            id.clone()
        } else {
            String::from("INVALID")
        }
    }

}

impl Into<FileIDType> for FileID {

    fn into(self) -> FileIDType {
        self.id_type.clone()
    }
}

impl From<String> for FileID {

    fn from(s: String) -> FileID {
        FileID::from(&s)
    }

}

impl<'a> From<&'a String> for FileID {

    fn from(string: &'a String) -> FileID {
        // we assume that it is an path
        let regex = Regex::new(r"([:alnum:]*)-([:upper:]*)-([A-Za-z0-9-_]*)\.(.*)").unwrap();
        let s = string.split("/").last().unwrap_or("");

        debug!("Regex build: {:?}", regex);
        debug!("Matching string: '{}'", s);
        regex.captures(s).and_then(|capts| {
            // first one is the whole string, index 1-N are the matches.
            if capts.len() != 5 {
                debug!("Matches, but not expected number of groups");
                return None;
            }
            debug!("Matches: {}", capts.len());

            let modname     = capts.at(1).unwrap();
            let hashname    = capts.at(2).unwrap();
            let mut hash    = capts.at(3).unwrap();

            debug!("Destructure FilePath to ID:");
            debug!("                  FilePath: {:?}", s);
            debug!("               Module Name: {:?}", modname);
            debug!("                 Hash Name: {:?}", hashname);
            debug!("                      Hash: {:?}", hash);

            let idtype = FileIDType::from(hashname);
            match idtype {
                FileIDType::NONE => hash = "INVALID",
                _ => {},
            }

            Some(FileID::new(idtype, String::from(hash)))
        }).unwrap_or({
            debug!("Did not match");
            debug!("It is no path, actually. So we assume it is an ID already");
            FileID {
                id_type: FileIDType::NONE,
                id: Some(string.clone()),
            }
        })
    }

}

impl From<PathBuf> for FileID {

    fn from(s: PathBuf) -> FileID {
        unimplemented!()
    }

}

impl<'a> From<&'a PathBuf> for FileID {

    fn from(pb: &'a PathBuf) -> FileID {
        let s = pb.to_str().unwrap_or("");
        FileID::from(String::from(s))
    }

}

pub struct FileIDError {
    summary: String,
    descrip: String,
}

impl FileIDError {

    pub fn new(s: String, d: String) -> FileIDError {
        FileIDError {
            summary: s,
            descrip: d,
        }
    }

}

impl<'a> Error for FileIDError {

    fn description(&self) -> &str {
        &self.summary[..]
    }

    fn cause(&self) -> Option<&Error> {
        None
    }

}

impl<'a> Debug for FileIDError {

    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        write!(fmt, "FileIDError: '{}'\n{}", self.summary, self.descrip);
        Ok(())
    }

}

impl<'a> Display for FileIDError {

    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        write!(fmt, "FileIDError: '{}'", self.summary);
        Ok(())
    }

}

pub type FileIDResult = Result<FileID, FileIDError>;

#[cfg(test)]
mod test {

    use super::{FileID, FileIDType};

    #[test]
    fn file_id_from_string() {
        setup_logger();

        let s1 = String::from("/home/user/testmodule-UUID-some-id.imag");
        let s2 = String::from("/home/user/testmodule-UUID-some-id.extension.imag");
        let s3 = String::from("/home/user/testmodule-NOHASH-some-id.imag");

        let id1 = FileID::from(s1);
        let id2 = FileID::from(s2);
        let id3 = FileID::from(s3);

        println!("Id 1 : {:?}", id1);
        println!("Id 2 : {:?}", id2);
        println!("Id 3 : {:?}", id3);

        assert_eq!(FileIDType::UUID, id1.get_type());
        assert_eq!(FileIDType::UUID, id2.get_type());
        assert_eq!(FileIDType::NONE, id3.get_type());

        let f1 : String = id1.into();
        let f2 : String = id2.into();
        let f3 : String = id3.into();

        assert_eq!(String::from("some-id"), f1);
        assert_eq!(String::from("some-id"), f2);
        assert_eq!(String::from("INVALID"), f3);
    }

    fn setup_logger() {
        extern crate log;
        use log::{LogLevelFilter, set_logger};
        use runtime::ImagLogger;

        log::set_logger(|max_log_lvl| {
            let lvl = LogLevelFilter::Debug;
            max_log_lvl.set(lvl);
            Box::new(ImagLogger::new(lvl.to_log_level().unwrap()))
        });
        debug!("Init logger for test");
    }

}

<|endoftext|>


<commit_before>// Copyright 2017-2018, The Gtk-rs Project Developers.
// See the COPYRIGHT file at the top-level directory of this distribution.
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>

//! This module contains simple instance and class structs to be used for
//! `GObject` subclasses that don't require any additional data in these
//! structs and don't provide any new virtual methods.

use super::prelude::*;
use object::ObjectType;

use std::ops;

/// A simple instance struct that does not store any additional data.
#[repr(C)]
pub struct InstanceStruct<T: ObjectSubclass> {
    parent: <T::ParentType as ObjectType>::GlibType,
}

unsafe impl<T: ObjectSubclass> super::types::InstanceStruct for InstanceStruct<T> {
    type Type = T;
}

/// A simple class struct that does not store any additional data
/// or virtual methods.
#[repr(C)]
pub struct ClassStruct<T: ObjectSubclass> {
    parent_class: <T::ParentType as ObjectType>::GlibClassType,
}

unsafe impl<T: ObjectSubclass> super::types::ClassStruct for ClassStruct<T> {
    type Type = T;
}

impl<T: ObjectSubclass> ops::Deref for ClassStruct<T> {
    type Target = <<T as ObjectSubclass>::ParentType as ObjectType>::RustClassType;

    fn deref(&self) -> &Self::Target {
        unsafe { &*(self as *const _ as *const Self::Target) }
    }
}

impl<T: ObjectSubclass> ops::DerefMut for ClassStruct<T> {
    fn deref_mut(&mut self) -> &mut Self::Target {
        unsafe { &mut *(self as *mut _ as *mut Self::Target) }
    }
}
<commit_msg>Implement fmt::Debug for subclass::simple::{InstanceStruct, ClassStruct}<commit_after>// Copyright 2017-2018, The Gtk-rs Project Developers.
// See the COPYRIGHT file at the top-level directory of this distribution.
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>

//! This module contains simple instance and class structs to be used for
//! `GObject` subclasses that don't require any additional data in these
//! structs and don't provide any new virtual methods.

use super::prelude::*;
use object::ObjectType;

use std::fmt;
use std::ops;

/// A simple instance struct that does not store any additional data.
#[repr(C)]
pub struct InstanceStruct<T: ObjectSubclass> {
    parent: <T::ParentType as ObjectType>::GlibType,
}

impl<T: ObjectSubclass> fmt::Debug for InstanceStruct<T>
where
    <T::ParentType as ObjectType>::GlibType: fmt::Debug,
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("InstanceStruct")
            .field("parent", &self.parent)
            .finish()
    }
}

unsafe impl<T: ObjectSubclass> super::types::InstanceStruct for InstanceStruct<T> {
    type Type = T;
}

/// A simple class struct that does not store any additional data
/// or virtual methods.
#[repr(C)]
pub struct ClassStruct<T: ObjectSubclass> {
    parent_class: <T::ParentType as ObjectType>::GlibClassType,
}

impl<T: ObjectSubclass> fmt::Debug for ClassStruct<T>
where
    <T::ParentType as ObjectType>::GlibClassType: fmt::Debug,
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("InstanceStruct")
            .field("parent_class", &self.parent_class)
            .finish()
    }
}

unsafe impl<T: ObjectSubclass> super::types::ClassStruct for ClassStruct<T> {
    type Type = T;
}

impl<T: ObjectSubclass> ops::Deref for ClassStruct<T> {
    type Target = <<T as ObjectSubclass>::ParentType as ObjectType>::RustClassType;

    fn deref(&self) -> &Self::Target {
        unsafe { &*(self as *const _ as *const Self::Target) }
    }
}

impl<T: ObjectSubclass> ops::DerefMut for ClassStruct<T> {
    fn deref_mut(&mut self) -> &mut Self::Target {
        unsafe { &mut *(self as *mut _ as *mut Self::Target) }
    }
}
<|endoftext|>


<commit_before>// Copyright 2013-2015, The Gtk-rs Project Developers.
// See the COPYRIGHT file at the top-level directory of this distribution.
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>

use ffi;
use glib::object::{Downcast, IsA};
use glib::translate::*;

use {TreeModel, TreeModelSort};

impl TreeModelSort {
    pub fn new<T: IsA<TreeModel>>(child_model: &T) -> TreeModelSort {
        skip_assert_initialized!();
        unsafe {
            TreeModel::from_glib_none(
                ffi::gtk_tree_model_sort_new_with_model(
                    child_model.to_glib_none().0)
                ).downcast_unchecked()
        }
    }
}
<commit_msg>Fix manual code<commit_after>// Copyright 2013-2015, The Gtk-rs Project Developers.
// See the COPYRIGHT file at the top-level directory of this distribution.
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>

use ffi;
use glib::Cast;
use glib::object::IsA;
use glib::translate::*;

use {TreeModel, TreeModelSort};

impl TreeModelSort {
    pub fn new<T: IsA<TreeModel>>(child_model: &T) -> TreeModelSort {
        skip_assert_initialized!();
        unsafe {
            TreeModel::from_glib_none(
                ffi::gtk_tree_model_sort_new_with_model(
                    child_model.as_ref().to_glib_none().0)
                ).unsafe_cast()
        }
    }
}
<|endoftext|>


<commit_before>use error::Result;
use evaluator::Evaluator;
use event::Event;
use top_level_event::TopLevelEvent;
use sass::rule::SassRule;
use sass::variable::SassVariable;
use sass::number_value::NumberValue;
use sass::value_part::ValuePart;
use std::collections::HashMap;
use std::borrow::Cow;

pub struct VariableMapper<'vm, I> {
    tokenizer: I,
    variables: HashMap<String, ValuePart<'vm>>,
}

impl<'vm, I> VariableMapper<'vm, I> {
    pub fn new(tokenizer: I) -> VariableMapper<'vm, I> {
        VariableMapper {
            tokenizer: tokenizer,
            variables: HashMap::new(),
        }
    }

    fn replace_children_in_scope<'b>(&self, children: Vec<Event<'b>>, mut local_variables: HashMap<String, ValuePart<'b>>) -> Result<Vec<Event<'b>>> {
        children.into_iter().filter_map(|c|
            match c {
                Event::Variable(SassVariable { name, value }) => {
                    let val = match owned_evaluated_value(value, &local_variables) {
                        Ok(v) => v,
                        Err(e) => return Some(Err(e)),
                    };
                    local_variables.insert((*name).to_string(), val);
                    None
                },
                Event::UnevaluatedProperty(name, value) => {
                    let mut ev = Evaluator::new_from_string(&value);
                    let ev_res = match ev.evaluate(&local_variables) {
                        Ok(s)  => s.into_owned(),
                        Err(e) => return Some(Err(e)),
                    };

                    Some(Ok(Event::Property(
                        name,
                        ev_res,
                    )))
                },
                Event::ChildRule(rule) => {
                    let res = match self.replace_children_in_scope(
                        rule.children, local_variables.clone()
                    ) {
                        Ok(children) => children,
                        Err(e) => return Some(Err(e)),
                    };
                    Some(Ok(Event::ChildRule(SassRule {
                        children: res, ..rule
                    })))
                },
                other => Some(Ok(other))
            }
        ).collect()
    }
}

fn owned_evaluated_value<'a>(
    value: Cow<'a, str>,
    variables: &HashMap<String, ValuePart<'a>>) -> Result<ValuePart<'a>> {

    let value_part = match value {
        Cow::Borrowed(v) => {
            try!(Evaluator::new_from_string(&v).evaluate(variables))
        },
        Cow::Owned(v) => {
            try!(Evaluator::new_from_string(&v).evaluate(variables)).into_owned()
        },
    };
    Ok(match value_part {
        ValuePart::Number(nv) => ValuePart::Number(NumberValue { computed: true, ..nv }),
        other => other,
    })
}

impl<'a, I> Iterator for VariableMapper<'a, I>
    where I: Iterator<Item = Result<TopLevelEvent<'a>>>
{
    type Item = Result<TopLevelEvent<'a>>;

    fn next(&mut self) -> Option<Result<TopLevelEvent<'a>>> {
        match self.tokenizer.next() {
            Some(Ok(TopLevelEvent::Variable(SassVariable { name, value }))) => {
                let val = match owned_evaluated_value(value, &self.variables) {
                    Ok(v) => v,
                    Err(e) => return Some(Err(e)),
                };
                self.variables.insert((*name).to_string(), val);
                self.next()
            },
            Some(Ok(TopLevelEvent::Rule(sass_rule))) => {
                let replaced = match self.replace_children_in_scope(
                    sass_rule.children, self.variables.clone()
                ) {
                    Ok(children) => children,
                    Err(e) => return Some(Err(e)),
                };

                Some(Ok(TopLevelEvent::Rule(SassRule {
                    children: replaced, ..sass_rule
                })))
            },
            other => other,
        }
    }
}
<commit_msg>replace_children_in_scope can be independent of VariableMapper<commit_after>use error::Result;
use evaluator::Evaluator;
use event::Event;
use top_level_event::TopLevelEvent;
use sass::rule::SassRule;
use sass::variable::SassVariable;
use sass::number_value::NumberValue;
use sass::value_part::ValuePart;
use std::collections::HashMap;
use std::borrow::Cow;

pub struct VariableMapper<'vm, I> {
    tokenizer: I,
    variables: HashMap<String, ValuePart<'vm>>,
}

impl<'vm, I> VariableMapper<'vm, I> {
    pub fn new(tokenizer: I) -> VariableMapper<'vm, I> {
        VariableMapper {
            tokenizer: tokenizer,
            variables: HashMap::new(),
        }
    }
}

impl<'a, I> Iterator for VariableMapper<'a, I>
    where I: Iterator<Item = Result<TopLevelEvent<'a>>>
{
    type Item = Result<TopLevelEvent<'a>>;

    fn next(&mut self) -> Option<Result<TopLevelEvent<'a>>> {
        match self.tokenizer.next() {
            Some(Ok(TopLevelEvent::Variable(SassVariable { name, value }))) => {
                let val = match owned_evaluated_value(value, &self.variables) {
                    Ok(v) => v,
                    Err(e) => return Some(Err(e)),
                };
                self.variables.insert((*name).to_string(), val);
                self.next()
            },
            Some(Ok(TopLevelEvent::Rule(sass_rule))) => {
                let replaced = match replace_children_in_scope(
                    sass_rule.children, self.variables.clone()
                ) {
                    Ok(children) => children,
                    Err(e) => return Some(Err(e)),
                };

                Some(Ok(TopLevelEvent::Rule(SassRule {
                    children: replaced, ..sass_rule
                })))
            },
            other => other,
        }
    }
}

fn replace_children_in_scope<'b>(children: Vec<Event<'b>>, mut local_variables: HashMap<String, ValuePart<'b>>) -> Result<Vec<Event<'b>>> {
    children.into_iter().filter_map(|c|
        match c {
            Event::Variable(SassVariable { name, value }) => {
                let val = match owned_evaluated_value(value, &local_variables) {
                    Ok(v) => v,
                    Err(e) => return Some(Err(e)),
                };
                local_variables.insert((*name).to_string(), val);
                None
            },
            Event::UnevaluatedProperty(name, value) => {
                let mut ev = Evaluator::new_from_string(&value);
                let ev_res = match ev.evaluate(&local_variables) {
                    Ok(s)  => s.into_owned(),
                    Err(e) => return Some(Err(e)),
                };

                Some(Ok(Event::Property(
                    name,
                    ev_res,
                )))
            },
            Event::ChildRule(rule) => {
                let res = match replace_children_in_scope(
                    rule.children, local_variables.clone()
                ) {
                    Ok(children) => children,
                    Err(e) => return Some(Err(e)),
                };
                Some(Ok(Event::ChildRule(SassRule {
                    children: res, ..rule
                })))
            },
            other => Some(Ok(other))
        }
    ).collect()
}

fn owned_evaluated_value<'a>(
    value: Cow<'a, str>,
    variables: &HashMap<String, ValuePart<'a>>) -> Result<ValuePart<'a>> {

    let value_part = match value {
        Cow::Borrowed(v) => {
            try!(Evaluator::new_from_string(&v).evaluate(variables))
        },
        Cow::Owned(v) => {
            try!(Evaluator::new_from_string(&v).evaluate(variables)).into_owned()
        },
    };
    Ok(match value_part {
        ValuePart::Number(nv) => ValuePart::Number(NumberValue { computed: true, ..nv }),
        other => other,
    })
}
<|endoftext|>