<commit_before>use error::*;
use flate2::Compression;
use flate2::write::GzEncoder;
use modules::pkg::ar;
use std::fs::File;
use std::io::prelude::*;
use std::path::{Path, PathBuf};
use tar;
use time;

#[cfg(unix)]
use std::os::unix::fs::MetadataExt;

/// An enum of allowed package target architectures.
pub enum Arch {
    X86,
    X64,
    All,
}

impl ToString for Arch {
    fn to_string(&self) -> String {
        match *self {
            Arch::X86 => "i386",
            Arch::X64 => "amd64",
            Arch::All => "all",
        }.to_string()
    }
}

/// An enum of allowed package priorities.
pub enum Priority {
    Essential,
    Extra,
    Important,
    Optional,
    Required,
    Standard,
}

impl ToString for Priority {
    fn to_string(&self) -> String {
        match *self {
            Priority::Essential => "essential",
            Priority::Extra => "extra",
            Priority::Important => "important",
            Priority::Optional => "optional",
            Priority::Required => "required",
            Priority::Standard => "standard",
        }.to_string()
    }
}

/// A representation of a Debian binary package file.
pub struct Package {
    pub name: String,
    pub files: Vec<(PathBuf, PathBuf)>,
    pub priority: Priority,
    pub section: String,
    pub depends: Vec<(String, String)>,
    pub maintainer: String,
    pub arch: Arch,
    pub version: String,
    pub homepage: Option<String>,
    pub short_desc: String,
    pub long_desc: Option<String>,
}

impl Package {
    /// Writes a Debian package to a stream.
    pub fn write_to<T: Write>(&self, stream: &mut T) {
        let mut ar = ar::Ar::new(stream).unwrap();

        ar.append(ar::Entry::new("2.0\n".as_bytes())
            .name("debian-binary")
        ).unwrap();

        let control_archive = self.create_control_archive();
        ar.append(ar::Entry::new(&control_archive as &[u8])
            .name("control.tar.gz")
        ).unwrap();

        let data_archive = self.create_data_archive();
        ar.append(ar::Entry::new(&data_archive as &[u8])
            .name("data.tar.gz")
        ).unwrap();
    }

    /// Creates the control archive file.
    fn create_control_archive(&self) -> Vec<u8> {
        let mut buffer = Vec::new();

        {
            // Create a tar wrapped in a gzip encoder.
            let encoder = GzEncoder::new(&mut buffer, Compression::Default);
            let archive = tar::Archive::new(encoder);

            let control_file = self.create_control_file();

            let mut header = tar::Header::new();
            header.set_path("control").unwrap();
            header.set_size(control_file.len() as u64);
            header.set_mode(0o644);
            header.set_mtime(time::now().to_timespec().sec as u64);
            header.set_cksum();
            archive.append(&header, &mut control_file.as_bytes()).unwrap();

            archive.finish().unwrap();
            archive.into_inner().finish().unwrap();
        }

        buffer
    }

    /// Creates the data archive file.
    fn create_data_archive(&self) -> Vec<u8> {
        let mut buffer = Vec::new();

        {
            // Create a tar wrapped in a gzip encoder.
            let encoder = GzEncoder::new(&mut buffer, Compression::Default);
            let archive = tar::Archive::new(encoder);

            for paths in &self.files {
                let mut file = File::open(&paths.0).unwrap();

                let mut header = tar::Header::new();
                header.set_metadata(&paths.0.metadata().unwrap());
                header.set_path(&paths.1).unwrap();
                header.set_mode(0o755);
                header.set_uid(0);
                header.set_gid(0);
                header.set_cksum();
                archive.append(&header, &mut file).unwrap();
            }

            archive.finish().unwrap();
            archive.into_inner().finish().unwrap();
        }

        buffer
    }

    /// Generates a control file from the package metadata.
    fn create_control_file(&self) -> String {
        let mut string = String::new();

        string.push_str(&format!("Package: {}\n", self.name));
        string.push_str(&format!("Priority: {}\n", self.priority.to_string()));
        string.push_str(&format!("Section: {}\n", self.section));
        string.push_str(&format!("Installed-Size: {}\n", self.get_size()));

        if !self.depends.is_empty() {
            string.push_str("Depends: ");
            let mut start = true;

            for &(ref package, ref version) in &self.depends {
                if !start {
                    string.push_str(", ");
                } else {
                    start = false;
                }

                string.push_str(&format!("{} ({})", package, version));
            }

            string.push_str("\n");
        }

        string.push_str(&format!("Maintainer: {}\n", self.maintainer));
        string.push_str(&format!("Architecture: {}\n", self.arch.to_string()));
        string.push_str(&format!("Version: {}\n", self.version));

        if let Some(ref homepage) = self.homepage {
            string.push_str(&format!("Homepage: {}\n", homepage));
        }

        string.push_str(&format!("Description: {}\n", self.short_desc));

        if let Some(ref long_desc) = self.long_desc {
            for line in long_desc.lines() {
                if line.len() == 0 {
                    string.push_str(" .\n");
                } else {
                    string.push_str(&format!(" {}\n", line));
                }
            }
        }

        string
    }

    /// Calculates the installed size of the package based on the input files.
    fn get_size(&self) -> u64 {
        let mut size = 0;

        if cfg!(unix) {
            for paths in &self.files {
                size += paths.0.metadata().unwrap().size();
            }
        }

        (size / 1024) as u64
    }
}

/// A builder object for sequentially creating a package.
pub struct PackageBuilder {
    name: Option<String>,
    files: Vec<(PathBuf, PathBuf)>,
    priority: Priority,
    section: String,
    depends: Vec<(String, String)>,
    maintainer: Option<String>,
    arch: Arch,
    version: Option<String>,
    homepage: Option<String>,
    short_desc: Option<String>,
    long_desc: Option<String>,
}

impl PackageBuilder {
    /// Creates a new package builder.
    pub fn new() -> PackageBuilder {
        PackageBuilder {
            name: None,
            files: Vec::new(),
            priority: Priority::Optional,
            section: "misc".to_string(),
            depends: Vec::new(),
            maintainer: None,
            arch: Arch::All,
            version: None,
            homepage: None,
            short_desc: None,
            long_desc: None,
        }
    }

    /// Attempts to build a package object from the current data.
    ///
    /// If the required fields have not been set, an error will be returned.
    pub fn build(self) -> Result<Package, Error> {
        if self.name.is_none() {
            return Err(Error::new_desc("the package name must be specified"));
        }

        if self.maintainer.is_none() {
            return Err(Error::new_desc("the package maintainer must be specified"));
        }

        if self.version.is_none() {
            return Err(Error::new_desc("the package version must be specified"));
        }

        if self.short_desc.is_none() {
            return Err(Error::new_desc("the package short description must be specified"));
        }

        Ok(Package {
            name: self.name.unwrap(),
            files: self.files,
            priority: self.priority,
            section: self.section,
            depends: self.depends,
            maintainer: self.maintainer.unwrap(),
            arch: self.arch,
            version: self.version.unwrap(),
            homepage: self.homepage,
            short_desc: self.short_desc.unwrap(),
            long_desc: self.long_desc,
        })
    }

    /// Sets the package name.
    pub fn name(&mut self, name: &str) -> &mut Self {
        self.name = Some(name.to_string());
        self
    }

    /// Adds a file to the package.
    pub fn add_file(&mut self, source: &Path, destination: &Path) -> &mut Self {
        self.files.push((source.to_path_buf(), destination.to_path_buf()));
        self
    }

    /// Sets the package priority.
    pub fn priority(&mut self, priority: Priority) -> &mut Self {
        self.priority = priority;
        self
    }

    /// Sets the package section name.
    pub fn section(&mut self, section: &str) -> &mut Self {
        self.section = section.to_string();
        self
    }

    /// Adds a package dependency.
    pub fn add_depends(&mut self, depends: (&str, &str)) -> &mut Self {
        self.depends.push((depends.0.to_string(), depends.1.to_string()));
        self
    }

    /// Sets the package maintainer.
    pub fn maintainer(&mut self, maintainer: &str) -> &mut Self {
        self.maintainer = Some(maintainer.to_string());
        self
    }

    /// Sets the package target architecture.
    pub fn arch(&mut self, arch: Arch) -> &mut Self {
        self.arch = arch;
        self
    }

    /// Sets the package version.
    pub fn version(&mut self, version: &str) -> &mut Self {
        self.version = Some(version.to_string());
        self
    }

    /// Sets the package homepage.
    pub fn homepage(&mut self, homepage: &str) -> &mut Self {
        self.homepage = Some(homepage.to_string());
        self
    }

    /// Sets the package short description.
    pub fn short_desc(&mut self, short_desc: &str) -> &mut Self {
        self.short_desc = Some(short_desc.to_string());
        self
    }

    /// Sets the package long description.
    pub fn long_desc(&mut self, long_desc: &str) -> &mut Self {
        self.long_desc = Some(long_desc.to_string());
        self
    }
}
<commit_msg>Fix compilation on Windows<commit_after>use error::*;
use flate2::Compression;
use flate2::write::GzEncoder;
use modules::pkg::ar;
use std::fs::File;
use std::io::prelude::*;
use std::path::{Path, PathBuf};
use tar;
use time;

