<commit_before>use {VRService, VRServicePtr, VRDevice, VRDevicePtr, VRDisplayEvent, VRDisplayEventReason};
use super::constants;
use super::device::{OpenVRDevice, OpenVRDevicePtr};
use super::openvr_sys as openvr;
use super::openvr_sys::EVRInitError::*;
use super::openvr_sys::EVRApplicationType::*;
use super::openvr_sys::ETrackedDeviceClass::*;
use super::openvr_sys::EVREventType::*;
use std::ffi::CString;
use std::sync::Arc;
use std::ptr;
use std::cell::RefCell;
use std::mem;

pub struct OpenVRService {
    initialized: bool,
    devices: Vec<OpenVRDevicePtr>,
    system: *mut openvr::VR_IVRSystem_FnTable,
}

unsafe impl Send for OpenVRService {}

impl VRService for OpenVRService {
    fn initialize(&mut self) -> Result<(), String> {
        if self.initialized {
            return Ok(());
        }
        if !self.is_available() {
            return Err("Not available".into());
        }

        let mut error = EVRInitError_VRInitError_None;
        unsafe {
             openvr::VR_InitInternal(&mut error, EVRApplicationType_VRApplication_Scene);
        }

        if error as u32 != EVRInitError_VRInitError_None as u32 {
            return Err(format!("OpenVR Internal failed with error {}", error as u32));
        }

        error = EVRInitError_VRInitError_None;
        unsafe {
            let name = CString::new(format!("FnTable:{}",constants::IVRSYSTEM_VERSION)).unwrap();
            self.system = openvr::VR_GetGenericInterface(name.as_ptr(), &mut error)
                          as *mut openvr::VR_IVRSystem_FnTable;
            (*self.system).AcknowledgeQuit_UserPrompt.unwrap();
        }

        if error as u32 != EVRInitError_VRInitError_None as u32 {
            return Err(format!("OpenVR GetGenericInterface failed with error {}", error as u32));
        }

        self.initialized = true;
        Ok(())
    }

    fn fetch_devices(&mut self) -> Result<Vec<VRDevicePtr>,String> {
        // Return cached devices if available
        if self.initialized && self.devices.len() > 0 {
            return Ok(self.clone_devices());
        }
        // Ensure that there are not initialization errors
        try!(self.initialize());

        let max_device_count: u32 = constants::K_UNMAXTRACKEDDEVICECOUNT;

        self.devices.clear();

        for i in 0..max_device_count {
            let device_class: openvr::ETrackedDeviceClass = unsafe {
                (*self.system).GetTrackedDeviceClass.unwrap()(i as openvr::TrackedDeviceIndex_t)
            };

            match device_class {
                ETrackedDeviceClass_TrackedDeviceClass_HMD => {
                    self.devices.push(OpenVRDevice::new(self.system, i));
                },
                _ => {}
            }

        }

        Ok(self.clone_devices())
    }

    fn is_available(&self) -> bool {
        unsafe {
            return openvr::VR_IsHmdPresent() > 0;
        }
    }

    fn poll_events(&self) -> Vec<VRDisplayEvent> {
        let mut result = Vec::new();
        let mut event: openvr::VREvent_t = unsafe { mem::uninitialized() };
        let size = mem::size_of::<openvr::VREvent_t>() as u32;
        while unsafe { (*self.system).PollNextEvent.unwrap()(&mut event, size) } != 0 {

            let event_type: openvr::EVREventType = unsafe { mem::transmute(event.eventType) };

            match event_type {
                EVREventType_VREvent_TrackedDeviceUserInteractionStarted => {
                    if let Some(device) = self.get_device(event.trackedDeviceIndex) {

                        result.push(VRDisplayEvent::Activate(device.borrow().get_display_data(),
                                                                   VRDisplayEventReason::Mounted));
                    }
                },
                EVREventType_VREvent_TrackedDeviceUserInteractionEnded => {
                    if let Some(device) = self.get_device(event.trackedDeviceIndex) {

                        result.push(VRDisplayEvent::Deactivate(device.borrow().get_display_data(),
                                                                     VRDisplayEventReason::Unmounted));
                    }
                },
                EVREventType_VREvent_TrackedDeviceActivated => {
                    if let Some(device) = self.get_device(event.trackedDeviceIndex) {
                        result.push(VRDisplayEvent::Connect(device.borrow().get_display_data()))
                    }
                },
                EVREventType_VREvent_TrackedDeviceDeactivated => {
                    if let Some(device) = self.get_device(event.trackedDeviceIndex) {
                        result.push(VRDisplayEvent::Disconnect(device.borrow().device_id()))
                    }
                },
                EVREventType_VREvent_DashboardActivated => {
                    if let Some(device) = self.get_device(event.trackedDeviceIndex) {
                        result.push(VRDisplayEvent::Blur(device.borrow().get_display_data()))
                    }
                },
                EVREventType_VREvent_DashboardDeactivated => {
                    if let Some(device) = self.get_device(event.trackedDeviceIndex) {
                        result.push(VRDisplayEvent::Focus(device.borrow().get_display_data()))
                    }
                },
                EVREventType_VREvent_ChaperoneDataHasChanged |
                EVREventType_VREvent_IpdChanged |
                EVREventType_VREvent_TrackedDeviceUpdated => {
                    if let Some(device) = self.get_device(event.trackedDeviceIndex) {
                        result.push(VRDisplayEvent::Change(device.borrow().get_display_data()))
                    }
                },
                _ => {}
            };
        }

        result
    }
}

impl Drop for OpenVRService {
    fn drop(&mut self) {
        if self.initialized {
            unsafe {
                debug!("OpenVR Shutdown");
                openvr::VR_ShutdownInternal();
            }
        }
    }
}

impl OpenVRService {
    pub fn new() -> VRServicePtr {
        Arc::new(RefCell::new(OpenVRService {
            initialized: false,
            devices: Vec::new(),
            system: ptr::null_mut(),
        }))
    }
    fn clone_devices(&self) -> Vec<VRDevicePtr> {
        self.devices.iter().map(|d| d.clone() as VRDevicePtr).collect()
    }

    pub fn get_device(&self, index: openvr::TrackedDeviceIndex_t) -> Option<&OpenVRDevicePtr> {
        self.devices.iter().find(|&d| d.borrow().index() == index)
    }
}<commit_msg>Safety check when polling events<commit_after>use {VRService, VRServicePtr, VRDevice, VRDevicePtr, VRDisplayEvent, VRDisplayEventReason};
use super::constants;
use super::device::{OpenVRDevice, OpenVRDevicePtr};
use super::openvr_sys as openvr;
use super::openvr_sys::EVRInitError::*;
use super::openvr_sys::EVRApplicationType::*;
use super::openvr_sys::ETrackedDeviceClass::*;
use super::openvr_sys::EVREventType::*;
use std::ffi::CString;
use std::sync::Arc;
use std::ptr;
use std::cell::RefCell;
use std::mem;

pub struct OpenVRService {
    initialized: bool,
    devices: Vec<OpenVRDevicePtr>,
    system: *mut openvr::VR_IVRSystem_FnTable,
}

unsafe impl Send for OpenVRService {}

impl VRService for OpenVRService {
    fn initialize(&mut self) -> Result<(), String> {
        if self.initialized {
            return Ok(());
        }
        if !self.is_available() {
            return Err("Not available".into());
        }

        let mut error = EVRInitError_VRInitError_None;
        unsafe {
             openvr::VR_InitInternal(&mut error, EVRApplicationType_VRApplication_Scene);
        }

        if error as u32 != EVRInitError_VRInitError_None as u32 {
            return Err(format!("OpenVR Internal failed with error {}", error as u32));
        }

        error = EVRInitError_VRInitError_None;
        unsafe {
            let name = CString::new(format!("FnTable:{}",constants::IVRSYSTEM_VERSION)).unwrap();
            self.system = openvr::VR_GetGenericInterface(name.as_ptr(), &mut error)
                          as *mut openvr::VR_IVRSystem_FnTable;
            (*self.system).AcknowledgeQuit_UserPrompt.unwrap();
        }

        if error as u32 != EVRInitError_VRInitError_None as u32 {
            return Err(format!("OpenVR GetGenericInterface failed with error {}", error as u32));
        }

        self.initialized = true;
        Ok(())
    }

    fn fetch_devices(&mut self) -> Result<Vec<VRDevicePtr>,String> {
        // Return cached devices if available
        if self.initialized && self.devices.len() > 0 {
            return Ok(self.clone_devices());
        }
        // Ensure that there are not initialization errors
        try!(self.initialize());

        let max_device_count: u32 = constants::K_UNMAXTRACKEDDEVICECOUNT;

        self.devices.clear();

        for i in 0..max_device_count {
            let device_class: openvr::ETrackedDeviceClass = unsafe {
                (*self.system).GetTrackedDeviceClass.unwrap()(i as openvr::TrackedDeviceIndex_t)
            };

            match device_class {
                ETrackedDeviceClass_TrackedDeviceClass_HMD => {
                    self.devices.push(OpenVRDevice::new(self.system, i));
                },
                _ => {}
            }

        }

        Ok(self.clone_devices())
    }

    fn is_available(&self) -> bool {
        unsafe {
            return openvr::VR_IsHmdPresent() > 0;
        }
    }

    fn poll_events(&self) -> Vec<VRDisplayEvent> {
        let mut result = Vec::new();
        if !self.initialized || self.system.is_null() {
            return result;
        }
        let mut event: openvr::VREvent_t = unsafe { mem::uninitialized() };
        let size = mem::size_of::<openvr::VREvent_t>() as u32;
        while unsafe { (*self.system).PollNextEvent.unwrap()(&mut event, size) } != 0 {

            let event_type: openvr::EVREventType = unsafe { mem::transmute(event.eventType) };

            match event_type {
                EVREventType_VREvent_TrackedDeviceUserInteractionStarted => {
                    if let Some(device) = self.get_device(event.trackedDeviceIndex) {

                        result.push(VRDisplayEvent::Activate(device.borrow().get_display_data(),
                                                                   VRDisplayEventReason::Mounted));
                    }
                },
                EVREventType_VREvent_TrackedDeviceUserInteractionEnded => {
                    if let Some(device) = self.get_device(event.trackedDeviceIndex) {

                        result.push(VRDisplayEvent::Deactivate(device.borrow().get_display_data(),
                                                                     VRDisplayEventReason::Unmounted));
                    }
                },
                EVREventType_VREvent_TrackedDeviceActivated => {
                    if let Some(device) = self.get_device(event.trackedDeviceIndex) {
                        result.push(VRDisplayEvent::Connect(device.borrow().get_display_data()))
                    }
                },
                EVREventType_VREvent_TrackedDeviceDeactivated => {
                    if let Some(device) = self.get_device(event.trackedDeviceIndex) {
                        result.push(VRDisplayEvent::Disconnect(device.borrow().device_id()))
                    }
                },
                EVREventType_VREvent_DashboardActivated => {
                    if let Some(device) = self.get_device(event.trackedDeviceIndex) {
                        result.push(VRDisplayEvent::Blur(device.borrow().get_display_data()))
                    }
                },
                EVREventType_VREvent_DashboardDeactivated => {
                    if let Some(device) = self.get_device(event.trackedDeviceIndex) {
                        result.push(VRDisplayEvent::Focus(device.borrow().get_display_data()))
                    }
                },
                EVREventType_VREvent_ChaperoneDataHasChanged |
                EVREventType_VREvent_IpdChanged |
                EVREventType_VREvent_TrackedDeviceUpdated => {
                    if let Some(device) = self.get_device(event.trackedDeviceIndex) {
                        result.push(VRDisplayEvent::Change(device.borrow().get_display_data()))
                    }
                },
                _ => {}
            };
        }

        result
    }
}

