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

use std::collections::btree_map::BTreeMap;
use std::thread;
use std::fs::{File};
use std::path::Path;
use std::fmt::{Debug, Formatter};
use std::fmt::Result as FmtResult;
use std::sync::{Mutex, RwLock};
use std::sync::mpsc::{channel, Sender, Receiver};
use std::io::Read;
use super::LUA;

use convert::json::lua_to_json;

use rustc_serialize::json::Json;
use uuid::Uuid;
use rlua;

use super::types::*;
use super::rust_interop;
use super::init_path;
use super::super::keys;

use registry::{self};

use ::layout::{lock_tree, ContainerType};

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);

    /// Requests to update the registry state from Lua
    static ref REGISTRY_QUEUE: RwLock<Vec<String>> = RwLock::new(vec![]);
}

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

const INIT_LUA_FUNC: &'static str = "way_cooler.on_init()";
const LUA_TERMINATE_CODE: &'static str = "way_cooler.on_terminate()";
const LUA_RESTART_CODE: &'static str = "way_cooler.on_restart()";

/// 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)
}

/// Appends this combination of category and key to the registry queue.
pub fn update_registry_value(category: String) {
    let mut queue = REGISTRY_QUEUE.write().expect(ERR_LOCK_QUEUE);
    queue.push(category);
}

// 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() -> Result<(), rlua::Error> {
    info!("Initializing lua...");
    let (tx, receiver) = channel();
    *SENDER.lock().expect(ERR_LOCK_SENDER) = Some(tx);
    let mut lua = LUA.lock().expect("LUA was poisoned!");
    let mut lua = &mut lua.0;
    info!("Loading way-cooler libraries...");
    rust_interop::register_libraries(&mut lua)?;

    let (use_config, maybe_init_file) = init_path::get_config();
    if use_config {
        match maybe_init_file {
            Ok((init_dir, mut init_file)) => {
                if init_dir.components().next().is_some() {
                    // Add the config directory to the package path.
                    let globals = lua.globals();
                    let package: rlua::Table = globals.get("package")
                        .expect("package not defined in Lua");
                    let paths: String = package.get("path")
                        .expect("package.path not defined in Lua");
                    package.set("path", paths + ";" + init_dir.join("?.lua").to_str()
                                .expect("init_dir not a valid UTF-8 string"))?;
                }
                let mut init_contents = String::new();
                init_file.read_to_string(&mut init_contents)
                    .expect("Could not read contents");
                lua.exec(init_contents.as_str(), Some("init.lua".into()))
                    .map(|_:()| info!("Read init.lua successfully"))
                    .or_else(|err| {
                        match err {
                            rlua::Error::RuntimeError(ref err) => {
                                error!("{}", err);
                            }
                            rlua::Error::CallbackError{traceback: ref err, ref cause } => {
                                error!("traceback: {}", err);
                                error!("cause: {}", *cause)
                            },
                            err => {
                                error!("init file error: {:?}", err);
                            }
                        }
                        // Keeping this an error, so that it is visible
                        // in release builds.
                        info!("Defaulting to pre-compiled init.lua");
                        lua.exec(init_path::DEFAULT_CONFIG,
                                 Some("init.lua <DEFAULT>".into()))
                        })
                    .expect("Unable to load pre-compiled init file");
            }
            Err(_) => {
                warn!("Defaulting to pre-compiled init.lua");
                let _: () = lua.exec(init_path::DEFAULT_CONFIG,
                                     Some("init.lua <DEFAULT>".into()))
                    .expect("Unable to load pre-compiled init file");
            }
        }
    }
    else {
        info!("Skipping config search");
    }

    // Only ready after loading libs
    *RUNNING.write().expect(ERR_LOCK_RUNNING) = true;
    info!("Entering main loop...");
    let _lua_handle = thread::Builder::new()
        .name("Lua thread".to_string())
        .spawn(move || main_loop(receiver));
    // Immediately update all the values that the init file set
    send(LuaQuery::UpdateRegistryFromCache)
        .expect("Could not update registry from cache");

    // Re-tile the layout tree, to make any changes appear immediantly.
    if let Ok(mut tree) = lock_tree() {
        tree.layout_active_of(ContainerType::Root)
            .unwrap_or_else(|_| {
                warn!("Lua thread could not re-tile the layout tree");
            });
        // Yeah this is silly, it's so the active border can be updated properly.
        if let Some(active_id) = tree.active_id() {
            tree.focus(active_id)
                .expect("Could not focus on the focused id");
        }
    }
    Ok(())
}

pub fn on_compositor_ready() {
    info!("Running lua on_init()");
    // Call the special init hook function that we read from the init file
    send(LuaQuery::Execute(INIT_LUA_FUNC.to_owned())).err()
        .map(|error| warn!("Lua init callback returned an error: {:?}", error));
}

/// Main loop of the Lua thread:
///
/// ## Loop
/// * Wait for a message from the receiver
/// * Handle message
/// * Send response
fn main_loop(receiver: Receiver<LuaMessage>) {
    loop {
        trace!("Lua: awaiting request");
        let request = receiver.recv();
        let mut lua = LUA.lock().expect("LUA was poisoned!");
        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");
                if !handle_message(message, &mut lua.0) {
                    return
                }
            }
        }
    }
}

/// Handle each LuaQuery option sent to the thread
fn handle_message(request: LuaMessage, lua: &mut rlua::Lua) -> bool {
    match request.query {
        LuaQuery::Terminate => {
            trace!("Received terminate signal");
            if let Err(error) = lua.exec::<()>(LUA_TERMINATE_CODE,
                                               Some("custom terminate code".into())) {
                warn!("Lua termination callback returned an error: {:?}", error);
                warn!("However, termination will continue");
            }
            *RUNNING.write().expect(ERR_LOCK_RUNNING) = false;
            thread_send(request.reply, LuaResponse::Pong);

            info!("Lua thread terminating!");
            return false
        },
        LuaQuery::Restart => {
            trace!("Received restart signal!");
            if let Err(error) = lua.exec::<()>(LUA_RESTART_CODE,
                                         Some("custom restart code".into())) {
                warn!("Lua restart callback returned an error: {:?}", error);
                warn!("However, Lua will be restarted");
            }
            *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 || {
                    init().expect("Could not init");
                    keys::init();
                });

            info!("Lua thread restarting");
            return false
        },
        LuaQuery::Execute(code) => {
            trace!("Received request to execute {}", code);

            match lua.exec::<()>(&code, None) {
                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(mut file) = try_file {
                let mut file_contents = String::new();
                file.read_to_string(&mut file_contents)
                    .expect("Could not read file contents");
                let result = lua.exec::<rlua::Value>(file_contents.as_str(),
                                      Some(name.as_str()));
                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 =
                    rlua::Error::RuntimeError(format!("{:#?}", 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::HandleKey(press) => {
            trace!("Lua: handling keypress {}", &press);
            let press_ix = press.get_lua_index_string();
            // Access the index
            let code = format!("__key_map['{}']()", press_ix);
            match lua.exec::<()>(&code, Some(&format!("{}", press))) {
                Err(error) => {
                    if let rlua::Error::RuntimeError(ref err) = error {
                        warn!("Error handling {}:\n {}", press, err);
                    } else {
                        warn!("Error handling {}: {:?}", press, error);
                    }
                    thread_send(request.reply, LuaResponse::Error(error));
                }
                Ok(_) => {
                    trace!("Handled keypress okay.");
                    thread_send(request.reply, LuaResponse::Pong);
                }
            }
        }
        LuaQuery::Ping => {
            thread_send(request.reply, LuaResponse::Pong);
        },
        LuaQuery::UpdateRegistryFromCache => {
            let lock = registry::clients_read();
            // Lua has access to everything
            let client = lock.client(Uuid::nil()).unwrap();
            let mut handle = registry::WriteHandle::new(&client);

            let mut queue = REGISTRY_QUEUE.write().expect(ERR_LOCK_QUEUE);
            for category in queue.drain(0..) {
                let globals = lua.globals();
                let registry_cache: rlua::Table = globals.get("__registry_cache")
                    .expect("__registry_cache wasn't defined");
                let category_str = lua.create_string(category.as_str());
                if let Ok(mut category_table) = registry_cache.get::<rlua::String, rlua::Table>(category_str) {
                    let cat_table = match handle.write(category.clone()) {
                        Ok(cat) => cat,
                        Err(err) => {
                            warn!("Could not lock {}: {:?}", category, err);
                            break;
                        }
                    };
                    update_values(&mut category_table, cat_table);
                }
                drop(registry_cache)
            }
            lua.exec::<()>("__registry_cache = {}", None)
                .expect("Could not clear __registry_cache");
        },
    }
    return true
}

fn update_values<'lua>(table: &mut rlua::Table<'lua>,
                    category: &mut registry::Category) {
    use rlua::Value;
    let mut keys = Vec::new();
    for entry in table.clone().pairs::<rlua::String, Value>() {
        if let Ok((key, value)) = entry {
            match value {
                rlua::Value::Table(_) => {
                    keys.push(key.clone());
                    category.insert(key.to_str().unwrap().into(),
                                    Json::Object(BTreeMap::new()));
                },
                value => {
                    match lua_to_json(value) {
                        Ok(val) => {
                            trace!("Updating {}:{:?} = {:#?}", category.name(), key, &val);
                            category.insert(key.to_str().unwrap().into(), val);
                        },
                        Err(value) => {
                            warn!("Could not translate {:?} to JSON", value);
                        }
                    }
                }
            }
        }
    }
    for key in keys {
        let inner_mapping = category.get_mut(key.to_str().unwrap())
            .expect("Could not get the value we just made")
            .as_object_mut()
            .expect("The inner value was not an object!");
        if let Ok(inner_table) = table.get::<rlua::String, rlua::Table>(key) {
            for entry in inner_table.pairs::<rlua::String, Value>() {
                if let Ok((key, value)) = entry {
                    match value {
                        rlua::Value::Table(_) => {
                            warn!("Dropping inner table {:?}", key);
                        },
                        value => {
                            if let Ok(val) = lua_to_json(value) {
                                inner_mapping.insert(key.to_str().unwrap().into(),
                                                     val);
                            }
                        }
                    }
                }
            }
        }
    }
}

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>Fixes #382<commit_after>//! Code for the internal Lua thread which handles all Lua requests.

use std::collections::btree_map::BTreeMap;
use std::thread;
use std::fs::{File};
use std::path::Path;
use std::fmt::{Debug, Formatter};
use std::fmt::Result as FmtResult;
use std::sync::{Mutex, RwLock};
use std::sync::mpsc::{channel, Sender, Receiver};
use std::io::Read;
use super::LUA;

use convert::json::lua_to_json;

use rustc_serialize::json::Json;
use uuid::Uuid;
use rlua;

use super::types::*;
use super::rust_interop;
use super::init_path;
use super::super::keys;

use registry::{self};

use ::layout::{lock_tree, ContainerType};

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);

    /// Requests to update the registry state from Lua
    static ref REGISTRY_QUEUE: RwLock<Vec<String>> = RwLock::new(vec![]);
}

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

const INIT_LUA_FUNC: &'static str = "way_cooler.on_init()";
const LUA_TERMINATE_CODE: &'static str = "way_cooler.on_terminate()";
const LUA_RESTART_CODE: &'static str = "way_cooler.on_restart()";

/// 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)
}