#[cfg(unix)]
use std::os::unix::fs::MetadataExt;

/// An enum of allowed package target architectures.
pub enum Arch {
    X86,
    X64,
    All,
}

impl ToString for Arch {
    fn to_string(&self) -> String {
        match *self {
            Arch::X86 => "i386",
            Arch::X64 => "amd64",
            Arch::All => "all",
        }.to_string()
    }
}

/// An enum of allowed package priorities.
pub enum Priority {
    Essential,
    Extra,
    Important,
    Optional,
    Required,
    Standard,
}

impl ToString for Priority {
    fn to_string(&self) -> String {
        match *self {
            Priority::Essential => "essential",
            Priority::Extra => "extra",
            Priority::Important => "important",
            Priority::Optional => "optional",
            Priority::Required => "required",
            Priority::Standard => "standard",
        }.to_string()
    }
}

/// A representation of a Debian binary package file.
pub struct Package {
    pub name: String,
    pub files: Vec<(PathBuf, PathBuf)>,
    pub priority: Priority,
    pub section: String,
    pub depends: Vec<(String, String)>,
    pub maintainer: String,
    pub arch: Arch,
    pub version: String,
    pub homepage: Option<String>,
    pub short_desc: String,
    pub long_desc: Option<String>,
}

impl Package {
    /// Writes a Debian package to a stream.
    pub fn write_to<T: Write>(&self, stream: &mut T) {
        let mut ar = ar::Ar::new(stream).unwrap();

        ar.append(ar::Entry::new("2.0\n".as_bytes())
            .name("debian-binary")
        ).unwrap();

        let control_archive = self.create_control_archive();
        ar.append(ar::Entry::new(&control_archive as &[u8])
            .name("control.tar.gz")
        ).unwrap();

        let data_archive = self.create_data_archive();
        ar.append(ar::Entry::new(&data_archive as &[u8])
            .name("data.tar.gz")
        ).unwrap();
    }

    /// Creates the control archive file.
    fn create_control_archive(&self) -> Vec<u8> {
        let mut buffer = Vec::new();

        {
            // Create a tar wrapped in a gzip encoder.
            let encoder = GzEncoder::new(&mut buffer, Compression::Default);
            let archive = tar::Archive::new(encoder);

            let control_file = self.create_control_file();

            let mut header = tar::Header::new();
            header.set_path("control").unwrap();
            header.set_size(control_file.len() as u64);
            header.set_mode(0o644);
            header.set_mtime(time::now().to_timespec().sec as u64);
            header.set_cksum();
            archive.append(&header, &mut control_file.as_bytes()).unwrap();

            archive.finish().unwrap();
            archive.into_inner().finish().unwrap();
        }

        buffer
    }

    /// Creates the data archive file.
    fn create_data_archive(&self) -> Vec<u8> {
        let mut buffer = Vec::new();

        {
            // Create a tar wrapped in a gzip encoder.
            let encoder = GzEncoder::new(&mut buffer, Compression::Default);
            let archive = tar::Archive::new(encoder);

            for paths in &self.files {
                let mut file = File::open(&paths.0).unwrap();

                let mut header = tar::Header::new();
                header.set_metadata(&paths.0.metadata().unwrap());
                header.set_path(&paths.1).unwrap();
                header.set_mode(0o755);
                header.set_uid(0);
                header.set_gid(0);
                header.set_cksum();
                archive.append(&header, &mut file).unwrap();
            }

            archive.finish().unwrap();
            archive.into_inner().finish().unwrap();
        }

        buffer
    }

    /// Generates a control file from the package metadata.
    fn create_control_file(&self) -> String {
        let mut string = String::new();

        string.push_str(&format!("Package: {}\n", self.name));
        string.push_str(&format!("Priority: {}\n", self.priority.to_string()));
        string.push_str(&format!("Section: {}\n", self.section));
        string.push_str(&format!("Installed-Size: {}\n", self.get_size()));

        if !self.depends.is_empty() {
            string.push_str("Depends: ");
            let mut start = true;

            for &(ref package, ref version) in &self.depends {
                if !start {
                    string.push_str(", ");
                } else {
                    start = false;
                }

                string.push_str(&format!("{} ({})", package, version));
            }

            string.push_str("\n");
        }

        string.push_str(&format!("Maintainer: {}\n", self.maintainer));
        string.push_str(&format!("Architecture: {}\n", self.arch.to_string()));
        string.push_str(&format!("Version: {}\n", self.version));

        if let Some(ref homepage) = self.homepage {
            string.push_str(&format!("Homepage: {}\n", homepage));
        }

        string.push_str(&format!("Description: {}\n", self.short_desc));

        if let Some(ref long_desc) = self.long_desc {
            for line in long_desc.lines() {
                if line.len() == 0 {
                    string.push_str(" .\n");
                } else {
                    string.push_str(&format!(" {}\n", line));
                }
            }
        }

        string
    }

    /// Calculates the installed size of the package based on the input files.
    #[cfg(unix)]
    fn get_size(&self) -> u64 {
        let mut size = 0;

        for paths in &self.files {
            size += paths.0.metadata().unwrap().size();
        }

        (size / 1024) as u64
    }

    #[cfg(windows)]
    fn get_size(&self) -> u64 {
        0
    }
}

/// A builder object for sequentially creating a package.
pub struct PackageBuilder {
    name: Option<String>,
    files: Vec<(PathBuf, PathBuf)>,
    priority: Priority,
    section: String,
    depends: Vec<(String, String)>,
    maintainer: Option<String>,
    arch: Arch,
    version: Option<String>,
    homepage: Option<String>,
    short_desc: Option<String>,
    long_desc: Option<String>,
}

impl PackageBuilder {
    /// Creates a new package builder.
    pub fn new() -> PackageBuilder {
        PackageBuilder {
            name: None,
            files: Vec::new(),
            priority: Priority::Optional,
            section: "misc".to_string(),
            depends: Vec::new(),
            maintainer: None,
            arch: Arch::All,
            version: None,
            homepage: None,
            short_desc: None,
            long_desc: None,
        }
    }

    /// Attempts to build a package object from the current data.
    ///
    /// If the required fields have not been set, an error will be returned.
    pub fn build(self) -> Result<Package, Error> {
        if self.name.is_none() {
            return Err(Error::new_desc("the package name must be specified"));
        }

        if self.maintainer.is_none() {
            return Err(Error::new_desc("the package maintainer must be specified"));
        }

        if self.version.is_none() {
            return Err(Error::new_desc("the package version must be specified"));
        }

        if self.short_desc.is_none() {
            return Err(Error::new_desc("the package short description must be specified"));
        }

        Ok(Package {
            name: self.name.unwrap(),
            files: self.files,
            priority: self.priority,
            section: self.section,
            depends: self.depends,
            maintainer: self.maintainer.unwrap(),
            arch: self.arch,
            version: self.version.unwrap(),
            homepage: self.homepage,
            short_desc: self.short_desc.unwrap(),
            long_desc: self.long_desc,
        })
    }

    /// Sets the package name.
    pub fn name(&mut self, name: &str) -> &mut Self {
        self.name = Some(name.to_string());
        self
    }

    /// Adds a file to the package.
    pub fn add_file(&mut self, source: &Path, destination: &Path) -> &mut Self {
        self.files.push((source.to_path_buf(), destination.to_path_buf()));
        self
    }

    /// Sets the package priority.
    pub fn priority(&mut self, priority: Priority) -> &mut Self {
        self.priority = priority;
        self
    }

    /// Sets the package section name.
    pub fn section(&mut self, section: &str) -> &mut Self {
        self.section = section.to_string();
        self
    }

    /// Adds a package dependency.
    pub fn add_depends(&mut self, depends: (&str, &str)) -> &mut Self {
        self.depends.push((depends.0.to_string(), depends.1.to_string()));
        self
    }

    /// Sets the package maintainer.
    pub fn maintainer(&mut self, maintainer: &str) -> &mut Self {
        self.maintainer = Some(maintainer.to_string());
        self
    }

    /// Sets the package target architecture.
    pub fn arch(&mut self, arch: Arch) -> &mut Self {
        self.arch = arch;
        self
    }

    /// Sets the package version.
    pub fn version(&mut self, version: &str) -> &mut Self {
        self.version = Some(version.to_string());
        self
    }

    /// Sets the package homepage.
    pub fn homepage(&mut self, homepage: &str) -> &mut Self {
        self.homepage = Some(homepage.to_string());
        self
    }

    /// Sets the package short description.
    pub fn short_desc(&mut self, short_desc: &str) -> &mut Self {
        self.short_desc = Some(short_desc.to_string());
        self
    }

    /// Sets the package long description.
    pub fn long_desc(&mut self, long_desc: &str) -> &mut Self {
        self.long_desc = Some(long_desc.to_string());
        self
    }
}
<|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),
}