impl Drop for OpenVRService {
    fn drop(&mut self) {
        if self.initialized {
            unsafe {
                debug!("OpenVR Shutdown");
                openvr::VR_ShutdownInternal();
            }
        }
    }
}

impl OpenVRService {
    pub fn new() -> VRServicePtr {
        Arc::new(RefCell::new(OpenVRService {
            initialized: false,
            devices: Vec::new(),
            system: ptr::null_mut(),
        }))
    }
    fn clone_devices(&self) -> Vec<VRDevicePtr> {
        self.devices.iter().map(|d| d.clone() as VRDevicePtr).collect()
    }

    pub fn get_device(&self, index: openvr::TrackedDeviceIndex_t) -> Option<&OpenVRDevicePtr> {
        self.devices.iter().find(|&d| d.borrow().index() == index)
    }
}<|endoftext|>


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

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

use crate::state::{Group, 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, Eq, 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),

    /// Used to send some input to a process's stdin
    Send(SendMessage),

    /// The first part of the three-step protocol to edit a task.
    /// This one requests an edit from the daemon.
    EditRequest(usize),
    /// This is send by the client if something went wrong during the editing process.
    /// The daemon will go ahead and restore the task's old state.
    EditRestore(usize),
    /// The daemon locked the task and responds with the task's details.
    EditResponse(EditResponseMessage),
    /// The client sends the edited details to the daemon.
    Edit(EditMessage),

    Group(GroupMessage),
    GroupResponse(GroupResponseMessage),

    Status,
    StatusResponse(Box<State>),
    Log(LogRequestMessage),
    LogResponse(BTreeMap<usize, TaskLogMessage>),

    /// The client requests a continuous stream of a task's log.
    StreamRequest(StreamRequestMessage),
    /// The next chunk of output, that's send to the client.
    Stream(String),

    /// The boolean decides, whether the children should be get a SIGTERM as well.
    Reset(ResetMessage),
    Clean(CleanMessage),
    DaemonShutdown(Shutdown),

    Success(String),
    Failure(String),
    /// Simply notify the client that the connection is now closed.
    /// This is used to, for instance, close a `follow` stream if the task finished.
    Close,

    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, Eq, Clone, Debug, Deserialize, Serialize)]
pub enum TaskSelection {
    TaskIds(Vec<usize>),
    Group(String),
    All,
}

#[derive(PartialEq, Eq, Clone, Deserialize, Serialize)]
pub struct AddMessage {
    pub command: String,
    pub path: PathBuf,
    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,
}

/// We use a custom `Debug` implementation for [AddMessage], as the `envs` field just has
/// too much info in it and makes the log output much too verbose.
///
/// Furthermore, there might be secrets in the environment, resulting in a possible leak
/// if users copy-paste their log output for debugging.
impl std::fmt::Debug for AddMessage {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.debug_struct("Task")
            .field("command", &self.command)
            .field("path", &self.path)
            .field("envs", &"hidden")
            .field("start_immediately", &self.start_immediately)
            .field("stashed", &self.stashed)
            .field("group", &self.group)
            .field("enqueue_at", &self.enqueue_at)
            .field("dependencies", &self.dependencies)
            .field("label", &self.label)
            .field("print_task_id", &self.print_task_id)
            .finish()
    }
}

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

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

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

/// The messages used to restart tasks.
/// It's possible to update the command and paths when restarting tasks.
#[derive(PartialEq, Eq, Clone, Debug, Deserialize, Serialize)]
pub struct RestartMessage {
    pub tasks: Vec<TasksToRestart>,
    pub start_immediately: bool,
    pub stashed: bool,
}

#[derive(PartialEq, Eq, Clone, Debug, Deserialize, Serialize)]
pub struct TasksToRestart {
    pub task_id: usize,
    /// The command that should be used when restarting the task.
    pub command: String,
    /// The path that should be used when restarting the task.
    pub path: PathBuf,
}

#[derive(PartialEq, Eq, 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, Eq, 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, Eq, Clone, Debug, Deserialize, Serialize)]
pub struct KillMessage {
    pub tasks: TaskSelection,
    pub children: bool,
    pub signal: Option<Signal>,
}

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

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

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

#[derive(PartialEq, Eq, Clone, Debug, Deserialize, Serialize)]
pub enum GroupMessage {
    Add {
        name: String,
        parallel_tasks: Option<usize>,
    },
    Remove(String),
    List,
}

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

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

#[derive(PartialEq, Eq, Clone, Debug, Deserialize, Serialize)]
pub struct CleanMessage {
    #[serde(default = "bool::default")]
    pub successful_only: bool,

    #[serde(default = "Option::default")]
    pub group: Option<String>,
}

/// Determines which type of shutdown we're dealing with.
#[derive(PartialEq, Eq, 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,
}

#[derive(PartialEq, Eq, Clone, Debug, Deserialize, Serialize)]
pub struct StreamRequestMessage {
    pub task_id: Option<usize>,
    pub lines: Option<usize>,
}

/// Request logs for specific tasks.
///
/// `task_ids` specifies the requested tasks. If none are given, all tasks are selected.
/// `send_logs` Determines whether logs should be sent at all.
/// `lines` Determines whether only a few lines of log should be returned.
#[derive(PartialEq, Eq, 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, Eq, Clone, Debug, Deserialize, Serialize)]
pub struct TaskLogMessage {
    pub task: Task,
    #[serde(default = "bool::default")]
    /// Indicates whether the log output has been truncated or not.
    pub output_complete: bool,
    pub output: Option<Vec<u8>>,
}

#[derive(PartialEq, Eq, 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>change: Custom Debug impl for TaskLogMessage<commit_after>use std::collections::{BTreeMap, HashMap};
use std::path::PathBuf;

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

use crate::state::{Group, 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, Eq, 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),

    /// Used to send some input to a process's stdin
    Send(SendMessage),

    /// The first part of the three-step protocol to edit a task.
    /// This one requests an edit from the daemon.
    EditRequest(usize),
    /// This is send by the client if something went wrong during the editing process.
    /// The daemon will go ahead and restore the task's old state.
    EditRestore(usize),
    /// The daemon locked the task and responds with the task's details.
    EditResponse(EditResponseMessage),
    /// The client sends the edited details to the daemon.
    Edit(EditMessage),

    Group(GroupMessage),
    GroupResponse(GroupResponseMessage),

    Status,
    StatusResponse(Box<State>),
    Log(LogRequestMessage),
    LogResponse(BTreeMap<usize, TaskLogMessage>),

    /// The client requests a continuous stream of a task's log.
    StreamRequest(StreamRequestMessage),
    /// The next chunk of output, that's send to the client.
    Stream(String),

    /// The boolean decides, whether the children should be get a SIGTERM as well.
    Reset(ResetMessage),
    Clean(CleanMessage),
    DaemonShutdown(Shutdown),

    Success(String),
    Failure(String),
    /// Simply notify the client that the connection is now closed.
    /// This is used to, for instance, close a `follow` stream if the task finished.
    Close,

    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, Eq, Clone, Debug, Deserialize, Serialize)]
pub enum TaskSelection {
    TaskIds(Vec<usize>),
    Group(String),
    All,
}

#[derive(PartialEq, Eq, Clone, Deserialize, Serialize)]
pub struct AddMessage {
    pub command: String,
    pub path: PathBuf,
    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,
}

/// We use a custom `Debug` implementation for [AddMessage], as the `envs` field just has
/// too much info in it and makes the log output much too verbose.
///
/// Furthermore, there might be secrets in the environment, resulting in a possible leak
/// if users copy-paste their log output for debugging.
impl std::fmt::Debug for AddMessage {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.debug_struct("Task")
            .field("command", &self.command)
            .field("path", &self.path)
            .field("envs", &"hidden")
            .field("start_immediately", &self.start_immediately)
            .field("stashed", &self.stashed)
            .field("group", &self.group)
            .field("enqueue_at", &self.enqueue_at)
            .field("dependencies", &self.dependencies)
            .field("label", &self.label)
            .field("print_task_id", &self.print_task_id)
            .finish()
    }
}

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

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

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

/// The messages used to restart tasks.
/// It's possible to update the command and paths when restarting tasks.
#[derive(PartialEq, Eq, Clone, Debug, Deserialize, Serialize)]
pub struct RestartMessage {
    pub tasks: Vec<TasksToRestart>,
    pub start_immediately: bool,
    pub stashed: bool,
}

#[derive(PartialEq, Eq, Clone, Debug, Deserialize, Serialize)]
pub struct TasksToRestart {
    pub task_id: usize,
    /// The command that should be used when restarting the task.
    pub command: String,
    /// The path that should be used when restarting the task.
    pub path: PathBuf,
}

#[derive(PartialEq, Eq, 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, Eq, 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, Eq, Clone, Debug, Deserialize, Serialize)]
pub struct KillMessage {
    pub tasks: TaskSelection,
    pub children: bool,
    pub signal: Option<Signal>,
}

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

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

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

#[derive(PartialEq, Eq, Clone, Debug, Deserialize, Serialize)]
pub enum GroupMessage {
    Add {
        name: String,
        parallel_tasks: Option<usize>,
    },
    Remove(String),
    List,
}

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

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

#[derive(PartialEq, Eq, Clone, Debug, Deserialize, Serialize)]
pub struct CleanMessage {
    #[serde(default = "bool::default")]
    pub successful_only: bool,

    #[serde(default = "Option::default")]
    pub group: Option<String>,
}

/// Determines which type of shutdown we're dealing with.
#[derive(PartialEq, Eq, 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,
}

#[derive(PartialEq, Eq, Clone, Debug, Deserialize, Serialize)]
pub struct StreamRequestMessage {
    pub task_id: Option<usize>,
    pub lines: Option<usize>,
}

/// Request logs for specific tasks.
///
/// `task_ids` specifies the requested tasks. If none are given, all tasks are selected.
/// `send_logs` Determines whether logs should be sent at all.
/// `lines` Determines whether only a few lines of log should be returned.
#[derive(PartialEq, Eq, 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, Eq, Clone, Deserialize, Serialize)]
pub struct TaskLogMessage {
    pub task: Task,
    #[serde(default = "bool::default")]
    /// Indicates whether the log output has been truncated or not.
    pub output_complete: bool,
    pub output: Option<Vec<u8>>,
}

/// We use a custom `Debug` implementation for [TaskLogMessage], as the `output` field
/// has too much info in it and renders log output unreadable.
impl std::fmt::Debug for TaskLogMessage {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.debug_struct("TaskLogMessage")
            .field("task", &self.task)
            .field("output_complete", &self.output_complete)
            .field("output", &"hidden")
            .finish()
    }
}

#[derive(PartialEq, Eq, 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 std::net::{UdpSocket,SocketAddr};
use std::io::{self,Write,Error,ErrorKind};
use std::sync::Mutex;
use std::thread;
use std::time::Duration;
use std::str;

use network::buffer::Buffer;

lazy_static! {
  pub static ref METRICS: Mutex<ProxyMetrics> = Mutex::new(ProxyMetrics::new(String::from("sozu")));
}

pub struct ProxyMetrics {
  buffer: Buffer,
  prefix: String,
  remote: Option<(SocketAddr, UdpSocket)>,
}

impl ProxyMetrics {
  pub fn new(prefix: String) -> Self {
    ProxyMetrics {
      buffer: Buffer::with_capacity(2048),
      prefix: prefix,
      remote:   None,
    }
  }

  pub fn run() -> thread::JoinHandle<()> {
    thread::spawn(move || {
      loop {
        thread::sleep(Duration::from_millis(500));
        METRICS.lock().unwrap().send();
      }
    })
  }

  pub fn set_up_remote(&mut self, socket: UdpSocket, addr: SocketAddr) {
    self.remote = Some((addr, socket));
  }

