<commit_before>use ::std::sync::mpsc::Sender;

use crate::response_helper::*;
use ::pueue::message::*;
use ::pueue::state::SharedState;
use ::pueue::task::{Task, TaskStatus};

static SENDER_ERR: &str = "Failed to send message to task handler thread";

pub fn handle_message(message: Message, sender: &Sender<Message>, state: &SharedState) -> Message {
    match message {
        Message::Add(message) => add_task(message, sender, state),
        Message::Remove(message) => remove(message, state),
        Message::Switch(message) => switch(message, state),
        Message::Stash(message) => stash(message, state),
        Message::Enqueue(message) => enqueue(message, state),

        Message::Start(message) => start(message, sender, state),
        Message::Restart(message) => restart(message, sender, state),
        Message::Pause(message) => pause(message, sender, state),
        Message::Kill(message) => kill(message, sender, state),

        Message::Send(message) => send(message, sender, state),
        Message::EditRequest(message) => edit_request(message, state),
        Message::Edit(message) => edit(message, state),

        Message::Clean => clean(state),
        Message::Reset => reset(sender),
        Message::SimpleStatus => get_simple_status(state),
        Message::Status => get_status(state),
        Message::Parallel(amount) => set_parallel_tasks(amount, sender),
        _ => create_failure_message("Not implemented yet"),
    }
}

/// Queues a new task to the state.
/// If the start_immediately flag is set, send a StartMessage to the task handler
fn add_task(message: AddMessage, sender: &Sender<Message>, state: &SharedState) -> Message {
    let task = Task::new(message.command, message.path);
    let task_id: usize;
    {
        let mut state = state.lock().unwrap();
        task_id = state.add_task(task);
    }
    if message.start_immediately {
        let start_message = StartMessage {
            task_ids: Some(vec![task_id]),
        };
        sender
            .send(Message::Start(start_message))
            .expect(SENDER_ERR);
    }

    create_success_message("New task added.")
}

/// Remove tasks from the queue
fn remove(message: RemoveMessage, state: &SharedState) -> Message {
    let (matching, mismatching) = {
        let statuses = vec![TaskStatus::Running, TaskStatus::Paused];
        let mut state = state.lock().unwrap();
        state.tasks_not_in_statuses(Some(message.task_ids), statuses)
    };

    let message = "Tasks removed from list";
    let message = compile_task_response(message, matching, mismatching);
    create_success_message(message)
}

/// Switch the position of two tasks in the upcoming queue
fn switch(message: SwitchMessage, state: &SharedState) -> Message {
    let task_ids = vec![message.task_id_1, message.task_id_2];
    let statuses = vec![TaskStatus::Queued, TaskStatus::Stashed];
    let mut state = state.lock().unwrap();
    let (_, mismatching) = state.tasks_in_statuses(Some(task_ids.clone().to_vec()), statuses);
    if !mismatching.is_empty() {
        return create_failure_message("Tasks have to be either queued or stashed.");
    }

    // Get the tasks. Expect them to be there, since we found no mismatch
    let mut first_task = state.tasks.remove(&task_ids[0]).unwrap();
    let mut second_task = state.tasks.remove(&task_ids[1]).unwrap();

    // Switch task ids
    let temp_id = first_task.id;
    first_task.id = second_task.id;
    second_task.id = temp_id;

    // Put tasks back in again
    state.tasks.insert(first_task.id, first_task);
    state.tasks.insert(second_task.id, second_task);

    create_success_message("Tasks have been switched")
}

/// Stash specific queued tasks.
/// They won't be executed until enqueued again or explicitely started
fn stash(message: StashMessage, state: &SharedState) -> Message {
    let (matching, mismatching) = {
        let mut state = state.lock().unwrap();
        let (matching, mismatching) =
            state.tasks_in_statuses(Some(message.task_ids), vec![TaskStatus::Queued]);

        for task_id in &matching {
            state.change_status(*task_id, TaskStatus::Stashed);
        }

        (matching, mismatching)
    };

    let message = "Tasks are stashed";
    let response = compile_task_response(message, matching, mismatching);
    return create_success_message(response);
}

/// Enqueue specific stashed tasks.
/// They will be normally handled afterwards.
fn enqueue(message: EnqueueMessage, state: &SharedState) -> Message {
    let (matching, mismatching) = {
        let mut state = state.lock().unwrap();
        let (matching, mismatching) = state.tasks_in_statuses(
            Some(message.task_ids),
            vec![TaskStatus::Stashed, TaskStatus::Locked],
        );

        for task_id in &matching {
            state.change_status(*task_id, TaskStatus::Queued);
        }

        (matching, mismatching)
    };

    let message = "Tasks are enqueued";
    let response = compile_task_response(message, matching, mismatching);
    return create_success_message(response);
}

/// Forward the start message to the task handler and respond to the client
fn start(message: StartMessage, sender: &Sender<Message>, state: &SharedState) -> Message {
    sender
        .send(Message::Start(message.clone()))
        .expect(SENDER_ERR);
    if let Some(task_ids) = message.task_ids {
        let response = task_response_helper(
            "Tasks are being started",
            task_ids,
            vec![TaskStatus::Paused, TaskStatus::Queued, TaskStatus::Stashed],
            state,
        );
        return create_success_message(response);
    }

    return create_success_message("Daemon and all tasks are being resumed.");
}

/// Create and enqueue tasks from already finished tasks
/// The user can specify to immediately start the newly created tasks.
fn restart(message: RestartMessage, sender: &Sender<Message>, state: &SharedState) -> Message {
    let response: String;
    let new_ids = {
        let mut state = state.lock().unwrap();
        let statuses = vec![TaskStatus::Done, TaskStatus::Failed];
        let (matching, mismatching) = state.tasks_in_statuses(Some(message.task_ids), statuses);

        let mut new_ids = Vec::new();
        for task_id in &matching {
            let task = state.tasks.get(task_id).unwrap();
            let new_task = Task::from_task(task);
            new_ids.push(state.add_task(new_task));
        }

        // Already create the response string in here. Otherwise we would
        // need to get matching/mismatching out of this scope
        let message = "Restarted tasks";
        response = compile_task_response(message, matching, mismatching);

        new_ids
    };

    // If the restarted tasks should be started immediately, send a message
    // with the new task ids to the task handler.
    if message.start_immediately {
        let start_message = StartMessage {
            task_ids: Some(new_ids),
        };
        sender
            .send(Message::Start(start_message))
            .expect(SENDER_ERR);
    }

    return create_success_message(response);
}

/// Forward the pause message to the task handler and respond to the client
fn pause(message: PauseMessage, sender: &Sender<Message>, state: &SharedState) -> Message {
    sender
        .send(Message::Pause(message.clone()))
        .expect(SENDER_ERR);
    if let Some(task_ids) = message.task_ids {
        let response = task_response_helper(
            "Tasks are being paused",
            task_ids,
            vec![TaskStatus::Running],
            state,
        );
        return create_success_message(response);
    }

    return create_success_message("Daemon and all tasks are being paused.");
}

/// Forward the kill message to the task handler and respond to the client
fn kill(message: KillMessage, sender: &Sender<Message>, state: &SharedState) -> Message {
    sender
        .send(Message::Kill(message.clone()))
        .expect(SENDER_ERR);

    if !message.task_ids.is_empty() {
        let response = task_response_helper(
            "Tasks are being killed",
            message.task_ids,
            vec![TaskStatus::Running, TaskStatus::Paused],
            state,
        );
        return create_success_message(response);
    }

    return create_success_message("All tasks are being killed.");
}

// Send some user defined input to a process
// The message will be forwarded to the task handler.
// In here we only do some error handling.
fn send(message: SendMessage, sender: &Sender<Message>, state: &SharedState) -> Message {
    // Check whether the task exists and is running, abort if that's not the case
    {
        let state = state.lock().unwrap();
        match state.tasks.get(&message.task_id) {
            Some(task) => {
                if task.status != TaskStatus::Running {
                    return create_failure_message("You can only send input to a running task");
                }
            }
            None => return create_failure_message("No task with this id."),
        }
    }

    // Check whether the task exists and is running, abort if that's not the case
    sender.send(Message::Send(message)).expect(SENDER_ERR);

    return create_success_message("Message is being send to the process.");
}

// If a user wants to edit a message, we need to send him the current command
// and lock the task to prevent execution, before the user has finished editing the command
fn edit_request(message: EditRequestMessage, state: &SharedState) -> Message {
    // Check whether the task exists and is queued/stashed, abort if that's not the case
    let mut state = state.lock().unwrap();
    match state.tasks.get_mut(&message.task_id) {
        Some(task) => {
            if !task.is_queued() {
                return create_failure_message("You can only edit a queued/stashed task");
            }
            task.prev_status = task.status.clone();
            task.status = TaskStatus::Locked;

            let message = EditResponseMessage {
                task_id: task.id,
                command: task.command.clone(),
            };
            return Message::EditResponse(message);
        }
        None => return create_failure_message("No task with this id."),
    }
}

// Handle the actual updated command
fn edit(message: EditMessage, state: &SharedState) -> Message {
    // Check whether the task exists and is queued/stashed, abort if that's not the case
    let mut state = state.lock().unwrap();
    match state.tasks.get_mut(&message.task_id) {
        Some(task) => {
            if !(task.status == TaskStatus::Locked) {
                return create_failure_message("Task is no longer locked.");
            }

            task.status = task.prev_status.clone();
            task.command = message.command.clone();
            state.save();

            return create_success_message("Command has been updated");
        }
        None => {
            return create_failure_message(format!(
                "Task to edit has gone away: {}",
                message.task_id
            ))
        }
    }
}

/// Remove all failed or done tasks from the state
fn clean(state: &SharedState) -> Message {
    let mut state = state.lock().unwrap();
    state.clean();

    return create_success_message("All finished tasks have been removed");
}

// Forward the reset request to the task handler
// The handler then kills all children and clears the task queue
fn reset(sender: &Sender<Message>) -> Message {
    sender.send(Message::Reset).expect(SENDER_ERR);
    return create_success_message("Everything is being reset right now.");
}

/// Return the full current state to the client
fn get_status(state: &SharedState) -> Message {
    let state = state.lock().unwrap();
    Message::StatusResponse(state.clone())
}

/// Return the current state without any stdou/stderr to the client
fn get_simple_status(state: &SharedState) -> Message {
    let mut state = { state.lock().unwrap().clone() };
    for (_, task) in state.tasks.iter_mut() {
        task.stdout = None;
        task.stderr = None;
    }
    Message::StatusResponse(state)
}

fn set_parallel_tasks(amount: usize, sender: &Sender<Message>) -> Message {
    sender.send(Message::Parallel(amount)).expect(SENDER_ERR);
    return create_success_message("Parallel tasks setting adjusted");
}
<commit_msg>Fix remove command<commit_after>use ::std::sync::mpsc::Sender;

use crate::response_helper::*;
use ::pueue::message::*;
use ::pueue::state::SharedState;
use ::pueue::task::{Task, TaskStatus};

static SENDER_ERR: &str = "Failed to send message to task handler thread";