#[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, Default, Deserialize, Serialize)]
pub struct StartMessage {
    pub task_ids: Vec<usize>,
    pub group: String,
    pub all: bool,
    pub children: bool,
}

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

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

#[derive(PartialEq, Clone, Debug, Default, Deserialize, Serialize)]
pub struct PauseMessage {
    pub task_ids: Vec<usize>,
    pub group: String,
    pub wait: bool,
    pub all: 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, Default, 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: TaskSelection enum in messages<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 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())
}
<|endoftext|>


<commit_before>use crate::noise_fns::NoiseFn;
use std::cell::{Cell, RefCell};

/// Noise function that caches the last output value generated by the source
/// function.
///
/// If the input coordinates passed to `Cache::get` are equal to the previous
/// call, the function returns the cached result of the previous call to
/// `Source::get`. Otherwise, `Source::get` is called with the new coordinates,
/// overwriting the cache with the result, and returning the result to the
/// caller.
///
/// Caching a noise function is useful if it is used as a source function for
/// multiple noise functions. If a source function is not cached, the source
/// function will redundantly calculate the same output value once for each
/// noise function in which it is included.
#[derive(Clone, Debug)]
pub struct Cache<Source> {
    /// Outputs the value to be cached.
    pub source: Source,

    value: Cell<Option<f64>>,

    point: RefCell<Vec<f64>>,
}

impl<Source> Cache<Source> {
    pub fn new(source: Source) -> Self {
        Cache {
            source,
            value: Cell::new(None),
            point: RefCell::new(Vec::new()),
        }
    }
}

impl<Source> NoiseFn<f64, 2> for Cache<Source>
where
    Source: NoiseFn<f64, 2>,
{
    fn get(&self, point: [f64; 2]) -> f64 {
        match self.value.get() {
            Some(value) if quick_eq(&*self.point.borrow(), &point) => value,
            Some(_) | None => {
                let value = self.source.get(point);
                self.value.set(Some(value));

                let mut cached_point = self.point.borrow_mut();
                cached_point.clear();
                cached_point.extend_from_slice(&point);

                value
            }
        }
    }
}

impl<Source> NoiseFn<f64, 3> for Cache<Source>
where
    Source: NoiseFn<f64, 3>,
{
    fn get(&self, point: [f64; 3]) -> f64 {
        match self.value.get() {
            Some(value) if quick_eq(&*self.point.borrow(), &point) => value,
            Some(_) | None => {
                let value = self.source.get(point);
                self.value.set(Some(value));

                let mut cached_point = self.point.borrow_mut();
                cached_point.clear();
                cached_point.extend_from_slice(&point);

                value
            }
        }
    }
}

impl<Source> NoiseFn<f64, 4> for Cache<Source>
where
    Source: NoiseFn<f64, 4>,
{
    fn get(&self, point: [f64; 4]) -> f64 {
        match self.value.get() {
            Some(value) if quick_eq(&*self.point.borrow(), &point) => value,
            Some(_) | None => {
                let value = self.source.get(point);
                self.value.set(Some(value));

                let mut cached_point = self.point.borrow_mut();
                cached_point.clear();
                cached_point.extend_from_slice(&point);

                value
            }
        }
    }
}

fn quick_eq(a: &[f64], b: &[f64]) -> bool {
    assert_eq!(a.len(), b.len());

    a.iter().eq(b)
}
<commit_msg>Second pass: Cache<commit_after>use crate::noise_fns::NoiseFn;
use std::cell::{Cell, RefCell};

/// Noise function that caches the last output value generated by the source
/// function.
///
/// If the input coordinates passed to `Cache::get` are equal to the previous
/// call, the function returns the cached result of the previous call to
/// `Source::get`. Otherwise, `Source::get` is called with the new coordinates,
/// overwriting the cache with the result, and returning the result to the
/// caller.
///
/// Caching a noise function is useful if it is used as a source function for
/// multiple noise functions. If a source function is not cached, the source
/// function will redundantly calculate the same output value once for each
/// noise function in which it is included.
#[derive(Clone, Debug)]
pub struct Cache<Source> {
    /// Outputs the value to be cached.
    pub source: Source,

    value: Cell<Option<f64>>,

    point: RefCell<Vec<f64>>,
}

impl<Source> Cache<Source> {
    pub fn new(source: Source) -> Self {
        Cache {
            source,
            value: Cell::new(None),
            point: RefCell::new(Vec::new()),
        }
    }
}

impl<Source, const DIM: usize> NoiseFn<f64, DIM> for Cache<Source>
where
    Source: NoiseFn<f64, DIM>,
{
    fn get(&self, point: [f64; DIM]) -> f64 {
        match self.value.get() {
            Some(value) if quick_eq(&*self.point.borrow(), &point) => value,
            Some(_) | None => {
                let value = self.source.get(point);
                self.value.set(Some(value));

                let mut cached_point = self.point.borrow_mut();
                cached_point.clear();
                cached_point.extend_from_slice(&point);

                value
            }
        }
    }
}

fn quick_eq(a: &[f64], b: &[f64]) -> bool {
    assert_eq!(a.len(), b.len());

    a.iter().eq(b)
}
<|endoftext|>


<commit_before>//! Group records by a key, and apply a reduction function.
//!
//! The `group` operators act on data that can be viewed as pairs `(key, val)`. They group records
//! with the same key, and apply user supplied functions to the key and a list of values, which are
//! expected to populate a list of output values.
//!
//! Several variants of `group` exist which allow more precise control over how grouping is done.
//! For example, the `_by` suffixed variants take arbitrary data, but require a key-value selector
//! to be applied to each record. The `_u` suffixed variants use unsigned integers as keys, and
//! will use a dense array rather than a `HashMap` to store their keys.
//!
//! The list of values are presented as an iterator which internally merges sorted lists of values.
//! This ordering can be exploited in several cases to avoid computation when only the first few
//! elements are required.

use std::default::Default;

use timely::dataflow::*;
use timely::dataflow::operators::Unary;
use timely::dataflow::channels::pact::Pipeline;
use timely_sort::Unsigned;

use ::{Data, Collection, Diff};
use hashable::{Hashable, UnsignedWrapper};
use collection::AsCollection;
use operators::arrange::{Arrange, Arranged, ArrangeBySelf};
use lattice::TotalOrder;
use trace::{BatchReader, Cursor, Trace, TraceReader};
use trace::implementations::ord::OrdKeySpine as DefaultKeyTrace;

/// Extension trait for the `count` differential dataflow method.
pub trait CountTotal<G: Scope, K: Data, R: Diff> where G::Timestamp: TotalOrder+Ord {
    /// Counts the number of occurrences of each element.
    ///
    /// # Examples
    ///
    /// ```
    /// #
    /// extern crate timely;
    /// extern crate differential_dataflow;
    ///
    /// use differential_dataflow::input::Input;
    /// use differential_dataflow::operators::CountTotal;
    ///
    /// fn main() {
    ///     ::timely::example(|scope| {
    ///         // report the number of occurrences of each key
    ///         scope.new_collection_from(1 .. 10).1
    ///              .map(|x| x / 3)
    ///              .count_total();
    ///     });
    /// }
    /// ```
    fn count_total(&self) -> Collection<G, (K, R), isize>;
    /// Counts the number of occurrences of each element.
    ///
    /// This method is a specialization for when the key is an unsigned integer fit for distributing the data.
    ///
    /// # Examples
    ///
    /// ```
    /// #
    /// extern crate timely;
    /// extern crate differential_dataflow;
    ///
    /// use differential_dataflow::input::Input;
    /// use differential_dataflow::operators::CountTotal;
    ///
    /// fn main() {
    ///     ::timely::example(|scope| {
    ///         // report the number of occurrences of each key
    ///         scope.new_collection_from(1 .. 10u32).1
    ///              .map(|x| x / 3)
    ///              .count_total_u();
    ///     });
    /// }
    /// ```
    fn count_total_u(&self) -> Collection<G, (K, R), isize> where K: Unsigned+Copy;
}

impl<G: Scope, K: Data+Default+Hashable, R: Diff> CountTotal<G, K, R> for Collection<G, K, R>
where G::Timestamp: TotalOrder+Ord {
    fn count_total(&self) -> Collection<G, (K, R), isize> {
        self.arrange_by_self()
            .count_total_core()
            .map(|(k,c)| (k.item, c))
    }
    fn count_total_u(&self) -> Collection<G, (K, R), isize> where K: Unsigned+Copy {
        self.map(|k| (UnsignedWrapper::from(k), ()))
            .arrange(DefaultKeyTrace::new())
            .count_total_core()
            .map(|(k,c)| (k.item, c))
    }
}