  pub fn send(&mut self) -> io::Result<usize> {
    if self.buffer.available_data() > 0 {
      if let Some((ref addr, ref socket)) = self.remote {
        match socket.send_to(self.buffer.data(), addr) {
          Ok(sz) => {
            self.buffer.consume(sz);
            Ok(sz)
          },
          Err(e) => {
            Err(e)
          }
        }
      } else {
        Err(Error::new(ErrorKind::NotConnected, "metrics socket not set up"))
      }
    } else {
      Err(Error::new(ErrorKind::Other, "no data to send"))
    }
  }

  fn emit(&mut self, metric: &str) -> io::Result<usize> {
    self.buffer.write(metric.as_bytes())
  }

  pub fn count(&mut self, key: &str, count: i64) -> io::Result<usize> {
    let fmt = format!("{}.{}:{}|c\n", &self.prefix, key, count);
    self.emit(&fmt)
  }

  pub fn incr(&mut self, key: &str) -> io::Result<usize> {
    self.count(key, 1)
  }

  pub fn decr(&mut self, key: &str) -> io::Result<usize> {
    self.count(key, -1)
  }

  pub fn time(&mut self, key: &str, time: u64) -> io::Result<usize> {
    let fmt = format!("{}.{}:{}|ms\n", self.prefix, key, time);
    self.emit(&fmt)
  }

  pub fn gauge(&mut self, key: &str, value: u64) -> io::Result<usize> {
    let fmt = format!("{}.{}:{}|g\n", self.prefix, key, value);
    self.emit(&fmt)
  }

  pub fn meter(&mut self, key: &str, value: u64) -> io::Result<usize> {
    let fmt = format!("{}.{}:{}|m\n", self.prefix, key, value);
    self.emit(&fmt)
  }
}

#[macro_export]
macro_rules! count (
  ($key:expr, $value: expr) => (::network::metrics::METRICS.lock().unwrap().count($key, $value);)
);

#[macro_export]
macro_rules! incr (
  ($key:expr) => (::network::metrics::METRICS.lock().unwrap().incr($key);)
);

#[macro_export]
macro_rules! decr (
  ($key:expr) => (::network::metrics::METRICS.lock().unwrap().decr($key);)
);

#[macro_export]
macro_rules! time (
  ($key:expr, $value: expr) => (::network::metrics::METRICS.lock().unwrap().time($key, $value);)
);

#[macro_export]
macro_rules! gauge (
  ($key:expr, $value: expr) => (::network::metrics::METRICS.lock().unwrap().gauge($key, $value);)
);

#[macro_export]
macro_rules! meter (
  ($key:expr, $value: expr) => (::network::metrics::METRICS.lock().unwrap().meter($key, $value);)
);
<commit_msg>reduce allocations in metrics<commit_after>use std::net::{UdpSocket,SocketAddr};
use std::io::{self,Write,Error,ErrorKind};
use std::sync::Mutex;
use std::thread;
use std::time::Duration;
use std::str;

use network::buffer::Buffer;

lazy_static! {
  pub static ref METRICS: Mutex<ProxyMetrics> = Mutex::new(ProxyMetrics::new(String::from("sozu")));
}

pub struct ProxyMetrics {
  buffer: Buffer,
  prefix: String,
  remote: Option<(SocketAddr, UdpSocket)>,
}

impl ProxyMetrics {
  pub fn new(prefix: String) -> Self {
    ProxyMetrics {
      buffer: Buffer::with_capacity(2048),
      prefix: prefix,
      remote:   None,
    }
  }

  pub fn run() -> thread::JoinHandle<()> {
    thread::spawn(move || {
      loop {
        thread::sleep(Duration::from_millis(500));
        METRICS.lock().unwrap().send();
      }
    })
  }

  pub fn set_up_remote(&mut self, socket: UdpSocket, addr: SocketAddr) {
    self.remote = Some((addr, socket));
  }

  pub fn send(&mut self) -> io::Result<usize> {
    if self.buffer.available_data() > 0 {
      if let Some((ref addr, ref socket)) = self.remote {
        match socket.send_to(self.buffer.data(), addr) {
          Ok(sz) => {
            self.buffer.consume(sz);
            Ok(sz)
          },
          Err(e) => {
            Err(e)
          }
        }
      } else {
        Err(Error::new(ErrorKind::NotConnected, "metrics socket not set up"))
      }
    } else {
      Err(Error::new(ErrorKind::Other, "no data to send"))
    }
  }

  fn emit(&mut self, metric: &str) -> io::Result<usize> {
    self.buffer.write(metric.as_bytes())
  }

  pub fn count(&mut self, key: &str, count: i64) -> io::Result<()> {
    self.buffer.write_fmt(format_args!("{}.{}:{}|c\n", &self.prefix, key, count))
  }

  pub fn incr(&mut self, key: &str) -> io::Result<()> {
    self.count(key, 1)
  }

  pub fn decr(&mut self, key: &str) -> io::Result<()> {
    self.count(key, -1)
  }

  pub fn time(&mut self, key: &str, time: u64) -> io::Result<()> {
    self.buffer.write_fmt(format_args!("{}.{}:{}|ms\n", self.prefix, key, time))
  }

  pub fn gauge(&mut self, key: &str, value: u64) -> io::Result<()> {
    self.buffer.write_fmt(format_args!("{}.{}:{}|g\n", self.prefix, key, value))
  }

  pub fn meter(&mut self, key: &str, value: u64) -> io::Result<()> {
    self.buffer.write_fmt(format_args!("{}.{}:{}|m\n", self.prefix, key, value))
  }
}

#[macro_export]
macro_rules! count (
  ($key:expr, $value: expr) => (::network::metrics::METRICS.lock().unwrap().count($key, $value);)
);

#[macro_export]
macro_rules! incr (
  ($key:expr) => (::network::metrics::METRICS.lock().unwrap().incr($key);)
);

#[macro_export]
macro_rules! decr (
  ($key:expr) => (::network::metrics::METRICS.lock().unwrap().decr($key);)
);

#[macro_export]
macro_rules! time (
  ($key:expr, $value: expr) => (::network::metrics::METRICS.lock().unwrap().time($key, $value);)
);

#[macro_export]
macro_rules! gauge (
  ($key:expr, $value: expr) => (::network::metrics::METRICS.lock().unwrap().gauge($key, $value);)
);

#[macro_export]
macro_rules! meter (
  ($key:expr, $value: expr) => (::network::metrics::METRICS.lock().unwrap().meter($key, $value);)
);
<|endoftext|>


<commit_before>extern crate base64;
extern crate rand;
extern crate lithos;
extern crate ssh_keys;
#[macro_use] extern crate failure;
#[macro_use] extern crate structopt;

use std::fs::File;
use std::io::{Read, BufReader, BufRead, Write, stdout, stderr};
use std::path::Path;
use std::process::exit;

use failure::{Error, ResultExt};
use rand::Rng;
use ssh_keys::{PublicKey, PrivateKey, openssh};
use structopt::StructOpt;

use lithos::nacl;

#[derive(Debug, StructOpt)]
#[structopt(name = "lithos_crypt",
            about = "An utility to encrypt secrets for lithos. \
                     It also allows to decrypt secrets for introspection if \
                     you have access for private key (only for debugging)")]
enum Options {
    #[structopt(name="encrypt")]
    Encrypt(EncryptOpt),
    #[structopt(name="decrypt")]
    Decrypt(DecryptOpt),
}

#[derive(Debug, StructOpt)]
#[structopt(about = "Encrypt secret value to put in config")]
pub struct EncryptOpt {
    #[structopt(long="key-file", short="k", help="
        A openssh-formatted ed25519 public key to use for encryption
    ", parse(try_from_str="parse_public_key"))]
    key: PublicKey,
    #[structopt(long="data", short="d", help="data to encrypt")]
    data: String,
}

#[derive(Debug, StructOpt)]
#[structopt(about = "Decrypt secret value from config")]
pub struct DecryptOpt {
    #[structopt(long="key-file", short="i", help="
        A openssh-formatted ed25519 private key to use for decryption
    ", parse(try_from_str="parse_private_key"))]
    key: PrivateKey,
    #[structopt(long="data", short="d", help="base64-encoded data to decrypt")]
    data: String,
}

fn parse_public_key(filename: &str) -> Result<PublicKey, Error> {
    let mut buf = String::with_capacity(1024);
    File::open(filename)
        .and_then(|f| BufReader::new(f).read_line(&mut buf))
        .context(Path::new(filename).display().to_string())?;
    let key = openssh::parse_public_key(&buf)?;
    Ok(key)
}

fn parse_private_key(filename: &str) -> Result<PrivateKey, Error> {
    let mut buf = String::with_capacity(1024);
    File::open(filename)
        .and_then(|mut f| f.read_to_string(&mut buf))
        .context(Path::new(filename).display().to_string())?;
    let mut key = openssh::parse_private_key(&buf)?;
    Ok(key.pop().expect("at least one key parsed"))
}

fn encrypt(e: EncryptOpt) -> Result<(), Error> {
    let key_bytes = match e.key {
        PublicKey::Ed25519(key) => key,
        _ => bail!("Only ed25519 keys are supported"),
    };
    let mut nonce = [0u8; 24];
    let mut rng = rand::OsRng::new()?;
    rng.fill_bytes(&mut nonce);
    let cypher = nacl::crypto_secretbox(
        e.data.as_bytes(), &nonce[..], &key_bytes[..]);
    let mut buf = Vec::with_capacity(cypher.len() + 32 + 24);
    buf.write(&key_bytes[..]).unwrap();
    buf.write(&nonce[..]).unwrap();
    buf.write(&cypher).unwrap();
    let data = base64::encode(&buf);
    println!("v1:{}", data);
    Ok(())
}

fn decrypt(e: DecryptOpt) -> Result<(), Error> {
    let key_bytes = match e.key {
        PrivateKey::Ed25519(key) => key,
        _ => bail!("Only ed25519 keys are supported"),
    };
    if !e.data.starts_with("v1:") {
        bail!("Only v1 secrets are supported");
    }
    let data = base64::decode(&e.data["v1:".len()..])?;
    if data.len() < 32+24 {
        bail!("data is too short");
    }
    let plain = nacl::crypto_secretbox_open(
        &data[32+24..], &data[32..32+24], &key_bytes[32..])
        .map_err(|e| format_err!("{}", e))?;
    let mut out = stdout();
    out.write_all(&plain)?;
    out.flush()?;
    stderr().write_all(b"\n")?; // nicer in print
    Ok(())
}

fn main() {
    use Options::*;
    let opt = Options::from_args();
    let res = match opt {
        Encrypt(e) => encrypt(e),
        Decrypt(d) => decrypt(d),
    };
    match res {
        Ok(()) => {
            exit(0);
        }
        Err(e) => {
            eprintln!("{}", e);
            exit(1);
        }
    }
}
<commit_msg>Add `lithos_crypt check-key` command<commit_after>extern crate base64;
extern crate rand;
extern crate lithos;
extern crate ssh_keys;
#[macro_use] extern crate failure;
#[macro_use] extern crate structopt;

use std::fs::File;
use std::io::{Read, BufReader, BufRead, Write, stdout, stderr};
use std::path::Path;
use std::process::exit;

use failure::{Error, ResultExt};
use rand::Rng;
use ssh_keys::{PublicKey, PrivateKey, openssh};
use structopt::StructOpt;

use lithos::nacl;

#[derive(Debug, StructOpt)]
#[structopt(name = "lithos_crypt",
            about = "An utility to encrypt secrets for lithos. \
                     It also allows to decrypt secrets for introspection if \
                     you have access for private key (only for debugging)")]