pub fn handle_message(message: Message, sender: &Sender<Message>, state: &SharedState) -> Message {
    match message {
        Message::Add(message) => add_task(message, sender, state),
        Message::Remove(message) => remove(message, state),
        Message::Switch(message) => switch(message, state),
        Message::Stash(message) => stash(message, state),
        Message::Enqueue(message) => enqueue(message, state),

        Message::Start(message) => start(message, sender, state),
        Message::Restart(message) => restart(message, sender, state),
        Message::Pause(message) => pause(message, sender, state),
        Message::Kill(message) => kill(message, sender, state),

        Message::Send(message) => send(message, sender, state),
        Message::EditRequest(message) => edit_request(message, state),
        Message::Edit(message) => edit(message, state),

        Message::Clean => clean(state),
        Message::Reset => reset(sender),
        Message::SimpleStatus => get_simple_status(state),
        Message::Status => get_status(state),
        Message::Parallel(amount) => set_parallel_tasks(amount, sender),
        _ => create_failure_message("Not implemented yet"),
    }
}

/// Queues a new task to the state.
/// If the start_immediately flag is set, send a StartMessage to the task handler
fn add_task(message: AddMessage, sender: &Sender<Message>, state: &SharedState) -> Message {
    let task = Task::new(message.command, message.path);
    let task_id: usize;
    {
        let mut state = state.lock().unwrap();
        task_id = state.add_task(task);
    }
    if message.start_immediately {
        let start_message = StartMessage {
            task_ids: Some(vec![task_id]),
        };
        sender
            .send(Message::Start(start_message))
            .expect(SENDER_ERR);
    }

    create_success_message("New task added.")
}

/// Remove tasks from the queue
fn remove(message: RemoveMessage, state: &SharedState) -> Message {
    let mut state = state.lock().unwrap();
    let statuses = vec![TaskStatus::Running, TaskStatus::Paused];
    let (matching, mismatching) = state.tasks_not_in_statuses(Some(message.task_ids), statuses);

    for task_id in &matching {
        state.tasks.remove(task_id);
    }

    let message = "Tasks removed from list";
    let message = compile_task_response(message, matching, mismatching);
    create_success_message(message)
}

/// Switch the position of two tasks in the upcoming queue
fn switch(message: SwitchMessage, state: &SharedState) -> Message {
    let task_ids = vec![message.task_id_1, message.task_id_2];
    let statuses = vec![TaskStatus::Queued, TaskStatus::Stashed];
    let mut state = state.lock().unwrap();
    let (_, mismatching) = state.tasks_in_statuses(Some(task_ids.clone().to_vec()), statuses);
    if !mismatching.is_empty() {
        return create_failure_message("Tasks have to be either queued or stashed.");
    }

    // Get the tasks. Expect them to be there, since we found no mismatch
    let mut first_task = state.tasks.remove(&task_ids[0]).unwrap();
    let mut second_task = state.tasks.remove(&task_ids[1]).unwrap();

    // Switch task ids
    let temp_id = first_task.id;
    first_task.id = second_task.id;
    second_task.id = temp_id;

    // Put tasks back in again
    state.tasks.insert(first_task.id, first_task);
    state.tasks.insert(second_task.id, second_task);

    create_success_message("Tasks have been switched")
}

/// Stash specific queued tasks.
/// They won't be executed until enqueued again or explicitely started
fn stash(message: StashMessage, state: &SharedState) -> Message {
    let (matching, mismatching) = {
        let mut state = state.lock().unwrap();
        let (matching, mismatching) =
            state.tasks_in_statuses(Some(message.task_ids), vec![TaskStatus::Queued]);

        for task_id in &matching {
            state.change_status(*task_id, TaskStatus::Stashed);
        }

        (matching, mismatching)
    };

    let message = "Tasks are stashed";
    let response = compile_task_response(message, matching, mismatching);
    return create_success_message(response);
}

/// Enqueue specific stashed tasks.
/// They will be normally handled afterwards.
fn enqueue(message: EnqueueMessage, state: &SharedState) -> Message {
    let (matching, mismatching) = {
        let mut state = state.lock().unwrap();
        let (matching, mismatching) = state.tasks_in_statuses(
            Some(message.task_ids),
            vec![TaskStatus::Stashed, TaskStatus::Locked],
        );

        for task_id in &matching {
            state.change_status(*task_id, TaskStatus::Queued);
        }

        (matching, mismatching)
    };

    let message = "Tasks are enqueued";
    let response = compile_task_response(message, matching, mismatching);
    return create_success_message(response);
}

/// Forward the start message to the task handler and respond to the client
fn start(message: StartMessage, sender: &Sender<Message>, state: &SharedState) -> Message {
    sender
        .send(Message::Start(message.clone()))
        .expect(SENDER_ERR);
    if let Some(task_ids) = message.task_ids {
        let response = task_response_helper(
            "Tasks are being started",
            task_ids,
            vec![TaskStatus::Paused, TaskStatus::Queued, TaskStatus::Stashed],
            state,
        );
        return create_success_message(response);
    }

    return create_success_message("Daemon and all tasks are being resumed.");
}

/// Create and enqueue tasks from already finished tasks
/// The user can specify to immediately start the newly created tasks.
fn restart(message: RestartMessage, sender: &Sender<Message>, state: &SharedState) -> Message {
    let response: String;
    let new_ids = {
        let mut state = state.lock().unwrap();
        let statuses = vec![TaskStatus::Done, TaskStatus::Failed];
        let (matching, mismatching) = state.tasks_in_statuses(Some(message.task_ids), statuses);

        let mut new_ids = Vec::new();
        for task_id in &matching {
            let task = state.tasks.get(task_id).unwrap();
            let new_task = Task::from_task(task);
            new_ids.push(state.add_task(new_task));
        }

        // Already create the response string in here. Otherwise we would
        // need to get matching/mismatching out of this scope
        let message = "Restarted tasks";
        response = compile_task_response(message, matching, mismatching);

        new_ids
    };

    // If the restarted tasks should be started immediately, send a message
    // with the new task ids to the task handler.
    if message.start_immediately {
        let start_message = StartMessage {
            task_ids: Some(new_ids),
        };
        sender
            .send(Message::Start(start_message))
            .expect(SENDER_ERR);
    }

    return create_success_message(response);
}

/// Forward the pause message to the task handler and respond to the client
fn pause(message: PauseMessage, sender: &Sender<Message>, state: &SharedState) -> Message {
    sender
        .send(Message::Pause(message.clone()))
        .expect(SENDER_ERR);
    if let Some(task_ids) = message.task_ids {
        let response = task_response_helper(
            "Tasks are being paused",
            task_ids,
            vec![TaskStatus::Running],
            state,
        );
        return create_success_message(response);
    }

    return create_success_message("Daemon and all tasks are being paused.");
}

/// Forward the kill message to the task handler and respond to the client
fn kill(message: KillMessage, sender: &Sender<Message>, state: &SharedState) -> Message {
    sender
        .send(Message::Kill(message.clone()))
        .expect(SENDER_ERR);

    if !message.task_ids.is_empty() {
        let response = task_response_helper(
            "Tasks are being killed",
            message.task_ids,
            vec![TaskStatus::Running, TaskStatus::Paused],
            state,
        );
        return create_success_message(response);
    }

    return create_success_message("All tasks are being killed.");
}

// Send some user defined input to a process
// The message will be forwarded to the task handler.
// In here we only do some error handling.
fn send(message: SendMessage, sender: &Sender<Message>, state: &SharedState) -> Message {
    // Check whether the task exists and is running, abort if that's not the case
    {
        let state = state.lock().unwrap();
        match state.tasks.get(&message.task_id) {
            Some(task) => {
                if task.status != TaskStatus::Running {
                    return create_failure_message("You can only send input to a running task");
                }
            }
            None => return create_failure_message("No task with this id."),
        }
    }

    // Check whether the task exists and is running, abort if that's not the case
    sender.send(Message::Send(message)).expect(SENDER_ERR);

    return create_success_message("Message is being send to the process.");
}

// If a user wants to edit a message, we need to send him the current command
// and lock the task to prevent execution, before the user has finished editing the command
fn edit_request(message: EditRequestMessage, state: &SharedState) -> Message {
    // Check whether the task exists and is queued/stashed, abort if that's not the case
    let mut state = state.lock().unwrap();
    match state.tasks.get_mut(&message.task_id) {
        Some(task) => {
            if !task.is_queued() {
                return create_failure_message("You can only edit a queued/stashed task");
            }
            task.prev_status = task.status.clone();
            task.status = TaskStatus::Locked;

            let message = EditResponseMessage {
                task_id: task.id,
                command: task.command.clone(),
            };
            return Message::EditResponse(message);
        }
        None => return create_failure_message("No task with this id."),
    }
}

// Handle the actual updated command
fn edit(message: EditMessage, state: &SharedState) -> Message {
    // Check whether the task exists and is queued/stashed, abort if that's not the case
    let mut state = state.lock().unwrap();
    match state.tasks.get_mut(&message.task_id) {
        Some(task) => {
            if !(task.status == TaskStatus::Locked) {
                return create_failure_message("Task is no longer locked.");
            }

            task.status = task.prev_status.clone();
            task.command = message.command.clone();
            state.save();

            return create_success_message("Command has been updated");
        }
        None => {
            return create_failure_message(format!(
                "Task to edit has gone away: {}",
                message.task_id
            ))
        }
    }
}

/// Remove all failed or done tasks from the state
fn clean(state: &SharedState) -> Message {
    let mut state = state.lock().unwrap();
    state.clean();

    return create_success_message("All finished tasks have been removed");
}

// Forward the reset request to the task handler
// The handler then kills all children and clears the task queue
fn reset(sender: &Sender<Message>) -> Message {
    sender.send(Message::Reset).expect(SENDER_ERR);
    return create_success_message("Everything is being reset right now.");
}

/// Return the full current state to the client
fn get_status(state: &SharedState) -> Message {
    let state = state.lock().unwrap();
    Message::StatusResponse(state.clone())
}

/// Return the current state without any stdou/stderr to the client
fn get_simple_status(state: &SharedState) -> Message {
    let mut state = { state.lock().unwrap().clone() };
    for (_, task) in state.tasks.iter_mut() {
        task.stdout = None;
        task.stderr = None;
    }
    Message::StatusResponse(state)
}

fn set_parallel_tasks(amount: usize, sender: &Sender<Message>) -> Message {
    sender.send(Message::Parallel(amount)).expect(SENDER_ERR);
    return create_success_message("Parallel tasks setting adjusted");
}
<|endoftext|>


<commit_before>use {Event, Input, Motion};

/// Stores the touch state.
#[derive(Copy, Clone, Deserialize, Serialize, PartialEq, Debug)]
pub enum Touch {
    /// The start of touch, for example
    /// a finger pressed down on a touch screen.
    Start,
    /// The move of touch, for example
    /// a finger moving while touching a touch screen.
    Move,
    /// The end of touch, for example
    /// taking a finger away from a touch screen.
    End,
    /// The cancel of touch, for example
    /// the window loses focus.
    Cancel,
}

/// Touch arguments
///
/// The `id` might be reused for different touches that do not overlap in time.
///
/// - Coordinates are normalized to support both touch screens and trackpads
/// - Supports both 2D and 3D touch
/// - The pressure direction vector should have maximum length 1
///
/// For 2D touch the pressure is pointed the z direction.
/// Use `.pressure()` to get the pressure magnitude.
#[derive(Copy, Clone, Deserialize, Serialize, PartialEq, Debug)]
pub struct TouchArgs {
    /// A unique identifier for touch device.
    pub device: i64,
    /// A unique identifier for touch event.
    pub id: i64,
    /// The x coordinate of the touch position, normalized 0..1.
    pub x: f64,
    /// The y coordinate of the touch position, normalized 0..1.
    pub y: f64,
    /// The z coordinate of the touch position, normalized 0..1.
    pub z: f64,
    /// The x coordinate of the touch pressure direction.
    pub px: f64,
    /// The y coordinate of the touch pressure direction.
    pub py: f64,
    /// The z coordinate of the touch pressure direction.
    pub pz: f64,
    /// Whether the touch is in 3D.
    pub is_3d: bool,
    /// The touch state.
    pub touch: Touch,
}