/// Extension trait for the `group_arranged` differential dataflow method.
pub trait CountTotalCore<G: Scope, K: Data, R: Diff> where G::Timestamp: TotalOrder+Ord {
    /// Applies `group` to arranged data, and returns an arrangement of output data.
    ///
    /// This method is used by the more ergonomic `group`, `distinct`, and `count` methods, although
    /// it can be very useful if one needs to manually attach and re-use existing arranged collections.
    ///
    /// # Examples
    ///
    /// ```
    /// #
    /// extern crate timely;
    /// extern crate differential_dataflow;
    ///
    /// use differential_dataflow::input::Input;
    /// use differential_dataflow::operators::arrange::Arrange;
    /// use differential_dataflow::operators::count::CountTotalCore;
    /// use differential_dataflow::trace::Trace;
    /// use differential_dataflow::trace::implementations::ord::OrdKeySpine;
    /// use differential_dataflow::hashable::OrdWrapper;
    ///
    /// fn main() {
    ///     ::timely::example(|scope| {
    ///
    ///         // wrap and order input, then group manually.
    ///         scope.new_collection_from(1 .. 10u32).1
    ///              .map(|x| (OrdWrapper { item: x / 3 }, ()))
    ///              .arrange(OrdKeySpine::new())
    ///              .count_total_core();
    ///     });
    /// }
    /// ```
    fn count_total_core(&self) -> Collection<G, (K, R), isize>;
}

impl<G: Scope, K: Data, R: Diff, T1> CountTotalCore<G, K, R> for Arranged<G, K, (), R, T1>
where
    G::Timestamp: TotalOrder+Ord,
    T1: TraceReader<K, (), G::Timestamp, R>+Clone+'static,
    T1::Batch: BatchReader<K, (), G::Timestamp, R> {

    fn count_total_core(&self) -> Collection<G, (K, R), isize> {

        let mut trace = self.trace.clone();

        self.stream.unary_stream(Pipeline, "CountTotal", move |input, output| {

            input.for_each(|capability, batches| {

                let mut session = output.session(&capability);
                for batch in batches.drain(..).map(|x| x.item) {

                    let (mut batch_cursor, batch_storage) = batch.cursor();
                    let (mut trace_cursor, trace_storage) = trace.cursor_through(batch.lower()).unwrap();

                    while batch_cursor.key_valid(&batch_storage) {

                        let key: K = batch_cursor.key(&batch_storage).clone();
                        let mut count = R::zero();

                        trace_cursor.seek_key(&trace_storage, batch_cursor.key(&batch_storage));
                        if trace_cursor.key_valid(&trace_storage) && trace_cursor.key(&trace_storage) == batch_cursor.key(&batch_storage) {
                            trace_cursor.map_times(&trace_storage, |_, diff| count = count + diff);
                        }

                        batch_cursor.map_times(&batch_storage, |time, diff| {

                            if !count.is_zero() {
                                session.give(((key.clone(), count), time.clone(), -1));
                            }
                            count = count + diff;
                            if !count.is_zero() {
                                session.give(((key.clone(), count), time.clone(), 1));
                            }

                        });

                        batch_cursor.step_key(&batch_storage);
                    }

                    // tidy up the shared input trace.
                    trace.advance_by(batch.upper());
                    trace.distinguish_since(batch.upper());
                }
            });
        })
        .as_collection()
    }
}<commit_msg>remove clone of key<commit_after>//! Group records by a key, and apply a reduction function.
//!
//! The `group` operators act on data that can be viewed as pairs `(key, val)`. They group records
//! with the same key, and apply user supplied functions to the key and a list of values, which are
//! expected to populate a list of output values.
//!
//! Several variants of `group` exist which allow more precise control over how grouping is done.
//! For example, the `_by` suffixed variants take arbitrary data, but require a key-value selector
//! to be applied to each record. The `_u` suffixed variants use unsigned integers as keys, and
//! will use a dense array rather than a `HashMap` to store their keys.
//!
//! The list of values are presented as an iterator which internally merges sorted lists of values.
//! This ordering can be exploited in several cases to avoid computation when only the first few
//! elements are required.

use std::default::Default;

use timely::dataflow::*;
use timely::dataflow::operators::Unary;
use timely::dataflow::channels::pact::Pipeline;
use timely_sort::Unsigned;

use ::{Data, Collection, Diff};
use hashable::{Hashable, UnsignedWrapper};
use collection::AsCollection;
use operators::arrange::{Arrange, Arranged, ArrangeBySelf};
use lattice::TotalOrder;
use trace::{BatchReader, Cursor, Trace, TraceReader};
use trace::implementations::ord::OrdKeySpine as DefaultKeyTrace;

/// Extension trait for the `count` differential dataflow method.
pub trait CountTotal<G: Scope, K: Data, R: Diff> where G::Timestamp: TotalOrder+Ord {
    /// Counts the number of occurrences of each element.
    ///
    /// # Examples
    ///
    /// ```
    /// #
    /// extern crate timely;
    /// extern crate differential_dataflow;
    ///
    /// use differential_dataflow::input::Input;
    /// use differential_dataflow::operators::CountTotal;
    ///
    /// fn main() {
    ///     ::timely::example(|scope| {
    ///         // report the number of occurrences of each key
    ///         scope.new_collection_from(1 .. 10).1
    ///              .map(|x| x / 3)
    ///              .count_total();
    ///     });
    /// }
    /// ```
    fn count_total(&self) -> Collection<G, (K, R), isize>;
    /// Counts the number of occurrences of each element.
    ///
    /// This method is a specialization for when the key is an unsigned integer fit for distributing the data.
    ///
    /// # Examples
    ///
    /// ```
    /// #
    /// extern crate timely;
    /// extern crate differential_dataflow;
    ///
    /// use differential_dataflow::input::Input;
    /// use differential_dataflow::operators::CountTotal;
    ///
    /// fn main() {
    ///     ::timely::example(|scope| {
    ///         // report the number of occurrences of each key
    ///         scope.new_collection_from(1 .. 10u32).1
    ///              .map(|x| x / 3)
    ///              .count_total_u();
    ///     });
    /// }
    /// ```
    fn count_total_u(&self) -> Collection<G, (K, R), isize> where K: Unsigned+Copy;
}

impl<G: Scope, K: Data+Default+Hashable, R: Diff> CountTotal<G, K, R> for Collection<G, K, R>
where G::Timestamp: TotalOrder+Ord {
    fn count_total(&self) -> Collection<G, (K, R), isize> {
        self.arrange_by_self()
            .count_total_core()
            .map(|(k,c)| (k.item, c))
    }
    fn count_total_u(&self) -> Collection<G, (K, R), isize> where K: Unsigned+Copy {
        self.map(|k| (UnsignedWrapper::from(k), ()))
            .arrange(DefaultKeyTrace::new())
            .count_total_core()
            .map(|(k,c)| (k.item, c))
    }
}

/// Extension trait for the `group_arranged` differential dataflow method.
pub trait CountTotalCore<G: Scope, K: Data, R: Diff> where G::Timestamp: TotalOrder+Ord {
    /// Applies `group` to arranged data, and returns an arrangement of output data.
    ///
    /// This method is used by the more ergonomic `group`, `distinct`, and `count` methods, although
    /// it can be very useful if one needs to manually attach and re-use existing arranged collections.
    ///
    /// # Examples
    ///
    /// ```
    /// #
    /// extern crate timely;
    /// extern crate differential_dataflow;
    ///
    /// use differential_dataflow::input::Input;
    /// use differential_dataflow::operators::arrange::Arrange;
    /// use differential_dataflow::operators::count::CountTotalCore;
    /// use differential_dataflow::trace::Trace;
    /// use differential_dataflow::trace::implementations::ord::OrdKeySpine;
    /// use differential_dataflow::hashable::OrdWrapper;
    ///
    /// fn main() {
    ///     ::timely::example(|scope| {
    ///
    ///         // wrap and order input, then group manually.
    ///         scope.new_collection_from(1 .. 10u32).1
    ///              .map(|x| (OrdWrapper { item: x / 3 }, ()))
    ///              .arrange(OrdKeySpine::new())
    ///              .count_total_core();
    ///     });
    /// }
    /// ```
    fn count_total_core(&self) -> Collection<G, (K, R), isize>;
}

impl<G: Scope, K: Data, R: Diff, T1> CountTotalCore<G, K, R> for Arranged<G, K, (), R, T1>
where
    G::Timestamp: TotalOrder+Ord,
    T1: TraceReader<K, (), G::Timestamp, R>+Clone+'static,
    T1::Batch: BatchReader<K, (), G::Timestamp, R> {

    fn count_total_core(&self) -> Collection<G, (K, R), isize> {

        let mut trace = self.trace.clone();

        self.stream.unary_stream(Pipeline, "CountTotal", move |input, output| {

            input.for_each(|capability, batches| {

                let mut session = output.session(&capability);
                for batch in batches.drain(..).map(|x| x.item) {

                    let (mut batch_cursor, batch_storage) = batch.cursor();
                    let (mut trace_cursor, trace_storage) = trace.cursor_through(batch.lower()).unwrap();

                    while batch_cursor.key_valid(&batch_storage) {

                        let key = batch_cursor.key(&batch_storage);
                        let mut count = R::zero();

                        trace_cursor.seek_key(&trace_storage, key);
                        if trace_cursor.key_valid(&trace_storage) && trace_cursor.key(&trace_storage) == key {
                            trace_cursor.map_times(&trace_storage, |_, diff| count = count + diff);
                        }

                        batch_cursor.map_times(&batch_storage, |time, diff| {

                            if !count.is_zero() {
                                session.give(((key.clone(), count), time.clone(), -1));
                            }
                            count = count + diff;
                            if !count.is_zero() {
                                session.give(((key.clone(), count), time.clone(), 1));
                            }

                        });

                        batch_cursor.step_key(&batch_storage);
                    }

                    // tidy up the shared input trace.
                    trace.advance_by(batch.upper());
                    trace.distinguish_since(batch.upper());
                }
            });
        })
        .as_collection()
    }
}<|endoftext|>


