<commit_before>#![cfg(target_os = "macos")]

use std::convert::From;
use std::os::raw::c_void;
use cocoa::appkit::NSApplicationActivationPolicy;
use {Window, WindowBuilder};

/// Additional methods on `Window` that are specific to MacOS.
pub trait WindowExt {
    /// Returns a pointer to the cocoa `NSWindow` that is used by this window.
    ///
    /// The pointer will become invalid when the glutin `Window` is destroyed.
    fn get_nswindow(&self) -> *mut c_void;
}

impl WindowExt for Window {
    #[inline]
    fn get_nswindow(&self) -> *mut c_void {
        self.window.platform_window() as *mut c_void
    }
}

/// Corresponds to `NSApplicationActivationPolicy`.
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum ActivationPolicy {
    /// Corresponds to `NSApplicationActivationPolicyRegular`.
    Regular,
    /// Corresponds to `NSApplicationActivationPolicyAccessory`.
    Accessory,
    /// Corresponds to `NSApplicationActivationPolicyProhibited`.
    Prohibited,
}

impl Default for ActivationPolicy {
    fn default() -> Self {
        ActivationPolicy::Regular
    }
}

impl From<ActivationPolicy> for NSApplicationActivationPolicy {
    fn from(activation_policy: ActivationPolicy) -> Self {
        match activation_policy {
            ActivationPolicy::Regular =>
                NSApplicationActivationPolicy::NSApplicationActivationPolicyRegular,
            ActivationPolicy::Accessory =>
                NSApplicationActivationPolicy::NSApplicationActivationPolicyAccessory,
            ActivationPolicy::Prohibited =>
                NSApplicationActivationPolicy::NSApplicationActivationPolicyProhibited,
        }
    }
}

/// Additional methods on `WindowBuilder` that are specific to MacOS.
pub trait WindowBuilderExt<'a> {
    fn with_activation_policy(mut self, activation_policy: ActivationPolicy) -> WindowBuilder<'a>;
    fn with_app_name(mut self, app_name: String) -> WindowBuilder<'a>;
}

impl<'a> WindowBuilderExt<'a> for WindowBuilder<'a> {
    /// Sets the activation policy for the window being built
    #[inline]
    fn with_activation_policy(mut self, activation_policy: ActivationPolicy) -> WindowBuilder<'a> {
        self.platform_specific.activation_policy = activation_policy;
        self
    }

    /// Sets the name of the application in the menu bar and Dock
    #[inline]
    fn with_app_name(mut self, app_name: String) -> WindowBuilder<'a> {
        self.platform_specific.app_name = Some(app_name);
        self
    }
}
<commit_msg>Remove two patterns in method signatures without a body<commit_after>#![cfg(target_os = "macos")]

use std::convert::From;
use std::os::raw::c_void;
use cocoa::appkit::NSApplicationActivationPolicy;
use {Window, WindowBuilder};

/// Additional methods on `Window` that are specific to MacOS.
pub trait WindowExt {
    /// Returns a pointer to the cocoa `NSWindow` that is used by this window.
    ///
    /// The pointer will become invalid when the glutin `Window` is destroyed.
    fn get_nswindow(&self) -> *mut c_void;
}

impl WindowExt for Window {
    #[inline]
    fn get_nswindow(&self) -> *mut c_void {
        self.window.platform_window() as *mut c_void
    }
}

/// Corresponds to `NSApplicationActivationPolicy`.
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum ActivationPolicy {
    /// Corresponds to `NSApplicationActivationPolicyRegular`.
    Regular,
    /// Corresponds to `NSApplicationActivationPolicyAccessory`.
    Accessory,
    /// Corresponds to `NSApplicationActivationPolicyProhibited`.
    Prohibited,
}

impl Default for ActivationPolicy {
    fn default() -> Self {
        ActivationPolicy::Regular
    }
}

impl From<ActivationPolicy> for NSApplicationActivationPolicy {
    fn from(activation_policy: ActivationPolicy) -> Self {
        match activation_policy {
            ActivationPolicy::Regular =>
                NSApplicationActivationPolicy::NSApplicationActivationPolicyRegular,
            ActivationPolicy::Accessory =>
                NSApplicationActivationPolicy::NSApplicationActivationPolicyAccessory,
            ActivationPolicy::Prohibited =>
                NSApplicationActivationPolicy::NSApplicationActivationPolicyProhibited,
        }
    }
}

/// Additional methods on `WindowBuilder` that are specific to MacOS.
pub trait WindowBuilderExt<'a> {
    fn with_activation_policy(self, activation_policy: ActivationPolicy) -> WindowBuilder<'a>;
    fn with_app_name(self, app_name: String) -> WindowBuilder<'a>;
}

impl<'a> WindowBuilderExt<'a> for WindowBuilder<'a> {
    /// Sets the activation policy for the window being built
    #[inline]
    fn with_activation_policy(mut self, activation_policy: ActivationPolicy) -> WindowBuilder<'a> {
        self.platform_specific.activation_policy = activation_policy;
        self
    }

    /// Sets the name of the application in the menu bar and Dock
    #[inline]
    fn with_app_name(mut self, app_name: String) -> WindowBuilder<'a> {
        self.platform_specific.app_name = Some(app_name);
        self
    }
}
<|endoftext|>


<commit_before>
pub use self::manager::Manager;

/// The pass manager infrastructure.
pub mod manager;
/// Passes which perform transformations.
pub mod transforms;
/// Passes which perform analysis.
pub mod analysis;

use lang;

/// A pass identifier.
#[derive(Copy,Clone,Debug,PartialEq,Eq)]
pub struct Id(u32);

pub enum Info<M: lang::Module>
{
    Immutable(Box<Pass<M>>),
    Mutable(Box<PassMut<M>>),
}

impl<M: lang::Module> Metadata for Info<M>
{
    fn id(&self) -> Id {
        match self {
            &Info::Immutable(ref p) => p.id(),
            &Info::Mutable(ref p) => p.id(),
        }
    }

    fn dependencies(&self) -> &'static [Id] {
        match self {
            &Info::Immutable(ref p) => p.dependencies(),
            &Info::Mutable(ref p) => p.dependencies(),
        }
    }

    fn name(&self) -> &'static str {
        match self {
            &Info::Immutable(ref p) => p.name(),
            &Info::Mutable(ref p) => p.name(),
        }
    }
}

/// A pass over a set of instructions.
pub trait Metadata
{
    fn id(&self) -> Id;

    /// Gets the identifiers of the passes this pass
    /// depends on.
    fn dependencies(&self) -> &'static [Id] {
        &[]
    }

    fn name(&self) -> &'static str;
}

pub trait Pass<M> : Metadata
    where M: lang::Module
{
    fn run_module(&mut self, module: &M) {

        for func in module.functions() {
            self.run_function(func);
        }
    }

    fn run_function(&mut self, function: &M::Function) {
        use lang::Function;

        for bb in function.blocks() {
            self.run_block(bb);
        }
    }

    fn run_block(&mut self, block: &<M::Function as lang::Function>::Block) {
        use lang::Block;

        for value in block.subvalues() {
            self.run_value_recursive(&value);
        }
    }

    fn run_value(&mut self,
                 _: &<<M::Function as lang::Function>::Block as lang::Block>::Value) {

        panic!("the pass is not implemented");
    }

    fn run_value_recursive(&mut self,
                           value: &<<M::Function as lang::Function>::Block as lang::Block>::Value) {
        use lang::Value;

        // Recurse from the deepest node to the root node.
        for val in value.subvalues() {
            self.run_value_recursive(&val);
        }

        self.run_value(value)
    }
}

pub trait PassMut<M> : Metadata
    where M: lang::Module
{
    fn run_module(&mut self, module: M) -> M{
        module.map_functions(|a| self.run_function(a))
    }

    fn run_function(&mut self, function: M::Function)
        -> M::Function {
        use lang::Function;

        function.map_blocks(|a| self.run_block(a))
    }

    fn run_block(&mut self, block: <M::Function as lang::Function>::Block)
        -> <M::Function as lang::Function>::Block {
        use lang::Block;

        block.map_subvalues(|a| self.run_value_recursive(a))
    }

    fn run_value(&mut self,
                 _: <<M::Function as lang::Function>::Block as lang::Block>::Value)
        -> <<M::Function as lang::Function>::Block as lang::Block>::Value {

        panic!("the pass is not implemented");
    }

    fn run_value_recursive(&mut self,
                           value: <<M::Function as lang::Function>::Block as lang::Block>::Value)
        -> <<M::Function as lang::Function>::Block as lang::Block>::Value {
        use lang::Value;

        // Recurse from the deepest node to the root node.
        let val = value.map_subvalues(|v| self.run_value_recursive(v));
        self.run_value(val)
    }
}

<commit_msg>Add global variable support to the pass infrastructure<commit_after>
pub use self::manager::Manager;

/// The pass manager infrastructure.
pub mod manager;
/// Passes which perform transformations.
pub mod transforms;
/// Passes which perform analysis.
pub mod analysis;

use lang;

/// A pass identifier.
#[derive(Copy,Clone,Debug,PartialEq,Eq)]
pub struct Id(u32);

pub enum Info<M: lang::Module>
{
    Immutable(Box<Pass<M>>),
    Mutable(Box<PassMut<M>>),
}

impl<M: lang::Module> Metadata for Info<M>
{
    fn id(&self) -> Id {
        match self {
            &Info::Immutable(ref p) => p.id(),
            &Info::Mutable(ref p) => p.id(),
        }
    }

    fn dependencies(&self) -> &'static [Id] {
        match self {
            &Info::Immutable(ref p) => p.dependencies(),
            &Info::Mutable(ref p) => p.dependencies(),
        }
    }

    fn name(&self) -> &'static str {
        match self {
            &Info::Immutable(ref p) => p.name(),
            &Info::Mutable(ref p) => p.name(),
        }
    }
}

/// A pass over a set of instructions.
pub trait Metadata
{
    fn id(&self) -> Id;

    /// Gets the identifiers of the passes this pass
    /// depends on.
    fn dependencies(&self) -> &'static [Id] {
        &[]
    }

    fn name(&self) -> &'static str;
}

