<commit_before>//! Code for the internal Lua thread which handles all Lua requests.

use std::thread;
use std::fs::{File};
use std::path::Path;
use std::io::Write;
use std::fmt::{Debug, Formatter};
use std::fmt::Result as FmtResult;
use std::sync::{Mutex, RwLock};
use std::sync::mpsc::{channel, Sender, Receiver};

use hlua::{Lua, LuaError};

use super::types::*;
use super::funcs;

lazy_static! {
    /// Sends requests to the Lua thread
    static ref SENDER: Mutex<Option<Sender<LuaMessage>>> = Mutex::new(None);

    /// Whether the Lua thread is currently running
    pub static ref RUNNING: RwLock<bool> = RwLock::new(false);
}

const ERR_LOCK_RUNNING: &'static str = "Lua thread: unable to lock RUNNING";
const ERR_LOCK_SENDER: &'static str = "Lua thread: unable to lock SENDER";

/// Struct sent to the Lua query
struct LuaMessage {
    reply: Sender<LuaResponse>,
    query: LuaQuery
}

unsafe impl Send for LuaMessage { }
unsafe impl Sync for LuaMessage { }

impl Debug for LuaMessage {
    fn fmt(&self, f: &mut Formatter) -> FmtResult {
        write!(f, "LuaMessage({:?})", self.query)
    }
}

// Reexported in lua/mod.rs:11
/// Whether the Lua thread is currently available.
pub fn running() -> bool {
    *RUNNING.read().expect(ERR_LOCK_RUNNING)
}

// Reexported in lua/mod.rs:11
/// Errors which may arise from attempting
/// to sending a message to the Lua thread.
#[derive(Debug)]
pub enum LuaSendError {
    /// The thread crashed, was shut down, or rebooted.
    ThreadClosed,
    /// The thread has not been initialized yet (maybe not used)
    ThreadUninitialized,
    /// The sender had an issue, most likey because the thread panicked.
    /// Following the `Sender` API, the original value sent is returned.
    Sender(LuaQuery)
}

// Reexported in lua/mod.rs:11
/// Attemps to send a LuaQuery to the Lua thread.
pub fn send(query: LuaQuery) -> Result<Receiver<LuaResponse>, LuaSendError> {
    if !running() {
        return Err(LuaSendError::ThreadClosed);
    }
    let thread_sender: Sender<LuaMessage>;
    {
        let maybe_sender = SENDER.lock().expect(ERR_LOCK_SENDER);
        match *maybe_sender {
            Some(ref real_sender) => {
                // Senders are designed to be cloneable
                thread_sender = real_sender.clone();
            },
            // If the sender doesn't exist yet, the thread doesn't either
            None => {
                return Err(LuaSendError::ThreadUninitialized);
            }
        }
    }
    // Create a response channel
    let (response_tx, response_rx) = channel();
    let message = LuaMessage { reply: response_tx, query: query };
    match thread_sender.send(message) {
        Ok(_) => Ok(response_rx),
        Err(e) => Err(LuaSendError::Sender(e.0.query))
    }
}

/// Initialize the Lua thread.
pub fn init() {
    trace!("Initializing...");
    let (tx, receiver) = channel();
    *SENDER.lock().expect(ERR_LOCK_SENDER) = Some(tx);
    let mut lua = Lua::new();
    debug!("Loading Lua libraries...");
    lua.openlibs();
    trace!("Loading way-cooler lua extensions...");
    // We should have some good file handling, read files from /usr by default,
    // but for now we're reading directly from the source.
    lua.execute_from_reader::<(), File>(
        File::open("lib/lua/init.lua")
            .expect("Lua thread unable to find init file")
    ).expect("Lua thread: unable to execute init file");
    trace!("Loading way-cooler libraries...");
    funcs::register_libraries(&mut lua);
    // Only ready after loading libs
    *RUNNING.write().expect(ERR_LOCK_RUNNING) = true;
    debug!("Entering main loop...");
    let _lua_handle = thread::Builder::new()
        .name("Lua thread".to_string())
        .spawn(move || { main_loop(receiver, &mut lua) });
}

/// Main loop of the Lua thread:
///
/// ## Loop
/// * Wait for a message from the receiver
/// * Handle message
/// * Send response
fn main_loop(receiver: Receiver<LuaMessage>, lua: &mut Lua) {
    loop {
        trace!("Lua: awaiting request");
        let request = receiver.recv();
        match request {
            Err(e) => {
                error!("Lua thread: unable to receive message: {}", e);
                error!("Lua thread: now panicking!");
                *RUNNING.write().expect(ERR_LOCK_RUNNING) = false;

                panic!("Lua thread: lost contact with host, exiting!");
            }
            Ok(message) => {
                trace!("Handling a request");
                handle_message(message, lua);
            }
        }
    }
}

/// Handle each LuaQuery option sent to the thread
fn handle_message(request: LuaMessage, lua: &mut Lua) {
    match request.query {
        LuaQuery::Terminate => {
            trace!("Received terminate signal");
            *RUNNING.write().expect(ERR_LOCK_RUNNING) = false;

            info!("Lua thread terminating!");
            thread_send(request.reply, LuaResponse::Pong);
            return;
        },

        LuaQuery::Restart => {
            trace!("Received restart signal!");
            error!("Lua thread restart not supported!");

            *RUNNING.write().expect(ERR_LOCK_RUNNING) = false;
            thread_send(request.reply, LuaResponse::Pong);

            panic!("Lua thread: Restart not supported!");
        },

        LuaQuery::Execute(code) => {
            trace!("Received request to execute {}", code);

            match lua.execute::<()>(&code) {
                Err(error) => {
                    warn!("Error executing code: {:?}", error);
                    thread_send(request.reply, LuaResponse::Error(error));
                }
                Ok(_) => {
                    trace!("Code executed okay.");
                    thread_send(request.reply, LuaResponse::Pong);
                }
            }
        },

        LuaQuery::ExecFile(name) => {
            info!("Executing {}", name);

            let path = Path::new(&name);
            let try_file = File::open(path);

            if let Ok(file) = try_file {
                let result = lua.execute_from_reader::<(), File>(file);
                if let Err(err) = result {
                    warn!("Error executing {}!", name);

                    thread_send(request.reply, LuaResponse::Error(err));
                }
                else {
                    trace!("Execution of {} successful.", name);
                    thread_send(request.reply, LuaResponse::Pong);
                }
            }
            else { // Could not open file
                // Unwrap_err is used because we're in the else of let Ok
                let read_error =
                    LuaError::ReadError(try_file.unwrap_err());

                thread_send(request.reply, LuaResponse::Error(read_error));
            }
        },
        LuaQuery::ExecRust(func) => {
            let result = func(lua);
            thread_send(request.reply, LuaResponse::Variable(Some(result)));
        },
        LuaQuery::Ping => {
            thread_send(request.reply, LuaResponse::Pong);
        },
    }
}

fn thread_send(sender: Sender<LuaResponse>, response: LuaResponse) {
    match sender.send(response) {
        Err(err) => {
            match err.0 {
                LuaResponse::Pong => {}, // Those are boring
                _ => {
                    warn!("thread: Someone dropped an important Lua response!");
                }
            }
        }
        Ok(_) => {}
    }
}
<commit_msg>Implemented Lua restart/terminate<commit_after>//! Code for the internal Lua thread which handles all Lua requests.

use std::thread;
use std::fs::{File};
use std::path::Path;
use std::io::Write;
use std::fmt::{Debug, Formatter};
use std::fmt::Result as FmtResult;
use std::sync::{Mutex, RwLock};
use std::sync::mpsc::{channel, Sender, Receiver};

use hlua::{Lua, LuaError};

use super::types::*;
use super::funcs;

lazy_static! {
    /// Sends requests to the Lua thread
    static ref SENDER: Mutex<Option<Sender<LuaMessage>>> = Mutex::new(None);

    /// Whether the Lua thread is currently running
    pub static ref RUNNING: RwLock<bool> = RwLock::new(false);
}

const ERR_LOCK_RUNNING: &'static str = "Lua thread: unable to lock RUNNING";
const ERR_LOCK_SENDER: &'static str = "Lua thread: unable to lock SENDER";

/// Struct sent to the Lua query
struct LuaMessage {
    reply: Sender<LuaResponse>,
    query: LuaQuery
}

unsafe impl Send for LuaMessage { }
unsafe impl Sync for LuaMessage { }

impl Debug for LuaMessage {
    fn fmt(&self, f: &mut Formatter) -> FmtResult {
        write!(f, "LuaMessage({:?})", self.query)
    }
}

// Reexported in lua/mod.rs:11
/// Whether the Lua thread is currently available.
pub fn running() -> bool {
    *RUNNING.read().expect(ERR_LOCK_RUNNING)
}

// Reexported in lua/mod.rs:11
/// Errors which may arise from attempting
/// to sending a message to the Lua thread.
#[derive(Debug)]
pub enum LuaSendError {
    /// The thread crashed, was shut down, or rebooted.
    ThreadClosed,
    /// The thread has not been initialized yet (maybe not used)
    ThreadUninitialized,
    /// The sender had an issue, most likey because the thread panicked.
    /// Following the `Sender` API, the original value sent is returned.
    Sender(LuaQuery)
}

// Reexported in lua/mod.rs:11
/// Attemps to send a LuaQuery to the Lua thread.
pub fn send(query: LuaQuery) -> Result<Receiver<LuaResponse>, LuaSendError> {
    if !running() {
        return Err(LuaSendError::ThreadClosed);
    }
    let thread_sender: Sender<LuaMessage>;
    {
        let maybe_sender = SENDER.lock().expect(ERR_LOCK_SENDER);
        match *maybe_sender {
            Some(ref real_sender) => {
                // Senders are designed to be cloneable
                thread_sender = real_sender.clone();
            },
            // If the sender doesn't exist yet, the thread doesn't either
            None => {
                return Err(LuaSendError::ThreadUninitialized);
            }
        }
    }
    // Create a response channel
    let (response_tx, response_rx) = channel();
    let message = LuaMessage { reply: response_tx, query: query };
    match thread_sender.send(message) {
        Ok(_) => Ok(response_rx),
        Err(e) => Err(LuaSendError::Sender(e.0.query))
    }
}