<commit_before>// See LICENSE file for copyright and license details.

// Marauder is turn-based strategy game with hex grid.

extern mod glfw;
extern mod gl;
extern mod cgmath;

use std::f32::consts::{
  PI,
  FRAC_PI_2
};
use std::num::{
  sqrt,
  pow,
  abs,
  sin,
  cos
};
use std::option;
use gltypes = gl::types;
use cgmath::matrix::{
  Matrix,
  Mat4,
  Mat3,
  ToMat4
};
use cgmath::vector::{
  Vec3,
  Vec2,
  Vector
};
use cgmath::projection;
use cgmath::angle;

static mut MOUSE_POS: Vec2<f32> = Vec2{x: 0.0f32, y: 0.0};
static mut CAMERA_POS: Vec3<f32> = Vec3{x: 0.0f32, y: 0.0, z: 0.0};

static WIN_SIZE: Vec2<u32> = Vec2{x: 640, y: 480};

static VERTEX_SHADER_SRC: &'static str = "
  #version 130
  in vec3 position;
  uniform mat4 model_view_proj_matrix;
  void main() {
    vec4 v = vec4(position, 1);
    gl_Position = model_view_proj_matrix * v;
  }
";

static FRAGMENT_SHADER_SRC: &'static str = "
  #version 130
  out vec4 out_color;
  void main() {
    out_color = vec4(1.0, 1.0, 1.0, 1.0);
  }
";

pub struct Visualizer {
  hex_ex_radius: gltypes::GLfloat,
  hex_in_radius: gltypes::GLfloat
}

impl Visualizer {
  pub fn new() -> Visualizer {
    let hex_ex_radius: gltypes::GLfloat = 1.0 / 2.0;
    let hex_in_radius = sqrt(
        pow(hex_ex_radius, 2.0) - pow(hex_ex_radius / 2.0, 2.0));
    let visualizer = Visualizer {
      hex_ex_radius: hex_ex_radius,
      hex_in_radius: hex_in_radius
    };
    visualizer
  }

  pub fn dist(a: Vec2<f32>, b: Vec2<f32>) -> f32 {
    let dx = abs(b.x - a.x);
    let dy = abs(b.y - a.y);
    sqrt(pow(dx, 2.0) + pow(dy, 2.0))
  }

  pub fn v2i_to_v2f(&self, i: Vec2<i32>) -> Vec2<f32> {
    let v = Vec2 {
      x: (i.x as f32) * self.hex_in_radius * 2.0,
      y: (i.y as f32) * self.hex_ex_radius * 1.5
    };
    if i.y % 2 == 0 {
      Vec2{x: v.x + self.hex_in_radius, y: v.y}
    } else {
      v
    }
  }

  pub fn index_to_circle_vertex(&self, count: int, i: int) -> Vec2<f32> {
    let n = FRAC_PI_2 + 2.0 * PI * (i as f32) / (count as f32);
    Vec2{x: cos(n), y: sin(n)}.mul_s(self.hex_ex_radius)
  }

  pub fn index_to_hex_vertex(&self, i: int) -> Vec2<f32> {
    self.index_to_circle_vertex(6, i)
  }
}

fn compile_shader(src: &str, shader_type: gltypes::GLenum) -> gltypes::GLuint {
  let shader = gl::CreateShader(shader_type);
  unsafe {
    gl::ShaderSource(shader, 1, &src.to_c_str().unwrap(), std::ptr::null());
    gl::CompileShader(shader);

    let mut status = gl::FALSE as gltypes::GLint;
    gl::GetShaderiv(shader, gl::COMPILE_STATUS, &mut status);

    if status != (gl::TRUE as gltypes::GLint) {
      let mut len = 0;
      gl::GetShaderiv(shader, gl::INFO_LOG_LENGTH, &mut len);
      // subtract 1 to skip the trailing null character
      let mut buf = std::vec::from_elem(len as uint - 1, 0u8);
      gl::GetShaderInfoLog(shader, len, std::ptr::mut_null(),
        buf.as_mut_ptr() as *mut gltypes::GLchar
      );
      fail!("compile_shader(): " + std::str::raw::from_utf8(buf));
    }
  }
  shader
}

fn link_program(
    vertex_shader: gltypes::GLuint,
    fragment_shader: gltypes::GLuint
) -> gltypes::GLuint {
  let program = gl::CreateProgram();
  gl::AttachShader(program, vertex_shader);
  gl::AttachShader(program, fragment_shader);
  gl::LinkProgram(program);
  unsafe {
    let mut status = gl::FALSE as gltypes::GLint;
    gl::GetProgramiv(program, gl::LINK_STATUS, &mut status);

    if status != (gl::TRUE as gltypes::GLint) {
      let mut len: gltypes::GLint = 0;
      gl::GetProgramiv(program, gl::INFO_LOG_LENGTH, &mut len);
      // subtract 1 to skip the trailing null character
      let mut buf = std::vec::from_elem(len as uint - 1, 0u8);
      gl::GetProgramInfoLog(program, len, std::ptr::mut_null(),
        buf.as_mut_ptr() as *mut gltypes::GLchar
      );
      fail!("link_program(): " + std::str::raw::from_utf8(buf));
    }
  }
  program
}

fn tr(m: Mat4<f32>, v: Vec3<f32>) -> Mat4<f32> {
  let mut t = Mat4::<f32>::identity();
  *t.mut_cr(3, 0) = v.x;
  *t.mut_cr(3, 1) = v.y;
  *t.mut_cr(3, 2) = v.z;
  m.mul_m(&t)
}

fn rot_x(m: Mat4<f32>, angle: f32) -> Mat4<f32> {
  let r = Mat3::from_angle_x(angle::rad(angle)).to_mat4();
  m.mul_m(&r)
}

fn rot_y(m: Mat4<f32>, angle: f32) -> Mat4<f32> {
  let r = Mat3::from_angle_y(angle::rad(angle)).to_mat4();
  m.mul_m(&r)
}

pub struct Win {
  vertex_shader: gltypes::GLuint,
  fragment_shader: gltypes::GLuint,
  program: gltypes::GLuint,
  vertex_buffer_obj: gltypes::GLuint,
  matrix_id: gltypes::GLint,
  projection_matrix: Mat4<f32>,
  window: Option<glfw::Window>,
  vertex_data: ~[gltypes::GLfloat]
}

fn get_projection_matrix() -> Mat4<f32> {
  let fov = angle::deg(45.0f32);
  let ratio = 4.0 / 3.0;
  let display_range_min = 0.1;
  let display_range_max = 100.0;
  projection::perspective(
    fov, ratio, display_range_min, display_range_max
  )
}

impl Win {
  pub fn new() -> Win {
    let vertex_data = ~[
       0.0,  1.0, 0.0,
       2.0, -1.0, 0.0,
      -2.0, -1.0, 0.0,

      0.0,  1.0,  0.0,
      0.0, -1.0,  2.0,
      0.0, -1.0, -2.0
    ];
    let mut win = Win {
      vertex_shader: 0,
      fragment_shader: 0,
      program: 0,
      vertex_buffer_obj: 0,
      matrix_id: 0,
      projection_matrix: get_projection_matrix(),
      window: option::None,
      vertex_data: vertex_data
    };
    win.init_glfw();
    win.init_opengl();
    win.init_model();
    win
  }

  fn init_model(&mut self) {
    unsafe {
      // Create a Vertex Buffer Object
      gl::GenBuffers(1, &mut self.vertex_buffer_obj);
      gl::BindBuffer(gl::ARRAY_BUFFER, self.vertex_buffer_obj);

      // Copy vertex data to VBO
      let float_size = std::mem::size_of::<gltypes::GLfloat>();
      let vertices_ptr = (self.vertex_data.len() * float_size)
        as gltypes::GLsizeiptr;
      gl::BufferData(
        gl::ARRAY_BUFFER,
        vertices_ptr,
        std::cast::transmute(&self.vertex_data[0]),
        gl::STATIC_DRAW
      );

      gl::UseProgram(self.program);
      gl::BindFragDataLocation(
        self.program, 0, "out_color".to_c_str().unwrap());

      // Specify the layout of the vertex data
      let pos_attr = gl::GetAttribLocation(
        self.program, "position".to_c_str().unwrap()) as gltypes::GLuint;
      gl::EnableVertexAttribArray(pos_attr);

      let size = 3;
      let normalized = gl::FALSE;
      let stride = 0;
      gl::VertexAttribPointer(
        pos_attr,
        size,
        gl::FLOAT,
        normalized,
        stride,
        std::ptr::null()
      );

      self.matrix_id = gl::GetUniformLocation(
        self.program, "model_view_proj_matrix".to_c_str().unwrap()
      );
    }
  }