pub trait Pass<M> : Metadata
    where M: lang::Module
{
    /// Run the pass on an entire module.
    fn run_module(&mut self, module: &M) {

        for global in module.globals() {
            self.run_global(global);
        }

        for func in module.functions() {
            self.run_function(func);
        }
    }

    /// Run the pass on a global variable.
    fn run_global(&mut self, _: &M::Global) {
        // do nothing unless overidden
    }

    /// Run the pass on a function.
    fn run_function(&mut self, function: &M::Function) {
        use lang::Function;

        for bb in function.blocks() {
            self.run_block(bb);
        }
    }

    /// Run the pass on a basic block.
    fn run_block(&mut self, block: &<M::Function as lang::Function>::Block) {
        use lang::Block;

        for value in block.subvalues() {
            self.run_value_recursive(&value);
        }
    }

    /// Run the pass on a value.
    fn run_value(&mut self,
                 _: &<<M::Function as lang::Function>::Block as lang::Block>::Value) {

        panic!("the pass is not implemented");
    }

    fn run_value_recursive(&mut self,
                           value: &<<M::Function as lang::Function>::Block as lang::Block>::Value) {
        use lang::Value;

        // Recurse from the deepest node to the root node.
        for val in value.subvalues() {
            self.run_value_recursive(&val);
        }

        self.run_value(value)
    }
}

pub trait PassMut<M> : Metadata
    where M: lang::Module
{
    /// Run the pass on an entire module.
    fn run_module(&mut self, module: M) -> M{
        module.map_globals(|a| self.run_global(a))
              .map_functions(|a| self.run_function(a))
    }

    /// Run the pass on a global.
    fn run_global(&mut self, global: M::Global)
        -> M::Global {

        // do nothing unless overridden
        global
    }

    /// Run the pass on a function.
    fn run_function(&mut self, function: M::Function)
        -> M::Function {
        use lang::Function;

        function.map_blocks(|a| self.run_block(a))
    }

    /// Run the pass on a basic block.
    fn run_block(&mut self, block: <M::Function as lang::Function>::Block)
        -> <M::Function as lang::Function>::Block {
        use lang::Block;

        block.map_subvalues(|a| self.run_value_recursive(a))
    }

    /// Run the pass on a value.
    fn run_value(&mut self,
                 _: <<M::Function as lang::Function>::Block as lang::Block>::Value)
        -> <<M::Function as lang::Function>::Block as lang::Block>::Value {

        panic!("the pass is not implemented");
    }

    fn run_value_recursive(&mut self,
                           value: <<M::Function as lang::Function>::Block as lang::Block>::Value)
        -> <<M::Function as lang::Function>::Block as lang::Block>::Value {
        use lang::Value;

        // Recurse from the deepest node to the root node.
        let val = value.map_subvalues(|v| self.run_value_recursive(v));
        self.run_value(val)
    }
}

<|endoftext|>


<commit_before>use std::fs::File;
use std::io;
use std::time::SystemTime;

pub trait FileExt {
    fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize>;
}

impl FileExt for ::std::fs::File {
    #[cfg(unix)]
    fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> {
        use std::os::unix::fs::FileExt;

        FileExt::read_at(self, buf, offset)
    }

    #[cfg(windows)]
    fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> {
        use std::os::windows::fs::FileExt;

        FileExt::seek_read(self, buf, offset)
    }
}

pub struct FileInfo {
    pub inode: u64,
    pub len: u64,
    pub mtime: SystemTime,
}

#[cfg(windows)]
fn filetime_to_systemtime(time: ::winapi::shared::minwindef::FILETIME) -> SystemTime {
    use std::time::{Duration, UNIX_EPOCH};

    let ticks = (time.dwHighDateTime as u64) << 32 | time.dwLowDateTime as u64;

    const SECS_TO_UNIX_EPOCH: u64 = 11_644_473_600;
    let secs = ticks / 10_000_000 - SECS_TO_UNIX_EPOCH;
    let nanos = (ticks % 10_000_000 * 100) as u32;

    let duration = Duration::new(secs, nanos);
    UNIX_EPOCH + duration
}

#[cfg(unix)]
pub fn file_info(file: &File) -> io::Result<FileInfo> {
    use std::os::unix::fs::MetadataExt;

    let metadata = file.metadata()?;
    let info = FileInfo {
        inode: metadata.ino(),
        len: metadata.len(),
        mtime: metadata.modified()?,
    };

    Ok(info)
}

#[cfg(windows)]
pub fn file_info(file: &File) -> io::Result<FileInfo> {
    use std::os::windows::io::AsRawHandle;
    use winapi::shared::minwindef::FILETIME;
    use winapi::um::fileapi::{self, BY_HANDLE_FILE_INFORMATION};

    let handle = file.as_raw_handle();
    let zero_time = FILETIME {
        dwLowDateTime: 0,
        dwHighDateTime: 0,
    };
    let mut info = BY_HANDLE_FILE_INFORMATION {
        dwFileAttributes: 0,
        ftCreationTime: zero_time,
        ftLastAccessTime: zero_time,
        ftLastWriteTime: zero_time,
        dwVolumeSerialNumber: 0,
        nFileSizeHigh: 0,
        nFileSizeLow: 0,
        nNumberOfLinks: 0,
        nFileIndexHigh: 0,
        nFileIndexLow: 0,
    };

    let inode = if unsafe { fileapi::GetFileInformationByHandle(handle, &mut info) } != 0 {
        (info.nFileIndexHigh as u64) << 32 | info.nFileIndexLow as u64
    } else {
        return Err(io::Error::last_os_error());
    };
    let mtime = filetime_to_systemtime(info.ftLastWriteTime);
    let len = (info.nFileSizeHigh as u64) << 32 | info.nFileSizeLow as u64;

    let info = FileInfo { inode, len, mtime };
    Ok(info)
}
<commit_msg>clarify some platform specific handling<commit_after>use std::fs::File;
use std::io;
use std::time::SystemTime;

pub trait FileExt {
    fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize>;
}

impl FileExt for ::std::fs::File {
    #[cfg(unix)]
    fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> {
        use std::os::unix::fs::FileExt;

        FileExt::read_at(self, buf, offset)
    }

    #[cfg(windows)]
    fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> {
        use std::os::windows::fs::FileExt;

        // The difference between this and the Unix version is that `seek_read`
        // changes the file cursor position, while `read_at` doesn't.
        // We don't depend on the cursor, so that's all right.
        FileExt::seek_read(self, buf, offset)
    }
}

pub struct FileInfo {
    pub inode: u64,
    pub len: u64,
    pub mtime: SystemTime,
}

#[cfg(windows)]
/// Converts a Windows `FILETIME` to a Rust `SystemTime`
///
/// `FILETIME` is the number of 100 ns ticks since Jan 1 1601.
/// Unix time is the number of seconds since Jan 1 1970.
fn filetime_to_systemtime(time: ::winapi::shared::minwindef::FILETIME) -> SystemTime {
    use std::time::{Duration, UNIX_EPOCH};

    let ticks = (time.dwHighDateTime as u64) << 32 | time.dwLowDateTime as u64;

    // Number of seconds between the Windows and the Unix epoch
    const SECS_TO_UNIX_EPOCH: u64 = 11_644_473_600;
    let secs = ticks / 10_000_000 - SECS_TO_UNIX_EPOCH;
    let nanos = (ticks % 10_000_000 * 100) as u32;

    let duration = Duration::new(secs, nanos);
    UNIX_EPOCH + duration
}

#[cfg(unix)]
pub fn file_info(file: &File) -> io::Result<FileInfo> {
    use std::os::unix::fs::MetadataExt;

    let metadata = file.metadata()?;
    let info = FileInfo {
        inode: metadata.ino(),
        len: metadata.len(),
        mtime: metadata.modified()?,
    };

    Ok(info)
}

#[cfg(windows)]
pub fn file_info(file: &File) -> io::Result<FileInfo> {
    use std::os::windows::io::AsRawHandle;
    use winapi::shared::minwindef::FILETIME;
    use winapi::um::fileapi::{self, BY_HANDLE_FILE_INFORMATION};

    let handle = file.as_raw_handle();
    let zero_time = FILETIME {
        dwLowDateTime: 0,
        dwHighDateTime: 0,
    };
    let mut info = BY_HANDLE_FILE_INFORMATION {
        dwFileAttributes: 0,
        ftCreationTime: zero_time,
        ftLastAccessTime: zero_time,
        ftLastWriteTime: zero_time,
        dwVolumeSerialNumber: 0,
        nFileSizeHigh: 0,
        nFileSizeLow: 0,
        nNumberOfLinks: 0,
        nFileIndexHigh: 0,
        nFileIndexLow: 0,
    };

    let inode = if unsafe { fileapi::GetFileInformationByHandle(handle, &mut info) } != 0 {
        (info.nFileIndexHigh as u64) << 32 | info.nFileIndexLow as u64
    } else {
        return Err(io::Error::last_os_error());
    };
    let mtime = filetime_to_systemtime(info.ftLastWriteTime);
    let len = (info.nFileSizeHigh as u64) << 32 | info.nFileSizeLow as u64;

    let info = FileInfo { inode, len, mtime };
    Ok(info)
}
<|endoftext|>


<commit_before>use rand;
use rand::Rng;
use rand::distributions::{IndependentSample, Range};
use std::thread;
use std::sync::{Mutex, MutexGuard};
use std::collections::{BTreeMap, HashMap};
use self::state_machine::master::{MasterStateMachine, StateMachineCmds};
use std::cmp::min;
use std::cell::RefCell;
use bifrost_plugins::hash_str;
use utils::time::get_time;
use threadpool::ThreadPool;
use num_cpus;
use std::sync::mpsc::channel;
use std::cmp;

#[macro_use]
mod state_machine;

trait RaftMsg {
    fn encode(&self) -> (usize, Vec<u8>);
}

const CHECKER_MS: u64 = 50;

#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct LogEntry {
    id: u64,
    term: u64,
    sm_id: u64,
    fn_id: u64,
    data: Vec<u8>
}

type LogEntries = Vec<LogEntry>;

service! {
    rpc append_entries(term: u64, leaderId: u64, prev_log_id: u64, prev_log_term: u64, entries: Option<LogEntries>, leader_commit: u64) -> (u64, bool);
    rpc request_vote(term: u64, candidate_id: u64, last_log_id: u64, last_log_term: u64) -> ((u64, u64), bool); // term, voteGranted
    rpc install_snapshot(term: u64, leader_id: u64, last_included_index: u64, last_included_term: u64, data: Vec<u8>, done: bool) -> u64;
}

fn gen_rand(lower: u64, higher: u64) -> u64 {
    let between = Range::new(lower, higher);
    let mut rng = rand::thread_rng();
    between.ind_sample(&mut rng) + 1
}

fn gen_timeout() -> u64 {
    gen_rand(100, 500)
}

pub struct LeaderMeta {
    last_updated: u64,
    next_index: HashMap<u64, u64>,
    match_index: HashMap<u64, u64>,
}

impl LeaderMeta {
    fn new() -> LeaderMeta {
        LeaderMeta{
            last_updated: get_time(),
            next_index: HashMap::new(),
            match_index: HashMap::new(),
        }
    }
}

pub enum Membership {
    Leader(LeaderMeta),
    Follower,
    Candidate,
    Offline,
}