enum Options {
    #[structopt(name="encrypt")]
    Encrypt(EncryptOpt),
    #[structopt(name="decrypt")]
    Decrypt(DecryptOpt),
    #[structopt(name="check-key")]
    CheckKey(CheckKeyOpt),
}

#[derive(Debug, StructOpt)]
#[structopt(about = "Encrypt secret value to put in config")]
pub struct EncryptOpt {
    #[structopt(long="key-file", short="k", help="
        A openssh-formatted ed25519 public key to use for encryption
    ", parse(try_from_str="parse_public_key"))]
    key: PublicKey,
    #[structopt(long="data", short="d", help="data to encrypt")]
    data: String,
}

#[derive(Debug, StructOpt)]
#[structopt(about = "Check that the secret value is encrypted \
                     with specified public key")]
pub struct CheckKeyOpt {
    #[structopt(long="key-file", short="k", help="
        A openssh-formatted ed25519 public key to use for encryption
    ", parse(try_from_str="parse_public_key"))]
    key: PublicKey,
    #[structopt(long="data", short="d", help="data to encrypt")]
    data: String,
}

#[derive(Debug, StructOpt)]
#[structopt(about = "Decrypt secret value from config")]
pub struct DecryptOpt {
    #[structopt(long="key-file", short="i", help="
        A openssh-formatted ed25519 private key to use for decryption
    ", parse(try_from_str="parse_private_key"))]
    key: PrivateKey,
    #[structopt(long="data", short="d", help="base64-encoded data to decrypt")]
    data: String,
}

fn parse_public_key(filename: &str) -> Result<PublicKey, Error> {
    let mut buf = String::with_capacity(1024);
    File::open(filename)
        .and_then(|f| BufReader::new(f).read_line(&mut buf))
        .context(Path::new(filename).display().to_string())?;
    let key = openssh::parse_public_key(&buf)?;
    Ok(key)
}

fn parse_private_key(filename: &str) -> Result<PrivateKey, Error> {
    let mut buf = String::with_capacity(1024);
    File::open(filename)
        .and_then(|mut f| f.read_to_string(&mut buf))
        .context(Path::new(filename).display().to_string())?;
    let mut key = openssh::parse_private_key(&buf)?;
    Ok(key.pop().expect("at least one key parsed"))
}

fn encrypt(e: EncryptOpt) -> Result<(), Error> {
    let key_bytes = match e.key {
        PublicKey::Ed25519(key) => key,
        _ => bail!("Only ed25519 keys are supported"),
    };
    let mut nonce = [0u8; 24];
    let mut rng = rand::OsRng::new()?;
    rng.fill_bytes(&mut nonce);
    let cypher = nacl::crypto_secretbox(
        e.data.as_bytes(), &nonce[..], &key_bytes[..]);
    let mut buf = Vec::with_capacity(cypher.len() + 32 + 24);
    buf.write(&key_bytes[..]).unwrap();
    buf.write(&nonce[..]).unwrap();
    buf.write(&cypher).unwrap();
    let data = base64::encode(&buf);
    println!("v1:{}", data);
    Ok(())
}

fn check_key(o: CheckKeyOpt) -> Result<(), Error> {
    let key_bytes = match o.key {
        PublicKey::Ed25519(key) => key,
        _ => bail!("Only ed25519 keys are supported"),
    };
    if !o.data.starts_with("v1:") {
        bail!("Only v1 secrets are supported");
    }
    let data = base64::decode(&o.data["v1:".len()..])?;
    if data.len() < 32+24 {
        bail!("data is too short");
    }
    if data[..32] != key_bytes {
        bail!("Key mismatch");
    }
    Ok(())
}

fn decrypt(e: DecryptOpt) -> Result<(), Error> {
    let key_bytes = match e.key {
        PrivateKey::Ed25519(key) => key,
        _ => bail!("Only ed25519 keys are supported"),
    };
    if !e.data.starts_with("v1:") {
        bail!("Only v1 secrets are supported");
    }
    let data = base64::decode(&e.data["v1:".len()..])?;
    if data.len() < 32+24 {
        bail!("data is too short");
    }
    let plain = nacl::crypto_secretbox_open(
        &data[32+24..], &data[32..32+24], &key_bytes[32..])
        .map_err(|e| format_err!("{}", e))?;
    let mut out = stdout();
    out.write_all(&plain)?;
    out.flush()?;
    stderr().write_all(b"\n")?; // nicer in print
    Ok(())
}

fn main() {
    use Options::*;
    let opt = Options::from_args();
    let res = match opt {
        Encrypt(e) => encrypt(e),
        Decrypt(d) => decrypt(d),
        CheckKey(c) => check_key(c),
    };
    match res {
        Ok(()) => {
            exit(0);
        }
        Err(e) => {
            eprintln!("{}", e);
            exit(1);
        }
    }
}
<|endoftext|>


<commit_before>//
// zhttpto.rs
//
// Starting code for PS1
// Running on Rust 0.9
//
// Note that this code has serious security risks!  You should not run it
// on any system with access to sensitive files.
//
// University of Virginia - cs4414 Spring 2014
// Weilin Xu and David Evans
// Version 0.3

#[feature(globs)];
use std::io::*;
use std::io::net::ip::{SocketAddr};
use std::{str};
use std::io::buffered::BufferedReader;

static IP: &'static str  = "127.0.0.1";
static PORT:        int  = 4414;
static mut visitor_count: uint = 0;

fn main() {
    let addr = from_str::<SocketAddr>(format!("{:s}:{:d}", IP, PORT)).unwrap();
    let mut acceptor = net::tcp::TcpListener::bind(addr).listen();

    println(format!("Listening on [{:s}] ...", addr.to_str()));

    for stream in acceptor.incoming() {
        // Spawn a task to handle the connection
        do spawn {
            let mut stream = stream;
            match stream {
                Some(ref mut s) => {
                    match s.peer_name() {
                        Some(pn) => {
                            println!("Received connection from: [{:s}]",
                                    pn.to_str());
                            unsafe {
                                atomic_add(&mut visitor_count, 1);
                                println!("Visitor count: {:u}", visitor_count);
                            }
                            },
                        None => ()
                    }
                },
                None => ()
            }
            let mut buf = [0, ..500];
            stream.read(buf);
            let request_str = str::from_utf8(buf);
            let filename = get_requested_filename(request_str);
            if (filename == "") {
let response: ~str = ~"HTTP/1.1 200 OK\r\nContent-Type: text/html; charset=UTF-8\r\n\r\n
<doctype !html><title>Hello, Rust!</title>

Greetings, Krusty!

Visitor count: "
+ unsafe{
    visitor_count.to_str()
} + "

\r\n";
            stream.write(response.as_bytes());
            }
            else {
                println!("filename: {:s}", filename);
                println!("Received request :\n{:s}", request_str);
                let contents = read_filename(filename);
                let response = format_response(contents);
                stream.write(response.as_bytes());
            }
            println!("Connection terminates.");
        }
    }
}

fn get_requested_filename(request: &str) -> &str {
    let lines: ~[&str] = request.split('\n').collect();
    let firstline      = lines[0];
    let after          = firstline.slice_from(4).to_owned();
    let then: ~[&str]  = after.split(' ').collect();
    let filename       = then[0].slice_from(1);

    filename
}

fn read_filename(filename : &str) -> ~str {
    let mut contents = ~"";
    let filepath= Path::new(filename.clone());
    match File::open_mode(&filepath, Open, Read) {
        Some (file) => {
            println("File opened for reading ...");
            contents = get_file_contents(file);
        },
        _ => {
            println!("Error opening file: {:s}", filename);
        }
    }
    contents
}

fn get_file_contents(file: File) -> ~str {
    let mut filereader = ~BufferedReader::new(file);
    println("Reading file ...");
    let contents: ~[u8] = filereader.read_to_end();
    str::from_utf8(contents).to_owned()
}

fn format_response(file_contents : &str) -> ~str {
    let response = ~"HTTP/1.1 200 OK\r\nContent-Type: text/plain; charset=UTF-8\r\n\r\n"
    + file_contents;
    response
}

fn atomic_add(var: &mut uint, count: uint) -> uint {
    let oldval = var.clone();
    *var = *var + count;
    return oldval;
}
<commit_msg>problem 5 solution<commit_after>//
// zhttpto.rs
//
// Starting code for PS1
// Running on Rust 0.9
//
// Note that this code has serious security risks!  You should not run it
// on any system with access to sensitive files.
//
// University of Virginia - cs4414 Spring 2014
// Weilin Xu and David Evans
// Version 0.3

#[feature(globs)];
use std::io::*;
use std::io::net::ip::{SocketAddr};
use std::{str};
use std::io::buffered::BufferedReader;

static IP: &'static str  = "127.0.0.1";
static PORT:        int  = 4414;
static mut visitor_count: uint = 0;

fn main() {
    let addr = from_str::<SocketAddr>(format!("{:s}:{:d}", IP, PORT)).unwrap();
    let mut acceptor = net::tcp::TcpListener::bind(addr).listen();

    println(format!("Listening on [{:s}] ...", addr.to_str()));

    for stream in acceptor.incoming() {
        // Spawn a task to handle the connection
        do spawn {
            let mut stream = stream;
            match stream {
                Some(ref mut s) => {
                    match s.peer_name() {
                        Some(pn) => {
                            println!("Received connection from: [{:s}]",
                                    pn.to_str());
                            unsafe {
                                atomic_add(&mut visitor_count, 1);
                                println!("Visitor count: {:u}", visitor_count);
                            }
                            },
                        None => ()
                    }
                },
                None => ()
            }
            let mut buf = [0, ..500];
            stream.read(buf);
            let request_str = str::from_utf8(buf);
            let filename = get_requested_filename(request_str);
            if (filename == "") {
let response: ~str = ~"HTTP/1.1 200 OK\r\nContent-Type: text/html; charset=UTF-8\r\n\r\n
<doctype !html><title>Hello, Rust!</title>

Greetings, Krusty!

Visitor count: "
+ unsafe{
    visitor_count.to_str()
} + "

\r\n";
            stream.write(response.as_bytes());
            }
            else {
                println!("filename: {:s}", filename);
                println!("Received request :\n{:s}", request_str);
                let response = read_filename(filename);
                stream.write(response.as_bytes());
            }
            println!("Connection terminates.");
        }
    }
}

fn get_requested_filename(request: &str) -> &str {
    let lines: ~[&str] = request.split('\n').collect();
    let firstline      = lines[0];
    let after          = firstline.slice_from(4).to_owned();
    let then: ~[&str]  = after.split(' ').collect();
    let filename       = then[0].slice_from(1);

    filename
}

fn read_filename(filename : &str) -> ~str {
    let mut contents = ~"";
    if (filename.slice_from(filename.len() - 5) != ".html") {
        contents = fmt_bad_response() + "\nWanted: " + filename;
    }
    else {
        let filepath= Path::new(filename.clone());
        match File::open_mode(&filepath, Open, Read) {
            Some (file) => {
                println("File opened for reading ...");
                contents = fmt_response(get_file_contents(file));
            },
            _ => {
                println!("Error opening file: {:s}", filename);
            }
        }
    }
    contents
}

fn get_file_contents(file: File) -> ~str {
    let mut filereader = ~BufferedReader::new(file);
    println("Reading file ...");
    let contents: ~[u8] = filereader.read_to_end();
    str::from_utf8(contents).to_owned()
}

fn fmt_response(file_contents : &str) -> ~str {
    let response = ~"HTTP/1.1 200 OK\r\nContent-Type: text/html; charset=UTF-8\r\n\r\n"
    + file_contents;
    response
}

fn fmt_bad_response() -> ~str {
    let response = ~"HTTP/1.1 403 OK\r\nContent-Type: text/plain; charset=UTF-8\r\n\r\n"
    + "403 Bad filetype.";
    response
}