/// Initialize the Lua thread.
pub fn init() {
    trace!("Initializing...");
    let (tx, receiver) = channel();
    *SENDER.lock().expect(ERR_LOCK_SENDER) = Some(tx);
    let mut lua = Lua::new();
    debug!("Loading Lua libraries...");
    lua.openlibs();
    trace!("Loading way-cooler lua extensions...");
    // We should have some good file handling, read files from /usr by default,
    // but for now we're reading directly from the source.
    lua.execute_from_reader::<(), File>(
        File::open("lib/lua/init.lua")
            .expect("Lua thread unable to find init file")
    ).expect("Lua thread: unable to execute init file");
    trace!("Loading way-cooler libraries...");
    funcs::register_libraries(&mut lua);
    // Only ready after loading libs
    *RUNNING.write().expect(ERR_LOCK_RUNNING) = true;
    debug!("Entering main loop...");
    let _lua_handle = thread::Builder::new()
        .name("Lua thread".to_string())
        .spawn(move || { main_loop(receiver, &mut lua) });
}

/// Main loop of the Lua thread:
///
/// ## Loop
/// * Wait for a message from the receiver
/// * Handle message
/// * Send response
fn main_loop(receiver: Receiver<LuaMessage>, lua: &mut Lua) {
    loop {
        trace!("Lua: awaiting request");
        let request = receiver.recv();
        match request {
            Err(e) => {
                error!("Lua thread: unable to receive message: {}", e);
                error!("Lua thread: now panicking!");
                *RUNNING.write().expect(ERR_LOCK_RUNNING) = false;

                panic!("Lua thread: lost contact with host, exiting!");
            }
            Ok(message) => {
                trace!("Handling a request");
                handle_message(message, lua);
            }
        }
    }
}

/// Handle each LuaQuery option sent to the thread
fn handle_message(request: LuaMessage, lua: &mut Lua) {
    match request.query {
        LuaQuery::Terminate => {
            trace!("Received terminate signal");
            *RUNNING.write().expect(ERR_LOCK_RUNNING) = false;
            thread_send(request.reply, LuaResponse::Pong);

            info!("Lua thread terminating!");
            panic!("Lua thread received termination request.");
        },

        LuaQuery::Restart => {
            use std::time::Duration;
            trace!("Received restart signal!");
            error!("Lua thread restart not supported!");

            *RUNNING.write().expect(ERR_LOCK_RUNNING) = false;
            thread_send(request.reply, LuaResponse::Pong);

            // The only real way to restart
            let _new_handle = thread::Builder::new()
                .name("Lua re-init".to_string())
                .spawn(move || {
                    thread::sleep(Duration::from_secs(4));
                    init();
                });

            panic!("Lua thread: Restarting!");
        },

        LuaQuery::Execute(code) => {
            trace!("Received request to execute {}", code);

            match lua.execute::<()>(&code) {
                Err(error) => {
                    warn!("Error executing code: {:?}", error);
                    thread_send(request.reply, LuaResponse::Error(error));
                }
                Ok(_) => {
                    trace!("Code executed okay.");
                    thread_send(request.reply, LuaResponse::Pong);
                }
            }
        },

        LuaQuery::ExecFile(name) => {
            info!("Executing {}", name);

            let path = Path::new(&name);
            let try_file = File::open(path);

            if let Ok(file) = try_file {
                let result = lua.execute_from_reader::<(), File>(file);
                if let Err(err) = result {
                    warn!("Error executing {}!", name);

                    thread_send(request.reply, LuaResponse::Error(err));
                }
                else {
                    trace!("Execution of {} successful.", name);
                    thread_send(request.reply, LuaResponse::Pong);
                }
            }
            else { // Could not open file
                // Unwrap_err is used because we're in the else of let Ok
                let read_error =
                    LuaError::ReadError(try_file.unwrap_err());

                thread_send(request.reply, LuaResponse::Error(read_error));
            }
        },
        LuaQuery::ExecRust(func) => {
            let result = func(lua);
            thread_send(request.reply, LuaResponse::Variable(Some(result)));
        },
        LuaQuery::Ping => {
            thread_send(request.reply, LuaResponse::Pong);
        },
    }
}

fn thread_send(sender: Sender<LuaResponse>, response: LuaResponse) {
    match sender.send(response) {
        Err(err) => {
            match err.0 {
                LuaResponse::Pong => {}, // Those are boring
                _ => {
                    warn!("thread: Someone dropped an important Lua response!");
                }
            }
        }
        Ok(_) => {}
    }
}
<|endoftext|>


<commit_before>use bls::verify_proof_of_possession;
use spec::ChainSpec;
use types::{BeaconState, Deposit, ValidatorRecord, ValidatorStatus};

#[derive(Debug, PartialEq, Clone)]
pub enum ValidatorInductionError {
    InvalidShard,
    InvaidProofOfPossession,
    InvalidWithdrawalCredentials,
}

pub fn process_deposit(
    state: &mut BeaconState,
    deposit: &Deposit,
    spec: &ChainSpec,
) -> Result<usize, ValidatorInductionError> {
    let deposit_input = &deposit.deposit_data.deposit_input;
    let deposit_data = &deposit.deposit_data;

    // TODO: Update the signature validation as defined in the spec once issues #91 and #70 are completed
    if !verify_proof_of_possession(&deposit_input.proof_of_possession, &deposit_input.pubkey) {
        return Err(ValidatorInductionError::InvaidProofOfPossession);
    }

    let validator_index = state
        .validator_registry
        .iter()
        .position(|validator| validator.pubkey == deposit_input.pubkey);

    match validator_index {
        Some(i) => {
            if state.validator_registry[i].withdrawal_credentials
                == deposit_input.withdrawal_credentials
            {
                state.validator_balances[i] += deposit_data.value;
                return Ok(i);
            }

            Err(ValidatorInductionError::InvalidWithdrawalCredentials)
        }
        None => {
            let validator = ValidatorRecord {
                pubkey: deposit_input.pubkey.clone(),
                withdrawal_credentials: deposit_input.withdrawal_credentials,
                randao_commitment: deposit_input.randao_commitment,
                randao_layers: 0,
                status: ValidatorStatus::PendingActivation,
                latest_status_change_slot: state.validator_registry_latest_change_slot,
                exit_count: 0,
                custody_commitment: deposit_input.custody_commitment,
                latest_custody_reseed_slot: 0,
                penultimate_custody_reseed_slot: 0,
            };

            match min_empty_validator_index(state, spec) {
                Some(i) => {
                    state.validator_registry[i] = validator;
                    state.validator_balances[i] = deposit_data.value;
                    Ok(i)
                }
                None => {
                    state.validator_registry.push(validator);
                    state.validator_balances.push(deposit_data.value);
                    Ok(state.validator_registry.len() - 1)
                }
            }
        }
    }
}

fn min_empty_validator_index(state: &BeaconState, spec: &ChainSpec) -> Option<usize> {
    for i in 0..state.validator_registry.len() {
        if state.validator_balances[i] == 0
            && state.validator_registry[i].latest_status_change_slot
                + spec.zero_balance_validator_ttl
                <= state.slot
        {
            return Some(i);
        }
    }
    None
}

#[cfg(test)]
mod tests {
    use super::*;
    use types::test_utils::{SeedableRng, TestRandom, XorShiftRng};

    use bls::{create_proof_of_possession, Keypair};

    /// The size of a validators deposit in GWei.
    pub const DEPOSIT_GWEI: u64 = 32_000_000_000;

    fn get_deposit() -> Deposit {
        let mut rng = XorShiftRng::from_seed([42; 16]);
        let mut deposit = Deposit::random_for_test(&mut rng);

        let kp = Keypair::random();
        deposit.deposit_data.deposit_input.pubkey = kp.pk.clone();
        deposit.deposit_data.deposit_input.proof_of_possession = create_proof_of_possession(&kp);
        deposit
    }

    fn get_validator() -> ValidatorRecord {
        let mut rng = XorShiftRng::from_seed([42; 16]);
        ValidatorRecord::random_for_test(&mut rng)
    }

    fn deposit_equals_record(dep: &Deposit, val: &ValidatorRecord) -> bool {
        (dep.deposit_data.deposit_input.pubkey == val.pubkey)
            & (dep.deposit_data.deposit_input.withdrawal_credentials == val.withdrawal_credentials)
            & (dep.deposit_data.deposit_input.randao_commitment == val.randao_commitment)
            & (verify_proof_of_possession(
                &dep.deposit_data.deposit_input.proof_of_possession,
                &val.pubkey,
            ))
    }

    #[test]
    fn test_process_deposit_valid_empty_validators() {
        let mut state = BeaconState::default();
        let mut deposit = get_deposit();
        let spec = ChainSpec::foundation();
        deposit.deposit_data.value = DEPOSIT_GWEI;

        let result = process_deposit(&mut state, &deposit, &spec);

        assert_eq!(result.unwrap(), 0);
        assert!(deposit_equals_record(
            &deposit,
            &state.validator_registry[0]
        ));
        assert_eq!(state.validator_registry.len(), 1);
        assert_eq!(state.validator_balances.len(), 1);
    }

    #[test]
    fn test_process_deposits_empty_validators() {
        let mut state = BeaconState::default();
        let spec = ChainSpec::foundation();

        for i in 0..5 {
            let mut deposit = get_deposit();
            let result = process_deposit(&mut state, &deposit, &spec);
            deposit.deposit_data.value = DEPOSIT_GWEI;
            assert_eq!(result.unwrap(), i);
            assert!(deposit_equals_record(
                &deposit,
                &state.validator_registry[i]
            ));
            assert_eq!(state.validator_registry.len(), i + 1);
            assert_eq!(state.validator_balances.len(), i + 1);
        }
    }