pub struct RaftMeta {
    term: u64,
    vote_for: Option<u64>,
    timeout: u64,
    last_checked: u64,
    membership: Membership,
    logs: BTreeMap<u64, LogEntry>,
    state_machine: RefCell<MasterStateMachine>,
    commit_index: u64,
    last_applied: u64,
    last_log_id: u64,
    last_log_term: u64,
    workers: ThreadPool,
    leader_id: u64,
}

#[derive(Clone)]
pub enum Storage {
    MEMORY,
    DISK(String),
}

impl Storage {
    pub fn Default() -> Storage {
        Storage::MEMORY
    }
}

#[derive(Clone)]
pub struct Options {
    pub storage: Storage,
    pub address: String,
}

pub struct RaftServer {
    meta: Arc<Mutex<RaftMeta>>,
    pub id: u64,
    pub options: Options,
}

enum CheckerAction {
    SendHeartbeat,
    BecomeCandidate,
    ExitLoop,
    None
}
enum RequestVoteResponse {
    Granted,
    TermOut(u64, u64),
    NotGranted,
}
impl RaftServer {
    pub fn new(opts: Options) -> Arc<RaftServer> {
        let server = Arc::new(RaftServer {
            meta: Arc::new(Mutex::new(
                RaftMeta {
                    term: 0, //TODO: read from persistent state
                    vote_for: None, //TODO: read from persistent state
                    timeout: gen_timeout(), // 10~500 ms for timeout
                    last_checked: get_time(),
                    membership: Membership::Follower,
                    logs: BTreeMap::new(), //TODO: read from persistent state
                    state_machine: RefCell::new(MasterStateMachine::new()),
                    commit_index: 0,
                    last_applied: 0,
                    last_log_id: 0,
                    last_log_term: 0,
                    workers: ThreadPool::new(num_cpus::get()),
                    leader_id: 0,
                }
            )),
            options: opts.clone(),
            id: hash_str(opts.address.clone()),
        });
        let svr_ref = server.clone();
        thread::spawn(move ||{
            listen(svr_ref, &opts.address);
        });
        let checker_ref = server.clone();
        thread::spawn(move ||{
            let server = checker_ref;
            loop {
                {
                    let mut meta = server.meta.lock().unwrap(); //WARNING: Reentering not supported
                    let action = match meta.membership {
                        Membership::Leader(ref leader_meta) => {
                            if get_time() > (leader_meta.last_updated + CHECKER_MS) {
                                CheckerAction::SendHeartbeat
                            } else {
                                CheckerAction::None
                            }
                        },
                        Membership::Follower | Membership::Candidate => {
                            if get_time() > (meta.timeout + meta.last_checked) {
                                //Timeout, require election
                                CheckerAction::BecomeCandidate
                            } else {
                                CheckerAction::None
                            }
                        },
                        Membership::Offline => {
                            CheckerAction::ExitLoop
                        }
                    };
                    match action {
                        CheckerAction::SendHeartbeat => {
                            server.send_heartbeat(&mut meta, None);
                        },
                        CheckerAction::BecomeCandidate => {
                            RaftServer::become_candidate(server.clone(), &mut meta);
                        },
                        CheckerAction::ExitLoop => {
                            break;
                        },
                        CheckerAction::None => {}
                    }
                }
                thread::sleep(Duration::from_millis(CHECKER_MS));
            }
        });
        server
    }
    fn switch_membership(&self, meta: &mut MutexGuard<RaftMeta>, membership: Membership) {
        self.reset_last_checked(meta);
        meta.membership = membership;
    }
    fn become_candidate(server: Arc<RaftServer>, meta: &mut MutexGuard<RaftMeta>) {
        server.reset_last_checked(meta);
        meta.term += 1;
        meta.vote_for = Some(server.id);
        server.switch_membership(meta, Membership::Candidate);
        let term = meta.term;
        let id = server.id;
        let last_log_id = meta.last_log_id;
        let last_log_term = meta.last_log_term;
        let (tx, rx) = channel();
        let mut members = 0;
        let timeout = meta.timeout;
        for member in meta.state_machine.borrow().configs.members.values() {
            let rpc = member.rpc.clone();
            let tx = tx.clone();
            members += 1;
            meta.workers.execute(move||{
                let mut rpc = rpc.lock().unwrap();
                if let Some(Ok(((remote_term, remote_leader_id), vote_granted))) = rpc.request_vote(term, id, last_log_id, last_log_term) {
                    if vote_granted {
                        tx.send(RequestVoteResponse::Granted);
                    } else if remote_term > term {
                        tx.send(RequestVoteResponse::TermOut(remote_term, remote_leader_id));
                    } else {
                        tx.send(RequestVoteResponse::NotGranted);
                    }
                }
            });
        }
        meta.workers.execute(move||{
            let mut granted = 0;
            for _ in 0..members {
                let received = rx.recv_timeout(Duration::from_millis(timeout));
                let mut meta = server.meta.lock().unwrap();
                if meta.term != term {break;}
                match received {
                    Ok(res) => {
                        match res {
                            RequestVoteResponse::TermOut(remote_term, remote_leader_id) => {
                                server.become_follower(&mut meta, remote_term, remote_leader_id);
                                return;
                            },
                            RequestVoteResponse::Granted => {
                                granted += 1;
                                if granted > (members / 2 + 1) {
                                    server.become_leader(&mut meta);
                                    break;
                                }
                            },
                            _ => {}
                        }
                    },
                    Err(_) => {}
                }
            }
        });
    }
    fn become_follower(&self, meta: &mut MutexGuard<RaftMeta>, term: u64, leader_id: u64) {
        meta.term = term;
        meta.leader_id = leader_id;
        self.switch_membership(meta, Membership::Follower);
    }
    fn become_leader(&self, meta: &mut MutexGuard<RaftMeta>) {
        self.switch_membership(meta, Membership::Leader(LeaderMeta::new()));
    }
    fn send_heartbeat(&self, meta: &mut MutexGuard<RaftMeta>, entries: Option<LogEntries>) {

    }

    //check term number, return reject = false if server term is stale
    fn check_term(&self, meta: &mut MutexGuard<RaftMeta>, remote_term: u64, leader_id: u64) -> bool {
        if remote_term > meta.term {
            meta.term = remote_term;
            meta.vote_for = None;
            self.become_follower(meta, remote_term, leader_id)
        } else if remote_term < meta.term {
            return false;
        }
        return true;
    }

    fn check_commit(&self, meta: &mut MutexGuard<RaftMeta>) { //not need to return result for follower
        while meta.commit_index > meta.last_applied {
            (*meta).last_applied += 1;
            let last_applied = meta.last_applied;
            if let Some(entry) = meta.logs.get(&last_applied) {
                meta.state_machine.borrow_mut().commit(&entry);
            };
        }
    }
    fn reset_last_checked(&self, meta: &mut MutexGuard<RaftMeta>) {
        meta.last_checked = get_time();
        meta.timeout = gen_timeout();
    }
}

impl Server for RaftServer {
    fn append_entries(
        &self,
        term: u64, leader_id: u64, prev_log_id: u64,
        prev_log_term: u64, entries: Option<LogEntries>,
        leader_commit: u64
    ) -> Result<(u64, bool), ()>  {
        let mut meta = self.meta.lock().unwrap();
        let term_ok = self.check_term(&mut meta, term, leader_id); // RI, 1
        self.reset_last_checked(&mut meta);
        if term_ok {
            if let Membership::Candidate = meta.membership {
                self.become_follower(&mut meta, term, leader_id);
            }
            self.check_commit(&mut meta);
            { //RI, 2
                let contains_prev_log = (*meta).logs.contains_key(&prev_log_id);
                let mut log_mismatch = false;
                if contains_prev_log {
                    let entry = (*meta).logs.get(&prev_log_id).unwrap();
                    log_mismatch = entry.term != prev_log_term;
                } else {
                    return Ok((meta.term, false))
                }
                if log_mismatch { //RI, 3
                    let keys: Vec<u64> = (*meta).logs.keys().cloned().collect();
                    for id in keys {
                        if id >= prev_log_id {
                            (*meta).logs.remove(&id);
                        }
                    }
                    return Ok((meta.term, false))
                }
            }
            if let Some(entries) = entries { // entry not empty
                let entries_len = entries.len();
                for entry in entries {
                    meta.logs.entry(entry.id).or_insert(entry);// RI, 4
                }
                if leader_commit > meta.commit_index { //RI, 5
                    meta.commit_index = min(leader_commit, prev_log_id + entries_len as u64);
                }
            }
            Ok((meta.term, true))
        } else {
            Ok((meta.term, false))
        }
    }

    fn request_vote(
        &self,
        term: u64, candidate_id: u64,
        last_log_id: u64, last_log_term: u64
    ) -> Result<((u64, u64), bool), ()> {
        let mut meta = self.meta.lock().unwrap();
        let vote_for = meta.vote_for;
        let mut vote_granted = false;
        if term >= meta.term {
            self.check_commit(&mut meta);
            if vote_for.is_none() || vote_for.unwrap() == candidate_id {
                if !meta.logs.is_empty() {
                    let (last_id, _) = meta.logs.iter().next_back().unwrap();
                    let last_term = meta.logs.get(last_id).unwrap().term;
                    if last_log_id >= *last_id && last_log_term >= last_term {
                        vote_granted = true;
                    }
                } else {
                    vote_granted = true;
                }
            }
        }
        if vote_granted {
            meta.vote_for = Some(candidate_id);
        }
        Ok(((meta.term, meta.leader_id), vote_granted))
    }

    fn install_snapshot(
        &self,
        term: u64, leader_id: u64, last_included_index: u64,
        last_included_term: u64, data: Vec<u8>, done: bool
    ) -> Result<u64, ()> {
        let mut meta = self.meta.lock().unwrap();
        let term_ok = self.check_term(&mut meta, term, leader_id);
        if term_ok {
            self.check_commit(&mut meta);
        }
        Ok(meta.term)
    }
}
<commit_msg>remove last_log_id and last_log_item in RaftServer<commit_after>use rand;
use rand::Rng;
use rand::distributions::{IndependentSample, Range};
use std::thread;
use std::sync::{Mutex, MutexGuard};
use std::collections::{BTreeMap, HashMap};
use self::state_machine::master::{MasterStateMachine, StateMachineCmds};
use std::cmp::min;
use std::cell::RefCell;
use bifrost_plugins::hash_str;
use utils::time::get_time;
use threadpool::ThreadPool;
use num_cpus;
use std::sync::mpsc::channel;
use std::cmp;

#[macro_use]
mod state_machine;

trait RaftMsg {
    fn encode(&self) -> (usize, Vec<u8>);
}

const CHECKER_MS: u64 = 50;

#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct LogEntry {
    id: u64,
    term: u64,
    sm_id: u64,
    fn_id: u64,
    data: Vec<u8>
}