impl TouchArgs {
    /// Creates arguments for 2D touch.
    pub fn new(device: i64, id: i64, pos: [f64; 2], pressure: f64, touch: Touch) -> TouchArgs {
        TouchArgs {
            device: device,
            id: id,
            x: pos[0],
            y: pos[1],
            z: 0.0,
            is_3d: false,
            px: 0.0,
            py: 0.0,
            pz: pressure,
            touch: touch,
        }
    }

    /// Creates arguments for 3D touch.
    ///
    /// The pressure direction vector should have maximum length 1.
    pub fn new_3d(device: i64,
                  id: i64,
                  pos: [f64; 3],
                  pressure: [f64; 3],
                  touch: Touch)
                  -> TouchArgs {
        TouchArgs {
            device: device,
            id: id,
            x: pos[0],
            y: pos[1],
            z: pos[2],
            is_3d: true,
            px: pressure[0],
            py: pressure[1],
            pz: pressure[2],
            touch: touch,
        }
    }

    /// The position of the touch in 2D.
    pub fn position(&self) -> [f64; 2] {
        [self.x, self.y]
    }

    /// The position of the touch in 3D.
    pub fn position_3d(&self) -> [f64; 3] {
        [self.x, self.y, self.z]
    }

    /// The pressure magnitude, normalized 0..1.
    pub fn pressure(&self) -> f64 {
        (self.px * self.px + self.py * self.py + self.pz * self.pz).sqrt()
    }

    /// The pressure vector in 3D.
    pub fn pressure_3d(&self) -> [f64; 3] {
        [self.px, self.py, self.pz]
    }
}

/// When a touch is started, moved, ended or cancelled.
pub trait TouchEvent: Sized {
    /// Creates a touch event.
    fn from_touch_args(args: &TouchArgs, old_event: &Self) -> Option<Self>;
    /// Calls closure if this is a touch event.
    fn touch<U, F>(&self, f: F) -> Option<U> where F: FnMut(&TouchArgs) -> U;
    /// Returns touch arguments.
    fn touch_args(&self) -> Option<TouchArgs> {
        self.touch(|args| args.clone())
    }
}

impl TouchEvent for Event {
    fn from_touch_args(args: &TouchArgs, old_event: &Self) -> Option<Self> {
        let timestamp = if let Event::Input(_, x) = old_event {*x} else {None};
        Some(Event::Input(Input::Move(Motion::Touch(*args)), timestamp))
    }

    fn touch<U, F>(&self, mut f: F) -> Option<U>
        where F: FnMut(&TouchArgs) -> U
    {
        match *self {
            Event::Input(Input::Move(Motion::Touch(ref args)), _) => Some(f(args)),
            _ => None,
        }
    }
}

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

    #[test]
    fn test_input_touch() {
        let pos = [0.0; 2];
        let e: Event = TouchArgs::new(0, 0, pos, 1.0, Touch::Start).into();
        let a: Option<Event> =
            TouchEvent::from_touch_args(&TouchArgs::new(0, 0, pos, 1.0, Touch::Start), &e);
        let b: Option<Event> = a.clone()
            .unwrap()
            .touch(|t| {
                TouchEvent::from_touch_args(&TouchArgs::new(t.device,
                                                            t.id,
                                                            t.position(),
                                                            t.pressure(),
                                                            Touch::Start),
                                            a.as_ref().unwrap())
            })
            .unwrap();
        assert_eq!(a, b);
    }

    #[test]
    fn test_input_touch_3d() {
        use super::super::Event;

        let pos = [0.0; 3];
        let pressure = [0.0, 0.0, 1.0];
        let e: Event = TouchArgs::new_3d(0, 0, pos, pressure, Touch::Start).into();
        let a: Option<Event> =
            TouchEvent::from_touch_args(&TouchArgs::new_3d(0, 0, pos, pressure, Touch::Start), &e);
        let b: Option<Event> = a.clone()
            .unwrap()
            .touch(|t| {
                TouchEvent::from_touch_args(&TouchArgs::new_3d(t.device,
                                                               t.id,
                                                               t.position_3d(),
                                                               t.pressure_3d(),
                                                               Touch::Start),
                                            a.as_ref().unwrap())
            })
            .unwrap();
        assert_eq!(a, b);
    }
}
<commit_msg>Added derive traits for `Touch` and `TouchArgs`<commit_after>use {Event, Input, Motion};

/// Stores the touch state.
#[derive(Copy, Clone, Deserialize, Serialize, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
pub enum Touch {
    /// The start of touch, for example
    /// a finger pressed down on a touch screen.
    Start,
    /// The move of touch, for example
    /// a finger moving while touching a touch screen.
    Move,
    /// The end of touch, for example
    /// taking a finger away from a touch screen.
    End,
    /// The cancel of touch, for example
    /// the window loses focus.
    Cancel,
}

/// Touch arguments
///
/// The `id` might be reused for different touches that do not overlap in time.
///
/// - Coordinates are normalized to support both touch screens and trackpads
/// - Supports both 2D and 3D touch
/// - The pressure direction vector should have maximum length 1
///
/// For 2D touch the pressure is pointed the z direction.
/// Use `.pressure()` to get the pressure magnitude.
#[derive(Copy, Clone, Deserialize, Serialize, PartialEq, PartialOrd, Debug)]
pub struct TouchArgs {
    /// A unique identifier for touch device.
    pub device: i64,
    /// A unique identifier for touch event.
    pub id: i64,
    /// The x coordinate of the touch position, normalized 0..1.
    pub x: f64,
    /// The y coordinate of the touch position, normalized 0..1.
    pub y: f64,
    /// The z coordinate of the touch position, normalized 0..1.
    pub z: f64,
    /// The x coordinate of the touch pressure direction.
    pub px: f64,
    /// The y coordinate of the touch pressure direction.
    pub py: f64,
    /// The z coordinate of the touch pressure direction.
    pub pz: f64,
    /// Whether the touch is in 3D.
    pub is_3d: bool,
    /// The touch state.
    pub touch: Touch,
}

impl TouchArgs {
    /// Creates arguments for 2D touch.
    pub fn new(device: i64, id: i64, pos: [f64; 2], pressure: f64, touch: Touch) -> TouchArgs {
        TouchArgs {
            device: device,
            id: id,
            x: pos[0],
            y: pos[1],
            z: 0.0,
            is_3d: false,
            px: 0.0,
            py: 0.0,
            pz: pressure,
            touch: touch,
        }
    }

    /// Creates arguments for 3D touch.
    ///
    /// The pressure direction vector should have maximum length 1.
    pub fn new_3d(device: i64,
                  id: i64,
                  pos: [f64; 3],
                  pressure: [f64; 3],
                  touch: Touch)
                  -> TouchArgs {
        TouchArgs {
            device: device,
            id: id,
            x: pos[0],
            y: pos[1],
            z: pos[2],
            is_3d: true,
            px: pressure[0],
            py: pressure[1],
            pz: pressure[2],
            touch: touch,
        }
    }

    /// The position of the touch in 2D.
    pub fn position(&self) -> [f64; 2] {
        [self.x, self.y]
    }

    /// The position of the touch in 3D.
    pub fn position_3d(&self) -> [f64; 3] {
        [self.x, self.y, self.z]
    }

    /// The pressure magnitude, normalized 0..1.
    pub fn pressure(&self) -> f64 {
        (self.px * self.px + self.py * self.py + self.pz * self.pz).sqrt()
    }

    /// The pressure vector in 3D.
    pub fn pressure_3d(&self) -> [f64; 3] {
        [self.px, self.py, self.pz]
    }
}

/// When a touch is started, moved, ended or cancelled.
pub trait TouchEvent: Sized {
    /// Creates a touch event.
    fn from_touch_args(args: &TouchArgs, old_event: &Self) -> Option<Self>;
    /// Calls closure if this is a touch event.
    fn touch<U, F>(&self, f: F) -> Option<U> where F: FnMut(&TouchArgs) -> U;
    /// Returns touch arguments.
    fn touch_args(&self) -> Option<TouchArgs> {
        self.touch(|args| args.clone())
    }
}

impl TouchEvent for Event {
    fn from_touch_args(args: &TouchArgs, old_event: &Self) -> Option<Self> {
        let timestamp = if let Event::Input(_, x) = old_event {*x} else {None};
        Some(Event::Input(Input::Move(Motion::Touch(*args)), timestamp))
    }

    fn touch<U, F>(&self, mut f: F) -> Option<U>
        where F: FnMut(&TouchArgs) -> U
    {
        match *self {
            Event::Input(Input::Move(Motion::Touch(ref args)), _) => Some(f(args)),
            _ => None,
        }
    }
}

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

    #[test]
    fn test_input_touch() {
        let pos = [0.0; 2];
        let e: Event = TouchArgs::new(0, 0, pos, 1.0, Touch::Start).into();
        let a: Option<Event> =
            TouchEvent::from_touch_args(&TouchArgs::new(0, 0, pos, 1.0, Touch::Start), &e);
        let b: Option<Event> = a.clone()
            .unwrap()
            .touch(|t| {
                TouchEvent::from_touch_args(&TouchArgs::new(t.device,
                                                            t.id,
                                                            t.position(),
                                                            t.pressure(),
                                                            Touch::Start),
                                            a.as_ref().unwrap())
            })
            .unwrap();
        assert_eq!(a, b);
    }

    #[test]
    fn test_input_touch_3d() {
        use super::super::Event;

        let pos = [0.0; 3];
        let pressure = [0.0, 0.0, 1.0];
        let e: Event = TouchArgs::new_3d(0, 0, pos, pressure, Touch::Start).into();
        let a: Option<Event> =
            TouchEvent::from_touch_args(&TouchArgs::new_3d(0, 0, pos, pressure, Touch::Start), &e);
        let b: Option<Event> = a.clone()
            .unwrap()
            .touch(|t| {
                TouchEvent::from_touch_args(&TouchArgs::new_3d(t.device,
                                                               t.id,
                                                               t.position_3d(),
                                                               t.pressure_3d(),
                                                               Touch::Start),
                                            a.as_ref().unwrap())
            })
            .unwrap();
        assert_eq!(a, b);
    }
}
<|endoftext|>


<commit_before>// Copyright 2015 Pierre Talbot (IRCAM)

// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at

//     http://www.apache.org/licenses/LICENSE-2.0

// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::cmp::Ord;

pub trait Hull<RHS = Self> {
  type Output;
  fn hull(self, rhs: RHS) -> Self::Output;
}

pub trait Range<Bound: Ord> {
  fn new(lb: Bound, ub: Bound) -> Self;
}
<commit_msg>Remove the PartialOrd bound due to some limitation of the genericity in Rust.<commit_after>// Copyright 2015 Pierre Talbot (IRCAM)

// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at

//     http://www.apache.org/licenses/LICENSE-2.0

// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