fn atomic_add(var: &mut uint, count: uint) -> uint {
    let oldval = var.clone();
    *var = *var + count;
    return oldval;
}
<|endoftext|>


<commit_before>use gl::types::*;
use id_allocator::IdAllocator;
use nalgebra::{normalize, cross};
use nalgebra::{Pnt3, Vec3};
use ncollide::bounding_volume::{AABB, AABB3};
use noise::{Seed, Brownian2, Point2};
use state::EntityId;
use std::cmp::partial_max;
use std::collections::hash_map::HashMap;
use std::num::Float;
use std::ops::Add;
use stopwatch::TimerSet;
use terrain::{AMPLITUDE, TerrainType};

pub const BLOCK_WIDTH: i32 = 4;

#[derive(Show, PartialEq, Eq, Hash, Copy, Clone)]
pub struct BlockPosition(Pnt3<i32>);

impl BlockPosition {
  #[inline(always)]
  pub fn new(x: i32, y: i32, z: i32) -> BlockPosition {
    BlockPosition(Pnt3::new(x, y, z))
  }

  #[inline(always)]
  pub fn as_pnt<'a>(&'a self) -> &'a Pnt3<i32> {
    let BlockPosition(ref pnt) = *self;
    pnt
  }

  #[inline(always)]
  pub fn as_mut_pnt3<'a>(&'a mut self) -> &'a mut Pnt3<i32> {
    let BlockPosition(ref mut pnt) = *self;
    pnt
  }

  pub fn from_world_position(world_position: &Pnt3<f32>) -> BlockPosition {
    macro_rules! convert_coordinate(
      ($x: expr) => ({
        let x = $x.floor() as i32;
        let x =
          if x < 0 {
            x - (BLOCK_WIDTH - 1)
          } else {
            x
          };
        x / BLOCK_WIDTH
      })
    );
    BlockPosition(
      Pnt3::new(
        convert_coordinate!(world_position.x),
        convert_coordinate!(world_position.y),
        convert_coordinate!(world_position.z),
      )
    )
  }

  pub fn to_world_position(&self) -> Pnt3<f32> {
    Pnt3::new(
      (self.as_pnt().x * BLOCK_WIDTH) as f32,
      (self.as_pnt().y * BLOCK_WIDTH) as f32,
      (self.as_pnt().z * BLOCK_WIDTH) as f32,
    )
  }
}

impl Add<Vec3<i32>> for BlockPosition {
  type Output = BlockPosition;

  fn add(mut self, rhs: Vec3<i32>) -> Self {
    self.as_mut_pnt3().x += rhs.x;
    self.as_mut_pnt3().y += rhs.y;
    self.as_mut_pnt3().z += rhs.z;
    self
  }
}

/// Ductyped heightmap methods.
trait HeightMapExt {
  /// The coordinate of the tile at a given x/z.
  fn point_at(&self, seed: &Seed, x: f32, z: f32) -> Pnt3<f32>;
  /// The lighting normal of the tile at a given x/z.
  fn normal_at(&self, seed: &Seed, x: f32, z: f32) -> Vec3<f32>;
}

impl HeightMapExt for Brownian2<f64, fn (&Seed, &Point2<f64>) -> f64> {
  fn point_at(&self, seed: &Seed, x: f32, z: f32) -> Pnt3<f32> {
    let y = AMPLITUDE * (self.call((seed, &[x as f64, z as f64])) + 1.0) / 2.0;
    Pnt3::new(x as f32, y as f32, z as f32)
  }

  fn normal_at(&self, seed: &Seed, x: f32, z: f32) -> Vec3<f32> {
    const DELTA: f32 = 0.2;
    let dx =
      self.point_at(seed, x + DELTA, z).to_vec()
      - self.point_at(seed, x - DELTA, z).to_vec();
    let dz =
      self.point_at(seed, x, z + DELTA).to_vec()
      - self.point_at(seed, x, z - DELTA).to_vec();
    normalize(&cross(&dx, &dz))
  }
}

pub struct TerrainBlock {
  // These Vecs must all be ordered the same way.

  // vertex coordinates flattened into separate GLfloats (x, y, z order)
  pub vertex_coordinates: Vec<GLfloat>,
  // per-vertex normal vectors flattened into separate GLfloats (x, y, z order)
  pub normals: Vec<GLfloat>,
  // per-triangle terrain types
  pub typs: Vec<GLuint>,

  // per-triangle entity IDs
  pub ids: Vec<EntityId>,
  // per-triangle bounding boxes
  pub bounds: HashMap<EntityId, AABB3<GLfloat>>,
}

impl TerrainBlock {
  pub fn empty() -> TerrainBlock {
    TerrainBlock {
      vertex_coordinates: Vec::new(),
      normals: Vec::new(),
      typs: Vec::new(),
      ids: Vec::new(),
      bounds: HashMap::new(),
    }
  }

  pub fn generate<HeightMap: HeightMapExt>(
    timers: &TimerSet,
    id_allocator: &mut IdAllocator<EntityId>,
    heightmap: &HeightMap,
    position: &BlockPosition,
    lateral_samples: u32,
    seed: &Seed,
  ) -> TerrainBlock {
    timers.time("update.generate_block", || {
      let mut block = TerrainBlock::empty();

      let x = (position.as_pnt().x * BLOCK_WIDTH) as f32;
      let y = (position.as_pnt().y * BLOCK_WIDTH) as f32;
      let z = (position.as_pnt().z * BLOCK_WIDTH) as f32;

      let sample_width = BLOCK_WIDTH as f32 / lateral_samples as f32;

      for dx in range(0, lateral_samples) {
        let x = x + dx as f32 * sample_width;
        for dz in range(0, lateral_samples) {
          let z = z + dz as f32 * sample_width;
          let position = Pnt3::new(x, y, z);
          TerrainBlock::add_tile(
            timers,
            heightmap,
            id_allocator,
            &mut block,
            sample_width,
            &position,
            seed,
          );
        }
      }

      block
    })
  }

  fn add_tile<'a, HeightMap: HeightMapExt>(
    timers: &TimerSet,
    hm: &HeightMap,
    id_allocator: &mut IdAllocator<EntityId>,
    block: &mut TerrainBlock,
    sample_width: f32,
    position: &Pnt3<f32>,
    seed: &Seed,
  ) {
    let half_width = sample_width / 2.0;
    let center = hm.point_at(seed, position.x + half_width, position.z + half_width);

    if position.y >= center.y || center.y > position.y + BLOCK_WIDTH as f32 {
      return;
    }

    timers.time("update.generate_block.add_tile", || {
      let center_normal = hm.normal_at(seed, position.x + half_width, position.z + half_width);

      let x2 = position.x + sample_width;
      let z2 = position.z + sample_width;

      let ps: [Pnt3<f32>; 4] =
        [ hm.point_at(seed, position.x, position.z)
        , hm.point_at(seed, position.x, z2)
        , hm.point_at(seed, x2, z2)
        , hm.point_at(seed, x2, position.z)
        ];

      let ns: [Vec3<f32>; 4] =
        [ hm.normal_at(seed, position.x, position.z)
        , hm.normal_at(seed, position.x, z2)
        , hm.normal_at(seed, x2, z2)
        , hm.normal_at(seed, x2, position.z)
        ];

      let center_lower_than = ps.iter().filter(|v| center.y < v.y).count();

      let terrain_type =
        if center_lower_than >= 3 {
          TerrainType::Dirt
        } else {
          TerrainType::Grass
        };

      macro_rules! place_terrain(
        ($v1: expr,
         $v2: expr,
         $n1: expr,
         $n2: expr,
         $minx: expr,
         $minz: expr,
         $maxx: expr,
         $maxz: expr
        ) => ({
          let maxy = partial_max($v1.y, $v2.y);
          let maxy = maxy.and_then(|m| partial_max(m, center.y));
          let maxy = maxy.unwrap();

          let id = id_allocator.allocate();
          block.vertex_coordinates.push_all(&[
            $v1.x, $v1.y, $v1.z,
            $v2.x, $v2.y, $v2.z,
            center.x, center.y, center.z,
          ]);
          block.normals.push_all(&[
            $n1.x, $n1.y, $n1.z,
            $n2.x, $n2.y, $n2.z,
            center_normal.x, center_normal.y, center_normal.z,
          ]);
          block.typs.push(terrain_type as GLuint);
          block.ids.push(id);
          block.bounds.insert(
            id,
            AABB::new(
              Pnt3::new($minx, $v1.y, $minz),
              Pnt3::new($maxx, maxy, $maxz),
            ),
          );
        });
      );

      let placements = 4;
      block.vertex_coordinates.reserve(placements*9);
      block.normals.reserve(placements*9);
      block.typs.reserve(placements);
      block.ids.reserve(placements);
      block.bounds.reserve(placements);

      let centr = center; // makes alignment nice
      place_terrain!(&ps[0], &ps[1], &ns[0], &ns[1], ps[0].x, ps[0].z, centr.x, ps[1].z);
      place_terrain!(&ps[1], &ps[2], &ns[1], &ns[2], ps[1].x, centr.z, ps[2].x, ps[2].z);
      place_terrain!(&ps[2], &ps[3], &ns[2], &ns[3], centr.x, centr.z, ps[2].x, ps[2].z);
      place_terrain!(&ps[3], &ps[0], &ns[3], &ns[0], ps[0].x, ps[0].z, ps[3].x, centr.z);
    })
  }
}
<commit_msg>Improve terrain normal calculation, especially at lower LODs.<commit_after>use gl::types::*;
use id_allocator::IdAllocator;
use nalgebra::{normalize, cross};
use nalgebra::{Pnt3, Vec3};
use ncollide::bounding_volume::{AABB, AABB3};
use noise::{Seed, Brownian2, Point2};
use state::EntityId;
use std::cmp::partial_max;
use std::collections::hash_map::HashMap;
use std::num::Float;
use std::ops::Add;
use stopwatch::TimerSet;
use terrain::{AMPLITUDE, TerrainType};

pub const BLOCK_WIDTH: i32 = 4;

#[derive(Show, PartialEq, Eq, Hash, Copy, Clone)]
pub struct BlockPosition(Pnt3<i32>);

impl BlockPosition {
  #[inline(always)]
  pub fn new(x: i32, y: i32, z: i32) -> BlockPosition {
    BlockPosition(Pnt3::new(x, y, z))
  }

  #[inline(always)]
  pub fn as_pnt<'a>(&'a self) -> &'a Pnt3<i32> {
    let BlockPosition(ref pnt) = *self;
    pnt
  }

  #[inline(always)]
  pub fn as_mut_pnt3<'a>(&'a mut self) -> &'a mut Pnt3<i32> {
    let BlockPosition(ref mut pnt) = *self;
    pnt
  }

  pub fn from_world_position(world_position: &Pnt3<f32>) -> BlockPosition {
    macro_rules! convert_coordinate(
      ($x: expr) => ({
        let x = $x.floor() as i32;
        let x =
          if x < 0 {
            x - (BLOCK_WIDTH - 1)
          } else {
            x
          };
        x / BLOCK_WIDTH
      })
    );
    BlockPosition(
      Pnt3::new(
        convert_coordinate!(world_position.x),
        convert_coordinate!(world_position.y),
        convert_coordinate!(world_position.z),
      )
    )
  }

  pub fn to_world_position(&self) -> Pnt3<f32> {
    Pnt3::new(
      (self.as_pnt().x * BLOCK_WIDTH) as f32,
      (self.as_pnt().y * BLOCK_WIDTH) as f32,
      (self.as_pnt().z * BLOCK_WIDTH) as f32,
    )
  }
}

impl Add<Vec3<i32>> for BlockPosition {
  type Output = BlockPosition;