#[derive(Serialize, Deserialize, Debug, Clone)]
pub enum ClientCmdResponse {
    Success(Vec<u8>),
    NotLeader(u64)
}

type LogEntries = Vec<LogEntry>;

service! {
    rpc append_entries(term: u64, leaderId: u64, prev_log_id: u64, prev_log_term: u64, entries: Option<LogEntries>, leader_commit: u64) -> (u64, bool);
    rpc request_vote(term: u64, candidate_id: u64, last_log_id: u64, last_log_term: u64) -> ((u64, u64), bool); // term, voteGranted
    rpc install_snapshot(term: u64, leader_id: u64, last_included_index: u64, last_included_term: u64, data: Vec<u8>, done: bool) -> u64;
    rpc client_commands(entries: LogEntries) -> ClientCmdResponse;
}

fn gen_rand(lower: u64, higher: u64) -> u64 {
    let between = Range::new(lower, higher);
    let mut rng = rand::thread_rng();
    between.ind_sample(&mut rng) + 1
}

fn gen_timeout() -> u64 {
    gen_rand(100, 500)
}

pub struct LeaderMeta {
    last_updated: u64,
    next_index: HashMap<u64, u64>,
    match_index: HashMap<u64, u64>,
}

impl LeaderMeta {
    fn new() -> LeaderMeta {
        LeaderMeta{
            last_updated: get_time(),
            next_index: HashMap::new(),
            match_index: HashMap::new(),
        }
    }
}

pub enum Membership {
    Leader(LeaderMeta),
    Follower,
    Candidate,
    Offline,
}

pub struct RaftMeta {
    term: u64,
    vote_for: Option<u64>,
    timeout: u64,
    last_checked: u64,
    membership: Membership,
    logs: BTreeMap<u64, LogEntry>,
    state_machine: RefCell<MasterStateMachine>,
    commit_index: u64,
    last_applied: u64,
    workers: ThreadPool,
    leader_id: u64,
}

#[derive(Clone)]
pub enum Storage {
    MEMORY,
    DISK(String),
}

impl Storage {
    pub fn Default() -> Storage {
        Storage::MEMORY
    }
}

#[derive(Clone)]
pub struct Options {
    pub storage: Storage,
    pub address: String,
}

pub struct RaftServer {
    meta: Arc<Mutex<RaftMeta>>,
    pub id: u64,
    pub options: Options,
}

enum CheckerAction {
    SendHeartbeat,
    BecomeCandidate,
    ExitLoop,
    None
}
enum RequestVoteResponse {
    Granted,
    TermOut(u64, u64),
    NotGranted,
}
impl RaftServer {
    pub fn new(opts: Options) -> Arc<RaftServer> {
        let server = Arc::new(RaftServer {
            meta: Arc::new(Mutex::new(
                RaftMeta {
                    term: 0, //TODO: read from persistent state
                    vote_for: None, //TODO: read from persistent state
                    timeout: gen_timeout(), // 10~500 ms for timeout
                    last_checked: get_time(),
                    membership: Membership::Follower,
                    logs: BTreeMap::new(), //TODO: read from persistent state
                    state_machine: RefCell::new(MasterStateMachine::new()),
                    commit_index: 0,
                    last_applied: 0,
                    workers: ThreadPool::new(num_cpus::get()),
                    leader_id: 0,
                }
            )),
            options: opts.clone(),
            id: hash_str(opts.address.clone()),
        });
        let svr_ref = server.clone();
        thread::spawn(move ||{
            listen(svr_ref, &opts.address);
        });
        let checker_ref = server.clone();
        thread::spawn(move ||{
            let server = checker_ref;
            loop {
                {
                    let mut meta = server.meta.lock().unwrap(); //WARNING: Reentering not supported
                    let action = match meta.membership {
                        Membership::Leader(ref leader_meta) => {
                            if get_time() > (leader_meta.last_updated + CHECKER_MS) {
                                CheckerAction::SendHeartbeat
                            } else {
                                CheckerAction::None
                            }
                        },
                        Membership::Follower | Membership::Candidate => {
                            if get_time() > (meta.timeout + meta.last_checked) && meta.vote_for == None {
                                //Timeout, require election
                                CheckerAction::BecomeCandidate
                            } else {
                                CheckerAction::None
                            }
                        },
                        Membership::Offline => {
                            CheckerAction::ExitLoop
                        }
                    };
                    match action {
                        CheckerAction::SendHeartbeat => {
                            server.send_heartbeat(&mut meta, None);
                        },
                        CheckerAction::BecomeCandidate => {
                            RaftServer::become_candidate(server.clone(), &mut meta);
                        },
                        CheckerAction::ExitLoop => {
                            break;
                        },
                        CheckerAction::None => {}
                    }
                }
                thread::sleep(Duration::from_millis(CHECKER_MS));
            }
        });
        server
    }
    fn switch_membership(&self, meta: &mut MutexGuard<RaftMeta>, membership: Membership) {
        self.reset_last_checked(meta);
        meta.membership = membership;
    }
    fn get_last_log_info(&self, meta: &mut MutexGuard<RaftMeta>) -> (u64, u64) {
        let last_log = meta.logs.iter().next_back();
        match last_log {
            Some((last_log_id, last_log_item)) => {
                (*last_log_id, last_log_item.term)
            },
            None => (0, 0)
        }
    }
    fn become_candidate(server: Arc<RaftServer>, meta: &mut MutexGuard<RaftMeta>) {
        server.reset_last_checked(meta);
        meta.term += 1;
        meta.vote_for = Some(server.id);
        server.switch_membership(meta, Membership::Candidate);
        let term = meta.term;
        let id = server.id;
        let (last_log_id, last_log_term) = server.get_last_log_info(meta);
        let (tx, rx) = channel();
        let mut members = 0;
        let timeout = meta.timeout;
        for member in meta.state_machine.borrow().configs.members.values() {
            let rpc = member.rpc.clone();
            let tx = tx.clone();
            members += 1;
            meta.workers.execute(move||{
                let mut rpc = rpc.lock().unwrap();
                if let Some(Ok(((remote_term, remote_leader_id), vote_granted))) = rpc.request_vote(term, id, last_log_id, last_log_term) {
                    if vote_granted {
                        tx.send(RequestVoteResponse::Granted);
                    } else if remote_term > term {
                        tx.send(RequestVoteResponse::TermOut(remote_term, remote_leader_id));
                    } else {
                        tx.send(RequestVoteResponse::NotGranted);
                    }
                }
            });
        }
        meta.workers.execute(move||{
            let mut granted = 0;
            for _ in 0..members {
                let received = rx.recv_timeout(Duration::from_millis(timeout));
                let mut meta = server.meta.lock().unwrap();
                if meta.term != term {break;}
                match received {
                    Ok(res) => {
                        match res {
                            RequestVoteResponse::TermOut(remote_term, remote_leader_id) => {
                                server.become_follower(&mut meta, remote_term, remote_leader_id);
                                return;
                            },
                            RequestVoteResponse::Granted => {
                                granted += 1;
                                if granted > (members / 2 + 1) {
                                    server.become_leader(&mut meta);
                                    break;
                                }
                            },
                            _ => {}
                        }
                    },
                    Err(_) => {}
                }
            }
        });
    }
    fn become_follower(&self, meta: &mut MutexGuard<RaftMeta>, term: u64, leader_id: u64) {
        meta.term = term;
        meta.leader_id = leader_id;
        self.switch_membership(meta, Membership::Follower);
    }
    fn become_leader(&self, meta: &mut MutexGuard<RaftMeta>) {
        self.switch_membership(meta, Membership::Leader(LeaderMeta::new()));
    }
    fn send_heartbeat(&self, meta: &mut MutexGuard<RaftMeta>, entries: Option<LogEntries>) {

    }

    //check term number, return reject = false if server term is stale
    fn check_term(&self, meta: &mut MutexGuard<RaftMeta>, remote_term: u64, leader_id: u64) -> bool {
        if remote_term > meta.term {
            meta.term = remote_term;
            meta.vote_for = None;
            self.become_follower(meta, remote_term, leader_id)
        } else if remote_term < meta.term {
            return false;
        }
        return true;
    }

    fn check_commit(&self, meta: &mut MutexGuard<RaftMeta>) { //not need to return result for follower
        while meta.commit_index > meta.last_applied {
            (*meta).last_applied += 1;
            let last_applied = meta.last_applied;
            if let Some(entry) = meta.logs.get(&last_applied) {
                meta.state_machine.borrow_mut().commit(&entry);
            };
        }
    }
    fn reset_last_checked(&self, meta: &mut MutexGuard<RaftMeta>) {
        meta.last_checked = get_time();
        meta.timeout = gen_timeout();
    }
}

impl Server for RaftServer {
    fn append_entries(
        &self,
        term: u64, leader_id: u64, prev_log_id: u64,
        prev_log_term: u64, entries: Option<LogEntries>,
        leader_commit: u64
    ) -> Result<(u64, bool), ()>  {
        let mut meta = self.meta.lock().unwrap();
        let term_ok = self.check_term(&mut meta, term, leader_id); // RI, 1
        self.reset_last_checked(&mut meta);
        if term_ok {
            if let Membership::Candidate = meta.membership {
                self.become_follower(&mut meta, term, leader_id);
            }
            self.check_commit(&mut meta);
            { //RI, 2
                let contains_prev_log = (*meta).logs.contains_key(&prev_log_id);
                let mut log_mismatch = false;
                if contains_prev_log {
                    let entry = (*meta).logs.get(&prev_log_id).unwrap();
                    log_mismatch = entry.term != prev_log_term;
                } else {
                    return Ok((meta.term, false))
                }
                if log_mismatch { //RI, 3
                    let keys: Vec<u64> = (*meta).logs.keys().cloned().collect();
                    for id in keys {
                        if id >= prev_log_id {
                            (*meta).logs.remove(&id);
                        }
                    }
                    return Ok((meta.term, false))
                }
            }
            if let Some(entries) = entries { // entry not empty
                let entries_len = entries.len();
                for entry in entries {
                    meta.logs.entry(entry.id).or_insert(entry);// RI, 4
                }
                if leader_commit > meta.commit_index { //RI, 5
                    meta.commit_index = min(leader_commit, prev_log_id + entries_len as u64);
                }
            }
            Ok((meta.term, true))
        } else {
            Ok((meta.term, false))
        }
    }