  fn init_glfw(&mut self) {
    // glfw::window_hint::context_version(3, 2);
    glfw::set_error_callback(~glfw::LogErrorHandler);
    glfw::init();
    self.window = option::Some(
      glfw::Window::create(
        WIN_SIZE.x,
        WIN_SIZE.y,
        "OpenGL",
        glfw::Windowed
      ).unwrap()
    );
  }

  fn init_opengl(&mut self) {
    let window = self.window.get_ref();
    window.make_context_current();
    window.set_cursor_pos_callback(~CursorPosContext);
    window.set_key_callback(~KeyContext);

    // Load the OpenGL function pointers
    gl::load_with(glfw::get_proc_address);

    self.vertex_shader = compile_shader(
      VERTEX_SHADER_SRC, gl::VERTEX_SHADER);
    self.fragment_shader = compile_shader(
      FRAGMENT_SHADER_SRC, gl::FRAGMENT_SHADER);
    self.program = link_program(self.vertex_shader, self.fragment_shader);
  }

  pub fn cleanup_opengl(&self) {
    gl::DeleteProgram(self.program);
    gl::DeleteShader(self.fragment_shader);
    gl::DeleteShader(self.vertex_shader);
    unsafe {
      gl::DeleteBuffers(1, &self.vertex_buffer_obj);
    }
  }

  fn update_matrices(&self) {
    let mut mvp_matrix = self.projection_matrix;
    unsafe {
      mvp_matrix = tr(mvp_matrix, Vec3{x: 0.0f32, y: 0.0, z: -10.0f32});
      mvp_matrix = rot_x(mvp_matrix, MOUSE_POS.y / 100.0);
      mvp_matrix = rot_y(mvp_matrix, MOUSE_POS.x / 100.0);
      mvp_matrix = tr(mvp_matrix, CAMERA_POS);

      // Send our transformation to the currently bound shader,
      // in the "model_view_proj_matrix" uniform for each model
      // you render, since the model_view_proj_matrix will be
      // different (at least the M part).
      gl::UniformMatrix4fv(self.matrix_id, 1, gl::FALSE, mvp_matrix.cr(0, 0));
    }
  }

  pub fn draw(&self) {
    self.update_matrices();
    gl::ClearColor(0.3, 0.3, 0.3, 1.0);
    gl::Clear(gl::COLOR_BUFFER_BIT);
    gl::DrawArrays(gl::TRIANGLES, 0, self.vertex_data.len() as i32);
    self.window.get_ref().swap_buffers();
  }

  pub fn is_running(&self) -> bool {
    return !self.window.get_ref().should_close()
  }

  pub fn process_events(&self) {
    glfw::poll_events();
  }
}

impl Drop for Win {
  fn drop(&mut self) {
    self.cleanup_opengl();

    // destroy glfw::Window before terminating glfw
    self.window = option::None;

    glfw::terminate();
  }
}

struct CursorPosContext;
impl glfw::CursorPosCallback for CursorPosContext {
  fn call(&self, w: &glfw::Window, xpos: f64, ypos: f64) {
    if w.get_mouse_button(glfw::MouseButtonRight) == glfw::Press {
      unsafe {
        MOUSE_POS.x = xpos as f32;
        MOUSE_POS.y = ypos as f32;
      }
    }
  }
}

struct KeyContext;
impl glfw::KeyCallback for KeyContext {
  fn call(
    &self,
    window: &glfw::Window,
    key:    glfw::Key,
    _:      std::libc::c_int,
    action: glfw::Action,
    _:      glfw::Modifiers
  ) {
    let distance = 1.0;
    if action != glfw::Press {
      return;
    }
    match key {
      glfw::KeyEscape | glfw::KeyQ
                     => window.set_should_close(true),
      glfw::KeySpace => println!("space"),
      glfw::KeyUp    => unsafe { CAMERA_POS.y -= distance },
      glfw::KeyDown  => unsafe { CAMERA_POS.y += distance },
      glfw::KeyRight => unsafe { CAMERA_POS.x -= distance },
      glfw::KeyLeft  => unsafe { CAMERA_POS.x += distance },
      _ => {}
    }
  }
}

// vim: set tabstop=2 shiftwidth=2 softtabstop=2 expandtab:
<commit_msg>win.rs: Render simple hex<commit_after>// See LICENSE file for copyright and license details.

// Marauder is turn-based strategy game with hex grid.

extern mod glfw;
extern mod gl;
extern mod cgmath;

use std::f32::consts::{
  PI,
  FRAC_PI_2
};
use std::num::{
  sqrt,
  pow,
  abs,
  sin,
  cos
};
use std::option;
use gltypes = gl::types;
use cgmath::matrix::{
  Matrix,
  Mat4,
  Mat3,
  ToMat4
};
use cgmath::vector::{
  Vec3,
  Vec2,
  Vector
};
use cgmath::projection;
use cgmath::angle;

static mut MOUSE_POS: Vec2<f32> = Vec2{x: 0.0f32, y: 0.0};
static mut CAMERA_POS: Vec3<f32> = Vec3{x: 0.0f32, y: 0.0, z: 0.0};

static WIN_SIZE: Vec2<u32> = Vec2{x: 640, y: 480};

static VERTEX_SHADER_SRC: &'static str = "
  #version 130
  in vec3 position;
  uniform mat4 model_view_proj_matrix;
  void main() {
    vec4 v = vec4(position, 1);
    gl_Position = model_view_proj_matrix * v;
  }
";

static FRAGMENT_SHADER_SRC: &'static str = "
  #version 130
  out vec4 out_color;
  void main() {
    out_color = vec4(1.0, 1.0, 1.0, 1.0);
  }
";

pub struct Visualizer {
  hex_ex_radius: gltypes::GLfloat,
  hex_in_radius: gltypes::GLfloat
}

impl Visualizer {
  pub fn new() -> Visualizer {
    let hex_ex_radius: gltypes::GLfloat = 1.0 / 2.0;
    let hex_in_radius = sqrt(
        pow(hex_ex_radius, 2.0) - pow(hex_ex_radius / 2.0, 2.0));
    let visualizer = Visualizer {
      hex_ex_radius: hex_ex_radius,
      hex_in_radius: hex_in_radius
    };
    visualizer
  }

  pub fn dist(a: Vec2<f32>, b: Vec2<f32>) -> f32 {
    let dx = abs(b.x - a.x);
    let dy = abs(b.y - a.y);
    sqrt(pow(dx, 2.0) + pow(dy, 2.0))
  }

  pub fn v2i_to_v2f(&self, i: Vec2<i32>) -> Vec2<f32> {
    let v = Vec2 {
      x: (i.x as f32) * self.hex_in_radius * 2.0,
      y: (i.y as f32) * self.hex_ex_radius * 1.5
    };
    if i.y % 2 == 0 {
      Vec2{x: v.x + self.hex_in_radius, y: v.y}
    } else {
      v
    }
  }

  pub fn index_to_circle_vertex(&self, count: int, i: int) -> Vec2<f32> {
    let n = FRAC_PI_2 + 2.0 * PI * (i as f32) / (count as f32);
    Vec2{x: cos(n), y: sin(n)}.mul_s(self.hex_ex_radius)
  }

  pub fn index_to_hex_vertex(&self, i: int) -> Vec2<f32> {
    self.index_to_circle_vertex(6, i)
  }
}

fn compile_shader(src: &str, shader_type: gltypes::GLenum) -> gltypes::GLuint {
  let shader = gl::CreateShader(shader_type);
  unsafe {
    gl::ShaderSource(shader, 1, &src.to_c_str().unwrap(), std::ptr::null());
    gl::CompileShader(shader);

    let mut status = gl::FALSE as gltypes::GLint;
    gl::GetShaderiv(shader, gl::COMPILE_STATUS, &mut status);

    if status != (gl::TRUE as gltypes::GLint) {
      let mut len = 0;
      gl::GetShaderiv(shader, gl::INFO_LOG_LENGTH, &mut len);
      // subtract 1 to skip the trailing null character
      let mut buf = std::vec::from_elem(len as uint - 1, 0u8);
      gl::GetShaderInfoLog(shader, len, std::ptr::mut_null(),
        buf.as_mut_ptr() as *mut gltypes::GLchar
      );
      fail!("compile_shader(): " + std::str::raw::from_utf8(buf));
    }
  }
  shader
}