    #[test]
    fn test_process_deposit_top_out() {
        let mut state = BeaconState::default();
        let spec = ChainSpec::foundation();

        let mut deposit = get_deposit();
        let mut validator = get_validator();

        deposit.deposit_data.value = DEPOSIT_GWEI;
        validator.pubkey = deposit.deposit_data.deposit_input.pubkey.clone();
        validator.withdrawal_credentials =
            deposit.deposit_data.deposit_input.withdrawal_credentials;
        validator.randao_commitment = deposit.deposit_data.deposit_input.randao_commitment;

        state.validator_registry.push(validator);
        state.validator_balances.push(DEPOSIT_GWEI);

        let result = process_deposit(&mut state, &deposit, &spec);

        assert_eq!(result.unwrap(), 0);
        assert!(deposit_equals_record(
            &deposit,
            &state.validator_registry[0]
        ));
        assert_eq!(state.validator_balances[0], DEPOSIT_GWEI * 2);
        assert_eq!(state.validator_registry.len(), 1);
        assert_eq!(state.validator_balances.len(), 1);
    }

    #[test]
    fn test_process_deposit_replace_validator() {
        let mut state = BeaconState::default();
        let spec = ChainSpec::foundation();

        let mut validator = get_validator();
        validator.latest_status_change_slot = 0;
        state.validator_registry.push(validator);
        state.validator_balances.push(0);

        let mut deposit = get_deposit();
        deposit.deposit_data.value = DEPOSIT_GWEI;
        state.slot = spec.zero_balance_validator_ttl;

        let result = process_deposit(&mut state, &deposit, &spec);

        assert_eq!(result.unwrap(), 0);
        assert!(deposit_equals_record(
            &deposit,
            &state.validator_registry[0]
        ));
        assert_eq!(state.validator_balances[0], DEPOSIT_GWEI);
        assert_eq!(state.validator_registry.len(), 1);
        assert_eq!(state.validator_balances.len(), 1);
    }

    #[test]
    fn test_process_deposit_invalid_proof_of_possession() {
        let mut state = BeaconState::default();
        let mut deposit = get_deposit();
        let spec = ChainSpec::foundation();
        deposit.deposit_data.value = DEPOSIT_GWEI;
        deposit.deposit_data.deposit_input.proof_of_possession =
            create_proof_of_possession(&Keypair::random());

        let result = process_deposit(&mut state, &deposit, &spec);

        assert_eq!(
            result,
            Err(ValidatorInductionError::InvaidProofOfPossession)
        );
        assert_eq!(state.validator_registry.len(), 0);
        assert_eq!(state.validator_balances.len(), 0);
    }
}
<commit_msg>Gets this module to compile, at expense of deviating from old spec<commit_after>use bls::verify_proof_of_possession;
use spec::ChainSpec;
use types::{BeaconState, Deposit, ValidatorRecord};

#[derive(Debug, PartialEq, Clone)]
pub enum ValidatorInductionError {
    InvalidShard,
    InvaidProofOfPossession,
    InvalidWithdrawalCredentials,
}

pub fn process_deposit(
    state: &mut BeaconState,
    deposit: &Deposit,
    spec: &ChainSpec,
) -> Result<usize, ValidatorInductionError> {
    let deposit_input = &deposit.deposit_data.deposit_input;
    let deposit_data = &deposit.deposit_data;

    // TODO: Update the signature validation as defined in the spec once issues #91 and #70 are completed
    if !verify_proof_of_possession(&deposit_input.proof_of_possession, &deposit_input.pubkey) {
        return Err(ValidatorInductionError::InvaidProofOfPossession);
    }

    let validator_index = state
        .validator_registry
        .iter()
        .position(|validator| validator.pubkey == deposit_input.pubkey);

    match validator_index {
        Some(i) => {
            if state.validator_registry[i].withdrawal_credentials
                == deposit_input.withdrawal_credentials
            {
                state.validator_balances[i] += deposit_data.value;
                return Ok(i);
            }

            Err(ValidatorInductionError::InvalidWithdrawalCredentials)
        }
        None => {
            let validator = ValidatorRecord {
                pubkey: deposit_input.pubkey.clone(),
                withdrawal_credentials: deposit_input.withdrawal_credentials,
                randao_commitment: deposit_input.randao_commitment,
                custody_commitment: deposit_input.custody_commitment,
                latest_custody_reseed_slot: 0,
                penultimate_custody_reseed_slot: 0,
                ..std::default::Default::default()
            };

            match min_empty_validator_index(state, spec) {
                Some(i) => {
                    state.validator_registry[i] = validator;
                    state.validator_balances[i] = deposit_data.value;
                    Ok(i)
                }
                None => {
                    state.validator_registry.push(validator);
                    state.validator_balances.push(deposit_data.value);
                    Ok(state.validator_registry.len() - 1)
                }
            }
        }
    }
}

// NOTE: this has been modified from the spec to get tests working
// this function is no longer used in the latest spec so this is simply a transition step
fn min_empty_validator_index(state: &BeaconState, _spec: &ChainSpec) -> Option<usize> {
    for i in 0..state.validator_registry.len() {
        if state.validator_balances[i] == 0 {
            return Some(i);
        }
    }
    None
}

#[cfg(test)]
mod tests {
    use super::*;
    use types::test_utils::{SeedableRng, TestRandom, XorShiftRng};

    use bls::{create_proof_of_possession, Keypair};

    /// The size of a validators deposit in GWei.
    pub const DEPOSIT_GWEI: u64 = 32_000_000_000;

    fn get_deposit() -> Deposit {
        let mut rng = XorShiftRng::from_seed([42; 16]);
        let mut deposit = Deposit::random_for_test(&mut rng);

        let kp = Keypair::random();
        deposit.deposit_data.deposit_input.pubkey = kp.pk.clone();
        deposit.deposit_data.deposit_input.proof_of_possession = create_proof_of_possession(&kp);
        deposit
    }

    fn get_validator() -> ValidatorRecord {
        let mut rng = XorShiftRng::from_seed([42; 16]);
        ValidatorRecord::random_for_test(&mut rng)
    }

    fn deposit_equals_record(dep: &Deposit, val: &ValidatorRecord) -> bool {
        (dep.deposit_data.deposit_input.pubkey == val.pubkey)
            & (dep.deposit_data.deposit_input.withdrawal_credentials == val.withdrawal_credentials)
            & (dep.deposit_data.deposit_input.randao_commitment == val.randao_commitment)
            & (verify_proof_of_possession(
                &dep.deposit_data.deposit_input.proof_of_possession,
                &val.pubkey,
            ))
    }

    #[test]
    fn test_process_deposit_valid_empty_validators() {
        let mut state = BeaconState::default();
        let mut deposit = get_deposit();
        let spec = ChainSpec::foundation();
        deposit.deposit_data.value = DEPOSIT_GWEI;

        let result = process_deposit(&mut state, &deposit, &spec);

        assert_eq!(result.unwrap(), 0);
        assert!(deposit_equals_record(
            &deposit,
            &state.validator_registry[0]
        ));
        assert_eq!(state.validator_registry.len(), 1);
        assert_eq!(state.validator_balances.len(), 1);
    }

    #[test]
    fn test_process_deposits_empty_validators() {
        let mut state = BeaconState::default();
        let spec = ChainSpec::foundation();

        for i in 0..5 {
            let mut deposit = get_deposit();
            let result = process_deposit(&mut state, &deposit, &spec);
            deposit.deposit_data.value = DEPOSIT_GWEI;
            assert_eq!(result.unwrap(), i);
            assert!(deposit_equals_record(
                &deposit,
                &state.validator_registry[i]
            ));
            assert_eq!(state.validator_registry.len(), i + 1);
            assert_eq!(state.validator_balances.len(), i + 1);
        }
    }

    #[test]
    fn test_process_deposit_top_out() {
        let mut state = BeaconState::default();
        let spec = ChainSpec::foundation();

        let mut deposit = get_deposit();
        let mut validator = get_validator();

        deposit.deposit_data.value = DEPOSIT_GWEI;
        validator.pubkey = deposit.deposit_data.deposit_input.pubkey.clone();
        validator.withdrawal_credentials =
            deposit.deposit_data.deposit_input.withdrawal_credentials;
        validator.randao_commitment = deposit.deposit_data.deposit_input.randao_commitment;

        state.validator_registry.push(validator);
        state.validator_balances.push(DEPOSIT_GWEI);

        let result = process_deposit(&mut state, &deposit, &spec);

        assert_eq!(result.unwrap(), 0);
        assert!(deposit_equals_record(
            &deposit,
            &state.validator_registry[0]
        ));
        assert_eq!(state.validator_balances[0], DEPOSIT_GWEI * 2);
        assert_eq!(state.validator_registry.len(), 1);
        assert_eq!(state.validator_balances.len(), 1);
    }

    #[test]
    fn test_process_deposit_replace_validator() {
        let mut state = BeaconState::default();
        let spec = ChainSpec::foundation();

        let validator = get_validator();
        state.validator_registry.push(validator);
        state.validator_balances.push(0);

        let mut deposit = get_deposit();
        deposit.deposit_data.value = DEPOSIT_GWEI;
        state.slot = spec.zero_balance_validator_ttl;

        let result = process_deposit(&mut state, &deposit, &spec);

        assert_eq!(result.unwrap(), 0);
        assert!(deposit_equals_record(
            &deposit,
            &state.validator_registry[0]
        ));
        assert_eq!(state.validator_balances[0], DEPOSIT_GWEI);
        assert_eq!(state.validator_registry.len(), 1);
        assert_eq!(state.validator_balances.len(), 1);
    }