    fn request_vote(
        &self,
        term: u64, candidate_id: u64,
        last_log_id: u64, last_log_term: u64
    ) -> Result<((u64, u64), bool), ()> {
        let mut meta = self.meta.lock().unwrap();
        let vote_for = meta.vote_for;
        let mut vote_granted = false;
        if term >= meta.term {
            self.check_commit(&mut meta);
            if vote_for.is_none() || vote_for.unwrap() == candidate_id {
                if !meta.logs.is_empty() {
                    let (last_id, _) = meta.logs.iter().next_back().unwrap();
                    let last_term = meta.logs.get(last_id).unwrap().term;
                    if last_log_id >= *last_id && last_log_term >= last_term {
                        vote_granted = true;
                    }
                } else {
                    vote_granted = true;
                }
            }
        }
        if vote_granted {
            meta.vote_for = Some(candidate_id);
        }
        Ok(((meta.term, meta.leader_id), vote_granted))
    }

    fn install_snapshot(
        &self,
        term: u64, leader_id: u64, last_included_index: u64,
        last_included_term: u64, data: Vec<u8>, done: bool
    ) -> Result<u64, ()> {
        let mut meta = self.meta.lock().unwrap();
        let term_ok = self.check_term(&mut meta, term, leader_id);
        if term_ok {
            self.check_commit(&mut meta);
        }
        Ok(meta.term)
    }

    fn client_commands(&self, entries: LogEntries) -> Result<ClientCmdResponse, ()> {
        Err(())
    }
}
<|endoftext|>


<commit_before>// FIXME: add the support of transient objects

use any_cache::{self, Cache, HashCache};
use notify::{self, RecommendedWatcher, Watcher};
use std::any::Any;
use std::cell::RefCell;
use std::collections::HashMap;
use std::ops::{Deref, DerefMut};
use std::path::{Path, PathBuf};
use std::rc::Rc;
use std::sync::{Arc, Mutex};
use std::sync::mpsc::{Receiver, Sender, channel};
use std::thread;
use time::precise_time_s;

use model::Model;
use object::Object;
use shader::Program;
use spline::Spline;
use texture::TextureImage;

/// Class of types that can be loaded.
pub trait Load: Sized {
  /// Arguments passed at loading.
  type Args: Clone;

  /// Static string representing the name of the type (used in filesystem caching).
  const TY_STR: &'static str;

  fn load<P>(path: P, cache: &mut ResCache, args: Self::Args) -> Result<Self> where P: AsRef<Path>;
}

/// Class of types that can be reloaded.
///
/// The idea is to simply recover the arguments used in `Load::load`.
pub trait Reload: Load {
  fn reload_args(&self) -> Self::Args;
}

/// Default implementation for types which are loaded without any arguments.
impl<T> Reload for T where T: Load<Args=()> {
  fn reload_args(&self) -> Self::Args {
    ()
  }
}

#[derive(Clone, Debug, Eq, PartialEq)]
pub enum LoadError {
  FileNotFound(PathBuf, String),
  ParseFailed(String),
  ConversionFailed(String)
}

pub type Result<T> = ::std::result::Result<T, LoadError>;

/// Resources are wrapped in this type.
#[derive(Debug)]
pub struct Res<T>(Rc<RefCell<T>>);

impl<T> Clone for Res<T> {
  fn clone(&self) -> Self {
    Res(self.0.clone())
  }
}

impl<T> Deref for Res<T> {
  type Target = RefCell<T>;

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

type Timestamp = f64;

/// Time to await after a resource update to establish that it should be reloaded.
const UPDATE_AWAIT_TIME: Timestamp = 1.; // 1s

/// Resource cache. Responsible for caching resource.
pub struct ResCache {
  // contains all the typed-erased Rc<RefCell<T>>
  cache: HashCache<PathBuf>,
  // contains all metadata on resources
  metadata: HashMap<PathBuf, ResMetaData>,
  // vector of pair (path, timestamp) giving indication on resources to reload
  dirty: Arc<Mutex<Vec<(PathBuf, Timestamp)>>>,
  watcher_thread: thread::JoinHandle<()>
}

struct ResMetaData {
  on_reload: Box<Fn(&mut ResCache)>,
  last_update_timestamp: Timestamp // timestamp of the last update
}

impl ResCache {
  /// Create a new cache.
  pub fn new<P>(root: P) -> Self where P: AsRef<Path> {
    let dirty: Arc<Mutex<Vec<(PathBuf, Timestamp)>>> = Arc::new(Mutex::new(Vec::new()));
    let dirty_ = dirty.clone();

    let root = root.as_ref().to_owned();
    let (wsx, wrx) = channel();
    let mut watcher: RecommendedWatcher = Watcher::new(wsx).unwrap();

    let join_handle = thread::spawn(move || {
      let _ = watcher.watch(root);

      for event in wrx.iter() {
        if let notify::Event { path: Some(path), op: Ok(notify::op::WRITE) } = event {
          dirty_.lock().unwrap().push((path.clone(), precise_time_s()));
        }
      }
    });

    ResCache {
      cache: HashCache::new(),
      metadata: HashMap::new(),
      dirty: dirty,
      watcher_thread: join_handle
    }
  }

  /// Get a resource from the cache.
  pub fn get<T>(&mut self, key: &str, args: T::Args) -> Option<Res<T>> where T: 'static + Any + Reload {
    let path_str = format!("data/{}/{}", T::TY_STR, key);
    let path = Path::new(&path_str);
    let path_buf = path.to_owned();

    match self.cache.get::<Res<T>>(&path_buf).cloned() {
      r@Some(..) => {
        deb!("cache hit for {} ({})", key, path_str);
        r
      },
      None => {
        deb!("cache miss for {} ({})", key, path_str);

        // specific loading
        if path.exists() {
          match T::load(&path, self, args.clone()) {
            Ok(resource) => {
              let res = Res(Rc::new(RefCell::new(resource)));
              let res_ = res.clone();

              let path_buf_ = path_buf.clone();
              // closure used to reload the object when needed
              let on_reload: Box<for<'a> Fn(&'a mut ResCache)> = Box::new(move |cache_| {
                match T::load(&path_buf_, cache_, args.clone()) {
                  Ok(new_resource) => {
                    // replace the current resource with the freshly loaded one
                    *res_.borrow_mut() = new_resource;
                    deb!("reloaded resource from {:?}", path_buf_);
                  },
                  Err(e) => {
                    warn!("reloading resource from {:?} has failed:\n{:#?}", path_buf_, e);
                  }
                }
              });

              let metadata = ResMetaData {
                on_reload: on_reload,
                last_update_timestamp: precise_time_s()
              };

              // cache the resource and its meta data
              self.cache.save(path_buf.clone(), res.clone());
              self.metadata.insert(path_buf, metadata);

              Some(res)
            },
            Err(e) => {
              err!("unable to load resource from {}:\n{:#?}", path_str, e);
              None
            }
          }
        } else { // path doesn’t exist
          err!("resource at {} cannot be found", path_str);
          None
        }
      }
    }
  }

  // TODO: maybe we should have a ResCache::update() instead of get() + save()?
  ///// Synchronize the cache by updating the resource that ought to.
  //pub fn sync(&mut self) {
  //  let mut dirty = self.dirty.lock().unwrap();

  //  for &(ref path, ref timestamp) in dirty.iter() {
  //    let mut cache_entry = self.cache.get::<ResCacheEntry>(&path).cloned().unwrap();

  //    if timestamp - cache_entry.last_update_timestamp >= UPDATE_AWAIT_TIME {
  //      cache_entry.on_reload();
  //    }

  //    cache_entry.last_update_timestamp = timestamp;
  //    self.cache.save(path.clone(), cache_entry);
  //  }

  //  dirty.clear();
  //}
}
<commit_msg>Implemented ResCache::sync correctly.<commit_after>// FIXME: add the support of transient objects

use any_cache::{self, Cache, HashCache};
use notify::{self, RecommendedWatcher, Watcher};
use std::any::Any;
use std::cell::RefCell;
use std::collections::HashMap;
use std::ops::{Deref, DerefMut};
use std::path::{Path, PathBuf};
use std::rc::Rc;
use std::sync::{Arc, Mutex};
use std::sync::mpsc::{Receiver, Sender, channel};
use std::thread;
use time::precise_time_s;

use model::Model;
use object::Object;
use shader::Program;
use spline::Spline;
use texture::TextureImage;

/// Class of types that can be loaded.
pub trait Load: Sized {
  /// Arguments passed at loading.
  type Args: Clone;

  /// Static string representing the name of the type (used in filesystem caching).
  const TY_STR: &'static str;

  fn load<P>(path: P, cache: &mut ResCache, args: Self::Args) -> Result<Self> where P: AsRef<Path>;
}

/// Class of types that can be reloaded.
///
/// The idea is to simply recover the arguments used in `Load::load`.
pub trait Reload: Load {
  fn reload_args(&self) -> Self::Args;
}

/// Default implementation for types which are loaded without any arguments.
impl<T> Reload for T where T: Load<Args=()> {
  fn reload_args(&self) -> Self::Args {
    ()
  }
}

#[derive(Clone, Debug, Eq, PartialEq)]
pub enum LoadError {
  FileNotFound(PathBuf, String),
  ParseFailed(String),
  ConversionFailed(String)
}

pub type Result<T> = ::std::result::Result<T, LoadError>;

/// Resources are wrapped in this type.
#[derive(Debug)]
pub struct Res<T>(Rc<RefCell<T>>);

impl<T> Clone for Res<T> {
  fn clone(&self) -> Self {
    Res(self.0.clone())
  }
}

impl<T> Deref for Res<T> {
  type Target = RefCell<T>;

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

type Timestamp = f64;

/// Time to await after a resource update to establish that it should be reloaded.
const UPDATE_AWAIT_TIME: Timestamp = 1.; // 1s

/// Resource cache. Responsible for caching resource.
pub struct ResCache {
  // contains all the typed-erased Rc<RefCell<T>>
  cache: HashCache<PathBuf>,
  // contains all metadata on resources
  metadata: HashMap<PathBuf, ResMetaData>,
  // vector of pair (path, timestamp) giving indication on resources to reload
  dirty: Arc<Mutex<Vec<(PathBuf, Timestamp)>>>,
  #[allow(dead_code)]
  watcher_thread: thread::JoinHandle<()>
}

struct ResMetaData {
  on_reload: Box<Fn(&mut ResCache)>,
  last_update_timestamp: Timestamp // timestamp of the last update
}

impl ResCache {
  /// Create a new cache.
  pub fn new<P>(root: P) -> Self where P: AsRef<Path> {
    let dirty: Arc<Mutex<Vec<(PathBuf, Timestamp)>>> = Arc::new(Mutex::new(Vec::new()));
    let dirty_ = dirty.clone();

    let root = root.as_ref().to_owned();
    let (wsx, wrx) = channel();
    let mut watcher: RecommendedWatcher = Watcher::new(wsx).unwrap();

    let join_handle = thread::spawn(move || {
      let _ = watcher.watch(root);

      for event in wrx.iter() {
        if let notify::Event { path: Some(path), op: Ok(notify::op::WRITE) } = event {
          dirty_.lock().unwrap().push((path.clone(), precise_time_s()));
        }
      }
    });

    ResCache {
      cache: HashCache::new(),
      metadata: HashMap::new(),
      dirty: dirty,
      watcher_thread: join_handle
    }
  }