pub trait Hull<RHS = Self> {
  type Output;
  fn hull(self, rhs: RHS) -> Self::Output;
}

pub trait Range<Bound> {
  fn new(lb: Bound, ub: Bound) -> Self;
}
<|endoftext|>


<commit_before>//! Provides a keyframe transformation which is a transform associated
//! with a specific point in time

use std::f32;

use linalg::{self, quaternion, Vector, Matrix4, Quaternion, Transform};

/// A transformation associated with a specific point in time
#[derive(Debug, Copy, Clone)]
pub struct Keyframe {
    pub time: f32,
    translation: Vector,
    rotation: Quaternion,
    scaling: Matrix4,
}

impl Keyframe {
    /// Construct a new keyframe transformation by associating the
    /// transform passed with the time point `time`. The transform will
    /// be stored in a decomposed form, M = TRS.
    pub fn new(transform: &Transform, time: f32) -> Keyframe {
        let (t, r, s) = Keyframe::decompose(transform);
        Keyframe { time: time, translation: t, rotation: r, scaling: s }
    }
    /// Decompose the transformation into its component translation, rotation and
    /// scaling operations.
    fn decompose(transform: &Transform) -> (Vector, Quaternion, Matrix4) {
        let mut m = transform.mat;
        // Extract the translation component and remove it from the matrix
        let translation = Vector::new(*m.at(0, 3), *m.at(1, 3), *m.at(2, 3));
        for i in 0..3 {
            *m.at_mut(i, 3) = 0.0;
            *m.at_mut(3, i) = 0.0;
        }
        *m.at_mut(3, 3) = 1.0;
        // Extract rotation component using polar decomposition by computing
        // M_{i + 1} = 1/2 (M_i + (M_i^T)^-1) to convergence
        let mut rot_mat = m;
        for _ in 0..100 {
            let m_inv_trans = rot_mat.transpose().inverse();
            let r_next: Matrix4 = rot_mat.iter().zip(m_inv_trans.iter())
                .map(|(&a, &b)| 0.5 * (a - b)).collect();
            let mut norm = 0.0;
            for i in 0..3 {
                let n = f32::abs(*rot_mat.at(i, 0) - *r_next.at(i, 0))
                    + f32::abs(*rot_mat.at(i, 1) - *r_next.at(i, 1))
                    + f32::abs(*rot_mat.at(i, 2) - *r_next.at(i, 2));
                norm = f32::max(norm, n);
            }
            rot_mat = r_next;
            if norm <= 0.0001 {
                break;
            }
        }
        (translation, Quaternion::from_matrix(&rot_mat), rot_mat.inverse() * m)
    }
}

/// Interpolate between the two keyframes at some time. If time is before
/// or after the interval spanned by the keyframes then the nearest one is
/// returned. Otherwise the transforms are interpolated and this new
/// transform is returned.
pub fn interpolate(time: f32, a: &Keyframe, b: &Keyframe) -> Transform {
    // Order the transformations by their time points
    let (first, second) = if a.time < b.time { (a, b) } else { (b, a) };
    if time <= first.time {
        let m = first.rotation.to_matrix() * first.scaling;
        Transform::translate(&first.translation) * Transform::from_mat(&m)
    } else if time >= second.time {
        let m = second.rotation.to_matrix() * second.scaling;
        Transform::translate(&second.translation) * Transform::from_mat(&m)
    } else {
        let dt = (time - first.time) / (second.time - first.time);
        let translation = (1.0 - dt) * first.translation + dt * second.translation;
        let rotation = quaternion::slerp(dt, &first.rotation, &second.rotation);
        let scaling: Matrix4 = first.scaling.iter().zip(second.scaling.iter())
                .map(|(a, b)| linalg::lerp(dt, a, b)).collect();
        let m = rotation.to_matrix() * scaling;
        Transform::translate(&translation) * Transform::from_mat(&m)
    }
}

<commit_msg>Add method to get the transform for this keyframe<commit_after>//! Provides a keyframe transformation which is a transform associated
//! with a specific point in time

use std::f32;
use std::cmp::{Eq, Ord, PartialOrd, PartialEq, Ordering};

use linalg::{self, quaternion, Vector, Matrix4, Quaternion, Transform};

/// A transformation associated with a specific point in time
#[derive(Debug, Copy, Clone)]
pub struct Keyframe {
    pub time: f32,
    translation: Vector,
    rotation: Quaternion,
    scaling: Matrix4,
}

impl Keyframe {
    /// Construct a new keyframe transformation by associating the
    /// transform passed with the time point `time`. The transform will
    /// be stored in a decomposed form, M = TRS.
    pub fn new(transform: &Transform, time: f32) -> Keyframe {
        assert!(f32::is_finite(time));
        let (t, r, s) = Keyframe::decompose(transform);
        Keyframe { time: time, translation: t, rotation: r, scaling: s }
    }
    /// Decompose the transformation into its component translation, rotation and
    /// scaling operations.
    fn decompose(transform: &Transform) -> (Vector, Quaternion, Matrix4) {
        let mut m = transform.mat;
        // Extract the translation component and remove it from the matrix
        let translation = Vector::new(*m.at(0, 3), *m.at(1, 3), *m.at(2, 3));
        for i in 0..3 {
            *m.at_mut(i, 3) = 0.0;
            *m.at_mut(3, i) = 0.0;
        }
        *m.at_mut(3, 3) = 1.0;
        // Extract rotation component using polar decomposition by computing
        // M_{i + 1} = 1/2 (M_i + (M_i^T)^-1) to convergence
        let mut rot_mat = m;
        for _ in 0..100 {
            let m_inv_trans = rot_mat.transpose().inverse();
            let r_next: Matrix4 = rot_mat.iter().zip(m_inv_trans.iter())
                .map(|(&a, &b)| 0.5 * (a - b)).collect();
            let mut norm = 0.0;
            for i in 0..3 {
                let n = f32::abs(*rot_mat.at(i, 0) - *r_next.at(i, 0))
                    + f32::abs(*rot_mat.at(i, 1) - *r_next.at(i, 1))
                    + f32::abs(*rot_mat.at(i, 2) - *r_next.at(i, 2));
                norm = f32::max(norm, n);
            }
            rot_mat = r_next;
            if norm <= 0.0001 {
                break;
            }
        }
        (translation, Quaternion::from_matrix(&rot_mat), rot_mat.inverse() * m)
    }
    /// Return the transformation stored for this keyframe
    pub fn transform(&self) -> Transform {
        let m = self.rotation.to_matrix() * self.scaling;
        Transform::translate(&self.translation) * Transform::from_mat(&m)
    }
}

/// Interpolate between the two keyframes at some time. If time is before
/// or after the interval spanned by the keyframes then the nearest one is
/// returned. Otherwise the transforms are interpolated and this new
/// transform is returned.
pub fn interpolate(time: f32, a: &Keyframe, b: &Keyframe) -> Transform {
    // Order the transformations by their time points
    let (first, second) = if a.time < b.time { (a, b) } else { (b, a) };
    if time <= first.time {
        let m = first.rotation.to_matrix() * first.scaling;
        Transform::translate(&first.translation) * Transform::from_mat(&m)
    } else if time >= second.time {
        let m = second.rotation.to_matrix() * second.scaling;
        Transform::translate(&second.translation) * Transform::from_mat(&m)
    } else {
        let dt = (time - first.time) / (second.time - first.time);
        let translation = (1.0 - dt) * first.translation + dt * second.translation;
        let rotation = quaternion::slerp(dt, &first.rotation, &second.rotation);
        let scaling: Matrix4 = first.scaling.iter().zip(second.scaling.iter())
                .map(|(a, b)| linalg::lerp(dt, a, b)).collect();
        let m = rotation.to_matrix() * scaling;
        Transform::translate(&translation) * Transform::from_mat(&m)
    }
}

impl Ord for Keyframe {
    fn cmp(&self, other: &Keyframe) -> Ordering {
        self.partial_cmp(other).unwrap()
    }
}

impl PartialOrd for Keyframe {
    fn partial_cmp(&self, other: &Keyframe) -> Option<Ordering> {
        self.time.partial_cmp(&other.time)
    }
}

impl Eq for Keyframe {}

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

<|endoftext|>


<commit_before>use chrono;
use log::Record;
use std::io::{Error, Write};
use std::thread;
use Config;

#[inline(always)]
pub fn try_log<W>(config: &Config, record: &Record, write: &mut W) -> Result<(), Error>
where
    W: Write + Sized,
{
    if let Some(time) = config.time {
        if time <= record.level() {
            try!(write_time(write, config));
        }
    }

    if let Some(level) = config.level {
        if level <= record.level() {
            try!(write_level(record, write));
        }
    }

    if let Some(thread) = config.thread {
        if thread <= record.level() {
            try!(write_thread_id(write));
        }
    }

    if let Some(target) = config.target {
        if target <= record.level() {
            try!(write_target(record, write));
        }
    }

    if let Some(location) = config.location {
        if location <= record.level() {
            try!(write_location(record, write));
        }
    }

    try!(write_args(record, write));
    Ok(())
}

#[inline(always)]
pub fn write_time<W>(write: &mut W, config: &Config) -> Result<(), Error>
where
    W: Write + Sized,
{
    let cur_time = chrono::Utc::now().with_timezone::<chrono::offset::FixedOffset>(
        &chrono::TimeZone::from_offset(&config.offset),
    );
    try!(write!(
        write,
        "{} ",
        cur_time.format(config.time_format.unwrap_or("%H:%M:%S"))
    ));
    Ok(())
}

#[inline(always)]
pub fn write_level<W>(record: &Record, write: &mut W) -> Result<(), Error>
where
    W: Write + Sized,
{
    try!(write!(write, "[{}] ", record.level()));
    Ok(())
}

#[inline(always)]
pub fn write_target<W>(record: &Record, write: &mut W) -> Result<(), Error>
where
    W: Write + Sized,
{
    try!(write!(write, "{}: ", record.target()));
    Ok(())
}

#[inline(always)]
pub fn write_location<W>(record: &Record, write: &mut W) -> Result<(), Error>
where
    W: Write + Sized,
{
    let file = record.file().unwrap_or("<unknown>");
    if let Some(line) = record.line() {
        try!(write!(write, "[{}:{}] ", file, line));
    } else {
        try!(write!(write, "[{}:<unknown>] ", file));
    }
    Ok(())
}

pub fn write_thread_id<W>(write: &mut W) -> Result<(), Error>
where
    W: Write + Sized,
{
    let id = format!("{:?}", thread::current().id());
    let id = id.replace("ThreadId(", "");
    let id = id.replace(")", "");
    try!(write!(write, "({}) ", id));
    Ok(())
}