    #[test]
    fn test_process_deposit_invalid_proof_of_possession() {
        let mut state = BeaconState::default();
        let mut deposit = get_deposit();
        let spec = ChainSpec::foundation();
        deposit.deposit_data.value = DEPOSIT_GWEI;
        deposit.deposit_data.deposit_input.proof_of_possession =
            create_proof_of_possession(&Keypair::random());

        let result = process_deposit(&mut state, &deposit, &spec);

        assert_eq!(
            result,
            Err(ValidatorInductionError::InvaidProofOfPossession)
        );
        assert_eq!(state.validator_registry.len(), 0);
        assert_eq!(state.validator_balances.len(), 0);
    }
}
<|endoftext|>


<commit_before>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.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.

use {LinkerFlavor, PanicStrategy};
use target::{LinkArgs, TargetOptions};
use std::default::Default;

pub fn opts() -> TargetOptions {
    let mut args = LinkArgs::new();
    args.insert(LinkerFlavor::Gcc, vec![
        // We want to be able to strip as much executable code as possible
        // from the linker command line, and this flag indicates to the
        // linker that it can avoid linking in dynamic libraries that don't
        // actually satisfy any symbols up to that point (as with many other
        // resolutions the linker does). This option only applies to all
        // following libraries so we're sure to pass it as one of the first
        // arguments.
        "-Wl,--as-needed".to_string(),

        // Always enable NX protection when it is available
        "-Wl,-z,noexecstack".to_string()
    ]);

    TargetOptions {
        pre_link_args: args,
        executables: true,
        relocation_model: "static".to_string(),
        disable_redzone: true,
        eliminate_frame_pointer: false,
        target_family: None,
        linker_is_gnu: true,
        has_elf_tls: true,
        panic_strategy: PanicStrategy::Abort,
        .. Default::default()
    }
}
<commit_msg>Auto merge of #43917 - ids1024:redox-unwind, r=alexcrichton<commit_after>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.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.

use LinkerFlavor;
use target::{LinkArgs, TargetOptions};
use std::default::Default;

pub fn opts() -> TargetOptions {
    let mut args = LinkArgs::new();
    args.insert(LinkerFlavor::Gcc, vec![
        // We want to be able to strip as much executable code as possible
        // from the linker command line, and this flag indicates to the
        // linker that it can avoid linking in dynamic libraries that don't
        // actually satisfy any symbols up to that point (as with many other
        // resolutions the linker does). This option only applies to all
        // following libraries so we're sure to pass it as one of the first
        // arguments.
        "-Wl,--as-needed".to_string(),

        // Always enable NX protection when it is available
        "-Wl,-z,noexecstack".to_string()
    ]);

    TargetOptions {
        pre_link_args: args,
        executables: true,
        relocation_model: "static".to_string(),
        disable_redzone: true,
        eliminate_frame_pointer: false,
        target_family: None,
        linker_is_gnu: true,
        has_elf_tls: true,
        .. Default::default()
    }
}
<|endoftext|>


<commit_before>fn main() {
    // Suffixed literals, their types is known at initialization
    let x = 1u8;
    let y = 2u;
    let z = 3f32;

    // Unsuffixed literal, their types depend on how they are used
    let i = 1;
    let f = 1.0;

    // `size_of_val` returns the size of a variable in bytes
    println!("size of `x` in bytes: {}", std::mem::size_of_val(&x));
    println!("size of `y` in bytes: {}", std::mem::size_of_val(&y));
    println!("size of `z` in bytes: {}", std::mem::size_of_val(&z));
    println!("size of `i` in bytes: {}", std::mem::size_of_val(&i));
    println!("size of `f` in bytes: {}", std::mem::size_of_val(&f));

    // Constraints (summands must have the same type) for `i` and `f`
    let _constraint_i = x + i;
    let _constraint_f = z + f;
    // TODO ^ Try commenting out these two lines
}
<commit_msg>type/literals: fix typo<commit_after>fn main() {
    // Suffixed literals, their types are known at initialization
    let x = 1u8;
    let y = 2u;
    let z = 3f32;

    // Unsuffixed literal, their types depend on how they are used
    let i = 1;
    let f = 1.0;

    // `size_of_val` returns the size of a variable in bytes
    println!("size of `x` in bytes: {}", std::mem::size_of_val(&x));
    println!("size of `y` in bytes: {}", std::mem::size_of_val(&y));
    println!("size of `z` in bytes: {}", std::mem::size_of_val(&z));
    println!("size of `i` in bytes: {}", std::mem::size_of_val(&i));
    println!("size of `f` in bytes: {}", std::mem::size_of_val(&f));

    // Constraints (summands must have the same type) for `i` and `f`
    let _constraint_i = x + i;
    let _constraint_f = z + f;
    // TODO ^ Try commenting out these two lines
}
<|endoftext|>


<commit_before>//
//  SOS: the Stupid Operating System
//  by Hawk Weisman (hi@hawkweisman.me)
//
//  Copyright (c) 2015 Hawk Weisman
//  Released under the terms of the MIT license. See `LICENSE` in the root
//  directory of this repository for more information.
//
//! Kernel memory management.
//!
//! This module contains all of the non-arch-specific paging code, and
//! re-exports memory-related definitions.
use alloc::buddy;

use core::{ops, cmp, convert};

pub use arch::memory::{PAddr, HEAP_BASE, HEAP_TOP};

pub mod paging;
#[macro_use] pub mod macros;

/// A virtual address is a machine-sized unsigned integer
#[derive(Copy, Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
pub struct VAddr(usize);

pub trait Addr: ops::Add<Self> + ops::Sub<Self>
              + ops::Mul<Self> + ops::Div<Self>
              + ops::Shl<Self> + ops::Shr<Self>
              + convert::From<*mut u8> + convert::From<*const u8>
              + Sized {
    type Repr;
}

derive_addr! { VAddr, usize }

impl VAddr {
    #[inline] pub fn from_ptr<T>(ptr: *mut T) -> Self { VAddr(ptr as usize) }
    #[inline] pub const fn from_usize(u: usize) -> Self { VAddr(u) }
    #[inline] pub const fn as_usize(&self) -> usize { self.0 }

    /// Calculate the index in the PML4 table corresponding to this address.
    #[inline] pub fn pml4_index(&self) -> usize {
        (self >> 39) & 0b111111111
    }

    /// Calculate the index in the PDPT table corresponding to this address.
    #[inline] pub fn pdpt_index(&self) -> usize {
        (self >> 30) & 0b111111111
    }

    /// Calculate the index in the PD table corresponding to this address.
    #[inline] pub fn pd_index(&self) -> usize {
        (self >> 21) & 0b111111111
    }

    /// Calculate the index in the PT table corresponding to this address.
    #[inline] pub fn pt_index(&self) -> usize {
        (self >> 12) & 0b111111111
    }
}

#[inline] pub fn heap_base_addr() -> usize {
    unsafe { (&mut HEAP_BASE as *mut _) as usize }
}

#[inline] pub fn heap_top_addr() -> usize {
    unsafe { (&mut HEAP_TOP as *mut _) as usize }
}

/// Initialise the kernel heap.
//  TODO: this is the Worst Thing In The Universe. De-stupid-ify it.
pub unsafe fn init_heap<'a>() -> Result<&'a str, &'a str> {
    let heap_base_ptr
        = &mut HEAP_BASE as *mut _;
    let heap_size
        = (&mut HEAP_TOP as *mut _) as usize - heap_base_ptr as usize;
    buddy::system::init_heap(heap_base_ptr, heap_size);
    Ok("[ OKAY ]")
}
//
//impl convert::From for P
//where P: Page<Address = A>  {
//
//}

/// Trait for a page. These can be virtual pages or physical frames.
pub trait Page
where Self: Sized
    , Self: ops::AddAssign<usize> + ops::SubAssign<usize>
    , Self: cmp::PartialEq<Self> + cmp::PartialOrd<Self>
    , Self: Copy + Clone {

    /// The type of address used to address this `Page`.
    ///
    /// Typically, this is a `PAddr` or `VAddr` (but it could be a "MAddr")
    /// in schemes where we differentiate between physical and machine
    /// addresses. If we ever have those.
    type Address: Addr;

    /// Returns a new `Page` containing the given `Address`.
    ///
    /// N.B. that since trait functions cannot be `const`, implementors of
    /// this trait may wish to provide implementations of this function
    /// outside of the `impl` block and then wrap them here.
    fn containing(addr: Self::Address) -> Self;

    /// Returns the base `Address` where this page starts.
    fn base(&self) -> Self::Address;

    ///// Convert the frame into a raw pointer to the frame's base address
    //#[inline]
    //unsafe fn as_ptr<T>(&self) -> *const T {
    //    mem::transmute(self.base())
    //}
    //
    ///// Convert the frame into a raw mutable pointer to the frame's base address
    //#[inline]
    //unsafe fn as_mut_ptr<T>(&self) -> *mut T {
    //    mem::transmute(self.base())
    //}

    /// Returns a `PageRange` between two pages
    fn range_between(start: Self, end: Self) -> PageRange<Self> {
        PageRange { start: start, end: end }
    }

    /// Returns a `FrameRange` on the frames from this frame until the end frame
    fn range_until(&self, end: Self) -> PageRange<Self> {
        PageRange { start: *self, end: end }
    }

    //fn number(&self) -> R;

}

/// A range of `Page`s.
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub struct PageRange

where P: Page { start: P, end: P }

impl
 PageRange

where P: Page
    , P: Clone {

    /// Returns an iterator over this `PageRange`
    pub fn iter<'a>(&'a self) -> PageRangeIter<'a, P> {
        PageRangeIter { range: self, current: self.start.clone() }
    }
}

/// An iterator over a range of pages
pub struct PageRangeIter<'a, P>
where P: Page
    , P: 'a { range: &'a PageRange
, current: P }

impl<'a, P> Iterator for PageRangeIter<'a, P>
where P: Page
    , P: Clone {
    type Item = P;

    fn next(&mut self) -> Option
 {
        let end = self.range.end;
      assert!(self.range.start <= end);
      if self.current < end {
          let page = self.current.clone();
          self.current += 1;
          Some(page)
      } else {
          None
      }
  }

}