/// Appends this combination of category and key to the registry queue.
pub fn update_registry_value(category: String) {
    let mut queue = REGISTRY_QUEUE.write().expect(ERR_LOCK_QUEUE);
    queue.push(category);
}

// 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() -> Result<(), rlua::Error> {
    info!("Initializing lua...");
    let (tx, receiver) = channel();
    *SENDER.lock().expect(ERR_LOCK_SENDER) = Some(tx);
    let mut lua = LUA.lock().expect("LUA was poisoned!");
    let mut lua = &mut lua.0;
    info!("Loading way-cooler libraries...");
    rust_interop::register_libraries(&mut lua)?;

    let (use_config, maybe_init_file) = init_path::get_config();
    if use_config {
        match maybe_init_file {
            Ok((init_dir, mut init_file)) => {
                if init_dir.components().next().is_some() {
                    // Add the config directory to the package path.
                    let globals = lua.globals();
                    let package: rlua::Table = globals.get("package")
                        .expect("package not defined in Lua");
                    let paths: String = package.get("path")
                        .expect("package.path not defined in Lua");
                    package.set("path", paths + ";" + init_dir.join("?.lua").to_str()
                                .expect("init_dir not a valid UTF-8 string"))?;
                }
                let mut init_contents = String::new();
                init_file.read_to_string(&mut init_contents)
                    .expect("Could not read contents");
                lua.exec(init_contents.as_str(), Some("init.lua".into()))
                    .map(|_:()| info!("Read init.lua successfully"))
                    .or_else(|err| {
                        match err {
                            rlua::Error::RuntimeError(ref err) => {
                                error!("{}", err);
                            }
                            rlua::Error::CallbackError{traceback: ref err, ref cause } => {
                                error!("traceback: {}", err);
                                error!("cause: {}", *cause)
                            },
                            err => {
                                error!("init file error: {:?}", err);
                            }
                        }
                        // Keeping this an error, so that it is visible
                        // in release builds.
                        info!("Defaulting to pre-compiled init.lua");
                        *lua = rlua::Lua::new();
                        rust_interop::register_libraries(&mut lua)?;
                        lua.exec(init_path::DEFAULT_CONFIG,
                                 Some("init.lua <DEFAULT>".into()))
                        })
                    .expect("Unable to load pre-compiled init file");
            }
            Err(_) => {
                warn!("Defaulting to pre-compiled init.lua");
                let _: () = lua.exec(init_path::DEFAULT_CONFIG,
                                     Some("init.lua <DEFAULT>".into()))
                    .expect("Unable to load pre-compiled init file");
            }
        }
    }
    else {
        info!("Skipping config search");
    }

    // Only ready after loading libs
    *RUNNING.write().expect(ERR_LOCK_RUNNING) = true;
    info!("Entering main loop...");
    let _lua_handle = thread::Builder::new()
        .name("Lua thread".to_string())
        .spawn(move || main_loop(receiver));
    // Immediately update all the values that the init file set
    send(LuaQuery::UpdateRegistryFromCache)
        .expect("Could not update registry from cache");

    // Re-tile the layout tree, to make any changes appear immediantly.
    if let Ok(mut tree) = lock_tree() {
        tree.layout_active_of(ContainerType::Root)
            .unwrap_or_else(|_| {
                warn!("Lua thread could not re-tile the layout tree");
            });
        // Yeah this is silly, it's so the active border can be updated properly.
        if let Some(active_id) = tree.active_id() {
            tree.focus(active_id)
                .expect("Could not focus on the focused id");
        }
    }
    Ok(())
}

pub fn on_compositor_ready() {
    info!("Running lua on_init()");
    // Call the special init hook function that we read from the init file
    send(LuaQuery::Execute(INIT_LUA_FUNC.to_owned())).err()
        .map(|error| warn!("Lua init callback returned an error: {:?}", error));
}

/// Main loop of the Lua thread:
///
/// ## Loop
/// * Wait for a message from the receiver
/// * Handle message
/// * Send response
fn main_loop(receiver: Receiver<LuaMessage>) {
    loop {
        trace!("Lua: awaiting request");
        let request = receiver.recv();
        let mut lua = LUA.lock().expect("LUA was poisoned!");
        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");
                if !handle_message(message, &mut lua.0) {
                    return
                }
            }
        }
    }
}