#[inline(always)]
pub fn write_args<W>(record: &Record, write: &mut W) -> Result<(), Error>
where
    W: Write + Sized,
{
    try!(writeln!(write, "{}", record.args()));
    Ok(())
}<commit_msg>Pad log level (Closes #35)<commit_after>use chrono;
use log::Record;
use std::io::{Error, Write};
use std::thread;
use Config;

#[inline(always)]
pub fn try_log<W>(config: &Config, record: &Record, write: &mut W) -> Result<(), Error>
where
    W: Write + Sized,
{
    if let Some(time) = config.time {
        if time <= record.level() {
            try!(write_time(write, config));
        }
    }

    if let Some(level) = config.level {
        if level <= record.level() {
            try!(write_level(record, write));
        }
    }

    if let Some(thread) = config.thread {
        if thread <= record.level() {
            try!(write_thread_id(write));
        }
    }

    if let Some(target) = config.target {
        if target <= record.level() {
            try!(write_target(record, write));
        }
    }

    if let Some(location) = config.location {
        if location <= record.level() {
            try!(write_location(record, write));
        }
    }

    try!(write_args(record, write));
    Ok(())
}

#[inline(always)]
pub fn write_time<W>(write: &mut W, config: &Config) -> Result<(), Error>
where
    W: Write + Sized,
{
    let cur_time = chrono::Utc::now().with_timezone::<chrono::offset::FixedOffset>(
        &chrono::TimeZone::from_offset(&config.offset),
    );
    try!(write!(
        write,
        "{} ",
        cur_time.format(config.time_format.unwrap_or("%H:%M:%S"))
    ));
    Ok(())
}

#[inline(always)]
pub fn write_level<W>(record: &Record, write: &mut W) -> Result<(), Error>
where
    W: Write + Sized,
{
    try!(write!(write, "[{: >5}] ", record.level()));
    Ok(())
}

#[inline(always)]
pub fn write_target<W>(record: &Record, write: &mut W) -> Result<(), Error>
where
    W: Write + Sized,
{
    try!(write!(write, "{}: ", record.target()));
    Ok(())
}

#[inline(always)]
pub fn write_location<W>(record: &Record, write: &mut W) -> Result<(), Error>
where
    W: Write + Sized,
{
    let file = record.file().unwrap_or("<unknown>");
    if let Some(line) = record.line() {
        try!(write!(write, "[{}:{}] ", file, line));
    } else {
        try!(write!(write, "[{}:<unknown>] ", file));
    }
    Ok(())
}

pub fn write_thread_id<W>(write: &mut W) -> Result<(), Error>
where
    W: Write + Sized,
{
    let id = format!("{:?}", thread::current().id());
    let id = id.replace("ThreadId(", "");
    let id = id.replace(")", "");
    try!(write!(write, "({}) ", id));
    Ok(())
}

#[inline(always)]
pub fn write_args<W>(record: &Record, write: &mut W) -> Result<(), Error>
where
    W: Write + Sized,
{
    try!(writeln!(write, "{}", record.args()));
    Ok(())
}<|endoftext|>


<commit_before>// Copyright 2016 Victor Brekenfeld
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.

//! Module providing the TestLogger Implementation

use super::logging::should_skip;
use crate::{Config, LevelPadding, SharedLogger};
use log::{set_boxed_logger, set_max_level, LevelFilter, Log, Metadata, Record, SetLoggerError};

use std::thread;

/// The TestLogger struct. Provides a very basic Logger implementation that may be captured by cargo.
pub struct TestLogger {
    level: LevelFilter,
    config: Config,
}

impl TestLogger {
    /// init function. Globally initializes the TestLogger as the one and only used log facility.
    ///
    /// Takes the desired `Level` and `Config` as arguments. They cannot be changed later on.
    /// Fails if another Logger was already initialized.
    ///
    /// # Examples
    /// ```
    /// # extern crate simplelog;
    /// # use simplelog::*;
    /// # fn main() {
    /// #[cfg(not(test))]
    /// // another logger
    /// # let _ = TestLogger::init(LevelFilter::Info, Config::default());
    /// #[cfg(test)]
    /// let _ = TestLogger::init(LevelFilter::Info, Config::default());
    /// # }
    /// ```
    pub fn init(log_level: LevelFilter, config: Config) -> Result<(), SetLoggerError> {
        set_max_level(log_level);
        set_boxed_logger(TestLogger::new(log_level, config))
    }

    /// allows to create a new logger, that can be independently used, no matter what is globally set.
    ///
    /// no macros are provided for this case and you probably
    /// dont want to use this function, but `init()`, if you dont want to build a `CombinedLogger`.
    ///
    /// Takes the desired `Level` and `Config` as arguments. They cannot be changed later on.
    ///
    /// # Examples
    /// ```
    /// # extern crate simplelog;
    /// # use simplelog::*;
    /// # fn main() {
    /// #[cfg(not(test))]
    /// // another logger
    /// # let test_logger = TestLogger::new(LevelFilter::Info, Config::default());
    /// #[cfg(test)]
    /// let test_logger = TestLogger::new(LevelFilter::Info, Config::default());
    /// # }
    /// ```
    pub fn new(log_level: LevelFilter, config: Config) -> Box<TestLogger> {
        Box::new(TestLogger {
            level: log_level,
            config,
        })
    }
}

impl Log for TestLogger {
    fn enabled(&self, metadata: &Metadata<'_>) -> bool {
        metadata.level() <= self.level
    }

    fn log(&self, record: &Record<'_>) {
        if self.enabled(record.metadata()) {
            let _ = log(&self.config, record);
        }
    }

    fn flush(&self) {}
}

impl SharedLogger for TestLogger {
    fn level(&self) -> LevelFilter {
        self.level
    }

    fn config(&self) -> Option<&Config> {
        Some(&self.config)
    }

    fn as_log(self: Box<Self>) -> Box<dyn Log> {
        Box::new(*self)
    }
}

#[inline(always)]
pub fn log(config: &Config, record: &Record<'_>) {
    if should_skip(&config, &record) {
        return;
    }

    if config.time <= record.level() && config.time != LevelFilter::Off {
        write_time(config);
    }

    if config.level <= record.level() && config.level != LevelFilter::Off {
        write_level(record, config);
    }

    if config.thread < record.level() && config.thread != LevelFilter::Off {
        write_thread_id();
    }

    if config.target <= record.level() && config.target != LevelFilter::Off {
        write_target(record);
    }

    if config.location <= record.level() && config.location != LevelFilter::Off {
        write_location(record);
    }

    write_args(record);
}

#[inline(always)]
pub fn write_time(config: &Config) {
    let cur_time = if config.time_local {
        chrono::Local::now().naive_local() + config.time_offset
    } else {
        chrono::Utc::now().naive_utc() + config.time_offset
    };
    print!("{} ", cur_time.format(&*config.time_format));
}

#[inline(always)]
pub fn write_level(record: &Record<'_>, config: &Config) {
    match config.level_padding {
        LevelPadding::Left => print!("[{: >5}] ", record.level()),
        LevelPadding::Right => print!("[{: <5}] ", record.level()),
        LevelPadding::Off => print!("[{}] ", record.level()),
    };
}

#[inline(always)]
pub fn write_thread_id() {
    let id = format!("{:?}", thread::current().id());
    let id = id.replace("ThreadId(", "");
    let id = id.replace(")", "");
    print!("({}) ", id);
}

#[inline(always)]
pub fn write_target(record: &Record<'_>) {
    print!("{}: ", record.target());
}

#[inline(always)]
pub fn write_location(record: &Record<'_>) {
    let file = record.file().unwrap_or("<unknown>");
    if let Some(line) = record.line() {
        print!("[{}:{}] ", file, line);
    } else {
        print!("[{}:<unknown>] ", file);
    }
}

#[inline(always)]
pub fn write_args(record: &Record<'_>) {
    println!("{}", record.args());
}
<commit_msg>fix TestLogger<commit_after>// Copyright 2016 Victor Brekenfeld
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.

//! Module providing the TestLogger Implementation

use super::logging::should_skip;
use crate::{config::TimeFormat, Config, LevelPadding, SharedLogger};
use log::{set_boxed_logger, set_max_level, LevelFilter, Log, Metadata, Record, SetLoggerError};

use std::thread;

/// The TestLogger struct. Provides a very basic Logger implementation that may be captured by cargo.
pub struct TestLogger {
    level: LevelFilter,
    config: Config,
}

impl TestLogger {
    /// init function. Globally initializes the TestLogger as the one and only used log facility.
    ///
    /// Takes the desired `Level` and `Config` as arguments. They cannot be changed later on.
    /// Fails if another Logger was already initialized.
    ///
    /// # Examples
    /// ```
    /// # extern crate simplelog;
    /// # use simplelog::*;
    /// # fn main() {
    /// #[cfg(not(test))]
    /// // another logger
    /// # let _ = TestLogger::init(LevelFilter::Info, Config::default());
    /// #[cfg(test)]
    /// let _ = TestLogger::init(LevelFilter::Info, Config::default());
    /// # }
    /// ```
    pub fn init(log_level: LevelFilter, config: Config) -> Result<(), SetLoggerError> {
        set_max_level(log_level);
        set_boxed_logger(TestLogger::new(log_level, config))
    }

    /// allows to create a new logger, that can be independently used, no matter what is globally set.
    ///
    /// no macros are provided for this case and you probably
    /// dont want to use this function, but `init()`, if you dont want to build a `CombinedLogger`.
    ///
    /// Takes the desired `Level` and `Config` as arguments. They cannot be changed later on.
    ///
    /// # Examples
    /// ```
    /// # extern crate simplelog;
    /// # use simplelog::*;
    /// # fn main() {
    /// #[cfg(not(test))]
    /// // another logger
    /// # let test_logger = TestLogger::new(LevelFilter::Info, Config::default());
    /// #[cfg(test)]
    /// let test_logger = TestLogger::new(LevelFilter::Info, Config::default());
    /// # }
    /// ```
    pub fn new(log_level: LevelFilter, config: Config) -> Box<TestLogger> {
        Box::new(TestLogger {
            level: log_level,
            config,
        })
    }
}

impl Log for TestLogger {
    fn enabled(&self, metadata: &Metadata<'_>) -> bool {
        metadata.level() <= self.level
    }

    fn log(&self, record: &Record<'_>) {
        if self.enabled(record.metadata()) {
            let _ = log(&self.config, record);
        }
    }

    fn flush(&self) {}
}

impl SharedLogger for TestLogger {
    fn level(&self) -> LevelFilter {
        self.level
    }

    fn config(&self) -> Option<&Config> {
        Some(&self.config)
    }

    fn as_log(self: Box<Self>) -> Box<dyn Log> {
        Box::new(*self)
    }
}

#[inline(always)]
pub fn log(config: &Config, record: &Record<'_>) {
    if should_skip(&config, &record) {
        return;
    }

    if config.time <= record.level() && config.time != LevelFilter::Off {
        write_time(config);
    }

    if config.level <= record.level() && config.level != LevelFilter::Off {
        write_level(record, config);
    }

    if config.thread < record.level() && config.thread != LevelFilter::Off {
        write_thread_id();
    }

    if config.target <= record.level() && config.target != LevelFilter::Off {
        write_target(record);
    }

    if config.location <= record.level() && config.location != LevelFilter::Off {
        write_location(record);
    }

    write_args(record);
}

#[inline(always)]
pub fn write_time(config: &Config) {
    use time::format_description::well_known::*;

    let time = time::OffsetDateTime::now_utc().to_offset(config.time_offset);
    let res = match config.time_format {
        TimeFormat::Rfc2822 => time.format(&Rfc2822),
        TimeFormat::Rfc3339 => time.format(&Rfc3339),
        TimeFormat::Custom(format) => time.format(&format),
    };
    match res {
        Ok(time) => println!("{} ", time),
        Err(err) => panic!("Invalid time format: {}", err),
    };
}

#[inline(always)]
pub fn write_level(record: &Record<'_>, config: &Config) {
    match config.level_padding {
        LevelPadding::Left => print!("[{: >5}] ", record.level()),
        LevelPadding::Right => print!("[{: <5}] ", record.level()),
        LevelPadding::Off => print!("[{}] ", record.level()),
    };
}

#[inline(always)]
pub fn write_thread_id() {
    let id = format!("{:?}", thread::current().id());
    let id = id.replace("ThreadId(", "");
    let id = id.replace(")", "");
    print!("({}) ", id);
}

#[inline(always)]
pub fn write_target(record: &Record<'_>) {
    print!("{}: ", record.target());
}

#[inline(always)]
pub fn write_location(record: &Record<'_>) {
    let file = record.file().unwrap_or("<unknown>");
    if let Some(line) = record.line() {
        print!("[{}:{}] ", file, line);
    } else {
        print!("[{}:<unknown>] ", file);
    }
}

#[inline(always)]
pub fn write_args(record: &Record<'_>) {
    println!("{}", record.args());
}
<|endoftext|>


<commit_before>use {
    AddColor,
    Borrowed,
    Color,
    Field,
    Matrix2d,
    PolygonColorContext,
    Value,
};
use internal::{
    CanTransform,
    CanViewTransform,
    HasTransform,
    HasViewTransform,
};

/// A polygon context.
pub struct PolygonContext<'a, 'b> {
    /// Base/origin transform.
    pub base: Field<'a, Matrix2d>,
    /// Current transform.
    pub transform: Field<'a, Matrix2d>,
    /// Current polygon.
    pub polygon: Field<'a, &'b [f64]>
}

impl<'a, 'b> Clone for PolygonContext<'a, 'b> {
    #[inline(always)]
    fn clone(&self) -> PolygonContext<'static, 'b> {
        PolygonContext {
            base: self.base.clone(),
            transform: self.transform.clone(),
            polygon: Value(*self.polygon.get()),
        }
    }
}

impl<'a, 'b> HasTransform<'a, Matrix2d> for PolygonContext<'a, 'b> {
    #[inline(always)]
    fn get_transform(&'a self) -> &'a Matrix2d {
        self.transform.get()
    }
}

impl<'a, 'b> CanTransform<'a, PolygonContext<'a, 'b>, Matrix2d> for PolygonContext<'a, 'b> {
    #[inline(always)]
    fn transform(&'a self, value: Matrix2d) -> PolygonContext<'a, 'b> {
        PolygonContext {
            base: Borrowed(self.base.get()),
            transform: Value(value),
            polygon: Borrowed(self.polygon.get()),
        }
    }
}