//macro_rules! make_addr_range {
//    $($name:ident, $addr:ty),+ => {$(
//
//    )+}
//}
<commit_msg>[memory] re-export stuff from arch<commit_after>//
//  SOS: the Stupid Operating System
//  by Hawk Weisman (hi@hawkweisman.me)
//
//  Copyright (c) 2015 Hawk Weisman
//  Released under the terms of the MIT license. See `LICENSE` in the root
//  directory of this repository for more information.
//
//! Kernel memory management.
//!
//! This module contains all of the non-arch-specific paging code, and
//! re-exports memory-related definitions.
use alloc::buddy;

use core::{ops, cmp, convert};

pub use arch::memory::{PAddr, HEAP_BASE, HEAP_TOP, PAGE_SHIFT, PAGE_SIZE};

pub mod paging;
#[macro_use] pub mod macros;

/// A virtual address is a machine-sized unsigned integer
#[derive(Copy, Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
pub struct VAddr(usize);

pub trait Addr: ops::Add<Self> + ops::Sub<Self>
              + ops::Mul<Self> + ops::Div<Self>
              + ops::Shl<Self> + ops::Shr<Self>
              + convert::From<*mut u8> + convert::From<*const u8>
              + Sized {
    type Repr;
}

derive_addr! { VAddr, usize }

impl VAddr {
    #[inline] pub fn from_ptr<T>(ptr: *mut T) -> Self { VAddr(ptr as usize) }
    #[inline] pub const fn from_usize(u: usize) -> Self { VAddr(u) }
    #[inline] pub const fn as_usize(&self) -> usize { self.0 }

    /// Calculate the index in the PML4 table corresponding to this address.
    #[inline] pub fn pml4_index(&self) -> usize {
        (self >> 39) & 0b111111111
    }

    /// Calculate the index in the PDPT table corresponding to this address.
    #[inline] pub fn pdpt_index(&self) -> usize {
        (self >> 30) & 0b111111111
    }

    /// Calculate the index in the PD table corresponding to this address.
    #[inline] pub fn pd_index(&self) -> usize {
        (self >> 21) & 0b111111111
    }

    /// Calculate the index in the PT table corresponding to this address.
    #[inline] pub fn pt_index(&self) -> usize {
        (self >> 12) & 0b111111111
    }
}

#[inline] pub fn heap_base_addr() -> usize {
    unsafe { (&mut HEAP_BASE as *mut _) as usize }
}

#[inline] pub fn heap_top_addr() -> usize {
    unsafe { (&mut HEAP_TOP as *mut _) as usize }
}

/// Initialise the kernel heap.
//  TODO: this is the Worst Thing In The Universe. De-stupid-ify it.
pub unsafe fn init_heap<'a>() -> Result<&'a str, &'a str> {
    let heap_base_ptr
        = &mut HEAP_BASE as *mut _;
    let heap_size
        = (&mut HEAP_TOP as *mut _) as usize - heap_base_ptr as usize;
    buddy::system::init_heap(heap_base_ptr, heap_size);
    Ok("[ OKAY ]")
}
//
//impl convert::From for P
//where P: Page<Address = A>  {
//
//}

/// Trait for a page. These can be virtual pages or physical frames.
pub trait Page
where Self: Sized
    , Self: ops::AddAssign<usize> + ops::SubAssign<usize>
    , Self: cmp::PartialEq<Self> + cmp::PartialOrd<Self>
    , Self: Copy + Clone {

    /// The type of address used to address this `Page`.
    ///
    /// Typically, this is a `PAddr` or `VAddr` (but it could be a "MAddr")
    /// in schemes where we differentiate between physical and machine
    /// addresses. If we ever have those.
    type Address: Addr;

    /// Returns a new `Page` containing the given `Address`.
    ///
    /// N.B. that since trait functions cannot be `const`, implementors of
    /// this trait may wish to provide implementations of this function
    /// outside of the `impl` block and then wrap them here.
    fn containing(addr: Self::Address) -> Self;

    /// Returns the base `Address` where this page starts.
    fn base(&self) -> Self::Address;

    ///// Convert the frame into a raw pointer to the frame's base address
    //#[inline]
    //unsafe fn as_ptr<T>(&self) -> *const T {
    //    mem::transmute(self.base())
    //}
    //
    ///// Convert the frame into a raw mutable pointer to the frame's base address
    //#[inline]
    //unsafe fn as_mut_ptr<T>(&self) -> *mut T {
    //    mem::transmute(self.base())
    //}

    /// Returns a `PageRange` between two pages
    fn range_between(start: Self, end: Self) -> PageRange<Self> {
        PageRange { start: start, end: end }
    }

    /// Returns a `FrameRange` on the frames from this frame until the end frame
    fn range_until(&self, end: Self) -> PageRange<Self> {
        PageRange { start: *self, end: end }
    }

    //fn number(&self) -> R;

}

/// A range of `Page`s.
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub struct PageRange

where P: Page { start: P, end: P }

impl
 PageRange

where P: Page
    , P: Clone {

    /// Returns an iterator over this `PageRange`
    pub fn iter<'a>(&'a self) -> PageRangeIter<'a, P> {
        PageRangeIter { range: self, current: self.start.clone() }
    }
}

/// An iterator over a range of pages
pub struct PageRangeIter<'a, P>
where P: Page
    , P: 'a { range: &'a PageRange
, current: P }

impl<'a, P> Iterator for PageRangeIter<'a, P>
where P: Page
    , P: Clone {
    type Item = P;

    fn next(&mut self) -> Option
 {
        let end = self.range.end;
      assert!(self.range.start <= end);
      if self.current < end {
          let page = self.current.clone();
          self.current += 1;
          Some(page)
      } else {
          None
      }
  }

}

//macro_rules! make_addr_range {
//    $($name:ident, $addr:ty),+ => {$(
//
//    )+}
//}
<|endoftext|>


<commit_before>extern crate sync;
extern crate nickel;
extern crate sqlite3;

use nickel::{Request, Middleware, Response, Action, NickelError, Continue};
use sqlite3::core::DatabaseConnection;
use sqlite3::access;
use self::sync::{Mutex, Arc};

#[deriving(Clone)]
pub struct Sqlite3Middleware
{
    conn: Arc<Mutex<DatabaseConnection>>
}

impl Sqlite3Middleware
{
    pub fn new(file: String) -> Sqlite3Middleware
    {
        Sqlite3Middleware
        {
            conn: Arc::new(Mutex::new(match access::open(file)
                                        {
                                          Ok(f) => f,
                                          Err(e) => fail!("Couldn't open db: {}", e),
                                        }
                                     ))
        }
    }
}

impl Middleware for Sqlite3Middleware
{
    fn invoke(&self, req: &mut Request, _: &mut Response) -> Result<Action, NickelError>
    {
        req.map.insert(self.conn.clone());
        Ok(Continue)
    }
}

pub trait Sqlite3RequestExtensions
{
    fn db_conn(&self) -> &Arc<Mutex<DatabaseConnection>>;
}

impl<'a> Sqlite3RequestExtensions for Request<'a>
{
    fn db_conn(&self) -> &Arc<Mutex<DatabaseConnection>>
    {
        return match self.map.find::<Arc<Mutex<DatabaseConnection>>>()
        {
            Some(db) => db,
            None => fail!("Couldn't find DB connection."),
        }
    }
}
<commit_msg>Update to build against nickel.<commit_after>extern crate sync;
extern crate nickel;
extern crate sqlite3;

use nickel::{Request, Middleware, Response, Action, NickelError, Continue};
use sqlite3::core::DatabaseConnection;
use sqlite3::access;
use self::sync::{Mutex, Arc};

#[deriving(Clone)]
pub struct Sqlite3Middleware
{
    conn: Arc<Mutex<DatabaseConnection>>
}

impl Sqlite3Middleware
{
    pub fn new(file: String) -> Sqlite3Middleware
    {
        Sqlite3Middleware
        {
            conn: Arc::new(Mutex::new(match access::open(file)
                                        {
                                          Ok(f) => f,
                                          Err(e) => fail!("Couldn't open db: {}", e),
                                        }
                                     ))
        }
    }
}

impl Middleware for Sqlite3Middleware
{
    fn invoke(&self, req: &mut Request, _: &mut Response) -> Result<Action, NickelError>
    {
        req.map.insert(self.conn.clone());
        Ok(Continue)
    }
}

pub trait Sqlite3RequestExtensions
{
    fn db_conn(&self) -> &Arc<Mutex<DatabaseConnection>>;
}

impl<'a, 'b> Sqlite3RequestExtensions for Request<'a, 'b>
{
    fn db_conn(&self) -> &Arc<Mutex<DatabaseConnection>>
    {
        return match self.map.find::<Arc<Mutex<DatabaseConnection>>>()
        {
            Some(db) => db,
            None => fail!("Couldn't find DB connection."),
        }
    }
}
<|endoftext|>


<commit_before>use std::{fmt, mem};
use super::utils::{into_map, into_string, remove};
use super::{
    CurrentUser,
    FriendSourceFlags,
    GuildContainer,
    GuildId,
    GuildInfo,
    Mention,
    RoleId,
    UserSettings,
    User,
};
use ::client::rest::GuildPagination;
use ::internal::prelude::*;
use ::utils::builder::EditProfile;
use ::utils::decode_array;

#[cfg(feature = "methods")]
use serde_json::builder::ObjectBuilder;
#[cfg(feature = "methods")]
use super::Message;
#[cfg(feature = "methods")]
use time::Timespec;
#[cfg(feature = "methods")]
use ::client::rest;

#[cfg(feature = "cache")]
use ::client::CACHE;

impl CurrentUser {
    /// Returns the formatted URL of the user's icon, if one exists.
    pub fn avatar_url(&self) -> Option<String> {
        self.avatar.as_ref().map(|av|
            format!(cdn!("/avatars/{}/{}.jpg"), self.id, av))
    }