  /// Get a resource from the cache.
  pub fn get<T>(&mut self, key: &str, args: T::Args) -> Option<Res<T>> where T: 'static + Any + Reload {
    let path_str = format!("data/{}/{}", T::TY_STR, key);
    let path = Path::new(&path_str);
    let path_buf = path.to_owned();

    match self.cache.get::<Res<T>>(&path_buf).cloned() {
      r@Some(..) => {
        deb!("cache hit for {} ({})", key, path_str);
        r
      },
      None => {
        deb!("cache miss for {} ({})", key, path_str);

        // specific loading
        if path.exists() {
          match T::load(&path, self, args.clone()) {
            Ok(resource) => {
              let res = Res(Rc::new(RefCell::new(resource)));
              let res_ = res.clone();

              let path_buf_ = path_buf.clone();
              // closure used to reload the object when needed
              let on_reload: Box<for<'a> Fn(&'a mut ResCache)> = Box::new(move |cache_| {
                match T::load(&path_buf_, cache_, args.clone()) {
                  Ok(new_resource) => {
                    // replace the current resource with the freshly loaded one
                    *res_.borrow_mut() = new_resource;
                    deb!("reloaded resource from {:?}", path_buf_);
                  },
                  Err(e) => {
                    warn!("reloading resource from {:?} has failed:\n{:#?}", path_buf_, e);
                  }
                }
              });

              let metadata = ResMetaData {
                on_reload: on_reload,
                last_update_timestamp: precise_time_s()
              };

              // cache the resource and its meta data
              self.cache.save(path_buf.clone(), res.clone());
              self.metadata.insert(path_buf, metadata);

              Some(res)
            },
            Err(e) => {
              err!("unable to load resource from {}:\n{:#?}", path_str, e);
              None
            }
          }
        } else { // path doesn’t exist
          err!("resource at {} cannot be found", path_str);
          None
        }
      }
    }
  }

  /// Synchronize the cache by updating the resource that ought to.
  pub fn sync(&mut self) {
    let dirty = self.dirty.clone();
    let mut dirty_ = dirty.lock().unwrap();

    for &(ref path, ref timestamp) in dirty_.iter() {
      let mut metadata = self.metadata.remove(path).unwrap();

      if timestamp - metadata.last_update_timestamp >= UPDATE_AWAIT_TIME {
        (metadata.on_reload)(self);
      }

      metadata.last_update_timestamp = *timestamp;
      self.metadata.insert(path.clone(), metadata);
    }

    dirty_.clear();
  }
}
<|endoftext|>


<commit_before>// FIXME: add the support of transient objects

use any_cache::{Cache, HashCache};
use notify::{self, RecommendedWatcher, Watcher};
use std::any::Any;
use std::cell::RefCell;
use std::collections::HashMap;
use std::ops::Deref;
use std::path::{Path, PathBuf};
use std::rc::Rc;
use std::sync::{Arc, Mutex};
use std::sync::mpsc::channel;
use std::thread;
use std::time::{Duration, Instant};

/// Class of types that can be loaded.
pub trait Load: Sized {
  /// Arguments passed at loading.
  type Args: Clone;

  /// Static string representing the name of the type (used in filesystem caching).
  const TY_STR: &'static str;

  fn load<P>(path: P, cache: &mut ResCache, args: Self::Args) -> Result<Self> where P: AsRef<Path>;
}

/// Class of types that can be reloaded.
///
/// The idea is to simply recover the arguments used in `Load::load`.
pub trait Reload: Load {
  fn reload_args(&self) -> Self::Args;
}

/// Default implementation for types which are loaded without any arguments.
impl<T> Reload for T where T: Load<Args=()> {
  fn reload_args(&self) -> Self::Args {
    ()
  }
}

#[derive(Clone, Debug, Eq, PartialEq)]
pub enum LoadError {
  FileNotFound(PathBuf, String),
  ParseFailed(String),
  ConversionFailed(String)
}

pub type Result<T> = ::std::result::Result<T, LoadError>;

/// Resources are wrapped in this type.
#[derive(Debug)]
pub struct Res<T>(Rc<RefCell<T>>);

impl<T> Res<T> {
  pub fn new(resource: T) -> Self {
    Res(Rc::new(RefCell::new(resource)))
  }

  pub fn as_rc(&self) -> &Rc<RefCell<T>> {
    &self.0
  }
}

impl<T> Clone for Res<T> {
  fn clone(&self) -> Self {
    Res(self.0.clone())
  }
}

impl<T> Deref for Res<T> {
  type Target = RefCell<T>;

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

impl<T> From<Rc<RefCell<T>>> for Res<T> {
  fn from(rc: Rc<RefCell<T>>) -> Self {
    Res(rc)
  }
}

/// Time to await after a resource update to establish that it should be reloaded.
const UPDATE_AWAIT_TIME_MS: u64 = 1000;

/// Resource cache. Responsible for caching resource.
pub struct ResCache {
  // contains all the typed-erased Rc<RefCell<T>>
  cache: HashCache<PathBuf>,
  // contains all metadata on resources
  metadata: HashMap<PathBuf, ResMetaData>,
  // vector of pair (path, timestamp) giving indication on resources to reload
  dirty: Arc<Mutex<Vec<(PathBuf, Instant)>>>,
  #[allow(dead_code)]
  watcher_thread: thread::JoinHandle<()>
}

struct ResMetaData {
  on_reload: Box<Fn(&mut ResCache)>,
  last_update_instant: Instant
}

impl ResCache {
  /// Create a new cache.
  pub fn new<P>(root: P) -> Self where P: AsRef<Path> {
    let dirty: Arc<Mutex<Vec<(PathBuf, Instant)>>> = Arc::new(Mutex::new(Vec::new()));
    let dirty_ = dirty.clone();

    let root = root.as_ref().to_owned();
    let (wsx, wrx) = channel();
    let mut watcher: RecommendedWatcher = Watcher::new(wsx).unwrap();

    let join_handle = thread::spawn(move || {
      let _ = watcher.watch(root);

      for event in wrx.iter() {
        if let notify::Event { path: Some(path), op: Ok(notify::op::WRITE) } = event {
          dirty_.lock().unwrap().push((path.clone(), Instant::now()));
        }
      }
    });

    ResCache {
      cache: HashCache::new(),
      metadata: HashMap::new(),
      dirty: dirty,
      watcher_thread: join_handle
    }
  }

  /// Inject a new resource in the cache.
  fn inject<P, T>(&mut self, path: P, resource: T, args: T::Args) -> Res<T> where P: AsRef<Path>, T: 'static + Any + Reload {
    let res = Res(Rc::new(RefCell::new(resource)));
    let res_ = res.clone();

    let path = path.as_ref();
    let path_buf = path.to_owned();
    let path_buf_ = path_buf.clone();

    // closure used to reload the object when needed
    let on_reload: Box<for<'a> Fn(&'a mut ResCache)> = Box::new(move |cache_| {
      match T::load(&path_buf_, cache_, args.clone()) {
        Ok(new_resource) => {
          // replace the current resource with the freshly loaded one
          *res_.borrow_mut() = new_resource;
          deb!("reloaded resource from {:?}", path_buf_);
        },
        Err(e) => {
          warn!("reloading resource from {:?} has failed:\n{:#?}", path_buf_, e);
        }
      }
    });

    let metadata = ResMetaData {
      on_reload: on_reload,
      last_update_instant: Instant::now()
    };

    // cache the resource and its meta data
    self.cache.save(path_buf.clone(), res.clone());
    self.metadata.insert(path_buf, metadata);

    res
  }

  /// Get a resource from the cache.
  pub fn get<T>(&mut self, key: &str, args: T::Args) -> Option<Res<T>> where T: 'static + Any + Reload {
    let path_str = format!("data/{}/{}", T::TY_STR, key);
    let path = Path::new(&path_str);
    let path_buf = path.to_owned();

    match self.cache.get::<Res<T>>(&path_buf).cloned() {
      r@Some(..) => {
        deb!("cache hit for {} ({})", key, path_str);
        r
      },
      None => {
        deb!("cache miss for {} ({})", key, path_str);

        // specific loading
        if path.exists() {
          match T::load(&path, self, args.clone()) {
            Ok(resource) => {
              let res = Res(Rc::new(RefCell::new(resource)));
              let res_ = res.clone();

              let path_buf_ = path_buf.clone();
              // closure used to reload the object when needed
              let on_reload: Box<for<'a> Fn(&'a mut ResCache)> = Box::new(move |cache_| {
                match T::load(&path_buf_, cache_, args.clone()) {
                  Ok(new_resource) => {
                    // replace the current resource with the freshly loaded one
                    *res_.borrow_mut() = new_resource;
                    deb!("reloaded resource from {:?}", path_buf_);
                  },
                  Err(e) => {
                    warn!("reloading resource from {:?} has failed:\n{:#?}", path_buf_, e);
                  }
                }
              });

              let metadata = ResMetaData {
                on_reload: on_reload,
                last_update_instant: Instant::now()
              };

              // cache the resource and its meta data
              self.cache.save(path_buf.clone(), res.clone());
              self.metadata.insert(path_buf, metadata);

              Some(res)
            },
            Err(e) => {
              err!("unable to load resource from {}:\n{:#?}", path_str, e);
              None
            }
          }
        } else { // path doesn’t exist
          err!("resource at {} cannot be found", path_str);
          None
        }
      }
    }
  }

//   /// Get a resource from the cache. If it fails, a proxy version of it is used, which will get
//   /// replaced by the resource once it’s avaible.
//   pub fn get_proxied<T, P>(&mut self, key: &str, args: T::Args, proxy: P) -> Option<Res<T>>
//       where T: 'static + Any + Reload,
//             P: FnOnce() -> T {
//     // riterite
//     self.get::<T>().unwrap_or_else(|| {
//       deb!("proxying resource {}", key);
//
//
//     })
//   }

  /// Synchronize the cache by updating the resource that ought to.
  pub fn sync(&mut self) {
    let dirty = self.dirty.clone();
    let mut dirty_ = dirty.lock().unwrap();

    for &(ref path, ref instant) in dirty_.iter() {
      let mut metadata = self.metadata.remove(path).unwrap();

      if instant.duration_since(metadata.last_update_instant) >= Duration::from_millis(UPDATE_AWAIT_TIME_MS) {
        (metadata.on_reload)(self);
      }

      metadata.last_update_instant = *instant;
      self.metadata.insert(path.clone(), metadata);
    }

    dirty_.clear();
  }
}
<commit_msg>Simplified the use of ResCache::inject().<commit_after>// FIXME: add the support of transient objects