fn link_program(
    vertex_shader: gltypes::GLuint,
    fragment_shader: gltypes::GLuint
) -> gltypes::GLuint {
  let program = gl::CreateProgram();
  gl::AttachShader(program, vertex_shader);
  gl::AttachShader(program, fragment_shader);
  gl::LinkProgram(program);
  unsafe {
    let mut status = gl::FALSE as gltypes::GLint;
    gl::GetProgramiv(program, gl::LINK_STATUS, &mut status);

    if status != (gl::TRUE as gltypes::GLint) {
      let mut len: gltypes::GLint = 0;
      gl::GetProgramiv(program, gl::INFO_LOG_LENGTH, &mut len);
      // subtract 1 to skip the trailing null character
      let mut buf = std::vec::from_elem(len as uint - 1, 0u8);
      gl::GetProgramInfoLog(program, len, std::ptr::mut_null(),
        buf.as_mut_ptr() as *mut gltypes::GLchar
      );
      fail!("link_program(): " + std::str::raw::from_utf8(buf));
    }
  }
  program
}

fn tr(m: Mat4<f32>, v: Vec3<f32>) -> Mat4<f32> {
  let mut t = Mat4::<f32>::identity();
  *t.mut_cr(3, 0) = v.x;
  *t.mut_cr(3, 1) = v.y;
  *t.mut_cr(3, 2) = v.z;
  m.mul_m(&t)
}

fn rot_x(m: Mat4<f32>, angle: f32) -> Mat4<f32> {
  let r = Mat3::from_angle_x(angle::rad(angle)).to_mat4();
  m.mul_m(&r)
}

fn rot_y(m: Mat4<f32>, angle: f32) -> Mat4<f32> {
  let r = Mat3::from_angle_y(angle::rad(angle)).to_mat4();
  m.mul_m(&r)
}

pub struct Win {
  vertex_shader: gltypes::GLuint,
  fragment_shader: gltypes::GLuint,
  program: gltypes::GLuint,
  vertex_buffer_obj: gltypes::GLuint,
  matrix_id: gltypes::GLint,
  projection_matrix: Mat4<f32>,
  window: Option<glfw::Window>,
  vertex_data: ~[gltypes::GLfloat]
}

fn get_projection_matrix() -> Mat4<f32> {
  let fov = angle::deg(45.0f32);
  let ratio = 4.0 / 3.0;
  let display_range_min = 0.1;
  let display_range_max = 100.0;
  projection::perspective(
    fov, ratio, display_range_min, display_range_max
  )
}

impl Win {
  pub fn new() -> Win {
    let mut win = Win {
      vertex_shader: 0,
      fragment_shader: 0,
      program: 0,
      vertex_buffer_obj: 0,
      matrix_id: 0,
      projection_matrix: get_projection_matrix(),
      window: option::None,
      vertex_data: ~[]
    };
    win.init_glfw();
    win.init_opengl();
    win.init_model();
    win
  }

  fn add_point(&mut self, x: f32, y: f32, z: f32) {
    self.vertex_data.push(x);
    self.vertex_data.push(y);
    self.vertex_data.push(z);
  }

  fn build_hex_mesh(&mut self) {
    let visualizer = Visualizer::new();
    for num in range(0, 6) {
      let v = visualizer.index_to_hex_vertex(num);
      let v2 = visualizer.index_to_hex_vertex(num + 1);
      self.add_point(v.x, v.y, 0.0);
      self.add_point(v2.x, v2.y, 0.0);
      self.add_point(0.0, 0.0, 0.0);
    }
  }

  fn init_model(&mut self) {
    self.build_hex_mesh();
    unsafe {
      // Create a Vertex Buffer Object
      gl::GenBuffers(1, &mut self.vertex_buffer_obj);
      gl::BindBuffer(gl::ARRAY_BUFFER, self.vertex_buffer_obj);

      // Copy vertex data to VBO
      let float_size = std::mem::size_of::<gltypes::GLfloat>();
      let vertices_ptr = (self.vertex_data.len() * float_size)
        as gltypes::GLsizeiptr;
      gl::BufferData(
        gl::ARRAY_BUFFER,
        vertices_ptr,
        std::cast::transmute(&self.vertex_data[0]),
        gl::STATIC_DRAW
      );

      gl::UseProgram(self.program);
      gl::BindFragDataLocation(
        self.program, 0, "out_color".to_c_str().unwrap());

      // Specify the layout of the vertex data
      let pos_attr = gl::GetAttribLocation(
        self.program, "position".to_c_str().unwrap()) as gltypes::GLuint;
      gl::EnableVertexAttribArray(pos_attr);

      let size = 3;
      let normalized = gl::FALSE;
      let stride = 0;
      gl::VertexAttribPointer(
        pos_attr,
        size,
        gl::FLOAT,
        normalized,
        stride,
        std::ptr::null()
      );

      self.matrix_id = gl::GetUniformLocation(
        self.program, "model_view_proj_matrix".to_c_str().unwrap()
      );
    }
  }

  fn init_glfw(&mut self) {
    // glfw::window_hint::context_version(3, 2);
    glfw::set_error_callback(~glfw::LogErrorHandler);
    glfw::init();
    self.window = option::Some(
      glfw::Window::create(
        WIN_SIZE.x,
        WIN_SIZE.y,
        "OpenGL",
        glfw::Windowed
      ).unwrap()
    );
  }

  fn init_opengl(&mut self) {
    let window = self.window.get_ref();
    window.make_context_current();
    window.set_cursor_pos_callback(~CursorPosContext);
    window.set_key_callback(~KeyContext);

    // Load the OpenGL function pointers
    gl::load_with(glfw::get_proc_address);

    self.vertex_shader = compile_shader(
      VERTEX_SHADER_SRC, gl::VERTEX_SHADER);
    self.fragment_shader = compile_shader(
      FRAGMENT_SHADER_SRC, gl::FRAGMENT_SHADER);
    self.program = link_program(self.vertex_shader, self.fragment_shader);
  }

  pub fn cleanup_opengl(&self) {
    gl::DeleteProgram(self.program);
    gl::DeleteShader(self.fragment_shader);
    gl::DeleteShader(self.vertex_shader);
    unsafe {
      gl::DeleteBuffers(1, &self.vertex_buffer_obj);
    }
  }

  fn update_matrices(&self) {
    let mut mvp_matrix = self.projection_matrix;
    unsafe {
      mvp_matrix = tr(mvp_matrix, Vec3{x: 0.0f32, y: 0.0, z: -10.0f32});
      mvp_matrix = rot_x(mvp_matrix, MOUSE_POS.y / 100.0);
      mvp_matrix = rot_y(mvp_matrix, MOUSE_POS.x / 100.0);
      mvp_matrix = tr(mvp_matrix, CAMERA_POS);

      // Send our transformation to the currently bound shader,
      // in the "model_view_proj_matrix" uniform for each model
      // you render, since the model_view_proj_matrix will be
      // different (at least the M part).
      gl::UniformMatrix4fv(self.matrix_id, 1, gl::FALSE, mvp_matrix.cr(0, 0));
    }
  }

  pub fn draw(&self) {
    self.update_matrices();
    gl::ClearColor(0.3, 0.3, 0.3, 1.0);
    gl::Clear(gl::COLOR_BUFFER_BIT);
    gl::DrawArrays(gl::TRIANGLES, 0, self.vertex_data.len() as i32);
    self.window.get_ref().swap_buffers();
  }

  pub fn is_running(&self) -> bool {
    return !self.window.get_ref().should_close()
  }

  pub fn process_events(&self) {
    glfw::poll_events();
  }
}

impl Drop for Win {
  fn drop(&mut self) {
    self.cleanup_opengl();

    // destroy glfw::Window before terminating glfw
    self.window = option::None;

    glfw::terminate();
  }
}

struct CursorPosContext;
impl glfw::CursorPosCallback for CursorPosContext {
  fn call(&self, w: &glfw::Window, xpos: f64, ypos: f64) {
    if w.get_mouse_button(glfw::MouseButtonRight) == glfw::Press {
      unsafe {
        MOUSE_POS.x = xpos as f32;
        MOUSE_POS.y = ypos as f32;
      }
    }
  }
}

struct KeyContext;
impl glfw::KeyCallback for KeyContext {
  fn call(
    &self,
    window: &glfw::Window,
    key:    glfw::Key,
    _:      std::libc::c_int,
    action: glfw::Action,
    _:      glfw::Modifiers
  ) {
    let distance = 1.0;
    if action != glfw::Press {
      return;
    }
    match key {
      glfw::KeyEscape | glfw::KeyQ
                     => window.set_should_close(true),
      glfw::KeySpace => println!("space"),
      glfw::KeyUp    => unsafe { CAMERA_POS.y -= distance },
      glfw::KeyDown  => unsafe { CAMERA_POS.y += distance },
      glfw::KeyRight => unsafe { CAMERA_POS.x -= distance },
      glfw::KeyLeft  => unsafe { CAMERA_POS.x += distance },
      _ => {}
    }
  }
}

// vim: set tabstop=2 shiftwidth=2 softtabstop=2 expandtab:
<|endoftext|>


<commit_before>use rustc_ast as ast;
use rustc_middle::mir::interpret::{
    Allocation, ConstValue, LitToConstError, LitToConstInput, Scalar,
};
use rustc_middle::ty::{self, ParamEnv, TyCtxt};
use rustc_span::symbol::Symbol;
use rustc_target::abi::Size;