    /// Edits the current user's profile settings.
    ///
    /// This mutates the current user in-place.
    ///
    /// Refer to `EditProfile`'s documentation for its methods.
    ///
    /// # Examples
    ///
    /// Change the avatar:
    ///
    /// ```rust,no_run
    /// use serenity::client::CACHE;
    ///
    /// let avatar = serenity::utils::read_image("./avatar.png").unwrap();
    ///
    /// CACHE.write()
    ///     .unwrap()
    ///     .user
    ///     .edit(|p| p
    ///         .avatar(Some(&avatar)));
    /// ```
    #[cfg(feature = "methods")]
    pub fn edit<F>(&mut self, f: F) -> Result<()>
        where F: FnOnce(EditProfile) -> EditProfile {
        let mut map = ObjectBuilder::new()
            .insert("avatar", Some(&self.avatar))
            .insert("username", &self.name);

        if let Some(email) = self.email.as_ref() {
            map = map.insert("email", email)
        }

        let edited = f(EditProfile(map)).0.build();

        match rest::edit_profile(edited) {
            Ok(new) => {
                mem::replace(self, new);

                Ok(())
            },
            Err(why) => Err(why),
        }
    }

    /// Gets a list of guilds that the current user is in.
    pub fn guilds(&self) -> Result<Vec<GuildInfo>> {
        rest::get_guilds(GuildPagination::After(GuildId(0)), 100)
    }
}

impl User {
    /// Returns the formatted URL of the user's icon, if one exists.
    pub fn avatar_url(&self) -> Option<String> {
        self.avatar.as_ref().map(|av|
            format!(cdn!("/avatars/{}/{}.jpg"), self.id, av))
    }

    /// Retrieves the time that this user was created at.
    #[cfg(feature = "methods")]
    #[inline]
    pub fn created_at(&self) -> Timespec {
        self.id.created_at()
    }

    /// This is an alias of [direct_message].
    ///
    /// [direct_message]: #method.direct_message
    #[cfg(feature="methods")]
    pub fn dm(&self, content: &str) -> Result<Message> {
        self.direct_message(content)
    }

    /// Send a direct message to a user. This will create or retrieve the
    /// PrivateChannel over REST if one is not already in the cache, and then
    /// send a message to it.
    #[cfg(feature="methods")]
    pub fn direct_message(&self, content: &str)
        -> Result<Message> {
        let private_channel_id = feature_cache! {{
            let finding = CACHE.read()
                .unwrap()
                .private_channels
                .values()
                .find(|ch| ch.recipient.id == self.id)
                .map(|ch| ch.id);

            if let Some(finding) = finding {
                finding
            } else {
                let map = ObjectBuilder::new()
                    .insert("recipient_id", self.id.0)
                    .build();

                try!(rest::create_private_channel(map)).id
            }
        } else {
            let map = ObjectBuilder::new()
                .insert("recipient_id", self.id.0)
                .build();

            try!(rest::create_private_channel(map)).id
        }};

        let map = ObjectBuilder::new()
            .insert("content", content)
            .insert("nonce", "")
            .insert("tts", false)
            .build();

        rest::send_message(private_channel_id.0, map)
    }

    /// Check if a user has a [`Role`]. This will retrieve the
    /// [`Guild`] from the [`Cache`] if it is available, and then check if that
    /// guild has the given [`Role`].
    ///
    /// If the [`Guild`] is not present, then the guild will be retrieved from
    /// the API and the cache will be updated with it.
    ///
    /// If there are issues with requesting the API, then `false` will be
    /// returned.
    ///
    /// Three forms of data may be passed in to the guild parameter: either a
    /// [`Guild`] itself, a [`GuildId`], or a `u64`.
    ///
    /// # Examples
    ///
    /// Check if a guild has a [`Role`] by Id:
    ///
    /// ```rust,ignore
    /// // Assumes a 'guild' and `role_id` have already been bound
    /// context.message.author.has_role(guild, role_id);
    /// ```
    ///
    /// [`Guild`]: struct.Guild.html
    /// [`GuildId`]: struct.GuildId.html
    /// [`Role`]: struct.Role.html
    /// [`Cache`]: ../ext/cache/struct.Cache.html
    pub fn has_role<G, R>(&self, guild: G, role: R) -> bool
        where G: Into<GuildContainer>, R: Into<RoleId> {
        let role_id = role.into();

        match guild.into() {
            GuildContainer::Guild(guild) => {
                guild.roles.get(&role_id).is_some()
            },
            GuildContainer::Id(guild_id) => {
                feature_cache! {{
                    let cache = CACHE.read().unwrap();

                    cache.get_role(guild_id, role_id).is_some()
                } else {
                    true
                }}
            },
        }
    }

    /// Return a [`Mention`] which will ping this user.
    ///
    /// [`Mention`]: struct.Mention.html
    pub fn mention(&self) -> Mention {
        self.id.mention()
    }
}

impl fmt::Display for User {
    /// Formats a string which will mention the user.
    // This is in the format of: `<@USER_ID>`
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Display::fmt(&self.id.mention(), f)
    }
}

impl UserSettings {
    #[doc(hidden)]
    pub fn decode(value: Value) -> Result<Option<UserSettings>> {
        let mut map = try!(into_map(value));

        if map.is_empty() {
            return Ok(None);
        }

        Ok(UserSettings {
            convert_emoticons: req!(try!(remove(&mut map, "convert_emoticons")).as_bool()),
            enable_tts_command: req!(try!(remove(&mut map, "enable_tts_command")).as_bool()),
            friend_source_flags: try!(remove(&mut map, "friend_source_flags").and_then(FriendSourceFlags::decode)),
            inline_attachment_media: req!(try!(remove(&mut map, "inline_attachment_media")).as_bool()),
            inline_embed_media: req!(try!(remove(&mut map, "inline_embed_media")).as_bool()),
            locale: try!(remove(&mut map, "locale").and_then(into_string)),
            message_display_compact: req!(try!(remove(&mut map, "message_display_compact")).as_bool()),
            render_embeds: req!(try!(remove(&mut map, "render_embeds")).as_bool()),
            restricted_guilds: try!(remove(&mut map, "restricted_guilds").and_then(|v| decode_array(v, GuildId::decode))),
            show_current_game: req!(try!(remove(&mut map, "show_current_game")).as_bool()),
            theme: try!(remove(&mut map, "theme").and_then(into_string)),
        }).map(Some)
    }
}
<commit_msg>Add User::distinct<commit_after>use std::{fmt, mem};
use super::utils::{into_map, into_string, remove};
use super::{
    CurrentUser,
    FriendSourceFlags,
    GuildContainer,
    GuildId,
    GuildInfo,
    Mention,
    RoleId,
    UserSettings,
    User,
};
use ::client::rest::GuildPagination;
use ::internal::prelude::*;
use ::utils::builder::EditProfile;
use ::utils::decode_array;

#[cfg(feature = "methods")]
use serde_json::builder::ObjectBuilder;
#[cfg(feature = "methods")]
use super::Message;
#[cfg(feature = "methods")]
use time::Timespec;
#[cfg(feature = "methods")]
use ::client::rest;

#[cfg(feature = "cache")]
use ::client::CACHE;

impl CurrentUser {
    /// Returns the formatted URL of the user's icon, if one exists.
    pub fn avatar_url(&self) -> Option<String> {
        self.avatar.as_ref().map(|av|
            format!(cdn!("/avatars/{}/{}.jpg"), self.id, av))
    }

    /// Edits the current user's profile settings.
    ///
    /// This mutates the current user in-place.
    ///
    /// Refer to `EditProfile`'s documentation for its methods.
    ///
    /// # Examples
    ///
    /// Change the avatar:
    ///
    /// ```rust,no_run
    /// use serenity::client::CACHE;
    ///
    /// let avatar = serenity::utils::read_image("./avatar.png").unwrap();
    ///
    /// CACHE.write()
    ///     .unwrap()
    ///     .user
    ///     .edit(|p| p
    ///         .avatar(Some(&avatar)));
    /// ```
    #[cfg(feature = "methods")]
    pub fn edit<F>(&mut self, f: F) -> Result<()>
        where F: FnOnce(EditProfile) -> EditProfile {
        let mut map = ObjectBuilder::new()
            .insert("avatar", Some(&self.avatar))
            .insert("username", &self.name);

        if let Some(email) = self.email.as_ref() {
            map = map.insert("email", email)
        }

        let edited = f(EditProfile(map)).0.build();

        match rest::edit_profile(edited) {
            Ok(new) => {
                mem::replace(self, new);

                Ok(())
            },
            Err(why) => Err(why),
        }
    }

    /// Returns the DiscordTag(tm) of a User.
    pub fn distinct(&self) -> String {
        format!("{}#{}", self.name, self.discriminator)
    }

    /// Gets a list of guilds that the current user is in.
    pub fn guilds(&self) -> Result<Vec<GuildInfo>> {
        rest::get_guilds(GuildPagination::After(GuildId(0)), 100)
    }
}

impl User {
    /// Returns the formatted URL of the user's icon, if one exists.
    pub fn avatar_url(&self) -> Option<String> {
        self.avatar.as_ref().map(|av|
            format!(cdn!("/avatars/{}/{}.jpg"), self.id, av))
    }

    /// Retrieves the time that this user was created at.
    #[cfg(feature = "methods")]
    #[inline]
    pub fn created_at(&self) -> Timespec {
        self.id.created_at()
    }

    /// This is an alias of [direct_message].
    ///
    /// [direct_message]: #method.direct_message
    #[cfg(feature="methods")]
    pub fn dm(&self, content: &str) -> Result<Message> {
        self.direct_message(content)
    }