/// Handle each LuaQuery option sent to the thread
fn handle_message(request: LuaMessage, lua: &mut rlua::Lua) -> bool {
    match request.query {
        LuaQuery::Terminate => {
            trace!("Received terminate signal");
            if let Err(error) = lua.exec::<()>(LUA_TERMINATE_CODE,
                                               Some("custom terminate code".into())) {
                warn!("Lua termination callback returned an error: {:?}", error);
                warn!("However, termination will continue");
            }
            *RUNNING.write().expect(ERR_LOCK_RUNNING) = false;
            thread_send(request.reply, LuaResponse::Pong);

            info!("Lua thread terminating!");
            return false
        },
        LuaQuery::Restart => {
            trace!("Received restart signal!");
            if let Err(error) = lua.exec::<()>(LUA_RESTART_CODE,
                                         Some("custom restart code".into())) {
                warn!("Lua restart callback returned an error: {:?}", error);
                warn!("However, Lua will be restarted");
            }
            *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 || {
                    init().expect("Could not init");
                    keys::init();
                });

            info!("Lua thread restarting");
            return false
        },
        LuaQuery::Execute(code) => {
            trace!("Received request to execute {}", code);

            match lua.exec::<()>(&code, None) {
                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(mut file) = try_file {
                let mut file_contents = String::new();
                file.read_to_string(&mut file_contents)
                    .expect("Could not read file contents");
                let result = lua.exec::<rlua::Value>(file_contents.as_str(),
                                      Some(name.as_str()));
                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 =
                    rlua::Error::RuntimeError(format!("{:#?}", 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::HandleKey(press) => {
            trace!("Lua: handling keypress {}", &press);
            let press_ix = press.get_lua_index_string();
            // Access the index
            let code = format!("__key_map['{}']()", press_ix);
            match lua.exec::<()>(&code, Some(&format!("{}", press))) {
                Err(error) => {
                    if let rlua::Error::RuntimeError(ref err) = error {
                        warn!("Error handling {}:\n {}", press, err);
                    } else {
                        warn!("Error handling {}: {:?}", press, error);
                    }
                    thread_send(request.reply, LuaResponse::Error(error));
                }
                Ok(_) => {
                    trace!("Handled keypress okay.");
                    thread_send(request.reply, LuaResponse::Pong);
                }
            }
        }
        LuaQuery::Ping => {
            thread_send(request.reply, LuaResponse::Pong);
        },
        LuaQuery::UpdateRegistryFromCache => {
            let lock = registry::clients_read();
            // Lua has access to everything
            let client = lock.client(Uuid::nil()).unwrap();
            let mut handle = registry::WriteHandle::new(&client);

            let mut queue = REGISTRY_QUEUE.write().expect(ERR_LOCK_QUEUE);
            for category in queue.drain(0..) {
                let globals = lua.globals();
                let registry_cache: rlua::Table = globals.get("__registry_cache")
                    .expect("__registry_cache wasn't defined");
                let category_str = lua.create_string(category.as_str());
                if let Ok(mut category_table) = registry_cache.get::<rlua::String, rlua::Table>(category_str) {
                    let cat_table = match handle.write(category.clone()) {
                        Ok(cat) => cat,
                        Err(err) => {
                            warn!("Could not lock {}: {:?}", category, err);
                            break;
                        }
                    };
                    update_values(&mut category_table, cat_table);
                }
                drop(registry_cache)
            }
            lua.exec::<()>("__registry_cache = {}", None)
                .expect("Could not clear __registry_cache");
        },
    }
    return true
}

fn update_values<'lua>(table: &mut rlua::Table<'lua>,
                    category: &mut registry::Category) {
    use rlua::Value;
    let mut keys = Vec::new();
    for entry in table.clone().pairs::<rlua::String, Value>() {
        if let Ok((key, value)) = entry {
            match value {
                rlua::Value::Table(_) => {
                    keys.push(key.clone());
                    category.insert(key.to_str().unwrap().into(),
                                    Json::Object(BTreeMap::new()));
                },
                value => {
                    match lua_to_json(value) {
                        Ok(val) => {
                            trace!("Updating {}:{:?} = {:#?}", category.name(), key, &val);
                            category.insert(key.to_str().unwrap().into(), val);
                        },
                        Err(value) => {
                            warn!("Could not translate {:?} to JSON", value);
                        }
                    }
                }
            }
        }
    }
    for key in keys {
        let inner_mapping = category.get_mut(key.to_str().unwrap())
            .expect("Could not get the value we just made")
            .as_object_mut()
            .expect("The inner value was not an object!");
        if let Ok(inner_table) = table.get::<rlua::String, rlua::Table>(key) {
            for entry in inner_table.pairs::<rlua::String, Value>() {
                if let Ok((key, value)) = entry {
                    match value {
                        rlua::Value::Table(_) => {
                            warn!("Dropping inner table {:?}", key);
                        },
                        value => {
                            if let Ok(val) = lua_to_json(value) {
                                inner_mapping.insert(key.to_str().unwrap().into(),
                                                     val);
                            }
                        }
                    }
                }
            }
        }
    }
}

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>// ignore-tidy-undocumented-unsafe

use crate::cmp;
use crate::mem::{self, MaybeUninit};
use crate::ptr;

/// Rotates the range `[mid-left, mid+right)` such that the element at `mid` becomes the first
/// element. Equivalently, rotates the range `left` elements to the left or `right` elements to the
/// right.
///
/// # Safety
///
/// The specified range must be valid for reading and writing.
///
/// # Algorithm
///
/// Algorithm 1 is used for small values of `left + right` or for large `T`. The elements are moved
/// into their final positions one at a time starting at `mid - left` and advancing by `right` steps
/// modulo `left + right`, such that only one temporary is needed. Eventually, we arrive back at
/// `mid - left`. However, if `gcd(left + right, right)` is not 1, the above steps skipped over
/// elements. For example:
/// ```text
/// left = 10, right = 6
/// the `^` indicates an element in its final place
/// 6 7 8 9 10 11 12 13 14 15 . 0 1 2 3 4 5
/// after using one step of the above algorithm (The X will be overwritten at the end of the round,
/// and 12 is stored in a temporary):
/// X 7 8 9 10 11 6 13 14 15 . 0 1 2 3 4 5
///               ^
/// after using another step (now 2 is in the temporary):
/// X 7 8 9 10 11 6 13 14 15 . 0 1 12 3 4 5
///               ^                 ^
/// after the third step (the steps wrap around, and 8 is in the temporary):
/// X 7 2 9 10 11 6 13 14 15 . 0 1 12 3 4 5
///     ^         ^                 ^
/// after 7 more steps, the round ends with the temporary 0 getting put in the X:
/// 0 7 2 9 4 11 6 13 8 15 . 10 1 12 3 14 5
/// ^   ^   ^    ^    ^       ^    ^    ^
/// ```
/// Fortunately, the number of skipped over elements between finalized elements is always equal, so
/// we can just offset our starting position and do more rounds (the total number of rounds is the
/// `gcd(left + right, right)` value). The end result is that all elements are finalized once and
/// only once.
///
/// Algorithm 2 is used if `left + right` is large but `min(left, right)` is small enough to
/// fit onto a stack buffer. The `min(left, right)` elements are copied onto the buffer, `memmove`
/// is applied to the others, and the ones on the buffer are moved back into the hole on the
/// opposite side of where they originated.
///
/// Algorithms that can be vectorized outperform the above once `left + right` becomes large enough.
/// Algorithm 1 can be vectorized by chunking and performing many rounds at once, but there are too
/// few rounds on average until `left + right` is enormous, and the worst case of a single
/// round is always there. Instead, algorithm 3 utilizes repeated swapping of
/// `min(left, right)` elements until a smaller rotate problem is left.
///
/// ```text
/// left = 11, right = 4
/// [4 5 6 7 8 9 10 11 12 13 14 . 0 1 2 3]
///                  ^  ^  ^  ^   ^ ^ ^ ^ swapping the right most elements with elements to the left
/// [4 5 6 7 8 9 10 . 0 1 2 3] 11 12 13 14
///        ^ ^ ^  ^   ^ ^ ^ ^ swapping these
/// [4 5 6 . 0 1 2 3] 7 8 9 10 11 12 13 14
/// we cannot swap any more, but a smaller rotation problem is left to solve
/// ```
/// when `left < right` the swapping happens from the left instead.
pub unsafe fn ptr_rotate<T>(mut left: usize, mut mid: *mut T, mut right: usize) {
    type BufType = [usize; 32];
    if mem::size_of::<T>() == 0 {
        return;
    }
    loop {
        // N.B. the below algorithms can fail if these cases are not checked
        if (right == 0) || (left == 0) {
            return;
        }
        if (left + right < 24) || (mem::size_of::<T>() > mem::size_of::<[usize; 4]>()) {
            // Algorithm 1
            // Microbenchmarks indicate that the average performance for random shifts is better all
            // the way until about `left + right == 32`, but the worst case performance breaks even
            // around 16. 24 was chosen as middle ground. If the size of `T` is larger than 4
            // `usize`s, this algorithm also outperforms other algorithms.
            let x = unsafe { mid.sub(left) };
            // beginning of first round
            let mut tmp: T = unsafe { x.read() };
            let mut i = right;
            // `gcd` can be found before hand by calculating `gcd(left + right, right)`,
            // but it is faster to do one loop which calculates the gcd as a side effect, then
            // doing the rest of the chunk
            let mut gcd = right;
            // benchmarks reveal that it is faster to swap temporaries all the way through instead
            // of reading one temporary once, copying backwards, and then writing that temporary at
            // the very end. This is possibly due to the fact that swapping or replacing temporaries
            // uses only one memory address in the loop instead of needing to manage two.
            loop {
                tmp = unsafe { x.add(i).replace(tmp) };
                // instead of incrementing `i` and then checking if it is outside the bounds, we
                // check if `i` will go outside the bounds on the next increment. This prevents
                // any wrapping of pointers or `usize`.
                if i >= left {
                    i -= left;
                    if i == 0 {
                        // end of first round
                        unsafe { x.write(tmp) };
                        break;
                    }
                    // this conditional must be here if `left + right >= 15`
                    if i < gcd {
                        gcd = i;
                    }
                } else {
                    i += right;
                }
            }
            // finish the chunk with more rounds
            for start in 1..gcd {
                tmp = unsafe { x.add(start).read() };
                i = start + right;
                loop {
                    tmp = unsafe { x.add(i).replace(tmp) };
                    if i >= left {
                        i -= left;
                        if i == start {
                            unsafe { x.add(start).write(tmp) };
                            break;
                        }
                    } else {
                        i += right;
                    }
                }
            }
            return;
        // `T` is not a zero-sized type, so it's okay to divide by its size.
        } else if cmp::min(left, right) <= mem::size_of::<BufType>() / mem::size_of::<T>() {
            // Algorithm 2
            // The `[T; 0]` here is to ensure this is appropriately aligned for T
            let mut rawarray = MaybeUninit::<(BufType, [T; 0])>::uninit();
            let buf = rawarray.as_mut_ptr() as *mut T;
            let dim = unsafe { mid.sub(left).add(right) };
            if left <= right {
                unsafe {
                    ptr::copy_nonoverlapping(mid.sub(left), buf, left);
                    ptr::copy(mid, mid.sub(left), right);
                    ptr::copy_nonoverlapping(buf, dim, left);
                }
            } else {
                unsafe {
                    ptr::copy_nonoverlapping(mid, buf, right);
                    ptr::copy(mid.sub(left), dim, left);
                    ptr::copy_nonoverlapping(buf, mid.sub(left), right);
                }
            }
            return;
        } else if left >= right {
            // Algorithm 3
            // There is an alternate way of swapping that involves finding where the last swap
            // of this algorithm would be, and swapping using that last chunk instead of swapping
            // adjacent chunks like this algorithm is doing, but this way is still faster.
            loop {
                unsafe {
                    ptr::swap_nonoverlapping(mid.sub(right), mid, right);
                    mid = mid.sub(right);
                }
                left -= right;
                if left < right {
                    break;
                }
            }
        } else {
            // Algorithm 3, `left < right`
            loop {
                unsafe {
                    ptr::swap_nonoverlapping(mid.sub(left), mid, left);
                    mid = mid.add(left);
                }
                right -= left;
                if right < left {
                    break;
                }
            }
        }
    }
}
<commit_msg>Rollup merge of #87127 - poliorcetics:ptr-rotate-safety, r=scottmcm<commit_after>use crate::cmp;
use crate::mem::{self, MaybeUninit};
use crate::ptr;

/// Rotates the range `[mid-left, mid+right)` such that the element at `mid` becomes the first
/// element. Equivalently, rotates the range `left` elements to the left or `right` elements to the
/// right.
///
/// # Safety
///
/// The specified range must be valid for reading and writing.
///
/// # Algorithm
///
/// Algorithm 1 is used for small values of `left + right` or for large `T`. The elements are moved
/// into their final positions one at a time starting at `mid - left` and advancing by `right` steps
/// modulo `left + right`, such that only one temporary is needed. Eventually, we arrive back at
/// `mid - left`. However, if `gcd(left + right, right)` is not 1, the above steps skipped over
/// elements. For example:
/// ```text
/// left = 10, right = 6
/// the `^` indicates an element in its final place
/// 6 7 8 9 10 11 12 13 14 15 . 0 1 2 3 4 5
/// after using one step of the above algorithm (The X will be overwritten at the end of the round,
/// and 12 is stored in a temporary):
/// X 7 8 9 10 11 6 13 14 15 . 0 1 2 3 4 5
///               ^
/// after using another step (now 2 is in the temporary):
/// X 7 8 9 10 11 6 13 14 15 . 0 1 12 3 4 5
///               ^                 ^
/// after the third step (the steps wrap around, and 8 is in the temporary):
/// X 7 2 9 10 11 6 13 14 15 . 0 1 12 3 4 5
///     ^         ^                 ^
/// after 7 more steps, the round ends with the temporary 0 getting put in the X:
/// 0 7 2 9 4 11 6 13 8 15 . 10 1 12 3 14 5
/// ^   ^   ^    ^    ^       ^    ^    ^
/// ```
/// Fortunately, the number of skipped over elements between finalized elements is always equal, so
/// we can just offset our starting position and do more rounds (the total number of rounds is the
/// `gcd(left + right, right)` value). The end result is that all elements are finalized once and
/// only once.
///
/// Algorithm 2 is used if `left + right` is large but `min(left, right)` is small enough to
/// fit onto a stack buffer. The `min(left, right)` elements are copied onto the buffer, `memmove`
/// is applied to the others, and the ones on the buffer are moved back into the hole on the
/// opposite side of where they originated.
///
/// Algorithms that can be vectorized outperform the above once `left + right` becomes large enough.
/// Algorithm 1 can be vectorized by chunking and performing many rounds at once, but there are too
/// few rounds on average until `left + right` is enormous, and the worst case of a single
/// round is always there. Instead, algorithm 3 utilizes repeated swapping of
/// `min(left, right)` elements until a smaller rotate problem is left.
///
/// ```text
/// left = 11, right = 4
/// [4 5 6 7 8 9 10 11 12 13 14 . 0 1 2 3]
///                  ^  ^  ^  ^   ^ ^ ^ ^ swapping the right most elements with elements to the left
/// [4 5 6 7 8 9 10 . 0 1 2 3] 11 12 13 14
///        ^ ^ ^  ^   ^ ^ ^ ^ swapping these
/// [4 5 6 . 0 1 2 3] 7 8 9 10 11 12 13 14
/// we cannot swap any more, but a smaller rotation problem is left to solve
/// ```
/// when `left < right` the swapping happens from the left instead.
pub unsafe fn ptr_rotate<T>(mut left: usize, mut mid: *mut T, mut right: usize) {
    type BufType = [usize; 32];
    if mem::size_of::<T>() == 0 {
        return;
    }
    loop {
        // N.B. the below algorithms can fail if these cases are not checked
        if (right == 0) || (left == 0) {
            return;
        }
        if (left + right < 24) || (mem::size_of::<T>() > mem::size_of::<[usize; 4]>()) {
            // Algorithm 1
            // Microbenchmarks indicate that the average performance for random shifts is better all
            // the way until about `left + right == 32`, but the worst case performance breaks even
            // around 16. 24 was chosen as middle ground. If the size of `T` is larger than 4
            // `usize`s, this algorithm also outperforms other algorithms.
            // SAFETY: callers must ensure `mid - left` is valid for reading and writing.
            let x = unsafe { mid.sub(left) };
            // beginning of first round
            // SAFETY: see previous comment.
            let mut tmp: T = unsafe { x.read() };
            let mut i = right;
            // `gcd` can be found before hand by calculating `gcd(left + right, right)`,
            // but it is faster to do one loop which calculates the gcd as a side effect, then
            // doing the rest of the chunk
            let mut gcd = right;
            // benchmarks reveal that it is faster to swap temporaries all the way through instead
            // of reading one temporary once, copying backwards, and then writing that temporary at
            // the very end. This is possibly due to the fact that swapping or replacing temporaries
            // uses only one memory address in the loop instead of needing to manage two.
            loop {
                // [long-safety-expl]
                // SAFETY: callers must ensure `[left, left+mid+right)` are all valid for reading and
                // writing.
                //
                // - `i` start with `right` so `mid-left <= x+i = x+right = mid-left+right < mid+right`
                // - `i <= left+right-1` is always true
                //   - if `i < left`, `right` is added so `i < left+right` and on the next
                //     iteration `left` is removed from `i` so it doesn't go further
                //   - if `i >= left`, `left` is removed immediately and so it doesn't go further.
                // - overflows cannot happen for `i` since the function's safety contract ask for
                //   `mid+right-1 = x+left+right` to be valid for writing
                // - underflows cannot happen because `i` must be bigger or equal to `left` for
                //   a substraction of `left` to happen.
                //
                // So `x+i` is valid for reading and writing if the caller respected the contract
                tmp = unsafe { x.add(i).replace(tmp) };
                // instead of incrementing `i` and then checking if it is outside the bounds, we
                // check if `i` will go outside the bounds on the next increment. This prevents
                // any wrapping of pointers or `usize`.
                if i >= left {
                    i -= left;
                    if i == 0 {
                        // end of first round
                        // SAFETY: tmp has been read from a valid source and x is valid for writing
                        // according to the caller.
                        unsafe { x.write(tmp) };
                        break;
                    }
                    // this conditional must be here if `left + right >= 15`
                    if i < gcd {
                        gcd = i;
                    }
                } else {
                    i += right;
                }
            }
            // finish the chunk with more rounds
            for start in 1..gcd {
                // SAFETY: `gcd` is at most equal to `right` so all values in `1..gcd` are valid for
                // reading and writing as per the function's safety contract, see [long-safety-expl]
                // above
                tmp = unsafe { x.add(start).read() };
                // [safety-expl-addition]
                //
                // Here `start < gcd` so `start < right` so `i < right+right`: `right` being the
                // greatest common divisor of `(left+right, right)` means that `left = right` so
                // `i < left+right` so `x+i = mid-left+i` is always valid for reading and writing
                // according to the function's safety contract.
                i = start + right;
                loop {
                    // SAFETY: see [long-safety-expl] and [safety-expl-addition]
                    tmp = unsafe { x.add(i).replace(tmp) };
                    if i >= left {
                        i -= left;
                        if i == start {
                            // SAFETY: see [long-safety-expl] and [safety-expl-addition]
                            unsafe { x.add(start).write(tmp) };
                            break;
                        }
                    } else {
                        i += right;
                    }
                }
            }
            return;
        // `T` is not a zero-sized type, so it's okay to divide by its size.
        } else if cmp::min(left, right) <= mem::size_of::<BufType>() / mem::size_of::<T>() {
            // Algorithm 2
            // The `[T; 0]` here is to ensure this is appropriately aligned for T
            let mut rawarray = MaybeUninit::<(BufType, [T; 0])>::uninit();
            let buf = rawarray.as_mut_ptr() as *mut T;
            // SAFETY: `mid-left <= mid-left+right < mid+right`
            let dim = unsafe { mid.sub(left).add(right) };
            if left <= right {
                // SAFETY:
                //
                // 1) The `else if` condition about the sizes ensures `[mid-left; left]` will fit in
                //    `buf` without overflow and `buf` was created just above and so cannot be
                //    overlapped with any value of `[mid-left; left]`
                // 2) [mid-left, mid+right) are all valid for reading and writing and we don't care
                //    about overlaps here.
                // 3) The `if` condition about `left <= right` ensures writing `left` elements to
                //    `dim = mid-left+right` is valid because:
                //    - `buf` is valid and `left` elements were written in it in 1)
                //    - `dim+left = mid-left+right+left = mid+right` and we write `[dim, dim+left)`
                unsafe {
                    // 1)
                    ptr::copy_nonoverlapping(mid.sub(left), buf, left);
                    // 2)
                    ptr::copy(mid, mid.sub(left), right);
                    // 3)
                    ptr::copy_nonoverlapping(buf, dim, left);
                }
            } else {
                // SAFETY: same reasoning as above but with `left` and `right` reversed
                unsafe {
                    ptr::copy_nonoverlapping(mid, buf, right);
                    ptr::copy(mid.sub(left), dim, left);
                    ptr::copy_nonoverlapping(buf, mid.sub(left), right);
                }
            }
            return;
        } else if left >= right {
            // Algorithm 3
            // There is an alternate way of swapping that involves finding where the last swap
            // of this algorithm would be, and swapping using that last chunk instead of swapping
            // adjacent chunks like this algorithm is doing, but this way is still faster.
            loop {
                // SAFETY:
                // `left >= right` so `[mid-right, mid+right)` is valid for reading and writing
                // Substracting `right` from `mid` each turn is counterbalanced by the addition and
                // check after it.
                unsafe {
                    ptr::swap_nonoverlapping(mid.sub(right), mid, right);
                    mid = mid.sub(right);
                }
                left -= right;
                if left < right {
                    break;
                }
            }
        } else {
            // Algorithm 3, `left < right`
            loop {
                // SAFETY: `[mid-left, mid+left)` is valid for reading and writing because
                // `left < right` so `mid+left < mid+right`.
                // Adding `left` to `mid` each turn is counterbalanced by the substraction and check
                // after it.
                unsafe {
                    ptr::swap_nonoverlapping(mid.sub(left), mid, left);
                    mid = mid.add(left);
                }
                right -= left;
                if right < left {
                    break;
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>fn main() {
    println!("Value in cents of Penny: {}", value_in_cents(Coin::Penny));
    println!(
        "Value in cents of Quarter: {}",
        value_in_cents(Coin::Quarter(UsState::California)));

    let five = Some(5);
    let six = plus_one(five);
    let none = plus_one(None);
}

#[derive(Debug)]
enum UsState {
    California,
    Georgia,
    Texas
}

enum Coin {
    Penny,
    Nickel,
    Dime,
    Quarter(UsState)
}

fn value_in_cents(coin: Coin) -> u32 {
    match coin {
        Coin::Penny => 1,
        Coin::Nickel => 5,
        Coin::Dime => 10,
        Coin::Quarter(state) => {
            println!("Quarter from state: {:?}", state);
            25
        },
    }
}

fn plus_one(x: Option<i32>) -> Option<i32> {
    match x {
        None => None,
        Some(i) => Some(i + 1)
    }
}
<commit_msg>Example of if let pattern<commit_after>fn main() {
    println!("Value in cents of Penny: {}", value_in_cents(Coin::Penny));
    println!(
        "Value in cents of Quarter: {}",
        value_in_cents(Coin::Quarter(UsState::California)));

    let five = Some(5);
    let six = plus_one(five);
    let none = plus_one(None);

    let some_u8_value = Some(3u8);
    if let Some(3) = some_u8_value {
        println!("three!");
    }
}

#[derive(Debug)]
enum UsState {
    California,
    Georgia,
    Texas
}

enum Coin {
    Penny,
    Nickel,
    Dime,
    Quarter(UsState)
}

fn value_in_cents(coin: Coin) -> u32 {
    match coin {
        Coin::Penny => 1,
        Coin::Nickel => 5,
        Coin::Dime => 10,
        Coin::Quarter(state) => {
            println!("Quarter from state: {:?}", state);
            25
        },
    }
}

fn plus_one(x: Option<i32>) -> Option<i32> {
    match x {
        None => None,
        Some(i) => Some(i + 1)
    }
}
<|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.

#![allow(non_snake_case)]

register_long_diagnostics! {

E0046: r##"
When trying to make some type implement a trait `Foo`, you must, at minimum,
provide implementations for all of `Foo`'s required methods (meaning the
methods that do not have default implementations), as well as any required
trait items like associated types or constants.
"##,

E0054: r##"
It is not allowed to cast to a bool. If you are trying to cast a numeric type
to a bool, you can compare it with zero instead:

```
let x = 5;

// Ok
let x_is_nonzero = x != 0;

// Not allowed, won't compile
let x_is_nonzero = x as bool;
```
"##,

E0062: r##"
This error indicates that during an attempt to build a struct or struct-like
enum variant, one of the fields was specified more than once. Each field should
be specified exactly one time.
"##,

E0063: r##"
This error indicates that during an attempt to build a struct or struct-like
enum variant, one of the fields was not provided. Each field should be specified
exactly once.
"##,

E0067: r##"
The left-hand side of an assignment operator must be an lvalue expression. An
lvalue expression represents a memory location and includes item paths (ie,
namespaced variables), dereferences, indexing expressions, and field references.

```
use std::collections::LinkedList;

// Good
let mut list = LinkedList::new();

// Bad: assignment to non-lvalue expression
LinkedList::new() += 1;
```
"##,

E0081: r##"
Enum discriminants are used to differentiate enum variants stored in memory.
This error indicates that the same value was used for two or more variants,
making them impossible to tell apart.

```
// Good.
enum Enum {
    P,
    X = 3,
    Y = 5
}

// Bad.
enum Enum {
    P = 3,
    X = 3,
    Y = 5
}
```

Note that variants without a manually specified discriminant are numbered from
top to bottom starting from 0, so clashes can occur with seemingly unrelated
variants.

```
enum Bad {
    X,
    Y = 0
}
```

Here `X` will have already been assigned the discriminant 0 by the time `Y` is
encountered, so a conflict occurs.
"##,

E0082: r##"
The default type for enum discriminants is `isize`, but it can be adjusted by
adding the `repr` attribute to the enum declaration. This error indicates that
an integer literal given as a discriminant is not a member of the discriminant
type. For example:

```
#[repr(u8)]
enum Thing {
    A = 1024,
    B = 5
}
```

Here, 1024 lies outside the valid range for `u8`, so the discriminant for `A` is
invalid. You may want to change representation types to fix this, or else change
invalid discriminant values so that they fit within the existing type.

Note also that without a representation manually defined, the compiler will
optimize by using the smallest integer type possible.
"##,

E0083: r##"
At present, it's not possible to define a custom representation for an enum with
a single variant. As a workaround you can add a `Dummy` variant.

See: https://github.com/rust-lang/rust/issues/10292
"##,

E0084: r##"
It is impossible to define an integer type to be used to represent zero-variant
enum values because there are no zero-variant enum values. There is no way to
construct an instance of the following type using only safe code:

```
enum Empty {}
```
"##,

E0131: r##"
It is not possible to define `main` with type parameters, or even with function
parameters. When `main` is present, it must take no arguments and return `()`.
"##,

E0132: r##"
It is not possible to declare type parameters on a function that has the `start`
attribute. Such a function must have the following type signature:

```
fn(isize, *const *const u8) -> isize
```
"##

}

register_diagnostics! {
    E0023,
    E0024,
    E0025,
    E0026,
    E0027,
    E0029,
    E0030,
    E0031,
    E0033,
    E0034, // multiple applicable methods in scope
    E0035, // does not take type parameters
    E0036, // incorrect number of type parameters given for this method
    E0038, // cannot convert to a trait object because trait is not object-safe
    E0040, // explicit use of destructor method
    E0044, // foreign items may not have type parameters
    E0045, // variadic function must have C calling convention
    E0049,
    E0050,
    E0053,
    E0055, // method has an incompatible type for trait
    E0057, // method has an incompatible type for trait
    E0059,
    E0060,
    E0061,
    E0066,
    E0068,
    E0069,
    E0070,
    E0071,
    E0072,
    E0073,
    E0074,
    E0075,
    E0076,
    E0077,
    E0085,
    E0086,
    E0087,
    E0088,
    E0089,
    E0090,
    E0091,
    E0092,
    E0093,
    E0094,
    E0101,
    E0102,
    E0103,
    E0104,
    E0106,
    E0107,
    E0116,
    E0117,
    E0118,
    E0119,
    E0120,
    E0121,
    E0122,
    E0123,
    E0124,
    E0127,
    E0128,
    E0129,
    E0130,
    E0141,
    E0159,
    E0163,
    E0164,
    E0166,
    E0167,
    E0168,
    E0172,
    E0173, // manual implementations of unboxed closure traits are experimental
    E0174, // explicit use of unboxed closure methods are experimental
    E0178,
    E0182,
    E0183,
    E0184,
    E0185,
    E0186,
    E0187, // can't infer the kind of the closure
    E0188, // types differ in mutability
    E0189, // can only cast a boxed pointer to a boxed object
    E0190, // can only cast a &-pointer to an &-object
    E0191, // value of the associated type must be specified
    E0192, // negative imples are allowed just for `Send` and `Sync`
    E0193, // cannot bound type where clause bounds may only be attached to types
           // involving type parameters
    E0194,
    E0195, // lifetime parameters or bounds on method do not match the trait declaration
    E0196, // cannot determine a type for this closure
    E0197, // inherent impls cannot be declared as unsafe
    E0198, // negative implementations are not unsafe
    E0199, // implementing trait is not unsafe
    E0200, // trait requires an `unsafe impl` declaration
    E0201, // duplicate method in trait impl
    E0202, // associated items are not allowed in inherent impls
    E0203, // type parameter has more than one relaxed default bound,
           // and only one is supported
    E0204, // trait `Copy` may not be implemented for this type; field
           // does not implement `Copy`
    E0205, // trait `Copy` may not be implemented for this type; variant
           // does not implement `copy`
    E0206, // trait `Copy` may not be implemented for this type; type is
           // not a structure or enumeration
    E0207, // type parameter is not constrained by the impl trait, self type, or predicate
    E0208,
    E0209, // builtin traits can only be implemented on structs or enums
    E0210, // type parameter is not constrained by any local type
    E0211,
    E0212, // cannot extract an associated type from a higher-ranked trait bound
    E0213, // associated types are not accepted in this context
    E0214, // parenthesized parameters may only be used with a trait
    E0215, // angle-bracket notation is not stable with `Fn`
    E0216, // parenthetical notation is only stable with `Fn`
    E0217, // ambiguous associated type, defined in multiple supertraits
    E0218, // no associated type defined
    E0219, // associated type defined in higher-ranked supertrait
    E0220, // associated type not found for type parameter
    E0221, // ambiguous associated type in bounds
    E0222, // variadic function must have C calling convention
    E0223, // ambiguous associated type
    E0224, // at least one non-builtin train is required for an object type
    E0225, // only the builtin traits can be used as closure or object bounds
    E0226, // only a single explicit lifetime bound is permitted
    E0227, // ambiguous lifetime bound, explicit lifetime bound required
    E0228, // explicit lifetime bound required
    E0229, // associated type bindings are not allowed here
    E0230, // there is no type parameter on trait
    E0231, // only named substitution parameters are allowed
    E0232, // this attribute must have a value
    E0233,
    E0234, // `for` loop expression has type which does not implement the `Iterator` trait
    E0235, // structure constructor specifies a structure of type but
    E0236, // no lang item for range syntax
    E0237, // no lang item for range syntax
    E0238, // parenthesized parameters may only be used with a trait
    E0239, // `next` method of `Iterator` trait has unexpected type
    E0240,
    E0241,
    E0242, // internal error looking up a definition
    E0243, // wrong number of type arguments
    E0244, // wrong number of type arguments
    E0245, // not a trait
    E0246, // illegal recursive type
    E0247, // found module name used as a type
    E0248, // found value name used as a type
    E0249, // expected constant expr for array length
    E0250, // expected constant expr for array length
    E0318, // can't create default impls for traits outside their crates
    E0319, // trait impls for defaulted traits allowed just for structs/enums
    E0320, // recursive overflow during dropck
    E0321, // extended coherence rules for defaulted traits violated
    E0322, // cannot implement Sized explicitly
    E0323, // implemented an associated const when another trait item expected
    E0324, // implemented a method when another trait item expected
    E0325, // implemented an associated type when another trait item expected
    E0326, // associated const implemented with different type from trait
    E0327, // referred to method instead of constant in match pattern
    E0366, // dropck forbid specialization to concrete type or region
    E0367, // dropck forbid specialization to predicate not in struct/enum
    E0368, // binary operation `<op>=` cannot be applied to types
    E0369, // binary operation `<op>` cannot be applied to types
    E0371, // impl Trait for Trait is illegal
    E0372  // impl Trait for Trait where Trait is not object safe
}
<commit_msg>Add long diagnostics for E0184, E0204, E0205, E0206, E0243, E0244.<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.

#![allow(non_snake_case)]

register_long_diagnostics! {

E0046: r##"
When trying to make some type implement a trait `Foo`, you must, at minimum,
provide implementations for all of `Foo`'s required methods (meaning the
methods that do not have default implementations), as well as any required
trait items like associated types or constants.
"##,

E0054: r##"
It is not allowed to cast to a bool. If you are trying to cast a numeric type
to a bool, you can compare it with zero instead:

```
let x = 5;

// Ok
let x_is_nonzero = x != 0;

// Not allowed, won't compile
let x_is_nonzero = x as bool;
```
"##,

E0062: r##"
This error indicates that during an attempt to build a struct or struct-like
enum variant, one of the fields was specified more than once. Each field should
be specified exactly one time.
"##,

E0063: r##"
This error indicates that during an attempt to build a struct or struct-like
enum variant, one of the fields was not provided. Each field should be specified
exactly once.
"##,

E0067: r##"
The left-hand side of an assignment operator must be an lvalue expression. An
lvalue expression represents a memory location and includes item paths (ie,
namespaced variables), dereferences, indexing expressions, and field references.

```
use std::collections::LinkedList;

// Good
let mut list = LinkedList::new();

// Bad: assignment to non-lvalue expression
LinkedList::new() += 1;
```
"##,

E0081: r##"
Enum discriminants are used to differentiate enum variants stored in memory.
This error indicates that the same value was used for two or more variants,
making them impossible to tell apart.

```
// Good.
enum Enum {
    P,
    X = 3,
    Y = 5
}

// Bad.
enum Enum {
    P = 3,
    X = 3,
    Y = 5
}
```

Note that variants without a manually specified discriminant are numbered from
top to bottom starting from 0, so clashes can occur with seemingly unrelated
variants.

```
enum Bad {
    X,
    Y = 0
}
```

Here `X` will have already been assigned the discriminant 0 by the time `Y` is
encountered, so a conflict occurs.
"##,

E0082: r##"
The default type for enum discriminants is `isize`, but it can be adjusted by
adding the `repr` attribute to the enum declaration. This error indicates that
an integer literal given as a discriminant is not a member of the discriminant
type. For example:

```
#[repr(u8)]
enum Thing {
    A = 1024,
    B = 5
}
```

Here, 1024 lies outside the valid range for `u8`, so the discriminant for `A` is
invalid. You may want to change representation types to fix this, or else change
invalid discriminant values so that they fit within the existing type.

Note also that without a representation manually defined, the compiler will
optimize by using the smallest integer type possible.
"##,

E0083: r##"
At present, it's not possible to define a custom representation for an enum with
a single variant. As a workaround you can add a `Dummy` variant.

See: https://github.com/rust-lang/rust/issues/10292
"##,

E0084: r##"
It is impossible to define an integer type to be used to represent zero-variant
enum values because there are no zero-variant enum values. There is no way to
construct an instance of the following type using only safe code:

```
enum Empty {}
```
"##,

E0131: r##"
It is not possible to define `main` with type parameters, or even with function
parameters. When `main` is present, it must take no arguments and return `()`.
"##,

E0132: r##"
It is not possible to declare type parameters on a function that has the `start`
attribute. Such a function must have the following type signature:

```
fn(isize, *const *const u8) -> isize
```
"##,

E0184: r##"
Explicitly implementing both Drop and Copy for a type is currently disallowed.
This feature can make some sense in theory, but the current implementation is
incorrect and can lead to memory unsafety (see issue #20126), so it has been
disabled for now.
"##,

E0204: r##"
An attempt to implement the `Copy` trait for a struct failed because one of the
fields does not implement `Copy`. To fix this, you must implement `Copy` for the
mentioned field. Note that this may not be possible, as in the example of

```
struct Foo {
    foo : Vec<u32>,
}

impl Copy for Foo { }
```

This fails because `Vec<T>` does not implement `Copy` for any `T`.

Here's another example that will fail:

```
#[derive(Copy)]
struct Foo<'a> {
    ty: &'a mut bool,
}
```

This fails because `&mut T` is not `Copy`, even when `T` is `Copy` (as opposed
to `&T`, which is).
"##,

E0205: r##"
An attempt to implement the `Copy` trait for an enum failed because one of the
variants does not implement `Copy`. To fix this, you must implement `Copy` for
the mentioned variant. Note that this may not be possible, as in the example of

```
enum Foo {
    Bar(Vec<u32>),
    Baz,
}

impl Copy for Foo { }
```

This fails because `Vec<T>` does not implement `Copy` for any `T`.

Here's another example that will fail:

```
#[derive(Copy)]
enum Foo<'a> {
    Bar(&'a mut bool),
    Baz
}
```

This fails because `&mut T` is not `Copy`, even when `T` is `Copy` (as opposed
to `&T`, which is).
"##,

E0206: r##"
You can only implement `Copy` for a struct or enum. For example, both of the
following examples will fail, because neither `i32` nor `&'static mut Bar` is
a struct or enum:

```
type Foo = i32;
impl Copy for Foo { } // error

#[derive(Copy, Clone)]
struct Bar;
impl Copy for &'static mut Bar { } // error
```
"##,

E0243: r##"
This error indicates that not enough type parameters were found in a type or
trait.

For example, the `Foo` struct below is defined to be generic in `T`, but the
type parameter is missing in the definition of `Bar`:

```
struct Foo<T> { x: T }

struct Bar { x: Foo }
```
"##,

E0244: r##"
This error indicates that too many type parameters were found in a type or
trait.

For example, the `Foo` struct below has no type parameters, but is supplied
with two in the definition of `Bar`:

```
struct Foo { x: bool }

struct Bar<S, T> { x: Foo<S, T> }
```
"##

}

register_diagnostics! {
    E0023,
    E0024,
    E0025,
    E0026,
    E0027,
    E0029,
    E0030,
    E0031,
    E0033,
    E0034, // multiple applicable methods in scope
    E0035, // does not take type parameters
    E0036, // incorrect number of type parameters given for this method
    E0038, // cannot convert to a trait object because trait is not object-safe
    E0040, // explicit use of destructor method
    E0044, // foreign items may not have type parameters
    E0045, // variadic function must have C calling convention
    E0049,
    E0050,
    E0053,
    E0055, // method has an incompatible type for trait
    E0057, // method has an incompatible type for trait
    E0059,
    E0060,
    E0061,
    E0066,
    E0068,
    E0069,
    E0070,
    E0071,
    E0072,
    E0073,
    E0074,
    E0075,
    E0076,
    E0077,
    E0085,
    E0086,
    E0087,
    E0088,
    E0089,
    E0090,
    E0091,
    E0092,
    E0093,
    E0094,
    E0101,
    E0102,
    E0103,
    E0104,
    E0106,
    E0107,
    E0116,
    E0117,
    E0118,
    E0119,
    E0120,
    E0121,
    E0122,
    E0123,
    E0124,
    E0127,
    E0128,
    E0129,
    E0130,
    E0141,
    E0159,
    E0163,
    E0164,
    E0166,
    E0167,
    E0168,
    E0172,
    E0173, // manual implementations of unboxed closure traits are experimental
    E0174, // explicit use of unboxed closure methods are experimental
    E0178,
    E0182,
    E0183,
    E0185,
    E0186,
    E0187, // can't infer the kind of the closure
    E0188, // types differ in mutability
    E0189, // can only cast a boxed pointer to a boxed object
    E0190, // can only cast a &-pointer to an &-object
    E0191, // value of the associated type must be specified
    E0192, // negative imples are allowed just for `Send` and `Sync`
    E0193, // cannot bound type where clause bounds may only be attached to types
           // involving type parameters
    E0194,
    E0195, // lifetime parameters or bounds on method do not match the trait declaration
    E0196, // cannot determine a type for this closure
    E0197, // inherent impls cannot be declared as unsafe
    E0198, // negative implementations are not unsafe
    E0199, // implementing trait is not unsafe
    E0200, // trait requires an `unsafe impl` declaration
    E0201, // duplicate method in trait impl
    E0202, // associated items are not allowed in inherent impls
    E0203, // type parameter has more than one relaxed default bound,
           // and only one is supported
    E0207, // type parameter is not constrained by the impl trait, self type, or predicate
    E0208,
    E0209, // builtin traits can only be implemented on structs or enums
    E0210, // type parameter is not constrained by any local type
    E0211,
    E0212, // cannot extract an associated type from a higher-ranked trait bound
    E0213, // associated types are not accepted in this context
    E0214, // parenthesized parameters may only be used with a trait
    E0215, // angle-bracket notation is not stable with `Fn`
    E0216, // parenthetical notation is only stable with `Fn`
    E0217, // ambiguous associated type, defined in multiple supertraits
    E0218, // no associated type defined
    E0219, // associated type defined in higher-ranked supertrait
    E0220, // associated type not found for type parameter
    E0221, // ambiguous associated type in bounds
    E0222, // variadic function must have C calling convention
    E0223, // ambiguous associated type
    E0224, // at least one non-builtin train is required for an object type
    E0225, // only the builtin traits can be used as closure or object bounds
    E0226, // only a single explicit lifetime bound is permitted
    E0227, // ambiguous lifetime bound, explicit lifetime bound required
    E0228, // explicit lifetime bound required
    E0229, // associated type bindings are not allowed here
    E0230, // there is no type parameter on trait
    E0231, // only named substitution parameters are allowed
    E0232, // this attribute must have a value
    E0233,
    E0234, // `for` loop expression has type which does not implement the `Iterator` trait
    E0235, // structure constructor specifies a structure of type but
    E0236, // no lang item for range syntax
    E0237, // no lang item for range syntax
    E0238, // parenthesized parameters may only be used with a trait
    E0239, // `next` method of `Iterator` trait has unexpected type
    E0240,
    E0241,
    E0242, // internal error looking up a definition
    E0245, // not a trait
    E0246, // illegal recursive type
    E0247, // found module name used as a type
    E0248, // found value name used as a type
    E0249, // expected constant expr for array length
    E0250, // expected constant expr for array length
    E0318, // can't create default impls for traits outside their crates
    E0319, // trait impls for defaulted traits allowed just for structs/enums
    E0320, // recursive overflow during dropck
    E0321, // extended coherence rules for defaulted traits violated
    E0322, // cannot implement Sized explicitly
    E0323, // implemented an associated const when another trait item expected
    E0324, // implemented a method when another trait item expected
    E0325, // implemented an associated type when another trait item expected
    E0326, // associated const implemented with different type from trait
    E0327, // referred to method instead of constant in match pattern
    E0366, // dropck forbid specialization to concrete type or region
    E0367, // dropck forbid specialization to predicate not in struct/enum
    E0368, // binary operation `<op>=` cannot be applied to types
    E0369, // binary operation `<op>` cannot be applied to types
    E0371, // impl Trait for Trait is illegal
    E0372  // impl Trait for Trait where Trait is not object safe
}
<|endoftext|>


<commit_before>import util::interner::interner;
import diagnostic::span_handler;
import ast::{token_tree, tt_delim, tt_tok, tt_seq, tt_nonterminal,ident};
import earley_parser::{named_match, matched_seq, matched_nonterminal};
import codemap::span;
import parse::token::{EOF, INTERPOLATED, IDENT, token, nt_ident};
import std::map::{hashmap, box_str_hash};

export tt_reader,  new_tt_reader, dup_tt_reader, tt_next_token;

enum tt_frame_up { /* to break a circularity */
    tt_frame_up(option<tt_frame>)
}

/* FIXME #2811: figure out how to have a uniquely linked stack, and change to
   `~` */
///an unzipping of `token_tree`s
type tt_frame = @{
    readme: ~[ast::token_tree],
    mut idx: uint,
    dotdotdoted: bool,
    sep: option<token>,
    up: tt_frame_up,
};

type tt_reader = @{
    sp_diag: span_handler,
    interner: @interner<@~str>,
    mut cur: tt_frame,
    /* for MBE-style macro transcription */
    interpolations: std::map::hashmap<ident, @named_match>,
    mut repeat_idx: ~[mut uint],
    mut repeat_len: ~[uint],
    /* cached: */
    mut cur_tok: token,
    mut cur_span: span
};

/** This can do Macro-By-Example transcription. On the other hand, if
 *  `src` contains no `tt_seq`s and `tt_nonterminal`s, `interp` can (and
 *  should) be none. */
fn new_tt_reader(sp_diag: span_handler, itr: @interner<@~str>,
                 interp: option<std::map::hashmap<ident,@named_match>>,
                 src: ~[ast::token_tree])
    -> tt_reader {
    let r = @{sp_diag: sp_diag, interner: itr,
              mut cur: @{readme: src, mut idx: 0u, dotdotdoted: false,
                         sep: none, up: tt_frame_up(option::none)},
              interpolations: alt interp { /* just a convienience */
                none { std::map::box_str_hash::<@named_match>() }
                some(x) { x }
              },
              mut repeat_idx: ~[mut], mut repeat_len: ~[],
              /* dummy values, never read: */
              mut cur_tok: EOF,
              mut cur_span: ast_util::mk_sp(0u,0u)
             };
    tt_next_token(r); /* get cur_tok and cur_span set up */
    ret r;
}

pure fn dup_tt_frame(&&f: tt_frame) -> tt_frame {
    @{readme: f.readme, mut idx: f.idx, dotdotdoted: f.dotdotdoted,
      sep: f.sep, up: alt f.up {
        tt_frame_up(some(up_frame)) {
          tt_frame_up(some(dup_tt_frame(up_frame)))
        }
        tt_frame_up(none) { tt_frame_up(none) }
      }
     }
}

pure fn dup_tt_reader(&&r: tt_reader) -> tt_reader {
    @{sp_diag: r.sp_diag, interner: r.interner,
      mut cur: dup_tt_frame(r.cur),
      interpolations: r.interpolations,
      mut repeat_idx: copy r.repeat_idx, mut repeat_len: copy r.repeat_len,
      mut cur_tok: r.cur_tok, mut cur_span: r.cur_span}
}

pure fn lookup_cur_matched_by_matched(r: tt_reader,
                                      start: @named_match) -> @named_match {
    pure fn red(&&ad: @named_match, &&idx: uint) -> @named_match {
        alt *ad {
          matched_nonterminal(_) {
            // end of the line; duplicate henceforth
            ad
          }
          matched_seq(ads, _) { ads[idx] }
        }
    }
    vec::foldl(start, r.repeat_idx, red)
}

fn lookup_cur_matched(r: tt_reader, name: ident) -> @named_match {
    lookup_cur_matched_by_matched(r, r.interpolations.get(name))
}
enum lis {
    lis_unconstrained, lis_constraint(uint, ident), lis_contradiction(~str)
}

fn lockstep_iter_size(&&t: token_tree, &&r: tt_reader) -> lis {
    fn lis_merge(lhs: lis, rhs: lis) -> lis {
        alt lhs {
          lis_unconstrained { rhs }
          lis_contradiction(_) { lhs }
          lis_constraint(l_len, l_id) {
            alt rhs {
              lis_unconstrained { lhs }
              lis_contradiction(_) { rhs }
              lis_constraint(r_len, _) if l_len == r_len { lhs }
              lis_constraint(r_len, r_id) {
                lis_contradiction(#fmt["Inconsistent lockstep iteration: \
                                        '%s' has %u items, but '%s' has %u",
                                       *l_id, l_len, *r_id, r_len])
              }
            }
          }
        }
    }
    alt t {
      tt_delim(tts) | tt_seq(_, tts, _, _) {
        vec::foldl(lis_unconstrained, tts, {|lis, tt|
            lis_merge(lis, lockstep_iter_size(tt, r)) })
      }
      tt_tok(*) { lis_unconstrained }
      tt_nonterminal(_, name) {
        alt *lookup_cur_matched(r, name) {
          matched_nonterminal(_) { lis_unconstrained }
          matched_seq(ads, _) { lis_constraint(ads.len(), name) }
        }
      }
    }
}

fn tt_next_token(&&r: tt_reader) -> {tok: token, sp: span} {
    let ret_val = { tok: r.cur_tok, sp: r.cur_span };
    while r.cur.idx >= r.cur.readme.len() {
        /* done with this set; pop or repeat? */
        if ! r.cur.dotdotdoted
            || r.repeat_idx.last() == r.repeat_len.last() - 1 {

            alt r.cur.up {
              tt_frame_up(none) {
                r.cur_tok = EOF;
                ret ret_val;
              }
              tt_frame_up(some(tt_f)) {
                if r.cur.dotdotdoted {
                    vec::pop(r.repeat_idx); vec::pop(r.repeat_len);
                }

                r.cur = tt_f;
                r.cur.idx += 1u;
              }
            }

        } else { /* repeat */
            r.cur.idx = 0u;
            r.repeat_idx[r.repeat_idx.len() - 1u] += 1u;
            alt r.cur.sep {
              some(tk) {
                r.cur_tok = tk; /* repeat same span, I guess */
                ret ret_val;
              }
              none {}
            }
        }
    }
    loop { /* because it's easiest, this handles `tt_delim` not starting
    with a `tt_tok`, even though it won't happen */
        alt r.cur.readme[r.cur.idx] {
          tt_delim(tts) {
            r.cur = @{readme: tts, mut idx: 0u, dotdotdoted: false,
                      sep: none, up: tt_frame_up(option::some(r.cur)) };
            // if this could be 0-length, we'd need to potentially recur here
          }
          tt_tok(sp, tok) {
            r.cur_span = sp; r.cur_tok = tok;
            r.cur.idx += 1u;
            ret ret_val;
          }
          tt_seq(sp, tts, sep, zerok) {
            alt lockstep_iter_size(tt_seq(sp, tts, sep, zerok), r) {
              lis_unconstrained {
                r.sp_diag.span_fatal(
                    sp, /* blame macro writer */
                    ~"attempted to repeat an expression containing no syntax \
                     variables matched as repeating at this depth");
              }
              lis_contradiction(msg) { /* FIXME #2887 blame macro invoker
                                          instead*/
                r.sp_diag.span_fatal(sp, msg);
              }
              lis_constraint(len, _) {
                if len == 0 {
                    if !zerok {
                        r.sp_diag.span_fatal(sp, /* FIXME #2887 blame invoker
                                                  */
                                             ~"this must repeat at least \
                                              once");
                    }

                    r.cur.idx += 1u;
                    ret tt_next_token(r);
                } else {
                    vec::push(r.repeat_len, len);
                    vec::push(r.repeat_idx, 0u);
                    r.cur = @{readme: tts, mut idx: 0u, dotdotdoted: true,
                              sep: sep, up: tt_frame_up(option::some(r.cur))};
                }
              }
            }
          }
          // FIXME #2887: think about span stuff here
          tt_nonterminal(sp, ident) {
            alt *lookup_cur_matched(r, ident) {
              /* sidestep the interpolation tricks for ident because
              (a) idents can be in lots of places, so it'd be a pain
              (b) we actually can, since it's a token. */
              matched_nonterminal(nt_ident(sn,b)) {
                r.cur_span = sp; r.cur_tok = IDENT(sn,b);
                r.cur.idx += 1u;
                ret ret_val;
              }
              matched_nonterminal(nt) {
                r.cur_span = sp; r.cur_tok = INTERPOLATED(nt);
                r.cur.idx += 1u;
                ret ret_val;
              }
              matched_seq(*) {
                r.sp_diag.span_fatal(
                    copy r.cur_span, /* blame the macro writer */
                    #fmt["variable '%s' is still repeating at this depth",
                         *ident]);
              }
            }
          }
        }
    }

}<commit_msg>Let's give that binder a name that's not incredibly confusing.<commit_after>import util::interner::interner;
import diagnostic::span_handler;
import ast::{token_tree, tt_delim, tt_tok, tt_seq, tt_nonterminal,ident};
import earley_parser::{named_match, matched_seq, matched_nonterminal};
import codemap::span;
import parse::token::{EOF, INTERPOLATED, IDENT, token, nt_ident};
import std::map::{hashmap, box_str_hash};

export tt_reader,  new_tt_reader, dup_tt_reader, tt_next_token;

enum tt_frame_up { /* to break a circularity */
    tt_frame_up(option<tt_frame>)
}

/* FIXME #2811: figure out how to have a uniquely linked stack, and change to
   `~` */
///an unzipping of `token_tree`s
type tt_frame = @{
    readme: ~[ast::token_tree],
    mut idx: uint,
    dotdotdoted: bool,
    sep: option<token>,
    up: tt_frame_up,
};

type tt_reader = @{
    sp_diag: span_handler,
    interner: @interner<@~str>,
    mut cur: tt_frame,
    /* for MBE-style macro transcription */
    interpolations: std::map::hashmap<ident, @named_match>,
    mut repeat_idx: ~[mut uint],
    mut repeat_len: ~[uint],
    /* cached: */
    mut cur_tok: token,
    mut cur_span: span
};

/** This can do Macro-By-Example transcription. On the other hand, if
 *  `src` contains no `tt_seq`s and `tt_nonterminal`s, `interp` can (and
 *  should) be none. */
fn new_tt_reader(sp_diag: span_handler, itr: @interner<@~str>,
                 interp: option<std::map::hashmap<ident,@named_match>>,
                 src: ~[ast::token_tree])
    -> tt_reader {
    let r = @{sp_diag: sp_diag, interner: itr,
              mut cur: @{readme: src, mut idx: 0u, dotdotdoted: false,
                         sep: none, up: tt_frame_up(option::none)},
              interpolations: alt interp { /* just a convienience */
                none { std::map::box_str_hash::<@named_match>() }
                some(x) { x }
              },
              mut repeat_idx: ~[mut], mut repeat_len: ~[],
              /* dummy values, never read: */
              mut cur_tok: EOF,
              mut cur_span: ast_util::mk_sp(0u,0u)
             };
    tt_next_token(r); /* get cur_tok and cur_span set up */
    ret r;
}

pure fn dup_tt_frame(&&f: tt_frame) -> tt_frame {
    @{readme: f.readme, mut idx: f.idx, dotdotdoted: f.dotdotdoted,
      sep: f.sep, up: alt f.up {
        tt_frame_up(some(up_frame)) {
          tt_frame_up(some(dup_tt_frame(up_frame)))
        }
        tt_frame_up(none) { tt_frame_up(none) }
      }
     }
}

pure fn dup_tt_reader(&&r: tt_reader) -> tt_reader {
    @{sp_diag: r.sp_diag, interner: r.interner,
      mut cur: dup_tt_frame(r.cur),
      interpolations: r.interpolations,
      mut repeat_idx: copy r.repeat_idx, mut repeat_len: copy r.repeat_len,
      mut cur_tok: r.cur_tok, mut cur_span: r.cur_span}
}

pure fn lookup_cur_matched_by_matched(r: tt_reader,
                                      start: @named_match) -> @named_match {
    pure fn red(&&ad: @named_match, &&idx: uint) -> @named_match {
        alt *ad {
          matched_nonterminal(_) {
            // end of the line; duplicate henceforth
            ad
          }
          matched_seq(ads, _) { ads[idx] }
        }
    }
    vec::foldl(start, r.repeat_idx, red)
}

fn lookup_cur_matched(r: tt_reader, name: ident) -> @named_match {
    lookup_cur_matched_by_matched(r, r.interpolations.get(name))
}
enum lis {
    lis_unconstrained, lis_constraint(uint, ident), lis_contradiction(~str)
}

fn lockstep_iter_size(&&t: token_tree, &&r: tt_reader) -> lis {
    fn lis_merge(lhs: lis, rhs: lis) -> lis {
        alt lhs {
          lis_unconstrained { rhs }
          lis_contradiction(_) { lhs }
          lis_constraint(l_len, l_id) {
            alt rhs {
              lis_unconstrained { lhs }
              lis_contradiction(_) { rhs }
              lis_constraint(r_len, _) if l_len == r_len { lhs }
              lis_constraint(r_len, r_id) {
                lis_contradiction(#fmt["Inconsistent lockstep iteration: \
                                        '%s' has %u items, but '%s' has %u",
                                       *l_id, l_len, *r_id, r_len])
              }
            }
          }
        }
    }
    alt t {
      tt_delim(tts) | tt_seq(_, tts, _, _) {
        vec::foldl(lis_unconstrained, tts, {|lis, tt|
            lis_merge(lis, lockstep_iter_size(tt, r)) })
      }
      tt_tok(*) { lis_unconstrained }
      tt_nonterminal(_, name) {
        alt *lookup_cur_matched(r, name) {
          matched_nonterminal(_) { lis_unconstrained }
          matched_seq(ads, _) { lis_constraint(ads.len(), name) }
        }
      }
    }
}

fn tt_next_token(&&r: tt_reader) -> {tok: token, sp: span} {
    let ret_val = { tok: r.cur_tok, sp: r.cur_span };
    while r.cur.idx >= r.cur.readme.len() {
        /* done with this set; pop or repeat? */
        if ! r.cur.dotdotdoted
            || r.repeat_idx.last() == r.repeat_len.last() - 1 {

            alt r.cur.up {
              tt_frame_up(none) {
                r.cur_tok = EOF;
                ret ret_val;
              }
              tt_frame_up(some(tt_f)) {
                if r.cur.dotdotdoted {
                    vec::pop(r.repeat_idx); vec::pop(r.repeat_len);
                }

                r.cur = tt_f;
                r.cur.idx += 1u;
              }
            }

        } else { /* repeat */
            r.cur.idx = 0u;
            r.repeat_idx[r.repeat_idx.len() - 1u] += 1u;
            alt r.cur.sep {
              some(tk) {
                r.cur_tok = tk; /* repeat same span, I guess */
                ret ret_val;
              }
              none {}
            }
        }
    }
    loop { /* because it's easiest, this handles `tt_delim` not starting
    with a `tt_tok`, even though it won't happen */
        alt r.cur.readme[r.cur.idx] {
          tt_delim(tts) {
            r.cur = @{readme: tts, mut idx: 0u, dotdotdoted: false,
                      sep: none, up: tt_frame_up(option::some(r.cur)) };
            // if this could be 0-length, we'd need to potentially recur here
          }
          tt_tok(sp, tok) {
            r.cur_span = sp; r.cur_tok = tok;
            r.cur.idx += 1u;
            ret ret_val;
          }
          tt_seq(sp, tts, sep, zerok) {
            alt lockstep_iter_size(tt_seq(sp, tts, sep, zerok), r) {
              lis_unconstrained {
                r.sp_diag.span_fatal(
                    sp, /* blame macro writer */
                    ~"attempted to repeat an expression containing no syntax \
                     variables matched as repeating at this depth");
              }
              lis_contradiction(msg) { /* FIXME #2887 blame macro invoker
                                          instead*/
                r.sp_diag.span_fatal(sp, msg);
              }
              lis_constraint(len, _) {
                if len == 0 {
                    if !zerok {
                        r.sp_diag.span_fatal(sp, /* FIXME #2887 blame invoker
                                                  */
                                             ~"this must repeat at least \
                                              once");
                    }

                    r.cur.idx += 1u;
                    ret tt_next_token(r);
                } else {
                    vec::push(r.repeat_len, len);
                    vec::push(r.repeat_idx, 0u);
                    r.cur = @{readme: tts, mut idx: 0u, dotdotdoted: true,
                              sep: sep, up: tt_frame_up(option::some(r.cur))};
                }
              }
            }
          }
          // FIXME #2887: think about span stuff here
          tt_nonterminal(sp, ident) {
            alt *lookup_cur_matched(r, ident) {
              /* sidestep the interpolation tricks for ident because
              (a) idents can be in lots of places, so it'd be a pain
              (b) we actually can, since it's a token. */
              matched_nonterminal(nt_ident(sn,b)) {
                r.cur_span = sp; r.cur_tok = IDENT(sn,b);
                r.cur.idx += 1u;
                ret ret_val;
              }
              matched_nonterminal(other_whole_nt) {
                r.cur_span = sp; r.cur_tok = INTERPOLATED(other_whole_nt);
                r.cur.idx += 1u;
                ret ret_val;
              }
              matched_seq(*) {
                r.sp_diag.span_fatal(
                    copy r.cur_span, /* blame the macro writer */
                    #fmt["variable '%s' is still repeating at this depth",
                         *ident]);
              }
            }
          }
        }
    }

}<|endoftext|>


<commit_before><commit_msg>Add batching for persistence.<commit_after><|endoftext|>


<commit_before>#[link(name = "protobuf", vers = "0.1.0")];
#[crate_type = "lib"];
#[feature(globs)];
#[feature(managed_boxes)];

#[desc = "protobuf implementation for rust"];
#[license = "BSD"];
#[author = "Stepan Koltsov"];

pub use core::*;

mod core;
pub mod descriptor;
pub mod codegen;
pub mod rt;
mod misc;
mod zigzag;
mod hex;

#[cfg(test)]
mod shrug;
#[cfg(test)]
mod test;

// so `use protobuf::*` could work in descriptor mod
pub mod protobuf {
    pub use descriptor;
    pub use codegen;
    pub use core::*;
    pub use rt;
}
<commit_msg>Remove author annotation to mute rustc complains<commit_after>#[link(name = "protobuf", vers = "0.1.0")];
#[crate_type = "lib"];
#[feature(globs)];
#[feature(managed_boxes)];

#[desc = "protobuf implementation for rust"];
#[license = "BSD"];

pub use core::*;

mod core;
pub mod descriptor;
pub mod codegen;
pub mod rt;
mod misc;
mod zigzag;
mod hex;

#[cfg(test)]
mod shrug;
#[cfg(test)]
mod test;

// so `use protobuf::*` could work in descriptor mod
pub mod protobuf {
    pub use descriptor;
    pub use codegen;
    pub use core::*;
    pub use rt;
}
<|endoftext|>