impl<'a, 'b> HasViewTransform<'a, Matrix2d> for PolygonContext<'a, 'b> {
    #[inline(always)]
    fn get_view_transform(&'a self) -> &'a Matrix2d {
        self.base.get()
    }
}

impl<'a, 'b> CanViewTransform<'a, PolygonContext<'a, 'b>, Matrix2d>
for PolygonContext<'a, 'b> {
    #[inline(always)]
    fn view_transform(&'a self, value: Matrix2d) -> PolygonContext<'a, 'b> {
        PolygonContext {
            base: Value(value),
            transform: Borrowed(self.transform.get()),
            polygon: Borrowed(self.polygon.get()),
        }
    }
}

impl<'a, 'b> AddColor<'a, PolygonColorContext<'a, 'b>> for PolygonContext<'a, 'b> {
    #[inline(always)]
    fn rgba(&'a self, r: f32, g: f32, b: f32, a: f32) -> PolygonColorContext<'a, 'b> {
        PolygonColorContext {
            base: Borrowed(self.base.get()),
            transform: Borrowed(self.transform.get()),
            color: Value(Color([r, g, b, a])),
            polygon: Borrowed(self.polygon.get()),
        }
    }
}

<commit_msg>Using type alias for `Polygon` in `PolygonContext`<commit_after>use {
    AddColor,
    Borrowed,
    Color,
    Field,
    Matrix2d,
    Polygon,
    PolygonColorContext,
    Value,
};
use internal::{
    CanTransform,
    CanViewTransform,
    HasTransform,
    HasViewTransform,
};

/// A polygon context.
pub struct PolygonContext<'a, 'b> {
    /// Base/origin transform.
    pub base: Field<'a, Matrix2d>,
    /// Current transform.
    pub transform: Field<'a, Matrix2d>,
    /// Current polygon.
    pub polygon: Field<'a, Polygon<'b>>
}

impl<'a, 'b> Clone for PolygonContext<'a, 'b> {
    #[inline(always)]
    fn clone(&self) -> PolygonContext<'static, 'b> {
        PolygonContext {
            base: self.base.clone(),
            transform: self.transform.clone(),
            polygon: Value(*self.polygon.get()),
        }
    }
}

impl<'a, 'b> HasTransform<'a, Matrix2d> for PolygonContext<'a, 'b> {
    #[inline(always)]
    fn get_transform(&'a self) -> &'a Matrix2d {
        self.transform.get()
    }
}

impl<'a, 'b> CanTransform<'a, PolygonContext<'a, 'b>, Matrix2d> for PolygonContext<'a, 'b> {
    #[inline(always)]
    fn transform(&'a self, value: Matrix2d) -> PolygonContext<'a, 'b> {
        PolygonContext {
            base: Borrowed(self.base.get()),
            transform: Value(value),
            polygon: Borrowed(self.polygon.get()),
        }
    }
}

impl<'a, 'b> HasViewTransform<'a, Matrix2d> for PolygonContext<'a, 'b> {
    #[inline(always)]
    fn get_view_transform(&'a self) -> &'a Matrix2d {
        self.base.get()
    }
}

impl<'a, 'b> CanViewTransform<'a, PolygonContext<'a, 'b>, Matrix2d>
for PolygonContext<'a, 'b> {
    #[inline(always)]
    fn view_transform(&'a self, value: Matrix2d) -> PolygonContext<'a, 'b> {
        PolygonContext {
            base: Value(value),
            transform: Borrowed(self.transform.get()),
            polygon: Borrowed(self.polygon.get()),
        }
    }
}

impl<'a, 'b> AddColor<'a, PolygonColorContext<'a, 'b>> for PolygonContext<'a, 'b> {
    #[inline(always)]
    fn rgba(&'a self, r: f32, g: f32, b: f32, a: f32) -> PolygonColorContext<'a, 'b> {
        PolygonColorContext {
            base: Borrowed(self.base.get()),
            transform: Borrowed(self.transform.get()),
            color: Value(Color([r, g, b, a])),
            polygon: Borrowed(self.polygon.get()),
        }
    }
}

<|endoftext|>


<commit_before>use uuid::Uuid;

pub struct Packet {
    id: i32,
    data: Vec<Field>
}

enum Field {
    Boolean(bool),
    Byte(i8),
    UByte(u8),
    Short(i16),
    UShort(u16),
    Int(i32),
    Long(i64),
    Float(f32),
    Double(f64),
    String(String),
    Chat(String),
    VarInt(i32),
    VarLong(i64),
    //TODO: Chunk Section, Entity Metadata, Slot, NBT Tag, Byte Array, Optional X, Array of X, X Enum
    Position {
        x: i32,
        y: i16,
        z: i32
    },
    Angle(i8),
    UUID(Uuid)
}

pub enum PacketType {
    HandshakingOut(HandshakingOut),
    PlayIn(PlayIn),
    PlayOut(PlayOut),
    StatusIn(StatusIn),
    StatusOut(StatusOut),
    LoginIn(LoginIn),
    LoginOut(LoginOut)
}

/// Client -> Server (Play)
pub enum HandshakingOut {
    Handshake = 0x00,
    LegacyServerListPing = 0xFE
}

/// Server -> Client (Play)
pub enum PlayIn {
    SpawnObject = 0x00,
    SpawnExpOrb = 0x01,
    SpawnGlobalEntity = 0x02,
    SpawnMob = 0x03,
    SpawnPainting = 0x04,
    SpawnPlayer = 0x05,
    Animation = 0x06,
    Statistics = 0x07,
    BlockBreakAnimation = 0x08,
    UpdateBlockEntity = 0x09,
    BlockAction = 0x0A,
    BlockChange = 0x0B,
    BossBar = 0x0C,
    ServerDifficulty = 0x0D,
    TabComplete = 0x0E,
    ChatMessage = 0x0F,
    MultiBlockChange = 0x10,
    ConfirmTransaction = 0x11,
    CloseWindow = 0x12,
    OpenWindow = 0x13,
    WindowItems = 0x14,
    WindowProperty = 0x15,
    SetSlot = 0x16,
    SetCooldown = 0x17,
    PluginMessage = 0x18,
    NamedSoundEffect = 0x19,
    Disconnect = 0x1A,
    EntityStatus = 0x1B,
    Explosion = 0x1C,
    UnloadChunk = 0x1D,
    ChangeGameState = 0x1E,
    KeepAlive = 0x1F,
    ChunkData = 0x20,
    Effect = 0x21,
    Particle = 0x22,
    JoinGame = 0x23,
    Map = 0x24,
    EntityRelativeMove = 0x25,
    EntityLookRelativeMove = 0x26,
    EntityLook = 0x27,
    Entity = 0x28,
    VehicleMove = 0x29,
    OpenSignEditor = 0x2A,
    PlayerAbilities = 0x2B,
    CombatEvent = 0x2C,
    PlayerListItem = 0x2D,
    PlayerPositionLook = 0x2E,
    UseBed = 0x2F,
    DestroyEntities = 0x30,
    RemoveEntityEffect = 0x31,
    ResourcePackSend = 0x32,
    Respawn = 0x33,
    EntityHeadLook = 0x34,
    WorldBorder = 0x35,
    Camera = 0x36,
    HeldItemChange = 0x37,
    DisplayScoreboard = 0x38,
    EntityMetadata = 0x39,
    AttachEntity = 0x3A,
    EntityVelocity = 0x3B,
    EntityEquipment = 0x3C,
    SetExp = 0x3D,
    UpdateHealth = 0x3E,
    ScoreboardObjective = 0x3F,
    SetPassengers = 0x40,
    Teams = 0x41,
    UpdateScore = 0x42,
    SpawnPosition = 0x43,
    TimeUpdate = 0x44,
    Title = 0x45,
    SoundEffect = 0x46,
    PlayerListHeaderFooter = 0x47,
    CollectItem = 0x48,
    EntityTeleport = 0x49,
    EntityProperties = 0x4A,
    EntityEffect = 0x4B
}

/// Client -> Server (Play)
pub enum PlayOut {
    TeleportConfirm = 0x00,
    TabComplete = 0x01,
    ChatMessage = 0x02,
    ClientStatus = 0x03,
    ClientSettings = 0x04,
    ConfirmTransaction = 0x05,
    EnchantItem = 0x06,
    ClickWindow = 0x07,
    CloseWindow = 0x08,
    PluginMessage = 0x09,
    UseEntity = 0x0A,
    KeepAlive = 0x0B,
    PlayerPosition = 0x0C,
    PlayerPositionLook = 0x0D,
    PlayerLook = 0x0E,
    Player = 0x0F,
    VehicleMove = 0x10,
    SteerBoat = 0x11,
    PlayerAbilities = 0x12,
    PlayerDigging = 0x13,
    EntityAction = 0x14,
    SteerVehicle = 0x15,
    ResourcePackStatus = 0x16,
    HeldItemChange = 0x17,
    CreativeInventoryAction = 0x18,
    UpdateSign = 0x19,
    Animation = 0x1A,
    Spectate = 0x1B,
    PlayerBlockPlacement = 0x1C,
    UseItem = 0x1D
}