crate fn lit_to_const<'tcx>(
    tcx: TyCtxt<'tcx>,
    lit_input: LitToConstInput<'tcx>,
) -> Result<&'tcx ty::Const<'tcx>, LitToConstError> {
    let LitToConstInput { lit, ty, neg } = lit_input;

    let trunc = |n| {
        let param_ty = ParamEnv::reveal_all().and(ty);
        let width = tcx.layout_of(param_ty).map_err(|_| LitToConstError::Reported)?.size;
        trace!("trunc {} with size {} and shift {}", n, width.bits(), 128 - width.bits());
        let result = width.truncate(n);
        trace!("trunc result: {}", result);
        Ok(ConstValue::Scalar(Scalar::from_uint(result, width)))
    };

    let lit = match (lit, &ty.kind()) {
        (ast::LitKind::Str(s, _), ty::Ref(_, inner_ty, _)) if inner_ty.is_str() => {
            let s = s.as_str();
            let allocation = Allocation::from_byte_aligned_bytes(s.as_bytes());
            let allocation = tcx.intern_const_alloc(allocation);
            ConstValue::Slice { data: allocation, start: 0, end: s.len() }
        }
        (ast::LitKind::ByteStr(data), ty::Ref(_, inner_ty, _))
            if matches!(inner_ty.kind(), ty::Slice(_)) =>
        {
            let allocation = Allocation::from_byte_aligned_bytes(data as &[u8]);
            let allocation = tcx.intern_const_alloc(allocation);
            ConstValue::Slice { data: allocation, start: 0, end: data.len() }
        }
        (ast::LitKind::ByteStr(data), ty::Ref(_, inner_ty, _)) if inner_ty.is_array() => {
            let id = tcx.allocate_bytes(data);
            ConstValue::Scalar(Scalar::Ptr(id.into()))
        }
        (ast::LitKind::Byte(n), ty::Uint(ty::UintTy::U8)) => {
            ConstValue::Scalar(Scalar::from_uint(*n, Size::from_bytes(1)))
        }
        (ast::LitKind::Int(n, _), ty::Uint(_)) | (ast::LitKind::Int(n, _), ty::Int(_)) => {
            trunc(if neg { (*n as i128).overflowing_neg().0 as u128 } else { *n })?
        }
        (ast::LitKind::Float(n, _), ty::Float(fty)) => {
            parse_float(*n, *fty, neg).map_err(|_| LitToConstError::UnparseableFloat)?
        }
        (ast::LitKind::Bool(b), ty::Bool) => ConstValue::Scalar(Scalar::from_bool(*b)),
        (ast::LitKind::Char(c), ty::Char) => ConstValue::Scalar(Scalar::from_char(*c)),
        (ast::LitKind::Err(_), _) => return Err(LitToConstError::Reported),
        _ => return Err(LitToConstError::TypeError),
    };
    Ok(ty::Const::from_value(tcx, lit, ty))
}

fn parse_float<'tcx>(num: Symbol, fty: ty::FloatTy, neg: bool) -> Result<ConstValue<'tcx>, ()> {
    let num = num.as_str();
    use rustc_apfloat::ieee::{Double, Single};
    let scalar = match fty {
        ty::FloatTy::F32 => {
            num.parse::<f32>().map_err(|_| ())?;
            let mut f = num.parse::<Single>().unwrap_or_else(|e| {
                panic!("apfloat::ieee::Single failed to parse `{}`: {:?}", num, e)
            });
            if neg {
                f = -f;
            }
            Scalar::from_f32(f)
        }
        ty::FloatTy::F64 => {
            num.parse::<f64>().map_err(|_| ())?;
            let mut f = num.parse::<Double>().unwrap_or_else(|e| {
                panic!("apfloat::ieee::Double failed to parse `{}`: {:?}", num, e)
            });
            if neg {
                f = -f;
            }
            Scalar::from_f64(f)
        }
    };

    Ok(ConstValue::Scalar(scalar))
}
<commit_msg>Reintroduce accidentally deleted assertions.<commit_after>use rustc_apfloat::Float;
use rustc_ast as ast;
use rustc_middle::mir::interpret::{
    Allocation, ConstValue, LitToConstError, LitToConstInput, Scalar,
};
use rustc_middle::ty::{self, ParamEnv, TyCtxt};
use rustc_span::symbol::Symbol;
use rustc_target::abi::Size;

crate fn lit_to_const<'tcx>(
    tcx: TyCtxt<'tcx>,
    lit_input: LitToConstInput<'tcx>,
) -> Result<&'tcx ty::Const<'tcx>, LitToConstError> {
    let LitToConstInput { lit, ty, neg } = lit_input;

    let trunc = |n| {
        let param_ty = ParamEnv::reveal_all().and(ty);
        let width = tcx.layout_of(param_ty).map_err(|_| LitToConstError::Reported)?.size;
        trace!("trunc {} with size {} and shift {}", n, width.bits(), 128 - width.bits());
        let result = width.truncate(n);
        trace!("trunc result: {}", result);
        Ok(ConstValue::Scalar(Scalar::from_uint(result, width)))
    };

    let lit = match (lit, &ty.kind()) {
        (ast::LitKind::Str(s, _), ty::Ref(_, inner_ty, _)) if inner_ty.is_str() => {
            let s = s.as_str();
            let allocation = Allocation::from_byte_aligned_bytes(s.as_bytes());
            let allocation = tcx.intern_const_alloc(allocation);
            ConstValue::Slice { data: allocation, start: 0, end: s.len() }
        }
        (ast::LitKind::ByteStr(data), ty::Ref(_, inner_ty, _))
            if matches!(inner_ty.kind(), ty::Slice(_)) =>
        {
            let allocation = Allocation::from_byte_aligned_bytes(data as &[u8]);
            let allocation = tcx.intern_const_alloc(allocation);
            ConstValue::Slice { data: allocation, start: 0, end: data.len() }
        }
        (ast::LitKind::ByteStr(data), ty::Ref(_, inner_ty, _)) if inner_ty.is_array() => {
            let id = tcx.allocate_bytes(data);
            ConstValue::Scalar(Scalar::Ptr(id.into()))
        }
        (ast::LitKind::Byte(n), ty::Uint(ty::UintTy::U8)) => {
            ConstValue::Scalar(Scalar::from_uint(*n, Size::from_bytes(1)))
        }
        (ast::LitKind::Int(n, _), ty::Uint(_)) | (ast::LitKind::Int(n, _), ty::Int(_)) => {
            trunc(if neg { (*n as i128).overflowing_neg().0 as u128 } else { *n })?
        }
        (ast::LitKind::Float(n, _), ty::Float(fty)) => {
            parse_float(*n, *fty, neg).map_err(|_| LitToConstError::UnparseableFloat)?
        }
        (ast::LitKind::Bool(b), ty::Bool) => ConstValue::Scalar(Scalar::from_bool(*b)),
        (ast::LitKind::Char(c), ty::Char) => ConstValue::Scalar(Scalar::from_char(*c)),
        (ast::LitKind::Err(_), _) => return Err(LitToConstError::Reported),
        _ => return Err(LitToConstError::TypeError),
    };
    Ok(ty::Const::from_value(tcx, lit, ty))
}

fn parse_float<'tcx>(num: Symbol, fty: ty::FloatTy, neg: bool) -> Result<ConstValue<'tcx>, ()> {
    let num = num.as_str();
    use rustc_apfloat::ieee::{Double, Single};
    let scalar = match fty {
        ty::FloatTy::F32 => {
            let rust_f = num.parse::<f32>().map_err(|_| ())?;
            let mut f = num.parse::<Single>().unwrap_or_else(|e| {
                panic!("apfloat::ieee::Single failed to parse `{}`: {:?}", num, e)
            });
            assert!(
                u128::from(rust_f.to_bits()) == f.to_bits(),
                "apfloat::ieee::Single gave different result for `{}`: \
                 {}({:#x}) vs Rust's {}({:#x})",
                rust_f,
                f,
                f.to_bits(),
                Single::from_bits(rust_f.to_bits().into()),
                rust_f.to_bits()
            );
            if neg {
                f = -f;
            }
            Scalar::from_f32(f)
        }
        ty::FloatTy::F64 => {
            let rust_f = num.parse::<f64>().map_err(|_| ())?;
            let mut f = num.parse::<Double>().unwrap_or_else(|e| {
                panic!("apfloat::ieee::Double failed to parse `{}`: {:?}", num, e)
            });
            assert!(
                u128::from(rust_f.to_bits()) == f.to_bits(),
                "apfloat::ieee::Double gave different result for `{}`: \
                 {}({:#x}) vs Rust's {}({:#x})",
                rust_f,
                f,
                f.to_bits(),
                Double::from_bits(rust_f.to_bits().into()),
                rust_f.to_bits()
            );
            if neg {
                f = -f;
            }
            Scalar::from_f64(f)
        }
    };

    Ok(ConstValue::Scalar(scalar))
}
<|endoftext|>