use any_cache::{Cache, HashCache};
use notify::{self, RecommendedWatcher, Watcher};
use std::any::Any;
use std::cell::RefCell;
use std::collections::HashMap;
use std::ops::Deref;
use std::path::{Path, PathBuf};
use std::rc::Rc;
use std::sync::{Arc, Mutex};
use std::sync::mpsc::channel;
use std::thread;
use std::time::{Duration, Instant};

/// Class of types that can be loaded.
pub trait Load: Sized {
  /// Arguments passed at loading.
  type Args: Clone;

  /// Static string representing the name of the type (used in filesystem caching).
  const TY_STR: &'static str;

  fn load<P>(path: P, cache: &mut ResCache, args: Self::Args) -> Result<Self> where P: AsRef<Path>;
}

/// Class of types that can be reloaded.
///
/// The idea is to simply recover the arguments used in `Load::load`.
pub trait Reload: Load {
  fn reload_args(&self) -> Self::Args;
}

/// Default implementation for types which are loaded without any arguments.
impl<T> Reload for T where T: Load<Args=()> {
  fn reload_args(&self) -> Self::Args {
    ()
  }
}

#[derive(Clone, Debug, Eq, PartialEq)]
pub enum LoadError {
  FileNotFound(PathBuf, String),
  ParseFailed(String),
  ConversionFailed(String)
}

pub type Result<T> = ::std::result::Result<T, LoadError>;

/// Resources are wrapped in this type.
#[derive(Debug)]
pub struct Res<T>(Rc<RefCell<T>>);

impl<T> Res<T> {
  pub fn new(resource: T) -> Self {
    Res(Rc::new(RefCell::new(resource)))
  }

  pub fn as_rc(&self) -> &Rc<RefCell<T>> {
    &self.0
  }
}

impl<T> Clone for Res<T> {
  fn clone(&self) -> Self {
    Res(self.0.clone())
  }
}

impl<T> Deref for Res<T> {
  type Target = RefCell<T>;

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

impl<T> From<Rc<RefCell<T>>> for Res<T> {
  fn from(rc: Rc<RefCell<T>>) -> Self {
    Res(rc)
  }
}

/// Time to await after a resource update to establish that it should be reloaded.
const UPDATE_AWAIT_TIME_MS: u64 = 1000;

/// Resource cache. Responsible for caching resource.
pub struct ResCache {
  // contains all the typed-erased Rc<RefCell<T>>
  cache: HashCache<PathBuf>,
  // contains all metadata on resources
  metadata: HashMap<PathBuf, ResMetaData>,
  // vector of pair (path, timestamp) giving indication on resources to reload
  dirty: Arc<Mutex<Vec<(PathBuf, Instant)>>>,
  #[allow(dead_code)]
  watcher_thread: thread::JoinHandle<()>
}

struct ResMetaData {
  on_reload: Box<Fn(&mut ResCache)>,
  last_update_instant: Instant
}

impl ResCache {
  /// Create a new cache.
  pub fn new<P>(root: P) -> Self where P: AsRef<Path> {
    let dirty: Arc<Mutex<Vec<(PathBuf, Instant)>>> = Arc::new(Mutex::new(Vec::new()));
    let dirty_ = dirty.clone();

    let root = root.as_ref().to_owned();
    let (wsx, wrx) = channel();
    let mut watcher: RecommendedWatcher = Watcher::new(wsx).unwrap();

    let join_handle = thread::spawn(move || {
      let _ = watcher.watch(root);

      for event in wrx.iter() {
        if let notify::Event { path: Some(path), op: Ok(notify::op::WRITE) } = event {
          dirty_.lock().unwrap().push((path.clone(), Instant::now()));
        }
      }
    });

    ResCache {
      cache: HashCache::new(),
      metadata: HashMap::new(),
      dirty: dirty,
      watcher_thread: join_handle
    }
  }

  /// Inject a new resource in the cache.
  fn inject<T>(&mut self, path_buf: &PathBuf, resource: T, args: T::Args) -> Res<T> where T: 'static + Any + Reload {
    let res = Res(Rc::new(RefCell::new(resource)));
    let res_ = res.clone();

    let path_buf_ = path_buf.clone();

    // closure used to reload the object when needed
    let on_reload: Box<for<'a> Fn(&'a mut ResCache)> = Box::new(move |cache_| {
      match T::load(&path_buf_, cache_, args.clone()) {
        Ok(new_resource) => {
          // replace the current resource with the freshly loaded one
          *res_.borrow_mut() = new_resource;
          deb!("reloaded resource from {:?}", path_buf_);
        },
        Err(e) => {
          warn!("reloading resource from {:?} has failed:\n{:#?}", path_buf_, e);
        }
      }
    });

    let metadata = ResMetaData {
      on_reload: on_reload,
      last_update_instant: Instant::now()
    };

    // cache the resource and its meta data
    self.cache.save(path_buf.clone(), res.clone());
    self.metadata.insert(path_buf.clone(), metadata);

    res
  }

  /// Get a resource from the cache.
  pub fn get<T>(&mut self, key: &str, args: T::Args) -> Option<Res<T>> where T: 'static + Any + Reload {
    let path_str = format!("data/{}/{}", T::TY_STR, key);
    let path = Path::new(&path_str);
    let path_buf = path.to_owned();

    match self.cache.get::<Res<T>>(&path_buf).cloned() {
      r@Some(..) => {
        deb!("cache hit for {} ({})", key, path_str);
        r
      },
      None => {
        deb!("cache miss for {} ({})", key, path_str);

        // specific loading
        if path.exists() {
          match T::load(&path, self, args.clone()) {
            Ok(resource) => {
              Some(self.inject(&path_buf, resource, args))
            },
            Err(e) => {
              err!("unable to load resource from {}:\n{:#?}", path_str, e);
              None
            }
          }
        } else { // path doesn’t exist
          err!("resource at {} cannot be found", path_str);
          None
        }
      }
    }
  }

//   /// Get a resource from the cache. If it fails, a proxy version of it is used, which will get
//   /// replaced by the resource once it’s avaible.
//   pub fn get_proxied<T, P>(&mut self, key: &str, args: T::Args, proxy: P) -> Option<Res<T>>
//       where T: 'static + Any + Reload,
//             P: FnOnce() -> T {
//     // riterite
//     self.get::<T>().unwrap_or_else(|| {
//       deb!("proxying resource {}", key);
//
//
//     })
//   }

  /// Synchronize the cache by updating the resource that ought to.
  pub fn sync(&mut self) {
    let dirty = self.dirty.clone();
    let mut dirty_ = dirty.lock().unwrap();

    for &(ref path, ref instant) in dirty_.iter() {
      let mut metadata = self.metadata.remove(path).unwrap();

      if instant.duration_since(metadata.last_update_instant) >= Duration::from_millis(UPDATE_AWAIT_TIME_MS) {
        (metadata.on_reload)(self);
      }

      metadata.last_update_instant = *instant;
      self.metadata.insert(path.clone(), metadata);
    }

    dirty_.clear();
  }
}
<|endoftext|>


<commit_before>// Copyright (c) 2016
// Jeff Nettleton
//
// Licensed under the MIT license (http://opensource.org/licenses/MIT). This
// file may not be copied, modified, or distributed except according to those
// terms

use std::collections::HashMap;
use chrono::UTC;
use rustc_serialize::{json, Encodable};

/// A trait that converts data from the handler function to a u8 slice.
pub trait ToOutput {
    fn to_output(&self) -> &[u8];
}

impl ToOutput for str {
    fn to_output(&self) -> &[u8] {
        self.as_bytes()
    }
}

impl ToOutput for &'static str {
    fn to_output(&self) -> &[u8] {
        self.as_bytes()
    }
}

impl ToOutput for String {
    fn to_output(&self) -> &[u8] {
        self.as_bytes()
    }
}

impl ToOutput for Vec<u8> {
    fn to_output(&self) -> &[u8] {
        self.as_slice()
    }
}

/// This struct reprsents the response to an HTTP client.
#[derive(Debug)]
pub struct Response {
    status:     u16,
    cmsg:       String,
    ctype:      String,
    headers:    HashMap<String, String>,
    payload:    Vec<u8>,
}

impl Response {
    /// Create a new, empty Response.
    pub fn new() -> Response {
        let mut res = Response {
            status:     200,
            cmsg:       String::from("OK"),
            ctype:      String::from("text/plain"),
            headers:    HashMap::new(),
            payload:    Vec::with_capacity(2048),
        };

        let now = UTC::now().format("%a, %d %b %Y, %H:%M:%S %Z").to_string();

        res.add_header("Connection", "close");
        res.add_header("Server", "canteen/0.0.1");
        res.add_header("Date", &now);

        res
    }

    /// Creates a Response with a JSON body
    ///
    /// # Examples
    ///
    /// ```rust,ignore
    /// use canteen::Response;
    ///
    /// #[derive(RustcEncodable)]
    /// struct Foo {
    ///     item: i32,
    /// }
    ///
    /// let foo = Foo { item: 12345 };
    /// let res = Response::as_json(&foo);
    /// ```
    pub fn as_json<T: Encodable>(data: &T) -> Response {
        let mut res = Response::new();

        res.set_content_type("application/json");
        res.append(json::encode(data).unwrap());

        res
    }

    /// Gets the HTTP message for a given status.
    fn get_http_message(status: u16) -> String {
        let msg = match status {
            100 => "Continue",
            101 => "Switching Protocols",
            200 => "OK",
            201 => "Created",
            202 => "Accepted",
            203 => "Non-Authoritative Information",
            204 => "No Content",
            205 => "Reset Content",
            206 => "Partial Content",
            300 => "Multiple Choices",
            301 => "Moved Permanently",
            302 => "Found",
            303 => "See Other",
            304 => "Not Modified",
            305 => "Use Proxy",
            307 => "Temporary Redirect",
            400 => "Bad Request",
            401 => "Unauthorized",
            402 => "Payment Required",
            403 => "Forbidden",
            404 => "Not Found",
            405 => "Method Not Allowed",
            406 => "Not Acceptable",
            407 => "Proxy Authentication Required",
            408 => "Request Time Out",
            409 => "Conflict",
            410 => "Gone",
            411 => "Length Required",
            412 => "Precondition Failed",
            413 => "Request Entity Too Large",
            414 => "Request-URI Too Large",
            415 => "Unsupported Media Type",
            416 => "Requested Range Not Satisfiable",
            417 => "Expectation Failed",
            500 => "Internal Server Error",
            501 => "Not Implemented",
            502 => "Bad Gateway",
            503 => "Service Unavailable",
            504 => "Gateway Time-out",
            505 => "HTTP Version Not Supported",
            _   => "OK",
        };

        String::from(msg)
    }