    /// Send a direct message to a user. This will create or retrieve the
    /// PrivateChannel over REST if one is not already in the cache, and then
    /// send a message to it.
    #[cfg(feature="methods")]
    pub fn direct_message(&self, content: &str)
        -> Result<Message> {
        let private_channel_id = feature_cache! {{
            let finding = CACHE.read()
                .unwrap()
                .private_channels
                .values()
                .find(|ch| ch.recipient.id == self.id)
                .map(|ch| ch.id);

            if let Some(finding) = finding {
                finding
            } else {
                let map = ObjectBuilder::new()
                    .insert("recipient_id", self.id.0)
                    .build();

                try!(rest::create_private_channel(map)).id
            }
        } else {
            let map = ObjectBuilder::new()
                .insert("recipient_id", self.id.0)
                .build();

            try!(rest::create_private_channel(map)).id
        }};

        let map = ObjectBuilder::new()
            .insert("content", content)
            .insert("nonce", "")
            .insert("tts", false)
            .build();

        rest::send_message(private_channel_id.0, map)
    }

    /// Check if a user has a [`Role`]. This will retrieve the
    /// [`Guild`] from the [`Cache`] if it is available, and then check if that
    /// guild has the given [`Role`].
    ///
    /// If the [`Guild`] is not present, then the guild will be retrieved from
    /// the API and the cache will be updated with it.
    ///
    /// If there are issues with requesting the API, then `false` will be
    /// returned.
    ///
    /// Three forms of data may be passed in to the guild parameter: either a
    /// [`Guild`] itself, a [`GuildId`], or a `u64`.
    ///
    /// # Examples
    ///
    /// Check if a guild has a [`Role`] by Id:
    ///
    /// ```rust,ignore
    /// // Assumes a 'guild' and `role_id` have already been bound
    /// context.message.author.has_role(guild, role_id);
    /// ```
    ///
    /// [`Guild`]: struct.Guild.html
    /// [`GuildId`]: struct.GuildId.html
    /// [`Role`]: struct.Role.html
    /// [`Cache`]: ../ext/cache/struct.Cache.html
    pub fn has_role<G, R>(&self, guild: G, role: R) -> bool
        where G: Into<GuildContainer>, R: Into<RoleId> {
        let role_id = role.into();

        match guild.into() {
            GuildContainer::Guild(guild) => {
                guild.roles.get(&role_id).is_some()
            },
            GuildContainer::Id(guild_id) => {
                feature_cache! {{
                    let cache = CACHE.read().unwrap();

                    cache.get_role(guild_id, role_id).is_some()
                } else {
                    true
                }}
            },
        }
    }

    /// Return a [`Mention`] which will ping this user.
    ///
    /// [`Mention`]: struct.Mention.html
    pub fn mention(&self) -> Mention {
        self.id.mention()
    }
}

impl fmt::Display for User {
    /// Formats a string which will mention the user.
    // This is in the format of: `<@USER_ID>`
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Display::fmt(&self.id.mention(), f)
    }
}

impl UserSettings {
    #[doc(hidden)]
    pub fn decode(value: Value) -> Result<Option<UserSettings>> {
        let mut map = try!(into_map(value));

        if map.is_empty() {
            return Ok(None);
        }

        Ok(UserSettings {
            convert_emoticons: req!(try!(remove(&mut map, "convert_emoticons")).as_bool()),
            enable_tts_command: req!(try!(remove(&mut map, "enable_tts_command")).as_bool()),
            friend_source_flags: try!(remove(&mut map, "friend_source_flags").and_then(FriendSourceFlags::decode)),
            inline_attachment_media: req!(try!(remove(&mut map, "inline_attachment_media")).as_bool()),
            inline_embed_media: req!(try!(remove(&mut map, "inline_embed_media")).as_bool()),
            locale: try!(remove(&mut map, "locale").and_then(into_string)),
            message_display_compact: req!(try!(remove(&mut map, "message_display_compact")).as_bool()),
            render_embeds: req!(try!(remove(&mut map, "render_embeds")).as_bool()),
            restricted_guilds: try!(remove(&mut map, "restricted_guilds").and_then(|v| decode_array(v, GuildId::decode))),
            show_current_game: req!(try!(remove(&mut map, "show_current_game")).as_bool()),
            theme: try!(remove(&mut map, "theme").and_then(into_string)),
        }).map(Some)
    }
}
<|endoftext|>


<commit_before>/// Module that provides various functions for working with files and the file system.

use modules::ModuleTable;
use runtime::Runtime;
use std::fs;
use std::fs::{File, OpenOptions};
use std::io::prelude::*;

pub const MTABLE: ModuleTable = ModuleTable(&[
    ("exists",      exists),
    ("is_dir",      is_dir),
    ("is_file",     is_file),
    ("is_symlink",  is_symlink),
    ("mkdir",       mkdir),
    ("copy",        copy),
    ("rename",      rename),
    ("remove",      remove),
    ("get",         get),
    ("put",         put),
    ("append",      append),
    ("combine",     combine),
]);

/// Checks if a file exists and is readable.
///
/// # Lua arguments
/// * `path: string`            - Path to the file to check.
fn exists(runtime: &mut Runtime, _: Option<usize>) -> i32 {
    let path = runtime.state().check_string(1).to_string();

    runtime.state().push_bool(
        fs::metadata(path).is_ok()
    );

    1
}

/// Checks if a given path is a directory.
///
/// # Lua arguments
/// * `path: string`            - Path to check.
fn is_dir(runtime: &mut Runtime, _: Option<usize>) -> i32 {
    let path = runtime.state().check_string(1).to_string();

    let metadata = fs::metadata(path);
    runtime.state().push_bool(
        metadata.is_ok() && metadata.unwrap().file_type().is_dir()
    );

    1
}

/// Checks if a given path is a file.
///
/// # Lua arguments
/// * `path: string`            - Path to check.
fn is_file(runtime: &mut Runtime, _: Option<usize>) -> i32 {
    let path = runtime.state().check_string(1).to_string();

    let metadata = fs::metadata(path);
    runtime.state().push_bool(
        metadata.is_ok() && metadata.unwrap().file_type().is_file()
    );

    1
}

/// Checks if a given path is a symbolic link.
///
/// # Lua arguments
/// * `path: string`            - Path to check.
fn is_symlink(runtime: &mut Runtime, _: Option<usize>) -> i32 {
    let path = runtime.state().check_string(1).to_string();

    let metadata = fs::metadata(path);
    runtime.state().push_bool(
        metadata.is_ok() && metadata.unwrap().file_type().is_symlink()
    );

    1
}

/// Creates a directory.
///
/// # Lua arguments
/// * `path: string`            - Path to create the directory.
fn mkdir(runtime: &mut Runtime, _: Option<usize>) -> i32 {
    // Get the path as the first argument.
    let path = runtime.state().check_string(1).to_string();

    if fs::create_dir(&path).is_err() {
        runtime.throw_error(&format!("file \"{}\" exists", path));
    }

    0
}

/// Copies a file to another location.
///
/// # Lua arguments
/// * `source: string`          - Path of the file to copy.
/// * `dest: string`            - Path to copy the file to.
fn copy(runtime: &mut Runtime, _: Option<usize>) -> i32 {
    let source = runtime.state().check_string(1).to_string();
    let dest = runtime.state().check_string(2).to_string();

    if fs::copy(&source, dest).is_err() {
        runtime.throw_error(&format!("failed to copy \"{}\"", source));
    }

    0
}

/// Moves a file from one name to another.
///
/// # Lua arguments
/// * `source: string`          - Path of the file to move.
/// * `dest: string`            - Path to move the file to.
fn rename(runtime: &mut Runtime, _: Option<usize>) -> i32 {
    let source = runtime.state().check_string(1).to_string();
    let destination = runtime.state().check_string(2).to_string();

    if fs::rename(source, destination).is_err() {
        runtime.throw_error("no such file or directory");
    }

    0
}

/// Removes a file or empty directory.
///
/// # Lua arguments
/// * `path: string`            - Path of the file or directory to remove.
fn remove(runtime: &mut Runtime, _: Option<usize>) -> i32 {
    let path = runtime.state().check_string(1).to_string();

    if let Ok(metadata) = fs::metadata(&path) {
        if metadata.file_type().is_dir() {
            if fs::remove_dir(path).is_err() {
                runtime.throw_error("failed to remove directory");
            }
        } else {
            if fs::remove_file(path).is_err() {
                runtime.throw_error("failed to remove file");
            }
        }
    }

    0
}

/// Reads an entire file and returns its contents.
///
/// # Lua arguments
/// * `path: string`            - Path of the file to read from.
fn get(runtime: &mut Runtime, _: Option<usize>) -> i32 {
    let path = runtime.state().check_string(1).to_string();

    let file = File::open(path);

    if file.is_err() {
        runtime.throw_error("failed to open file");
        return 0;
    }

    let mut file = file.unwrap();
    let mut buffer = String::new();

    if file.read_to_string(&mut buffer).is_err() {
        runtime.throw_error("failed to read file");
        return 0;
    }

    runtime.state().push_string(&buffer);

    1
}

/// Puts a string into the contents of a file.
///
/// # Lua arguments
/// * `path: string`            - Path to the file to write to.
/// * `contents: string`        - The contents to write.
fn put(runtime: &mut Runtime, _: Option<usize>) -> i32 {
    let path = runtime.state().check_string(1).to_string();
    let contents = String::from(runtime.state().check_string(2));

    let file = OpenOptions::new()
                .write(true)
                .truncate(true)
                .create(true)
                .open(path);

    if file.is_err() {
        runtime.throw_error("failed to open file");
        return 0;
    }

    let mut file = file.unwrap();
    if file.write_all(contents.as_bytes()).is_err() {
        runtime.throw_error("failed to write to file");
    }

    0
}