  fn add(mut self, rhs: Vec3<i32>) -> Self {
    self.as_mut_pnt3().x += rhs.x;
    self.as_mut_pnt3().y += rhs.y;
    self.as_mut_pnt3().z += rhs.z;
    self
  }
}

/// Ductyped heightmap methods.
trait HeightMapExt {
  /// The coordinate of the tile at a given x/z.
  fn point_at(&self, seed: &Seed, x: f32, z: f32) -> Pnt3<f32>;
  /// The lighting normal of the tile at a given x/z.
  fn normal_at(&self, seed: &Seed, delta: f32, x: f32, z: f32) -> Vec3<f32>;
}

impl HeightMapExt for Brownian2<f64, fn (&Seed, &Point2<f64>) -> f64> {
  fn point_at(&self, seed: &Seed, x: f32, z: f32) -> Pnt3<f32> {
    let y = AMPLITUDE * (self.call((seed, &[x as f64, z as f64])) + 1.0) / 2.0;
    Pnt3::new(x as f32, y as f32, z as f32)
  }

  fn normal_at(&self, seed: &Seed, delta: f32, x: f32, z: f32) -> Vec3<f32> {
    let dx =
      self.point_at(seed, x + delta, z).to_vec()
      - self.point_at(seed, x - delta, z).to_vec();
    let dz =
      self.point_at(seed, x, z + delta).to_vec()
      - self.point_at(seed, x, z - delta).to_vec();
    normalize(&cross(&dx, &dz))
  }
}

pub struct TerrainBlock {
  // These Vecs must all be ordered the same way.

  // vertex coordinates flattened into separate GLfloats (x, y, z order)
  pub vertex_coordinates: Vec<GLfloat>,
  // per-vertex normal vectors flattened into separate GLfloats (x, y, z order)
  pub normals: Vec<GLfloat>,
  // per-triangle terrain types
  pub typs: Vec<GLuint>,

  // per-triangle entity IDs
  pub ids: Vec<EntityId>,
  // per-triangle bounding boxes
  pub bounds: HashMap<EntityId, AABB3<GLfloat>>,
}

impl TerrainBlock {
  pub fn empty() -> TerrainBlock {
    TerrainBlock {
      vertex_coordinates: Vec::new(),
      normals: Vec::new(),
      typs: Vec::new(),
      ids: Vec::new(),
      bounds: HashMap::new(),
    }
  }

  pub fn generate<HeightMap: HeightMapExt>(
    timers: &TimerSet,
    id_allocator: &mut IdAllocator<EntityId>,
    heightmap: &HeightMap,
    position: &BlockPosition,
    lateral_samples: u32,
    seed: &Seed,
  ) -> TerrainBlock {
    timers.time("update.generate_block", || {
      let mut block = TerrainBlock::empty();

      let x = (position.as_pnt().x * BLOCK_WIDTH) as f32;
      let y = (position.as_pnt().y * BLOCK_WIDTH) as f32;
      let z = (position.as_pnt().z * BLOCK_WIDTH) as f32;

      let sample_width = BLOCK_WIDTH as f32 / lateral_samples as f32;

      for dx in range(0, lateral_samples) {
        let x = x + dx as f32 * sample_width;
        for dz in range(0, lateral_samples) {
          let z = z + dz as f32 * sample_width;
          let position = Pnt3::new(x, y, z);
          TerrainBlock::add_tile(
            timers,
            heightmap,
            id_allocator,
            &mut block,
            sample_width,
            &position,
            seed,
          );
        }
      }

      block
    })
  }

  fn add_tile<'a, HeightMap: HeightMapExt>(
    timers: &TimerSet,
    hm: &HeightMap,
    id_allocator: &mut IdAllocator<EntityId>,
    block: &mut TerrainBlock,
    sample_width: f32,
    position: &Pnt3<f32>,
    seed: &Seed,
  ) {
    let half_width = sample_width / 2.0;
    let center = hm.point_at(seed, position.x + half_width, position.z + half_width);

    if position.y >= center.y || center.y > position.y + BLOCK_WIDTH as f32 {
      return;
    }

    timers.time("update.generate_block.add_tile", || {
      let normal_delta = sample_width / 2.0;
      let center_normal =
        hm.normal_at(seed, normal_delta, position.x + half_width, position.z + half_width);

      let x2 = position.x + sample_width;
      let z2 = position.z + sample_width;

      let ps: [Pnt3<f32>; 4] =
        [ hm.point_at(seed, position.x, position.z)
        , hm.point_at(seed, position.x, z2)
        , hm.point_at(seed, x2, z2)
        , hm.point_at(seed, x2, position.z)
        ];

      let ns: [Vec3<f32>; 4] =
        [ hm.normal_at(seed, normal_delta, position.x, position.z)
        , hm.normal_at(seed, normal_delta, position.x, z2)
        , hm.normal_at(seed, normal_delta, x2, z2)
        , hm.normal_at(seed, normal_delta, x2, position.z)
        ];

      let center_lower_than = ps.iter().filter(|v| center.y < v.y).count();

      let terrain_type =
        if center_lower_than >= 3 {
          TerrainType::Dirt
        } else {
          TerrainType::Grass
        };

      macro_rules! place_terrain(
        ($v1: expr,
         $v2: expr,
         $n1: expr,
         $n2: expr,
         $minx: expr,
         $minz: expr,
         $maxx: expr,
         $maxz: expr
        ) => ({
          let maxy = partial_max($v1.y, $v2.y);
          let maxy = maxy.and_then(|m| partial_max(m, center.y));
          let maxy = maxy.unwrap();

          let id = id_allocator.allocate();
          block.vertex_coordinates.push_all(&[
            $v1.x, $v1.y, $v1.z,
            $v2.x, $v2.y, $v2.z,
            center.x, center.y, center.z,
          ]);
          block.normals.push_all(&[
            $n1.x, $n1.y, $n1.z,
            $n2.x, $n2.y, $n2.z,
            center_normal.x, center_normal.y, center_normal.z,
          ]);
          block.typs.push(terrain_type as GLuint);
          block.ids.push(id);
          block.bounds.insert(
            id,
            AABB::new(
              Pnt3::new($minx, $v1.y, $minz),
              Pnt3::new($maxx, maxy, $maxz),
            ),
          );
        });
      );

      let placements = 4;
      block.vertex_coordinates.reserve(placements*9);
      block.normals.reserve(placements*9);
      block.typs.reserve(placements);
      block.ids.reserve(placements);
      block.bounds.reserve(placements);

      let centr = center; // makes alignment nice
      place_terrain!(&ps[0], &ps[1], &ns[0], &ns[1], ps[0].x, ps[0].z, centr.x, ps[1].z);
      place_terrain!(&ps[1], &ps[2], &ns[1], &ns[2], ps[1].x, centr.z, ps[2].x, ps[2].z);
      place_terrain!(&ps[2], &ps[3], &ns[2], &ns[3], centr.x, centr.z, ps[2].x, ps[2].z);
      place_terrain!(&ps[3], &ps[0], &ns[3], &ns[0], ps[0].x, ps[0].z, ps[3].x, centr.z);
    })
  }
}
<|endoftext|>


<commit_before>use std::error::Error;
use std::result::Result as RResult;

use toml::{Table, Value};

pub mod error {
    use std::fmt::{Debug, Display, Formatter};
    use std::fmt;
    use std::error::Error;
    use toml;

    #[derive(Clone)]
    pub enum ParserErrorKind {
        TOMLParserErrors,
        MissingMainSection,
        MissingVersionInfo,
    }

    pub struct ParserError {
        kind: ParserErrorKind,
        cause: Option<Box<Error>>,
    }

    impl ParserError {

        pub fn new(k: ParserErrorKind, cause: Option<Box<Error>>) -> ParserError {
            ParserError {
                kind: k,
                cause: cause,
            }
        }

    }

    impl Debug for ParserError {

        fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> {
            try!(write!(f, "{:?}", self.description()));
            Ok(())
        }

    }

    impl Display for ParserError {

        fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> {
            try!(write!(f, "{}", self.description()));
            Ok(())
        }

    }

    impl Error for ParserError {

        fn description(&self) -> &str {
            match self.kind {
                ParserErrorKind::TOMLParserErrors   => "Several TOML-Parser-Errors",
                ParserErrorKind::MissingMainSection => "Missing main section",
                ParserErrorKind::MissingVersionInfo => "Missing version information in main section",
            }
        }

        fn cause(&self) -> Option<&Error> {
            self.cause.as_ref().map(|e| &**e)
        }

    }

}

use self::error::ParserErrorKind;
use self::error::ParserError;

/**
 * EntryHeader
 *
 * This is basically a wrapper around toml::Table which provides convenience to the user of the
 * librray.
 */
#[derive(Debug, Clone)]
pub struct EntryHeader {
    toml: Table,
}

pub type Result<V> = RResult<V, error::ParserError>;

/**
 * Wrapper type around file header (TOML) object
 */
impl EntryHeader {

    /**
     * Get a new header object with a already-filled toml table
     */
    pub fn new(toml: Table) -> EntryHeader {
        EntryHeader {
            toml: toml,
        }
    }

    /**
     * Get the table which lives in the background
     */
    pub fn toml(&self) -> &Table {
        &self.toml
    }

    pub fn parse(s: &str) -> Result<EntryHeader> {
        use toml::Parser;

        let mut parser = Parser::new(s);
        parser.parse()
            .ok_or(ParserError::new(ParserErrorKind::TOMLParserErrors, None))
            .and_then(|t| verify_header_consistency(t))
            .map(|t| EntryHeader::new(t))
    }

}

fn verify_header_consistency(t: Table) -> Result<Table> {
    if !has_main_section(&t) {
        Err(ParserError::new(ParserErrorKind::MissingMainSection, None))
    } else if !has_imag_version_in_main_section(&t) {
        Err(ParserError::new(ParserErrorKind::MissingVersionInfo, None))
    } else {
        Ok(t)
    }
}

fn has_main_section(t: &Table) -> bool {
    t.contains_key("imag") &&
        match t.get("imag") {
            Some(&Value::Table(_)) => true,
            Some(_)                => false,
            None                   => false,
        }
}

fn has_imag_version_in_main_section(t: &Table) -> bool {
    match t.get("imag").unwrap() {
        &Value::Table(ref sec) => {
            sec.get("version")
                .and_then(|v| {
                    match v {
                        &Value::String(_) => Some(true),
                        _                 => Some(false),
                    }
                })
                .unwrap_or(false)
        }
        _                  => false,
    }
}

#[cfg(test)]
mod test {
    use std::collections::BTreeMap;

    use toml::Value;

    #[test]
    fn test_imag_section() {
        use super::has_main_section;

        let mut map = BTreeMap::new();
        map.insert("imag".into(), Value::Table(BTreeMap::new()));

        assert!(has_main_section(&map));
    }

    #[test]
    fn test_imag_invalid_section_type() {
        use super::has_main_section;

        let mut map = BTreeMap::new();
        map.insert("imag".into(), Value::Boolean(false));

        assert!(!has_main_section(&map));
    }

    #[test]
    fn test_imag_abscent_main_section() {
        use super::has_main_section;

        let mut map = BTreeMap::new();
        map.insert("not_imag".into(), Value::Boolean(false));

        assert!(!has_main_section(&map));
    }

    #[test]
    fn test_main_section_without_version() {
        use super::has_imag_version_in_main_section;

        let mut map = BTreeMap::new();
        map.insert("imag".into(), Value::Table(BTreeMap::new()));

        assert!(!has_imag_version_in_main_section(&map));
    }

    #[test]
    fn test_main_section_with_version() {
        use super::has_imag_version_in_main_section;

        let mut map = BTreeMap::new();
        let mut sub = BTreeMap::new();
        sub.insert("version".into(), Value::String("0.0.0".into()));
        map.insert("imag".into(), Value::Table(sub));

        assert!(has_imag_version_in_main_section(&map));
    }