/// Server -> Client (Status)
pub enum StatusIn {
    Response = 0x00,
    Pong = 0x01
}

/// Client -> Server (Status)
pub enum StatusOut {
    Request = 0x00,
    Ping = 0x01
}

/// Server -> Client (Login)
pub enum LoginIn {
    Disconnect = 0x00,
    EncryptionRequest = 0x01,
    LoginSuccess = 0x02,
    SetCompression = 0x03
}

/// Client -> Server (Login)
pub enum LoginOut {
    LoginStart = 0x00,
    EncryptionResponse = 0x01
}

impl Packet {
    /// Create a new empty packet
    pub fn new(id: i32) -> Packet {
        Packet {
            id: id,
            data: vec![]
        }
    }

    // Decode a byte array into a packet
    //pub fn decode(data: &[u8]) -> Option<Packet> {}

    // Encode the packet into a byte array
    //pub fn encode(&self) -> &[u8] {}

    /// Get data field
    pub fn get_data(&self) -> &[Field] {
        &self.data
    }

    /// Get mutable data field
    pub fn get_data_mut(&mut self) -> &mut [Field] {
        &mut self.data
    }
}
<commit_msg>Read VarInts<commit_after>use uuid::Uuid;
use std::io;

pub struct Packet {
    id: i32,
    data: Vec<Field>,
    buf: Vec<u8>
}

#[derive(Debug, Clone)]
enum Field {
    Boolean(bool),
    Byte(i8),
    UByte(u8),
    Short(i16),
    UShort(u16),
    Int(i32),
    Long(i64),
    Float(f32),
    Double(f64),
    String(String),
    Chat(String),
    VarInt(i32),
    VarLong(i64),
    //TODO: Chunk Section, Entity Metadata, Slot, NBT Tag, Byte Array, Optional X, Array of X, X Enum
    Position {
        x: i32,
        y: i16,
        z: i32
    },
    Angle(i8),
    UUID(Uuid)
}

pub enum PacketType {
    HandshakingOut(HandshakingOut),
    PlayIn(PlayIn),
    PlayOut(PlayOut),
    StatusIn(StatusIn),
    StatusOut(StatusOut),
    LoginIn(LoginIn),
    LoginOut(LoginOut)
}

/// Client -> Server (Play)
pub enum HandshakingOut {
    Handshake = 0x00,
    LegacyServerListPing = 0xFE
}

/// Server -> Client (Play)
pub enum PlayIn {
    SpawnObject = 0x00,
    SpawnExpOrb = 0x01,
    SpawnGlobalEntity = 0x02,
    SpawnMob = 0x03,
    SpawnPainting = 0x04,
    SpawnPlayer = 0x05,
    Animation = 0x06,
    Statistics = 0x07,
    BlockBreakAnimation = 0x08,
    UpdateBlockEntity = 0x09,
    BlockAction = 0x0A,
    BlockChange = 0x0B,
    BossBar = 0x0C,
    ServerDifficulty = 0x0D,
    TabComplete = 0x0E,
    ChatMessage = 0x0F,
    MultiBlockChange = 0x10,
    ConfirmTransaction = 0x11,
    CloseWindow = 0x12,
    OpenWindow = 0x13,
    WindowItems = 0x14,
    WindowProperty = 0x15,
    SetSlot = 0x16,
    SetCooldown = 0x17,
    PluginMessage = 0x18,
    NamedSoundEffect = 0x19,
    Disconnect = 0x1A,
    EntityStatus = 0x1B,
    Explosion = 0x1C,
    UnloadChunk = 0x1D,
    ChangeGameState = 0x1E,
    KeepAlive = 0x1F,
    ChunkData = 0x20,
    Effect = 0x21,
    Particle = 0x22,
    JoinGame = 0x23,
    Map = 0x24,
    EntityRelativeMove = 0x25,
    EntityLookRelativeMove = 0x26,
    EntityLook = 0x27,
    Entity = 0x28,
    VehicleMove = 0x29,
    OpenSignEditor = 0x2A,
    PlayerAbilities = 0x2B,
    CombatEvent = 0x2C,
    PlayerListItem = 0x2D,
    PlayerPositionLook = 0x2E,
    UseBed = 0x2F,
    DestroyEntities = 0x30,
    RemoveEntityEffect = 0x31,
    ResourcePackSend = 0x32,
    Respawn = 0x33,
    EntityHeadLook = 0x34,
    WorldBorder = 0x35,
    Camera = 0x36,
    HeldItemChange = 0x37,
    DisplayScoreboard = 0x38,
    EntityMetadata = 0x39,
    AttachEntity = 0x3A,
    EntityVelocity = 0x3B,
    EntityEquipment = 0x3C,
    SetExp = 0x3D,
    UpdateHealth = 0x3E,
    ScoreboardObjective = 0x3F,
    SetPassengers = 0x40,
    Teams = 0x41,
    UpdateScore = 0x42,
    SpawnPosition = 0x43,
    TimeUpdate = 0x44,
    Title = 0x45,
    SoundEffect = 0x46,
    PlayerListHeaderFooter = 0x47,
    CollectItem = 0x48,
    EntityTeleport = 0x49,
    EntityProperties = 0x4A,
    EntityEffect = 0x4B
}

/// Client -> Server (Play)
pub enum PlayOut {
    TeleportConfirm = 0x00,
    TabComplete = 0x01,
    ChatMessage = 0x02,
    ClientStatus = 0x03,
    ClientSettings = 0x04,
    ConfirmTransaction = 0x05,
    EnchantItem = 0x06,
    ClickWindow = 0x07,
    CloseWindow = 0x08,
    PluginMessage = 0x09,
    UseEntity = 0x0A,
    KeepAlive = 0x0B,
    PlayerPosition = 0x0C,
    PlayerPositionLook = 0x0D,
    PlayerLook = 0x0E,
    Player = 0x0F,
    VehicleMove = 0x10,
    SteerBoat = 0x11,
    PlayerAbilities = 0x12,
    PlayerDigging = 0x13,
    EntityAction = 0x14,
    SteerVehicle = 0x15,
    ResourcePackStatus = 0x16,
    HeldItemChange = 0x17,
    CreativeInventoryAction = 0x18,
    UpdateSign = 0x19,
    Animation = 0x1A,
    Spectate = 0x1B,
    PlayerBlockPlacement = 0x1C,
    UseItem = 0x1D
}

/// Server -> Client (Status)
pub enum StatusIn {
    Response = 0x00,
    Pong = 0x01
}

/// Client -> Server (Status)
pub enum StatusOut {
    Request = 0x00,
    Ping = 0x01
}

/// Server -> Client (Login)
pub enum LoginIn {
    Disconnect = 0x00,
    EncryptionRequest = 0x01,
    LoginSuccess = 0x02,
    SetCompression = 0x03
}

/// Client -> Server (Login)
pub enum LoginOut {
    LoginStart = 0x00,
    EncryptionResponse = 0x01
}

impl Packet {
    /// Create a new empty packet
    pub fn new(id: i32, buffer: Vec<u8>) -> Packet {
        Packet {
            id: id,
            data: vec![],
            buf: buffer
        }
    }

    // Decode a byte array into a packet
    //pub fn decode(data: &[u8]) -> Option<Packet> {}

    // Encode the packet into a byte array
    //pub fn encode(&self) -> &[u8] {}

    /// Get data field
    pub fn get_data(&self) -> &[Field] {
        &self.data
    }

    /// Get mutable data field
    pub fn get_data_mut(&mut self) -> &mut [Field] {
        &mut self.data
    }

    /// Read a VarInt, return the value and add it to the packet fields
    pub fn read_varint(&mut self) -> Result<i32, &'static str> {
        const PART: u8 = 0x7F;
        let mut size = 0;
        let mut val = 0u32;
        for b in &self.buf {
            val |= ((b & PART) << (size * 7)) as u32;
            size += 1;
            if size > 5 {
                return Result::Err("VarInt too big");
            }
            if (b & 0x80) == 0 {
                break
            }
        }

        Result::Ok(val as i32)
    }
}
<|endoftext|>


<commit_before>pub extern mod core_foundation;
pub extern mod io_surface;
pub extern mod opengles;

use mod platform::opengles::gl2;

use core::cast::transmute;
use core::ptr::{null, to_unsafe_ptr};
use geom::size::Size2D;
use platform::io_surface::{IOSurface, kIOSurfaceBytesPerElement, kIOSurfaceBytesPerRow};
use platform::io_surface::{kIOSurfaceHeight, kIOSurfaceIsGlobal, kIOSurfaceWidth};
use platform::io_surface::IOSurfaceMethods;
use platform::opengles::cgl::{CGLChoosePixelFormat, CGLContextObj, CGLCreateContext};
use platform::opengles::cgl::{CGLLockContext, CGLSetCurrentContext, CGLTexImageIOSurface2D};
use platform::opengles::cgl::{kCGLNoError, kCGLPFACompliant, kCGLPFADoubleBuffer};
use platform::opengles::gl2::{BGRA, CLAMP_TO_EDGE, COLOR_ATTACHMENT0, FRAMEBUFFER};
use platform::opengles::gl2::{FRAMEBUFFER_COMPLETE, GLenum, GLint, GLsizei, GLuint, LINEAR};
use platform::opengles::gl2::{NEAREST, RGBA, TEXTURE_MAG_FILTER, TEXTURE_MIN_FILTER};
use platform::opengles::gl2::{TEXTURE_RECTANGLE_ARB, TEXTURE_WRAP_S, TEXTURE_WRAP_T};
use platform::opengles::gl2::{UNSIGNED_INT_8_8_8_8_REV};

use base::ShareContext;

// FIXME: This is not good.
#[link_args="-framework IOSurface -framework CoreFoundation"]
#[nolink]
extern {}

pub type Context = MacContext;

pub struct MacContext {
    surface: IOSurface,
    framebuffer: GLuint,
    texture: GLuint

    // FIXME: Needs drop.
}

pub fn init_cgl() -> CGLContextObj {
    // FIXME: We should expose some higher-level, safe abstractions inside the CGL module.
    unsafe {
        // Choose a pixel format.
        let attributes = [ kCGLPFADoubleBuffer, kCGLPFACompliant, 0 ];
        let pixel_format = null();
        let pixel_format_count = 1;
        let gl_error = CGLChoosePixelFormat(transmute(&attributes[0]),
                                            to_unsafe_ptr(&pixel_format),
                                            to_unsafe_ptr(&pixel_format_count));
        assert!(gl_error == kCGLNoError);

        // Create the context.
        let cgl_context = null();
        let gl_error = CGLCreateContext(pixel_format, null(), to_unsafe_ptr(&cgl_context));
        assert!(gl_error == kCGLNoError);

        // Set the context.
        let gl_error = CGLSetCurrentContext(cgl_context);
        assert!(gl_error == kCGLNoError);

        // Lock the context.
        let gl_error = CGLLockContext(cgl_context);
        assert!(gl_error == kCGLNoError);

        return cgl_context;
    }
}