/// Appends a string to the end of the contents of a file.
///
/// # Lua arguments
/// * `path: string`            - Path to the file to append to.
/// * `contents: string`        - The contents to append.
fn append(runtime: &mut Runtime, _: Option<usize>) -> i32 {
    let path = runtime.state().check_string(1).to_string();
    let contents = String::from(runtime.state().check_string(2));

    let file = OpenOptions::new()
                .write(true)
                .append(true)
                .open(path);

    if file.is_err() {
        runtime.throw_error("failed to open file");
        return 0;
    }

    let mut file = file.unwrap();
    if file.write_all(contents.as_bytes()).is_err() {
        runtime.throw_error("failed to write to file");
    }

    0
}

/// Combines the contents of two or more files into a new, single file.
///
/// # Lua arguments
/// * `sources: table`          - A list of source files to combine.
/// * `dest: string`            - The path to the output file.
fn combine(runtime: &mut Runtime, _: Option<usize>) -> i32 {
    if !runtime.state().is_table(1) {
        runtime.throw_error("first argument must be a table");
        return 0;
    }

    // Open the output file for writing.
    let dest = runtime.state().check_string(2).to_string();
    let out_file = OpenOptions::new()
                .write(true)
                .truncate(true)
                .create(true)
                .open(&dest);

    if out_file.is_err() {
        runtime.throw_error(&format!("failed to open file \"{}\"", dest));
        return 0;
    }

    let mut out_file = out_file.unwrap();

    // Walk through each path in the sources table and write their contents.
    runtime.state().push_nil();
    while runtime.state().next(1) {
        runtime.state().push_value(-2);
        let source = runtime.state().to_str(-2).unwrap().to_string();

        let in_file = File::open(&source);
        if in_file.is_err() {
            runtime.throw_error(&format!("failed to open file \"{}\"", source));
            return 0;
        }

        // Read the source file's contents.
        let mut in_file = in_file.unwrap();
        let mut buffer = String::new();

        if in_file.read_to_string(&mut buffer).is_err() {
            runtime.throw_error(&format!("failed to read file \"{}\"", source));
            return 0;
        }

        // Write the source file contents into the output file.
        if out_file.write_all(buffer.as_bytes()).is_err() {
            runtime.throw_error(&format!("failed to write to file \"{}\"", dest));
            return 0;
        }

        runtime.state().pop(1);
    }

    0
}
<commit_msg>Fix error message<commit_after>/// Module that provides various functions for working with files and the file system.

use modules::ModuleTable;
use runtime::Runtime;
use std::fs;
use std::fs::{File, OpenOptions};
use std::io::prelude::*;

pub const MTABLE: ModuleTable = ModuleTable(&[
    ("exists",      exists),
    ("is_dir",      is_dir),
    ("is_file",     is_file),
    ("is_symlink",  is_symlink),
    ("mkdir",       mkdir),
    ("copy",        copy),
    ("rename",      rename),
    ("remove",      remove),
    ("get",         get),
    ("put",         put),
    ("append",      append),
    ("combine",     combine),
]);

/// Checks if a file exists and is readable.
///
/// # Lua arguments
/// * `path: string`            - Path to the file to check.
fn exists(runtime: &mut Runtime, _: Option<usize>) -> i32 {
    let path = runtime.state().check_string(1).to_string();

    runtime.state().push_bool(
        fs::metadata(path).is_ok()
    );

    1
}

/// Checks if a given path is a directory.
///
/// # Lua arguments
/// * `path: string`            - Path to check.
fn is_dir(runtime: &mut Runtime, _: Option<usize>) -> i32 {
    let path = runtime.state().check_string(1).to_string();

    let metadata = fs::metadata(path);
    runtime.state().push_bool(
        metadata.is_ok() && metadata.unwrap().file_type().is_dir()
    );

    1
}

/// Checks if a given path is a file.
///
/// # Lua arguments
/// * `path: string`            - Path to check.
fn is_file(runtime: &mut Runtime, _: Option<usize>) -> i32 {
    let path = runtime.state().check_string(1).to_string();

    let metadata = fs::metadata(path);
    runtime.state().push_bool(
        metadata.is_ok() && metadata.unwrap().file_type().is_file()
    );

    1
}

/// Checks if a given path is a symbolic link.
///
/// # Lua arguments
/// * `path: string`            - Path to check.
fn is_symlink(runtime: &mut Runtime, _: Option<usize>) -> i32 {
    let path = runtime.state().check_string(1).to_string();

    let metadata = fs::metadata(path);
    runtime.state().push_bool(
        metadata.is_ok() && metadata.unwrap().file_type().is_symlink()
    );

    1
}

/// Creates a directory.
///
/// # Lua arguments
/// * `path: string`            - Path to create the directory.
fn mkdir(runtime: &mut Runtime, _: Option<usize>) -> i32 {
    // Get the path as the first argument.
    let path = runtime.state().check_string(1).to_string();

    if fs::create_dir(&path).is_err() {
        runtime.throw_error(&format!("fiailed to create directory \"{}\"", path));
    }

    0
}

/// Copies a file to another location.
///
/// # Lua arguments
/// * `source: string`          - Path of the file to copy.
/// * `dest: string`            - Path to copy the file to.
fn copy(runtime: &mut Runtime, _: Option<usize>) -> i32 {
    let source = runtime.state().check_string(1).to_string();
    let dest = runtime.state().check_string(2).to_string();

    if fs::copy(&source, dest).is_err() {
        runtime.throw_error(&format!("failed to copy \"{}\"", source));
    }

    0
}

/// Moves a file from one name to another.
///
/// # Lua arguments
/// * `source: string`          - Path of the file to move.
/// * `dest: string`            - Path to move the file to.
fn rename(runtime: &mut Runtime, _: Option<usize>) -> i32 {
    let source = runtime.state().check_string(1).to_string();
    let destination = runtime.state().check_string(2).to_string();

    if fs::rename(source, destination).is_err() {
        runtime.throw_error("no such file or directory");
    }

    0
}

/// Removes a file or empty directory.
///
/// # Lua arguments
/// * `path: string`            - Path of the file or directory to remove.
fn remove(runtime: &mut Runtime, _: Option<usize>) -> i32 {
    let path = runtime.state().check_string(1).to_string();

    if let Ok(metadata) = fs::metadata(&path) {
        if metadata.file_type().is_dir() {
            if fs::remove_dir_all(path).is_err() {
                runtime.throw_error("failed to remove directory");
            }
        } else {
            if fs::remove_file(path).is_err() {
                runtime.throw_error("failed to remove file");
            }
        }
    }

    0
}

/// Reads an entire file and returns its contents.
///
/// # Lua arguments
/// * `path: string`            - Path of the file to read from.
fn get(runtime: &mut Runtime, _: Option<usize>) -> i32 {
    let path = runtime.state().check_string(1).to_string();

    let file = File::open(path);

    if file.is_err() {
        runtime.throw_error("failed to open file");
        return 0;
    }

    let mut file = file.unwrap();
    let mut buffer = String::new();

    if file.read_to_string(&mut buffer).is_err() {
        runtime.throw_error("failed to read file");
        return 0;
    }

    runtime.state().push_string(&buffer);

    1
}

/// Puts a string into the contents of a file.
///
/// # Lua arguments
/// * `path: string`            - Path to the file to write to.
/// * `contents: string`        - The contents to write.
fn put(runtime: &mut Runtime, _: Option<usize>) -> i32 {
    let path = runtime.state().check_string(1).to_string();
    let contents = String::from(runtime.state().check_string(2));

    let file = OpenOptions::new()
                .write(true)
                .truncate(true)
                .create(true)
                .open(path);

    if file.is_err() {
        runtime.throw_error("failed to open file");
        return 0;
    }

    let mut file = file.unwrap();
    if file.write_all(contents.as_bytes()).is_err() {
        runtime.throw_error("failed to write to file");
    }

    0
}

/// Appends a string to the end of the contents of a file.
///
/// # Lua arguments
/// * `path: string`            - Path to the file to append to.
/// * `contents: string`        - The contents to append.
fn append(runtime: &mut Runtime, _: Option<usize>) -> i32 {
    let path = runtime.state().check_string(1).to_string();
    let contents = String::from(runtime.state().check_string(2));

    let file = OpenOptions::new()
                .write(true)
                .append(true)
                .open(path);

    if file.is_err() {
        runtime.throw_error("failed to open file");
        return 0;
    }

    let mut file = file.unwrap();
    if file.write_all(contents.as_bytes()).is_err() {
        runtime.throw_error("failed to write to file");
    }

    0
}

/// Combines the contents of two or more files into a new, single file.
///
/// # Lua arguments
/// * `sources: table`          - A list of source files to combine.
/// * `dest: string`            - The path to the output file.
fn combine(runtime: &mut Runtime, _: Option<usize>) -> i32 {
    if !runtime.state().is_table(1) {
        runtime.throw_error("first argument must be a table");
        return 0;
    }

    // Open the output file for writing.
    let dest = runtime.state().check_string(2).to_string();
    let out_file = OpenOptions::new()
                .write(true)
                .truncate(true)
                .create(true)
                .open(&dest);

    if out_file.is_err() {
        runtime.throw_error(&format!("failed to open file \"{}\"", dest));
        return 0;
    }

    let mut out_file = out_file.unwrap();

    // Walk through each path in the sources table and write their contents.
    runtime.state().push_nil();
    while runtime.state().next(1) {
        runtime.state().push_value(-2);
        let source = runtime.state().to_str(-2).unwrap().to_string();

        let in_file = File::open(&source);
        if in_file.is_err() {
            runtime.throw_error(&format!("failed to open file \"{}\"", source));
            return 0;
        }

        // Read the source file's contents.
        let mut in_file = in_file.unwrap();
        let mut buffer = String::new();

        if in_file.read_to_string(&mut buffer).is_err() {
            runtime.throw_error(&format!("failed to read file \"{}\"", source));
            return 0;
        }

        // Write the source file contents into the output file.
        if out_file.write_all(buffer.as_bytes()).is_err() {
            runtime.throw_error(&format!("failed to write to file \"{}\"", dest));
            return 0;
        }

        runtime.state().pop(1);
    }

    0
}
<|endoftext|>