    #[test]
    fn test_main_section_with_version_in_wrong_type() {
        use super::has_imag_version_in_main_section;

        let mut map = BTreeMap::new();
        let mut sub = BTreeMap::new();
        sub.insert("version".into(), Value::Boolean(false));
        map.insert("imag".into(), Value::Table(sub));

        assert!(!has_imag_version_in_main_section(&map));
    }

    #[test]
    fn test_verification_good() {
        use super::verify_header_consistency;

        let mut header = BTreeMap::new();
        let sub = {
            let mut sub = BTreeMap::new();
            sub.insert("version".into(), Value::String(String::from("0.0.0")));

            Value::Table(sub)
        };

        header.insert("imag".into(), sub);

        assert!(verify_header_consistency(header).is_ok());
    }

}

<commit_msg>Add header test: Invalid version string<commit_after>use std::error::Error;
use std::result::Result as RResult;

use toml::{Table, Value};

pub mod error {
    use std::fmt::{Debug, Display, Formatter};
    use std::fmt;
    use std::error::Error;
    use toml;

    #[derive(Clone)]
    pub enum ParserErrorKind {
        TOMLParserErrors,
        MissingMainSection,
        MissingVersionInfo,
    }

    pub struct ParserError {
        kind: ParserErrorKind,
        cause: Option<Box<Error>>,
    }

    impl ParserError {

        pub fn new(k: ParserErrorKind, cause: Option<Box<Error>>) -> ParserError {
            ParserError {
                kind: k,
                cause: cause,
            }
        }

    }

    impl Debug for ParserError {

        fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> {
            try!(write!(f, "{:?}", self.description()));
            Ok(())
        }

    }

    impl Display for ParserError {

        fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> {
            try!(write!(f, "{}", self.description()));
            Ok(())
        }

    }

    impl Error for ParserError {

        fn description(&self) -> &str {
            match self.kind {
                ParserErrorKind::TOMLParserErrors   => "Several TOML-Parser-Errors",
                ParserErrorKind::MissingMainSection => "Missing main section",
                ParserErrorKind::MissingVersionInfo => "Missing version information in main section",
            }
        }

        fn cause(&self) -> Option<&Error> {
            self.cause.as_ref().map(|e| &**e)
        }

    }

}

use self::error::ParserErrorKind;
use self::error::ParserError;

/**
 * EntryHeader
 *
 * This is basically a wrapper around toml::Table which provides convenience to the user of the
 * librray.
 */
#[derive(Debug, Clone)]
pub struct EntryHeader {
    toml: Table,
}

pub type Result<V> = RResult<V, error::ParserError>;

/**
 * Wrapper type around file header (TOML) object
 */
impl EntryHeader {

    /**
     * Get a new header object with a already-filled toml table
     */
    pub fn new(toml: Table) -> EntryHeader {
        EntryHeader {
            toml: toml,
        }
    }

    /**
     * Get the table which lives in the background
     */
    pub fn toml(&self) -> &Table {
        &self.toml
    }

    pub fn parse(s: &str) -> Result<EntryHeader> {
        use toml::Parser;

        let mut parser = Parser::new(s);
        parser.parse()
            .ok_or(ParserError::new(ParserErrorKind::TOMLParserErrors, None))
            .and_then(|t| verify_header_consistency(t))
            .map(|t| EntryHeader::new(t))
    }

}

fn verify_header_consistency(t: Table) -> Result<Table> {
    if !has_main_section(&t) {
        Err(ParserError::new(ParserErrorKind::MissingMainSection, None))
    } else if !has_imag_version_in_main_section(&t) {
        Err(ParserError::new(ParserErrorKind::MissingVersionInfo, None))
    } else {
        Ok(t)
    }
}

fn has_main_section(t: &Table) -> bool {
    t.contains_key("imag") &&
        match t.get("imag") {
            Some(&Value::Table(_)) => true,
            Some(_)                => false,
            None                   => false,
        }
}

fn has_imag_version_in_main_section(t: &Table) -> bool {
    match t.get("imag").unwrap() {
        &Value::Table(ref sec) => {
            sec.get("version")
                .and_then(|v| {
                    match v {
                        &Value::String(_) => Some(true),
                        _                 => Some(false),
                    }
                })
                .unwrap_or(false)
        }
        _                  => false,
    }
}

#[cfg(test)]
mod test {
    use std::collections::BTreeMap;

    use toml::Value;

    #[test]
    fn test_imag_section() {
        use super::has_main_section;

        let mut map = BTreeMap::new();
        map.insert("imag".into(), Value::Table(BTreeMap::new()));

        assert!(has_main_section(&map));
    }

    #[test]
    fn test_imag_invalid_section_type() {
        use super::has_main_section;

        let mut map = BTreeMap::new();
        map.insert("imag".into(), Value::Boolean(false));

        assert!(!has_main_section(&map));
    }

    #[test]
    fn test_imag_abscent_main_section() {
        use super::has_main_section;

        let mut map = BTreeMap::new();
        map.insert("not_imag".into(), Value::Boolean(false));

        assert!(!has_main_section(&map));
    }

    #[test]
    fn test_main_section_without_version() {
        use super::has_imag_version_in_main_section;

        let mut map = BTreeMap::new();
        map.insert("imag".into(), Value::Table(BTreeMap::new()));

        assert!(!has_imag_version_in_main_section(&map));
    }

    #[test]
    fn test_main_section_with_version() {
        use super::has_imag_version_in_main_section;

        let mut map = BTreeMap::new();
        let mut sub = BTreeMap::new();
        sub.insert("version".into(), Value::String("0.0.0".into()));
        map.insert("imag".into(), Value::Table(sub));

        assert!(has_imag_version_in_main_section(&map));
    }

    #[test]
    fn test_main_section_with_version_in_wrong_type() {
        use super::has_imag_version_in_main_section;

        let mut map = BTreeMap::new();
        let mut sub = BTreeMap::new();
        sub.insert("version".into(), Value::Boolean(false));
        map.insert("imag".into(), Value::Table(sub));

        assert!(!has_imag_version_in_main_section(&map));
    }

    #[test]
    fn test_verification_good() {
        use super::verify_header_consistency;

        let mut header = BTreeMap::new();
        let sub = {
            let mut sub = BTreeMap::new();
            sub.insert("version".into(), Value::String(String::from("0.0.0")));

            Value::Table(sub)
        };

        header.insert("imag".into(), sub);

        assert!(verify_header_consistency(header).is_ok());
    }

    #[test]
    fn test_verification_invalid_versionstring() {
        use super::verify_header_consistency;

        let mut header = BTreeMap::new();
        let sub = {
            let mut sub = BTreeMap::new();
            sub.insert("version".into(), Value::String(String::from("000")));

            Value::Table(sub)
        };

        header.insert("imag".into(), sub);

        assert!(!verify_header_consistency(header).is_ok());
    }

}

<|endoftext|>


<commit_before>use std::fmt::Debug;
use std::cmp::Ordering::*;
use std::mem::{self, transmute};

enum FindStrategy {
    Any,
    Before,
    After
}

#[derive(Debug)]
pub struct Node<K> {
    key: K,
    left: Tree<K>,
    right: Tree<K>,
}

#[derive(Debug)]
pub enum Tree<K> {
    Node(Box<Node<K>>),
    Empty
}

impl<K: Ord+Debug> Tree<K> {
    fn leaf(key: K) -> Tree<K> {
        Tree::Node(Box::new(Node {
            key: key,
            left: Tree::Empty,
            right: Tree::Empty
        }))
    }

    fn take(&mut self) -> Self {
        mem::replace(self, Tree::Empty)
    }

    fn find_mut(&mut self, key: &K, strategy: FindStrategy) -> &mut Self {
        let mut cur = self;

        loop {
            let temp = cur;
            if temp.inner.is_some() {
                cur = match temp.inner.as_mut().unwrap().key.cmp(key) {
                    Less    => &mut temp.inner.as_mut().unwrap().right,
                    Greater => &mut temp.inner.as_mut().unwrap().left,
                    Equal   => {
                        match strategy {
                            FindStrategy::Any    => temp,
                            FindStrategy::Before => &mut temp.inner.as_mut().unwrap().left,
                            FindStrategy::After  => &mut temp.inner.as_mut().unwrap().right
                        }
                    }
                };
            } else {
                return temp;
            }
        }

        cur
    }

    fn first_mut(&mut self) -> &mut Self {
        let mut cur = self;

        loop {
            let temp = cur;
            cur = match temp.inner {
                Some(ref mut node) => &mut node.left,
                None               => return temp,
            }
        }

        cur
    }

    pub fn has(&mut self, key: K) -> bool {
        match *self.find_mut(&key, FindStrategy::Any) {
            Tree::Node(_) => true,
            Tree::Empty => false
        }
    }

    pub fn insert(&mut self, key: K) {
        let tree = self.find_mut(&key, FindStrategy::After);

        match *tree {
            Tree::Node(_) => unreachable!(),
            Tree::Empty => *tree = Tree::leaf(key)
        }
    }