pub fn init_surface(size: Size2D<int>) -> IOSurface {
    use platform::core_foundation::boolean::{CFBooleanRef, CFBoolean};
    use number = platform::core_foundation::number::CFNumber::new;
    use string = platform::core_foundation::string::CFString::wrap_extern;

    // TODO: dictionary constructor should be less ridiculous.
    // Or, we could add bindings for mutable dictionaries.
    let k_width = string(kIOSurfaceWidth);
    let v_width = number(size.width as i32);

    let k_height = string(kIOSurfaceHeight);
    let v_height = number(size.height as i32);

    let k_bytes_per_row = string(kIOSurfaceBytesPerRow);
    let v_bytes_per_row = number(size.width as i32 * 4);

    let k_bytes_per_elem = string(kIOSurfaceBytesPerElement);
    let v_bytes_per_elem = number(4i32);

    let k_is_global = string(kIOSurfaceIsGlobal);
    let v_is_global = CFBoolean::true_value();

    io_surface::new(&core_foundation::dictionary::CFDictionary::new([
        (*k_width.borrow_ref(),          *v_width.borrow_type_ref()),
        (*k_height.borrow_ref(),         *v_height.borrow_type_ref()),
        (*k_bytes_per_row.borrow_ref(),  *v_bytes_per_row.borrow_type_ref()),
        (*k_bytes_per_elem.borrow_ref(), *v_bytes_per_elem.borrow_type_ref()),
        (*k_is_global.borrow_ref(),      *v_is_global.borrow_type_ref()),
    ]))
}

pub fn init_texture() -> GLuint {
    gl2::enable(TEXTURE_RECTANGLE_ARB);

    let texture = gl2::gen_textures(1)[0];
    gl2::bind_texture(TEXTURE_RECTANGLE_ARB, texture);
    gl2::tex_parameter_i(TEXTURE_RECTANGLE_ARB, TEXTURE_WRAP_S, CLAMP_TO_EDGE as GLint);
    gl2::tex_parameter_i(TEXTURE_RECTANGLE_ARB, TEXTURE_WRAP_T, CLAMP_TO_EDGE as GLint);
    gl2::tex_parameter_i(TEXTURE_RECTANGLE_ARB, TEXTURE_MAG_FILTER, LINEAR as GLint);
    gl2::tex_parameter_i(TEXTURE_RECTANGLE_ARB, TEXTURE_MIN_FILTER, NEAREST as GLint);
    return texture;
}

// Assumes the texture is already bound via gl2::bind_texture().
pub fn bind_surface_to_texture(context: &CGLContextObj, surface: &IOSurface, size: Size2D<int>) {
    // FIXME: There should be safe wrappers for this.
    unsafe {
        let gl_error = CGLTexImageIOSurface2D(*context,
                                              TEXTURE_RECTANGLE_ARB,
                                              RGBA as GLenum,
                                              size.width as GLsizei,
                                              size.height as GLsizei,
                                              BGRA as GLenum,
                                              UNSIGNED_INT_8_8_8_8_REV,
                                              transmute(copy surface.obj),
                                              0);
        assert!(gl_error == kCGLNoError);
    }
}

pub fn bind_texture_to_framebuffer(texture: GLuint) {
    gl2::bind_texture(TEXTURE_RECTANGLE_ARB, 0);
    gl2::framebuffer_texture_2d(FRAMEBUFFER, COLOR_ATTACHMENT0, TEXTURE_RECTANGLE_ARB, texture, 0);
    assert!(gl2::check_framebuffer_status(FRAMEBUFFER) == FRAMEBUFFER_COMPLETE);
}

impl ShareContext for MacContext {
    fn new(size: Size2D<int>) -> MacContext {
        // Initialize CGL.
        let context = init_cgl();

        // Create the surface.
        let surface = init_surface(copy size);

        // Create a framebuffer.
        let framebuffer = gl2::gen_framebuffers(1)[0];
        gl2::bind_framebuffer(FRAMEBUFFER, framebuffer);

        // Create and bind to the texture.
        let texture = init_texture();
        bind_surface_to_texture(&context, &surface, size);

        // Bind the texture to the framebuffer.
        bind_texture_to_framebuffer(texture);

        MacContext {
            surface: surface,
            framebuffer: framebuffer,
            texture: texture
        }
    }

    fn flush(&self) {
        gl2::finish();
    }

    fn id(&self) -> int {
        self.surface.get_id() as int
    }
}

<commit_msg>Remove unused imports.<commit_after>pub extern mod core_foundation;
pub extern mod io_surface;
pub extern mod opengles;

use mod platform::opengles::gl2;

use core::cast::transmute;
use core::ptr::{null, to_unsafe_ptr};
use geom::size::Size2D;
use platform::io_surface::{IOSurface, kIOSurfaceBytesPerElement, kIOSurfaceBytesPerRow};
use platform::io_surface::{kIOSurfaceHeight, kIOSurfaceIsGlobal, kIOSurfaceWidth};
use platform::io_surface::IOSurfaceMethods;
use platform::opengles::cgl::{CGLChoosePixelFormat, CGLContextObj, CGLCreateContext};
use platform::opengles::cgl::{CGLLockContext, CGLSetCurrentContext, CGLTexImageIOSurface2D};
use platform::opengles::cgl::{kCGLNoError, kCGLPFACompliant, kCGLPFADoubleBuffer};
use platform::opengles::gl2::{BGRA, CLAMP_TO_EDGE, COLOR_ATTACHMENT0, FRAMEBUFFER};
use platform::opengles::gl2::{FRAMEBUFFER_COMPLETE, GLenum, GLint, GLsizei, GLuint, LINEAR};
use platform::opengles::gl2::{NEAREST, RGBA, TEXTURE_MAG_FILTER, TEXTURE_MIN_FILTER};
use platform::opengles::gl2::{TEXTURE_RECTANGLE_ARB, TEXTURE_WRAP_S, TEXTURE_WRAP_T};
use platform::opengles::gl2::{UNSIGNED_INT_8_8_8_8_REV};

use base::ShareContext;

// FIXME: This is not good.
#[link_args="-framework IOSurface -framework CoreFoundation"]
#[nolink]
extern {}

pub type Context = MacContext;

pub struct MacContext {
    surface: IOSurface,
    framebuffer: GLuint,
    texture: GLuint

    // FIXME: Needs drop.
}

pub fn init_cgl() -> CGLContextObj {
    // FIXME: We should expose some higher-level, safe abstractions inside the CGL module.
    unsafe {
        // Choose a pixel format.
        let attributes = [ kCGLPFADoubleBuffer, kCGLPFACompliant, 0 ];
        let pixel_format = null();
        let pixel_format_count = 1;
        let gl_error = CGLChoosePixelFormat(transmute(&attributes[0]),
                                            to_unsafe_ptr(&pixel_format),
                                            to_unsafe_ptr(&pixel_format_count));
        assert!(gl_error == kCGLNoError);

        // Create the context.
        let cgl_context = null();
        let gl_error = CGLCreateContext(pixel_format, null(), to_unsafe_ptr(&cgl_context));
        assert!(gl_error == kCGLNoError);

        // Set the context.
        let gl_error = CGLSetCurrentContext(cgl_context);
        assert!(gl_error == kCGLNoError);

        // Lock the context.
        let gl_error = CGLLockContext(cgl_context);
        assert!(gl_error == kCGLNoError);

        return cgl_context;
    }
}

pub fn init_surface(size: Size2D<int>) -> IOSurface {
    use platform::core_foundation::boolean::CFBoolean;
    use number = platform::core_foundation::number::CFNumber::new;
    use string = platform::core_foundation::string::CFString::wrap_extern;

    // TODO: dictionary constructor should be less ridiculous.
    // Or, we could add bindings for mutable dictionaries.
    let k_width = string(kIOSurfaceWidth);
    let v_width = number(size.width as i32);

    let k_height = string(kIOSurfaceHeight);
    let v_height = number(size.height as i32);

    let k_bytes_per_row = string(kIOSurfaceBytesPerRow);
    let v_bytes_per_row = number(size.width as i32 * 4);

    let k_bytes_per_elem = string(kIOSurfaceBytesPerElement);
    let v_bytes_per_elem = number(4i32);

    let k_is_global = string(kIOSurfaceIsGlobal);
    let v_is_global = CFBoolean::true_value();

    io_surface::new(&core_foundation::dictionary::CFDictionary::new([
        (*k_width.borrow_ref(),          *v_width.borrow_type_ref()),
        (*k_height.borrow_ref(),         *v_height.borrow_type_ref()),
        (*k_bytes_per_row.borrow_ref(),  *v_bytes_per_row.borrow_type_ref()),
        (*k_bytes_per_elem.borrow_ref(), *v_bytes_per_elem.borrow_type_ref()),
        (*k_is_global.borrow_ref(),      *v_is_global.borrow_type_ref()),
    ]))
}

pub fn init_texture() -> GLuint {
    gl2::enable(TEXTURE_RECTANGLE_ARB);

    let texture = gl2::gen_textures(1)[0];
    gl2::bind_texture(TEXTURE_RECTANGLE_ARB, texture);
    gl2::tex_parameter_i(TEXTURE_RECTANGLE_ARB, TEXTURE_WRAP_S, CLAMP_TO_EDGE as GLint);
    gl2::tex_parameter_i(TEXTURE_RECTANGLE_ARB, TEXTURE_WRAP_T, CLAMP_TO_EDGE as GLint);
    gl2::tex_parameter_i(TEXTURE_RECTANGLE_ARB, TEXTURE_MAG_FILTER, LINEAR as GLint);
    gl2::tex_parameter_i(TEXTURE_RECTANGLE_ARB, TEXTURE_MIN_FILTER, NEAREST as GLint);
    return texture;
}

// Assumes the texture is already bound via gl2::bind_texture().
pub fn bind_surface_to_texture(context: &CGLContextObj, surface: &IOSurface, size: Size2D<int>) {
    // FIXME: There should be safe wrappers for this.
    unsafe {
        let gl_error = CGLTexImageIOSurface2D(*context,
                                              TEXTURE_RECTANGLE_ARB,
                                              RGBA as GLenum,
                                              size.width as GLsizei,
                                              size.height as GLsizei,
                                              BGRA as GLenum,
                                              UNSIGNED_INT_8_8_8_8_REV,
                                              transmute(copy surface.obj),
                                              0);
        assert!(gl_error == kCGLNoError);
    }
}

pub fn bind_texture_to_framebuffer(texture: GLuint) {
    gl2::bind_texture(TEXTURE_RECTANGLE_ARB, 0);
    gl2::framebuffer_texture_2d(FRAMEBUFFER, COLOR_ATTACHMENT0, TEXTURE_RECTANGLE_ARB, texture, 0);
    assert!(gl2::check_framebuffer_status(FRAMEBUFFER) == FRAMEBUFFER_COMPLETE);
}

impl ShareContext for MacContext {
    fn new(size: Size2D<int>) -> MacContext {
        // Initialize CGL.
        let context = init_cgl();

        // Create the surface.
        let surface = init_surface(copy size);

        // Create a framebuffer.
        let framebuffer = gl2::gen_framebuffers(1)[0];
        gl2::bind_framebuffer(FRAMEBUFFER, framebuffer);

        // Create and bind to the texture.
        let texture = init_texture();
        bind_surface_to_texture(&context, &surface, size);

        // Bind the texture to the framebuffer.
        bind_texture_to_framebuffer(texture);

        MacContext {
            surface: surface,
            framebuffer: framebuffer,
            texture: texture
        }
    }

    fn flush(&self) {
        gl2::finish();
    }

    fn id(&self) -> int {
        self.surface.get_id() as int
    }
}

<|endoftext|>