    /// Sets the response status for the HTTP response.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use canteen::Response;
    ///
    /// let mut res = Response::new();
    /// res.set_status(200);
    /// ```
    pub fn set_status(&mut self, status: u16) {
        self.status = status;
        self.cmsg = Response::get_http_message(status);
    }

    /// Sets the Content-Type header for the HTTP response.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use canteen::Response;
    ///
    /// let mut res = Response::new();
    /// res.set_content_type("text/html");
    /// ```
    pub fn set_content_type(&mut self, ctype: &str) {
        self.ctype = String::from(ctype);
    }

    /// Adds a header to the HTTP response.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use canteen::Response;
    ///
    /// let mut res = Response::new();
    /// res.add_header("Content-Type", "text/html");
    /// ```
    pub fn add_header(&mut self, key: &str, value: &str) {
        if !self.headers.contains_key(key) {
            self.headers.insert(String::from(key), String::from(value));
        }
    }

    /// Appends data to the body of the HTTP response. The trait ToOutput must
    /// be implemented for the type passed.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use canteen::Response;
    ///
    /// let mut res = Response::new();
    /// let data = "{ message: \"Hello, world!\" }";
    /// res.append(data);
    /// ```
    pub fn append<T: ToOutput>(&mut self, payload: T) {
        self.payload.extend(payload.to_output().into_iter());
    }

    /// Returns a byte array containing the full contents of the HTTP response,
    /// for use by the Canteen struct.
    pub fn gen_output(&self) -> Vec<u8> {
        let mut output: Vec<u8> = Vec::with_capacity(self.payload.len() + 500);
        let mut inter = String::new();

        inter.push_str(&format!("HTTP/1.1 {} {}\r\n", self.status, self.cmsg));

        for (key, value) in &self.headers {
            inter.push_str(&format!("{}: {}\r\n", key, value));
        }

        inter.push_str(&format!("Content-Type: {}\r\n", self.ctype));
        inter.push_str(&format!("Content-Length: {}\r\n", self.payload.len()));
        inter.push_str("\r\n");

        output.extend(inter.as_bytes());
        output.extend(self.payload.iter());

        output
    }
}

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

    #[derive(RustcEncodable)]
    struct Foo {
        item: i32,
    }

    #[test]
    fn test_response_as_json() {
        let foo = Foo { item: 12345 };
        let res_j = Response::as_json(&foo);
        let mut res_r = Response::new();

        res_r.set_content_type("application/json");
        res_r.append(json::encode(&foo).unwrap());

        assert_eq!(res_r.gen_output(), res_j.gen_output());
    }

    #[test]
    fn test_response_http_message() {
        assert_eq!("OK", Response::get_http_message(200));
    }

    #[test]
    fn test_tooutput_trait_static_str() {
        let ar: [u8; 3] = [97, 98, 99];

        assert_eq!(ar, "abc".to_output());
    }

    #[test]
    fn test_tooutput_trait_str() {
        let ar: [u8; 3] = [97, 98, 99];
        let st = "abc";

        assert_eq!(ar, st.to_output());
    }

    #[test]
    fn test_tooutput_trait_string() {
        let ar: [u8; 3] = [97, 98, 99];
        let st = String::from("abc");

        assert_eq!(ar, st.to_output());
    }

    #[test]
    fn test_tooutput_trait_vec() {
        let ar: [u8; 5] = [1, 2, 3, 4, 5];
        let vc: Vec<u8> = vec![1, 2, 3, 4, 5];

        assert_eq!(ar, vc.to_output());
    }
}
<commit_msg>use a cargo feature to build in version number<commit_after>// Copyright (c) 2016
// Jeff Nettleton
//
// Licensed under the MIT license (http://opensource.org/licenses/MIT). This
// file may not be copied, modified, or distributed except according to those
// terms

use std::collections::HashMap;
use chrono::UTC;
use rustc_serialize::{json, Encodable};

const VERSION: &'static str = env!("CARGO_PKG_VERSION");

/// A trait that converts data from the handler function to a u8 slice.
pub trait ToOutput {
    fn to_output(&self) -> &[u8];
}

impl ToOutput for str {
    fn to_output(&self) -> &[u8] {
        self.as_bytes()
    }
}

impl ToOutput for &'static str {
    fn to_output(&self) -> &[u8] {
        self.as_bytes()
    }
}

impl ToOutput for String {
    fn to_output(&self) -> &[u8] {
        self.as_bytes()
    }
}

impl ToOutput for Vec<u8> {
    fn to_output(&self) -> &[u8] {
        self.as_slice()
    }
}

/// This struct reprsents the response to an HTTP client.
#[derive(Debug)]
pub struct Response {
    status:     u16,
    cmsg:       String,
    ctype:      String,
    headers:    HashMap<String, String>,
    payload:    Vec<u8>,
}

impl Response {
    /// Create a new, empty Response.
    pub fn new() -> Response {
        let mut res = Response {
            status:     200,
            cmsg:       String::from("OK"),
            ctype:      String::from("text/plain"),
            headers:    HashMap::new(),
            payload:    Vec::with_capacity(2048),
        };

        let now = UTC::now().format("%a, %d %b %Y, %H:%M:%S %Z").to_string();

        res.add_header("Connection", "close");
        res.add_header("Server", &format!("canteen/{}", VERSION));
        res.add_header("Date", &now);

        res
    }

    /// Creates a Response with a JSON body
    ///
    /// # Examples
    ///
    /// ```rust,ignore
    /// use canteen::Response;
    ///
    /// #[derive(RustcEncodable)]
    /// struct Foo {
    ///     item: i32,
    /// }
    ///
    /// let foo = Foo { item: 12345 };
    /// let res = Response::as_json(&foo);
    /// ```
    pub fn as_json<T: Encodable>(data: &T) -> Response {
        let mut res = Response::new();

        res.set_content_type("application/json");
        res.append(json::encode(data).unwrap());

        res
    }

    /// Gets the HTTP message for a given status.
    fn get_http_message(status: u16) -> String {
        let msg = match status {
            100 => "Continue",
            101 => "Switching Protocols",
            200 => "OK",
            201 => "Created",
            202 => "Accepted",
            203 => "Non-Authoritative Information",
            204 => "No Content",
            205 => "Reset Content",
            206 => "Partial Content",
            300 => "Multiple Choices",
            301 => "Moved Permanently",
            302 => "Found",
            303 => "See Other",
            304 => "Not Modified",
            305 => "Use Proxy",
            307 => "Temporary Redirect",
            400 => "Bad Request",
            401 => "Unauthorized",
            402 => "Payment Required",
            403 => "Forbidden",
            404 => "Not Found",
            405 => "Method Not Allowed",
            406 => "Not Acceptable",
            407 => "Proxy Authentication Required",
            408 => "Request Time Out",
            409 => "Conflict",
            410 => "Gone",
            411 => "Length Required",
            412 => "Precondition Failed",
            413 => "Request Entity Too Large",
            414 => "Request-URI Too Large",
            415 => "Unsupported Media Type",
            416 => "Requested Range Not Satisfiable",
            417 => "Expectation Failed",
            500 => "Internal Server Error",
            501 => "Not Implemented",
            502 => "Bad Gateway",
            503 => "Service Unavailable",
            504 => "Gateway Time-out",
            505 => "HTTP Version Not Supported",
            _   => "OK",
        };

        String::from(msg)
    }

    /// Sets the response status for the HTTP response.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use canteen::Response;
    ///
    /// let mut res = Response::new();
    /// res.set_status(200);
    /// ```
    pub fn set_status(&mut self, status: u16) {
        self.status = status;
        self.cmsg = Response::get_http_message(status);
    }

    /// Sets the Content-Type header for the HTTP response.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use canteen::Response;
    ///
    /// let mut res = Response::new();
    /// res.set_content_type("text/html");
    /// ```
    pub fn set_content_type(&mut self, ctype: &str) {
        self.ctype = String::from(ctype);
    }

    /// Adds a header to the HTTP response.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use canteen::Response;
    ///
    /// let mut res = Response::new();
    /// res.add_header("Content-Type", "text/html");
    /// ```
    pub fn add_header(&mut self, key: &str, value: &str) {
        if !self.headers.contains_key(key) {
            self.headers.insert(String::from(key), String::from(value));
        }
    }

    /// Appends data to the body of the HTTP response. The trait ToOutput must
    /// be implemented for the type passed.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use canteen::Response;
    ///
    /// let mut res = Response::new();
    /// let data = "{ message: \"Hello, world!\" }";
    /// res.append(data);
    /// ```
    pub fn append<T: ToOutput>(&mut self, payload: T) {
        self.payload.extend(payload.to_output().into_iter());
    }

    /// Returns a byte array containing the full contents of the HTTP response,
    /// for use by the Canteen struct.
    pub fn gen_output(&self) -> Vec<u8> {
        let mut output: Vec<u8> = Vec::with_capacity(self.payload.len() + 500);
        let mut inter = String::new();

        inter.push_str(&format!("HTTP/1.1 {} {}\r\n", self.status, self.cmsg));

        for (key, value) in &self.headers {
            inter.push_str(&format!("{}: {}\r\n", key, value));
        }

        inter.push_str(&format!("Content-Type: {}\r\n", self.ctype));
        inter.push_str(&format!("Content-Length: {}\r\n", self.payload.len()));
        inter.push_str("\r\n");

        output.extend(inter.as_bytes());
        output.extend(self.payload.iter());

        output
    }
}

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

    #[derive(RustcEncodable)]
    struct Foo {
        item: i32,
    }

    #[test]
    fn test_response_as_json() {
        let foo = Foo { item: 12345 };
        let res_j = Response::as_json(&foo);
        let mut res_r = Response::new();

        res_r.set_content_type("application/json");
        res_r.append(json::encode(&foo).unwrap());

        assert_eq!(res_r.gen_output(), res_j.gen_output());
    }

    #[test]
    fn test_response_http_message() {
        assert_eq!("OK", Response::get_http_message(200));
    }

    #[test]
    fn test_tooutput_trait_static_str() {
        let ar: [u8; 3] = [97, 98, 99];

        assert_eq!(ar, "abc".to_output());
    }

    #[test]
    fn test_tooutput_trait_str() {
        let ar: [u8; 3] = [97, 98, 99];
        let st = "abc";

        assert_eq!(ar, st.to_output());
    }

    #[test]
    fn test_tooutput_trait_string() {
        let ar: [u8; 3] = [97, 98, 99];
        let st = String::from("abc");

        assert_eq!(ar, st.to_output());
    }

    #[test]
    fn test_tooutput_trait_vec() {
        let ar: [u8; 5] = [1, 2, 3, 4, 5];
        let vc: Vec<u8> = vec![1, 2, 3, 4, 5];

        assert_eq!(ar, vc.to_output());
    }
}
<|endoftext|>