    pub fn delete(&mut self, key: K) {
        let tree = self.find_mut(&key, FindStrategy::Any);

        *tree = if let Tree::Node(mut node) = tree.take() {
            if let Tree::Node(_) = node.right {
                let left = node.left.take();//first_mut();

                let mut right = node.right.take();//first_mut();

                let succ = {
                    let mut succ_slot = right.first_mut();
                    let mut succ = succ_slot.take();

                    *succ_slot = if let Tree::Node(ref mut node) = succ {
                        node.right.take()
                    } else {
                        unreachable!();
                    };

                    succ
                };

                if let Tree::Node(succ_node) = succ {
                    node.key = succ_node.key;
                    node.left = left;
                    node.right = right;
                } else {
                    unreachable!();
                }
                // node.left = left;
                // node.right = right.right

                Tree::Node(node)
            } else {
                node.left
            }
        } else {
            return; // The key wasn't in the tree
        };
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn insert() {
        let mut bst = Tree::Empty;

        bst.insert(5);
        bst.insert(2);

        assert_eq!(
            (0..10).map(|i| bst.has(i)).collect::<Vec<_>>(),
            [false, false, true, false, false, true, false, false, false, false]
        );

        bst.insert(3);
        bst.insert(1);
        bst.insert(7);

        assert_eq!(
            (0..10).map(|i| bst.has(i)).collect::<Vec<_>>(),
            [false, true, true, true, false, true, false, true, false, false]
        );
    }

    #[test]
    fn insert_and_delete() {
        let mut bst = Tree::Empty;

        const F: bool = false;
        const T: bool = true;

        bst.insert(7);
        bst.insert(3);
        bst.insert(11);
        bst.insert(1);
        bst.insert(5);
        bst.insert(9);
        bst.insert(13);
        assert_eq!((0..15).map(|i| bst.has(i)).collect::<Vec<_>>(), [F, T, F, T, F, T, F, T, F, T, F, T, F, T, F]);

        bst.insert(0);
        bst.insert(2);
        bst.insert(4);
        bst.insert(6);
        bst.insert(8);
        bst.insert(10);
        bst.insert(12);
        bst.insert(14);
        assert_eq!((0..15).map(|i| bst.has(i)).collect::<Vec<_>>(), [T, T, T, T, T, T, T, T, T, T, T, T, T, T, T]);

        bst.delete(7);
        assert_eq!((0..15).map(|i| bst.has(i)).collect::<Vec<_>>(), [T, T, T, T, T, T, T, F, T, T, T, T, T, T, T]);
        bst.delete(3);
        assert_eq!((0..15).map(|i| bst.has(i)).collect::<Vec<_>>(), [T, T, T, F, T, T, T, F, T, T, T, T, T, T, T]);
        bst.delete(11);
        assert_eq!((0..15).map(|i| bst.has(i)).collect::<Vec<_>>(), [T, T, T, F, T, T, T, F, T, T, T, F, T, T, T]);
        bst.delete(1);
        assert_eq!((0..15).map(|i| bst.has(i)).collect::<Vec<_>>(), [T, F, T, F, T, T, T, F, T, T, T, F, T, T, T]);
        bst.delete(5);
        assert_eq!((0..15).map(|i| bst.has(i)).collect::<Vec<_>>(), [T, F, T, F, T, F, T, F, T, T, T, F, T, T, T]);
        bst.delete(9);
        assert_eq!((0..15).map(|i| bst.has(i)).collect::<Vec<_>>(), [T, F, T, F, T, F, T, F, T, F, T, F, T, T, T]);
        bst.delete(13);
        assert_eq!((0..15).map(|i| bst.has(i)).collect::<Vec<_>>(), [T, F, T, F, T, F, T, F, T, F, T, F, T, F, T]);
        bst.delete(0);
        assert_eq!((0..15).map(|i| bst.has(i)).collect::<Vec<_>>(), [F, F, T, F, T, F, T, F, T, F, T, F, T, F, T]);
        bst.delete(2);
        assert_eq!((0..15).map(|i| bst.has(i)).collect::<Vec<_>>(), [F, F, F, F, T, F, T, F, T, F, T, F, T, F, T]);
        bst.delete(4);
        assert_eq!((0..15).map(|i| bst.has(i)).collect::<Vec<_>>(), [F, F, F, F, F, F, T, F, T, F, T, F, T, F, T]);
        bst.delete(6);
        assert_eq!((0..15).map(|i| bst.has(i)).collect::<Vec<_>>(), [F, F, F, F, F, F, F, F, T, F, T, F, T, F, T]);
        bst.delete(8);
        assert_eq!((0..15).map(|i| bst.has(i)).collect::<Vec<_>>(), [F, F, F, F, F, F, F, F, F, F, T, F, T, F, T]);
        bst.delete(10);
        assert_eq!((0..15).map(|i| bst.has(i)).collect::<Vec<_>>(), [F, F, F, F, F, F, F, F, F, F, F, F, T, F, T]);
        bst.delete(12);
        assert_eq!((0..15).map(|i| bst.has(i)).collect::<Vec<_>>(), [F, F, F, F, F, F, F, F, F, F, F, F, F, F, T]);
        bst.delete(14);
        assert_eq!((0..15).map(|i| bst.has(i)).collect::<Vec<_>>(), [F, F, F, F, F, F, F, F, F, F, F, F, F, F, F]);
    }

    #[test]
    fn insert_and_delete_duplicates() {
        let mut bst = Tree::Empty;

        bst.insert(0);
        bst.insert(1);
        bst.insert(0);
        bst.insert(1);
        bst.insert(0);
        bst.insert(1);

        assert_eq!(
            (0..2).map(|i| bst.has(i)).collect::<Vec<_>>(),
            [true, true]
        );

        // println!("{:#?}", bst);
        // println!("====================================================");

        bst.delete(0);
        // println!("{:#?}", bst);
        // println!("########################################################");
        bst.delete(0);
        bst.delete(1);

        assert_eq!(
            (0..2).map(|i| bst.has(i)).collect::<Vec<_>>(),
            [true, true]
        );

        bst.delete(0);

        assert_eq!(
            (0..2).map(|i| bst.has(i)).collect::<Vec<_>>(),
            [false, true]
        );
    }
}
<commit_msg>finish bst<commit_after>use std::fmt::Debug;
use std::cmp::Ordering::*;

enum Find { Any, After }

#[derive(Debug)]
struct Node<K> {
    key: K,
    left: Tree<K>,
    right: Tree<K>,
}

#[derive(Debug)]
pub struct Tree<K> {
    inner: Option<Box<Node<K>>>
}

impl<K: Ord+Debug> Tree<K> {
   pub fn new() -> Tree<K> {
        Tree { inner: None }
    }

    pub fn leaf(key: K) -> Tree<K> {
        let node = Node {
            key: key,
            left: Tree::new(),
            right: Tree::new()
        };

        Tree { inner: Some(Box::new(node)) }
    }

    pub fn has(&mut self, key: K) -> bool {
        let tree = self.find_mut(&key, Find::Any);

        tree.is_node()
    }

    pub fn insert(&mut self, key: K) {
        let tree = self.find_mut(&key, Find::After);

        *tree = Tree::leaf(key);
    }

    pub fn delete(&mut self, key: K) {
        let tree = self.find_mut(&key, Find::Any);

        if tree.is_node() {
            if tree.right_mut().is_node() {
                let succ = {
                    let succ = tree.right_mut().first_mut();
                    let mut taken = succ.take();
                    *succ = taken.right_mut().take();
                    taken
                };
                tree.node_mut().key = succ.into_key();
            } else {
                *tree = tree.left_mut().take();
            }
        }
    }

    fn find_mut(&mut self, key: &K, strategy: Find) -> &mut Self {
        let mut cur = self;

        loop {
            let temp = cur;
            if temp.is_node() {
                cur = match temp.key().cmp(key) {
                    Less    => temp.right_mut(),
                    Greater => temp.left_mut(),
                    Equal   => {
                        match strategy {
                            Find::After => temp.right_mut(),
                            Find::Any   => return temp
                        }
                    }
                };
            } else {
                return temp
            }
        }
    }

    fn first_mut(&mut self) -> &mut Self {
        if self.is_empty() { return self }

        let mut cur = self;
        loop {
            let temp = cur;
            if temp.left_mut().is_node() {
                cur = temp.left_mut()
            } else {
                return temp
            }
        }
    }

    fn into_node(self)      -> Node<K>      { *self.inner.unwrap() }
    fn into_key(self)       -> K            { self.into_node().key }

    fn take(&mut self)      -> Self         { Tree { inner: self.inner.take() } }
    fn node_mut(&mut self)  -> &mut Node<K> { self.inner.as_mut().unwrap() }
    fn left_mut(&mut self)  -> &mut Self    { &mut self.node_mut().left }
    fn right_mut(&mut self) -> &mut Self    { &mut self.node_mut().right }

    fn node(&self)          -> &Node<K>     { self.inner.as_ref().unwrap() }
    fn key(&self)           -> &K           { &self.node().key }
    fn is_node(&self)       -> bool         { self.inner.is_some() }
    fn is_empty(&self)      -> bool         { self.inner.is_none() }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn insert() {
        let mut bst = Tree::new();

        bst.insert(5);
        bst.insert(2);

        assert_eq!(
            (0..10).map(|i| bst.has(i)).collect::<Vec<_>>(),
            [false, false, true, false, false, true, false, false, false, false]
        );

        bst.insert(3);
        bst.insert(1);
        bst.insert(7);

        assert_eq!(
            (0..10).map(|i| bst.has(i)).collect::<Vec<_>>(),
            [false, true, true, true, false, true, false, true, false, false]
        );
    }

    #[test]
    fn insert_and_delete() {
        let mut bst = Tree::new();

        const F: bool = false;
        const T: bool = true;

        bst.insert(7);
        bst.insert(3);
        bst.insert(11);
        bst.insert(1);
        bst.insert(5);
        bst.insert(9);
        bst.insert(13);
        assert_eq!((0..15).map(|i| bst.has(i)).collect::<Vec<_>>(), [F, T, F, T, F, T, F, T, F, T, F, T, F, T, F]);

        bst.insert(0);
        bst.insert(2);
        bst.insert(4);
        bst.insert(6);
        bst.insert(8);
        bst.insert(10);
        bst.insert(12);
        bst.insert(14);
        assert_eq!((0..15).map(|i| bst.has(i)).collect::<Vec<_>>(), [T, T, T, T, T, T, T, T, T, T, T, T, T, T, T]);

        bst.delete(7);
        assert_eq!((0..15).map(|i| bst.has(i)).collect::<Vec<_>>(), [T, T, T, T, T, T, T, F, T, T, T, T, T, T, T]);
        bst.delete(3);
        assert_eq!((0..15).map(|i| bst.has(i)).collect::<Vec<_>>(), [T, T, T, F, T, T, T, F, T, T, T, T, T, T, T]);
        bst.delete(11);
        assert_eq!((0..15).map(|i| bst.has(i)).collect::<Vec<_>>(), [T, T, T, F, T, T, T, F, T, T, T, F, T, T, T]);
        bst.delete(1);
        assert_eq!((0..15).map(|i| bst.has(i)).collect::<Vec<_>>(), [T, F, T, F, T, T, T, F, T, T, T, F, T, T, T]);
        bst.delete(5);
        assert_eq!((0..15).map(|i| bst.has(i)).collect::<Vec<_>>(), [T, F, T, F, T, F, T, F, T, T, T, F, T, T, T]);
        bst.delete(9);
        assert_eq!((0..15).map(|i| bst.has(i)).collect::<Vec<_>>(), [T, F, T, F, T, F, T, F, T, F, T, F, T, T, T]);
        bst.delete(13);
        assert_eq!((0..15).map(|i| bst.has(i)).collect::<Vec<_>>(), [T, F, T, F, T, F, T, F, T, F, T, F, T, F, T]);
        bst.delete(0);
        assert_eq!((0..15).map(|i| bst.has(i)).collect::<Vec<_>>(), [F, F, T, F, T, F, T, F, T, F, T, F, T, F, T]);
        bst.delete(2);
        assert_eq!((0..15).map(|i| bst.has(i)).collect::<Vec<_>>(), [F, F, F, F, T, F, T, F, T, F, T, F, T, F, T]);
        bst.delete(4);
        assert_eq!((0..15).map(|i| bst.has(i)).collect::<Vec<_>>(), [F, F, F, F, F, F, T, F, T, F, T, F, T, F, T]);
        bst.delete(6);
        assert_eq!((0..15).map(|i| bst.has(i)).collect::<Vec<_>>(), [F, F, F, F, F, F, F, F, T, F, T, F, T, F, T]);
        bst.delete(8);
        assert_eq!((0..15).map(|i| bst.has(i)).collect::<Vec<_>>(), [F, F, F, F, F, F, F, F, F, F, T, F, T, F, T]);
        bst.delete(10);
        assert_eq!((0..15).map(|i| bst.has(i)).collect::<Vec<_>>(), [F, F, F, F, F, F, F, F, F, F, F, F, T, F, T]);
        bst.delete(12);
        assert_eq!((0..15).map(|i| bst.has(i)).collect::<Vec<_>>(), [F, F, F, F, F, F, F, F, F, F, F, F, F, F, T]);
        bst.delete(14);
        assert_eq!((0..15).map(|i| bst.has(i)).collect::<Vec<_>>(), [F, F, F, F, F, F, F, F, F, F, F, F, F, F, F]);
    }

    #[test]
    fn insert_and_delete_duplicates() {
        let mut bst = Tree::new();

        bst.insert(0);
        bst.insert(1);
        bst.insert(0);
        bst.insert(1);
        bst.insert(0);
        bst.insert(1);

        println!("{:#?}", bst);

        assert_eq!(
            (0..2).map(|i| bst.has(i)).collect::<Vec<_>>(),
            [true, true]
        );

        bst.delete(0);
        println!("{:#?}", bst);
        bst.delete(0);
        bst.delete(1);

        assert_eq!(
            (0..2).map(|i| bst.has(i)).collect::<Vec<_>>(),
            [true, true]
        );

        bst.delete(0);

        assert_eq!(
            (0..2).map(|i| bst.has(i)).collect::<Vec<_>>(),
            [false, true]
        );
    }
}
<|endoftext|>