<commit_before>//! Utility methods and constructors for Lua objects

use std::convert::From;
use std::cell;
use std::marker::PhantomData;

use rlua::{self, AnyUserData, FromLua, Function, Lua, MetaMethod, Table, ToLua, UserData,
           UserDataMethods, Value};

use super::class::Class;
use super::property::Property;
use super::signal;

/// The ObjectStateType trait is used to constrain the generic data types in the Object and Class structs.
/// They can be transferred to and from Lua user data and force type checking
pub trait ObjectStateType: UserData + Default + Send {}

impl<T> ObjectStateType for T where T: UserData + Default + Send {}

/// All Lua objects can be cast to this.
#[derive(Debug)]
pub struct Object<'lua, S: ObjectStateType>{
    pub obj: AnyUserData<'lua>,
    state: PhantomData<S>,
}

impl<'lua, S: ObjectStateType> Clone for Object<'lua, S> {
    fn clone(&self) -> Self {
        Object { obj: self.obj.clone(), state: PhantomData }
    }
}

impl<'lua, S: ObjectStateType> From<AnyUserData<'lua>> for Object<'lua, S> {
    fn from(obj: AnyUserData<'lua>) -> Self {
        Object { obj, state: PhantomData }
    }
}

impl<'lua, S: ObjectStateType> Into<AnyUserData<'lua>> for Object<'lua, S> {
    fn into(self) -> AnyUserData<'lua> {
        self.obj
    }
}

/// Construct a new object, used when using the default Objectable::new.
pub struct ObjectBuilder<'lua, S: ObjectStateType> {
    lua: &'lua Lua,
    object: Object<'lua, S>
}

impl<'lua, S: ObjectStateType> ObjectBuilder<'lua, S> {
    pub fn add_to_meta(self, new_meta: Table<'lua>) -> rlua::Result<Self> {
        let meta = self.object.get_metatable()?
                       .expect("Object had no meta table");
        for entry in new_meta.pairs::<rlua::Value, rlua::Value>() {
            let (key, value) = entry?;
            meta.set(key, value)?;
        }
        self.object.set_metatable(meta)?;
        Ok(self)
    }

    #[allow(dead_code)]
    pub fn add_to_signals(self, name: String, func: rlua::Function) -> rlua::Result<Self> {
        signal::connect_signal(self.lua, self.object.clone(), name, &[func])?;
        Ok(self)
    }

    pub fn handle_constructor_argument(self, args: Table) -> rlua::Result<Self> {
        let meta = self.object
                       .get_metatable()?
                       .expect("Object had no meta table");
        let class = meta.get::<_, AnyUserData>("__class")?;
        let class_table = class.get_user_value::<Table>()?;
        let props = class_table.get::<_, Vec<Property>>("properties")?;

        // Handle all table entries that correspond to known properties,
        // silently ignore all other keys
        for pair in args.pairs() {
            let (key, value): (Value, Value) = pair?;
            if let rlua::Value::String(key) = key {
                if let Ok(key) = key.to_str() {
                    // Find the property
                    for prop in props.iter() {
                        if prop.name == key {
                            // Property exists and has a cb_new callback
                            if let Some(ref new) = prop.cb_new {
                                let _: () = new.bind(self.object.clone())?.call(value)?;
                                break
                            }
                        }
                    }
                }
            }
        }
        Ok(self)
    }

    pub fn build(self) -> Object<'lua, S> {
        self.object
    }
}

/// Objects that represent OO lua objects.
///
/// Allows casting an object gotten back from the Lua runtime
/// into a concrete object so that Rust can do things with it.
///
impl<'lua, S: ObjectStateType> Object<'lua, S> {
    pub fn cast(obj: AnyUserData<'lua>) -> rlua::Result<Self> {
        if obj.is::<S>()? {
            Ok(obj.into())
        } else {
            use rlua::Error::RuntimeError;
            Err(RuntimeError("Could not cast object to concrete type".into()))
        }
    }

    /// Gets a reference to the internal state for the concrete object.
    pub fn state(&self) -> rlua::Result<cell::Ref<S>> {
        Ok(self.obj.borrow::<S>()?)
    }

    /// Gets a mutable reference to the internal state for the concrete object.
    pub fn state_mut(&mut self) -> rlua::Result<cell::RefMut<S>> {
        Ok(self.obj.borrow_mut::<S>()?)
    }

    /// Get the signals of the for this object
    pub fn signals(&self) -> rlua::Result<rlua::Table<'lua>> {
        self.get_associated_data::<Table>("signals")
    }

    /// Set a value to keep inside lua associate with the object, but
    ///     which should not be transfered to Rust for various reason
    ///     (e.g. reference to other objects which cause GC problems)
    pub fn set_associated_data<D: ToLua<'lua>>(&self, key: &str, value: D) -> rlua::Result<()> {
        self.obj.get_user_value::<Table<'lua>>()?.set::<_, D>(key, value)
    }

    /// Get a value to keep inside lua associate with the object
    pub fn get_associated_data<D: FromLua<'lua>>(&self, key: &str) -> rlua::Result<D> {
        self.obj.get_user_value::<Table<'lua>>()?.get::<_, D>(key)
    }

    /// Get the metatable for this object
    pub fn get_metatable(&self) -> rlua::Result<Option<Table<'lua>>> {
        Ok(self.obj.get_user_value::<Table<'lua>>()?.get_metatable())
    }

    /// Set the metatable for this object
    pub fn set_metatable(&self, meta: Table<'lua>) -> rlua::Result<()> {
         self.obj.get_user_value::<Table<'lua>>()?.set_metatable(Some(meta));
         Ok(())
    }

    /// Lua objects in Way Cooler are just how they are in Awesome:
    /// * We expose the user data directly.
    /// * ObjectStateType for the object is stored using set_user_value in a "wrapper"
    /// table. * The wrapper table has a data field which hosts the data.
    /// * Class methods/attributes are on the meta table of the wrapper table.
    pub fn allocate(lua: &'lua Lua, class: Class<S>) -> rlua::Result<ObjectBuilder<'lua, S>> {
        let obj = lua.create_userdata(S::default())?;
        // TODO Increment the instance count
        let wrapper_table = lua.create_table()?;
        let data_table = lua.create_table()?;
        wrapper_table.set("data", data_table)?;
        let meta = lua.create_table()?;
        meta.set("__class", class)?;
        meta.set("properties", Vec::<Property>::new().to_lua(lua)?)?;
        meta.set("signals", lua.create_table()?)?;
        meta.set("connect_signal", lua.create_function(connect_signal::<S>)?)?;
        meta.set("disconnect_signal", lua.create_function(disconnect_signal::<S>)?)?;
        meta.set("emit_signal", lua.create_function(emit_signal::<S>)?)?;
        meta.set("__index", meta.clone())?;
        meta.set("__tostring", lua.create_function(default_tostring::<S>)?)?;
        wrapper_table.set_metatable(Some(meta));
        obj.set_user_value(wrapper_table)?;
        // TODO Emit new signal event
        let object = Object { obj, state: PhantomData };
        Ok(ObjectBuilder { object, lua })
    }
}

impl<'lua, S: ObjectStateType> ToLua<'lua> for Object<'lua, S> {
    fn to_lua(self, _: &'lua Lua) -> rlua::Result<Value<'lua>> {
        Ok(Value::UserData(self.obj))
    }
}

impl<'lua, S: ObjectStateType> FromLua<'lua> for Object<'lua, S> {
    fn from_lua(val: Value<'lua>, _lua: &'lua Lua) -> rlua::Result<Self> {
        if let Value::UserData(obj) = val {
            Object::cast(obj)
        } else {
            Err(rlua::Error::RuntimeError("Invalid data supplied".into()))
        }
    }
}

/// Can be used for implementing UserData for Lua objects. This provides some
/// default metafunctions.
pub fn default_add_methods<S>(methods: &mut UserDataMethods<S>)
    where S: ObjectStateType
{
    methods.add_meta_function(MetaMethod::Index, default_index::<S>);
    methods.add_meta_function(MetaMethod::NewIndex, default_newindex::<S>);
    methods.add_meta_function(MetaMethod::ToString, default_tostring::<S>);
}

/// Default indexing of an Awesome object.
///
/// Automatically looks up contents in meta table, so instead of overriding this
/// it's easier to just add the required data in the meta table.
pub fn default_index<'lua, S: ObjectStateType>(lua: &'lua Lua,
                                    (obj, index): (Object<'lua, S>, Value<'lua>))
                                    -> rlua::Result<Value<'lua>> {
    // Look up in metatable first
    let meta = obj.get_metatable()?.expect("Object had no metatable");
    if meta.get::<_, AnyUserData>("__class").is_ok() {
        if let Ok(val) = meta.raw_get::<_, Value>(index.clone()) {
            match val {
                Value::Nil => {}
                val => return Ok(val)
            }
        }
    }
    let index = match String::from_lua(index, lua) {
        Ok(s) => s,
        Err(_) => return Ok(Value::Nil)
    };
    match index.as_str() {
        "valid" => {
            Ok(Value::Boolean(if let Ok(class) = meta.get::<_, AnyUserData>("__class") {
                                  let class: Class<S> = class.into();
                                  class.checker()?.map(|checker| checker(obj)).unwrap_or(true)
                              } else {
                                  false
                              }))
        }
        "data" => obj.obj.get_user_value(),
        index => {
            // Try see if there is a property of the class with the name
            if let Ok(class) = meta.get::<_, AnyUserData>("__class") {
                let class_table = class.get_user_value::<Table>()?;
                let props = class_table.get::<_, Vec<Property>>("properties")?;
                for prop in props {
                    if prop.name.as_str() == index {
                        // Property exists and has an index callback
                        if let Some(index) = prop.cb_index {
                            return index.call(obj)
                        }
                    }
                }
                if let Some(meta) = class_table.get_metatable() {
                    match meta.get::<_, Function>("__index_miss_handler") {
                        Ok(function) => return function.bind(obj)?.call(index),
                        Err(_) => {}
                    }
                }
            }
            // TODO property miss handler if index doesn't exst
            Ok(rlua::Value::Nil)
        }
    }
}

/// Default new indexing (assignment) of an Awesome object.
///
/// Automatically looks up contents in meta table, so instead of overriding this
/// it's easier to just add the required data in the meta table.
pub fn default_newindex<'lua, S: ObjectStateType>(
                _: &'lua Lua,
                (obj, index, val): (Object<'lua, S>, String, Value<'lua>))
                -> rlua::Result<Value<'lua>> {
    // Look up in metatable first
    if let Some(meta) = obj.get_metatable()? {
        if let Ok(val) = meta.raw_get::<_, Value>(index.clone()) {
            match val {
                Value::Nil => {}
                val => return Ok(val)
            }
        }
        let class = meta.get::<_, AnyUserData>("__class")?;
        let class_table = class.get_user_value::<Table>()?;
        let props = class_table.get::<_, Vec<Property>>("properties")?;
        for prop in props {
            if prop.name.as_str() == index {
                // Property exists and has a newindex callback
                if let Some(newindex) = prop.cb_newindex {
                    return newindex.bind(obj.clone())?.call(val)
                }
            }
        }
        if let Some(meta) = class_table.get_metatable() {
            match meta.get::<_, Function>("__newindex_miss_handler") {
                Ok(function) => return function.bind(obj)?.call((index, val)),
                Err(_) => {}
            }
        }
        // TODO property miss handler if index doesn't exist
    }
    Ok(Value::Nil)
}

pub fn default_tostring<'lua, S>(_: &'lua Lua, obj: Object<'lua, S>)
        -> rlua::Result<String>
        where S: ObjectStateType {
    if let Some(meta) = obj.get_metatable()? {
        let class = meta.get::<_, AnyUserData>("__class")?;
        let class_table = class.get_user_value::<Table>()?;
        let name = class_table.get::<_, String>("name")?;
        return Ok(format!("{}: {:p}", name, &*obj.state()?))
    }
    Err(rlua::Error::UserDataTypeMismatch)
}

fn connect_signal<S: ObjectStateType>(lua: &Lua,
                            (obj, signal, func): (Object<S>, String, Function))
                            -> rlua::Result<()> {
    signal::connect_signal(lua, obj.into(), signal, &[func])
}

fn disconnect_signal<S: ObjectStateType>(lua: &Lua,
                               (obj, signal): (Object<S>, String))
                               -> rlua::Result<()> {
    signal::disconnect_signal(lua, obj.into(), signal)
}

fn emit_signal<S: ObjectStateType>(lua: &Lua,
                        (obj, signal, args): (Object<S>, String, Value))
                        -> rlua::Result<()> {
    signal::emit_object_signal(lua, obj.into(), signal, args)
}
<commit_msg>Make `obj` property private<commit_after>//! Utility methods and constructors for Lua objects

use std::convert::From;
use std::cell;
use std::marker::PhantomData;

use rlua::{self, AnyUserData, FromLua, Function, Lua, MetaMethod, Table, ToLua, UserData,
           UserDataMethods, Value};

use super::class::Class;
use super::property::Property;
use super::signal;

/// The ObjectStateType trait is used to constrain the generic data types in the Object and Class structs.
/// They can be transferred to and from Lua user data and force type checking
pub trait ObjectStateType: UserData + Default + Send {}

impl<T> ObjectStateType for T where T: UserData + Default + Send {}

/// All Lua objects can be cast to this.
#[derive(Debug)]
pub struct Object<'lua, S: ObjectStateType>{
    obj: AnyUserData<'lua>,
    state: PhantomData<S>,
}

impl<'lua, S: ObjectStateType> Clone for Object<'lua, S> {
    fn clone(&self) -> Self {
        Object { obj: self.obj.clone(), state: PhantomData }
    }
}

impl<'lua, S: ObjectStateType> From<AnyUserData<'lua>> for Object<'lua, S> {
    fn from(obj: AnyUserData<'lua>) -> Self {
        Object { obj, state: PhantomData }
    }
}

impl<'lua, S: ObjectStateType> Into<AnyUserData<'lua>> for Object<'lua, S> {
    fn into(self) -> AnyUserData<'lua> {
        self.obj
    }
}

/// Construct a new object, used when using the default Objectable::new.
pub struct ObjectBuilder<'lua, S: ObjectStateType> {
    lua: &'lua Lua,
    object: Object<'lua, S>
}

impl<'lua, S: ObjectStateType> ObjectBuilder<'lua, S> {
    pub fn add_to_meta(self, new_meta: Table<'lua>) -> rlua::Result<Self> {
        let meta = self.object.get_metatable()?
                       .expect("Object had no meta table");
        for entry in new_meta.pairs::<rlua::Value, rlua::Value>() {
            let (key, value) = entry?;
            meta.set(key, value)?;
        }
        self.object.set_metatable(meta)?;
        Ok(self)
    }

    #[allow(dead_code)]
    pub fn add_to_signals(self, name: String, func: rlua::Function) -> rlua::Result<Self> {
        signal::connect_signal(self.lua, self.object.clone(), name, &[func])?;
        Ok(self)
    }

    pub fn handle_constructor_argument(self, args: Table) -> rlua::Result<Self> {
        let meta = self.object
                       .get_metatable()?
                       .expect("Object had no meta table");
        let class = meta.get::<_, AnyUserData>("__class")?;
        let class_table = class.get_user_value::<Table>()?;
        let props = class_table.get::<_, Vec<Property>>("properties")?;

        // Handle all table entries that correspond to known properties,
        // silently ignore all other keys
        for pair in args.pairs() {
            let (key, value): (Value, Value) = pair?;
            if let rlua::Value::String(key) = key {
                if let Ok(key) = key.to_str() {
                    // Find the property
                    for prop in props.iter() {
                        if prop.name == key {
                            // Property exists and has a cb_new callback
                            if let Some(ref new) = prop.cb_new {
                                let _: () = new.bind(self.object.clone())?.call(value)?;
                                break
                            }
                        }
                    }
                }
            }
        }
        Ok(self)
    }

    pub fn build(self) -> Object<'lua, S> {
        self.object
    }
}

/// Objects that represent OO lua objects.
///
/// Allows casting an object gotten back from the Lua runtime
/// into a concrete object so that Rust can do things with it.
///
impl<'lua, S: ObjectStateType> Object<'lua, S> {
    pub fn cast(obj: AnyUserData<'lua>) -> rlua::Result<Self> {
        if obj.is::<S>()? {
            Ok(obj.into())
        } else {
            use rlua::Error::RuntimeError;
            Err(RuntimeError("Could not cast object to concrete type".into()))
        }
    }

    /// Gets a reference to the internal state for the concrete object.
    pub fn state(&self) -> rlua::Result<cell::Ref<S>> {
        Ok(self.obj.borrow::<S>()?)
    }

    /// Gets a mutable reference to the internal state for the concrete object.
    pub fn state_mut(&mut self) -> rlua::Result<cell::RefMut<S>> {
        Ok(self.obj.borrow_mut::<S>()?)
    }

    /// Get the signals of the for this object
    pub fn signals(&self) -> rlua::Result<rlua::Table<'lua>> {
        self.get_associated_data::<Table>("signals")
    }

    /// Set a value to keep inside lua associate with the object, but
    ///     which should not be transfered to Rust for various reason
    ///     (e.g. reference to other objects which cause GC problems)
    pub fn set_associated_data<D: ToLua<'lua>>(&self, key: &str, value: D) -> rlua::Result<()> {
        self.obj
            .get_user_value::<Table<'lua>>()?
            .set::<_, D>(key, value)
    }

    /// Get a value to keep inside lua associate with the object
    pub fn get_associated_data<D: FromLua<'lua>>(&self, key: &str) -> rlua::Result<D> {
        self.obj
            .get_user_value::<Table<'lua>>()?
            .get::<_, D>(key)
    }

    /// Get the metatable for this object
    pub fn get_metatable(&self) -> rlua::Result<Option<Table<'lua>>> {
        Ok(self.obj.get_user_value::<Table<'lua>>()?.get_metatable())
    }

    /// Set the metatable for this object
    pub fn set_metatable(&self, meta: Table<'lua>) -> rlua::Result<()> {
         self.obj.get_user_value::<Table<'lua>>()?.set_metatable(Some(meta));
         Ok(())
    }

    /// Lua objects in Way Cooler are just how they are in Awesome:
    /// * We expose the user data directly.
    /// * ObjectStateType for the object is stored using set_user_value in a "wrapper"
    /// table. * The wrapper table has a data field which hosts the data.
    /// * Class methods/attributes are on the meta table of the wrapper table.
    pub fn allocate(lua: &'lua Lua, class: Class<S>) -> rlua::Result<ObjectBuilder<'lua, S>> {
        let obj = lua.create_userdata(S::default())?;
        // TODO Increment the instance count
        let wrapper_table = lua.create_table()?;
        let data_table = lua.create_table()?;
        wrapper_table.set("data", data_table)?;
        let meta = lua.create_table()?;
        meta.set("__class", class)?;
        meta.set("properties", Vec::<Property>::new().to_lua(lua)?)?;
        meta.set("signals", lua.create_table()?)?;
        meta.set("connect_signal", lua.create_function(connect_signal::<S>)?)?;
        meta.set("disconnect_signal", lua.create_function(disconnect_signal::<S>)?)?;
        meta.set("emit_signal", lua.create_function(emit_signal::<S>)?)?;
        meta.set("__index", meta.clone())?;
        meta.set("__tostring", lua.create_function(default_tostring::<S>)?)?;
        wrapper_table.set_metatable(Some(meta));
        obj.set_user_value(wrapper_table)?;
        // TODO Emit new signal event
        let object = Object { obj, state: PhantomData };
        Ok(ObjectBuilder { object, lua })
    }
}

impl<'lua, S: ObjectStateType> ToLua<'lua> for Object<'lua, S> {
    fn to_lua(self, _: &'lua Lua) -> rlua::Result<Value<'lua>> {
        Ok(Value::UserData(self.obj))
    }
}

impl<'lua, S: ObjectStateType> FromLua<'lua> for Object<'lua, S> {
    fn from_lua(val: Value<'lua>, _lua: &'lua Lua) -> rlua::Result<Self> {
        if let Value::UserData(obj) = val {
            Object::cast(obj)
        } else {
            Err(rlua::Error::RuntimeError("Invalid data supplied".into()))
        }
    }
}

/// Can be used for implementing UserData for Lua objects. This provides some
/// default metafunctions.
pub fn default_add_methods<S>(methods: &mut UserDataMethods<S>)
    where S: ObjectStateType
{
    methods.add_meta_function(MetaMethod::Index, default_index::<S>);
    methods.add_meta_function(MetaMethod::NewIndex, default_newindex::<S>);
    methods.add_meta_function(MetaMethod::ToString, default_tostring::<S>);
}

/// Default indexing of an Awesome object.
///
/// Automatically looks up contents in meta table, so instead of overriding this
/// it's easier to just add the required data in the meta table.
pub fn default_index<'lua, S: ObjectStateType>(lua: &'lua Lua,
                                    (obj, index): (Object<'lua, S>, Value<'lua>))
                                    -> rlua::Result<Value<'lua>> {
    // Look up in metatable first
    let meta = obj.get_metatable()?.expect("Object had no metatable");
    if meta.get::<_, AnyUserData>("__class").is_ok() {
        if let Ok(val) = meta.raw_get::<_, Value>(index.clone()) {
            match val {
                Value::Nil => {}
                val => return Ok(val)
            }
        }
    }
    let index = match String::from_lua(index, lua) {
        Ok(s) => s,
        Err(_) => return Ok(Value::Nil)
    };
    match index.as_str() {
        "valid" => {
            Ok(Value::Boolean(if let Ok(class) = meta.get::<_, AnyUserData>("__class") {
                                  let class: Class<S> = class.into();
                                  class.checker()?.map(|checker| checker(obj)).unwrap_or(true)
                              } else {
                                  false
                              }))
        }
        "data" => obj.obj.get_user_value(),
        index => {
            // Try see if there is a property of the class with the name
            if let Ok(class) = meta.get::<_, AnyUserData>("__class") {
                let class_table = class.get_user_value::<Table>()?;
                let props = class_table.get::<_, Vec<Property>>("properties")?;
                for prop in props {
                    if prop.name.as_str() == index {
                        // Property exists and has an index callback
                        if let Some(index) = prop.cb_index {
                            return index.call(obj)
                        }
                    }
                }
                if let Some(meta) = class_table.get_metatable() {
                    match meta.get::<_, Function>("__index_miss_handler") {
                        Ok(function) => return function.bind(obj)?.call(index),
                        Err(_) => {}
                    }
                }
            }
            // TODO property miss handler if index doesn't exst
            Ok(rlua::Value::Nil)
        }
    }
}

/// Default new indexing (assignment) of an Awesome object.
///
/// Automatically looks up contents in meta table, so instead of overriding this
/// it's easier to just add the required data in the meta table.
pub fn default_newindex<'lua, S: ObjectStateType>(
                _: &'lua Lua,
                (obj, index, val): (Object<'lua, S>, String, Value<'lua>))
                -> rlua::Result<Value<'lua>> {
    // Look up in metatable first
    if let Some(meta) = obj.get_metatable()? {
        if let Ok(val) = meta.raw_get::<_, Value>(index.clone()) {
            match val {
                Value::Nil => {}
                val => return Ok(val)
            }
        }
        let class = meta.get::<_, AnyUserData>("__class")?;
        let class_table = class.get_user_value::<Table>()?;
        let props = class_table.get::<_, Vec<Property>>("properties")?;
        for prop in props {
            if prop.name.as_str() == index {
                // Property exists and has a newindex callback
                if let Some(newindex) = prop.cb_newindex {
                    return newindex.bind(obj.clone())?.call(val)
                }
            }
        }
        if let Some(meta) = class_table.get_metatable() {
            match meta.get::<_, Function>("__newindex_miss_handler") {
                Ok(function) => return function.bind(obj)?.call((index, val)),
                Err(_) => {}
            }
        }
        // TODO property miss handler if index doesn't exist
    }
    Ok(Value::Nil)
}

pub fn default_tostring<'lua, S>(_: &'lua Lua, obj: Object<'lua, S>)
        -> rlua::Result<String>
        where S: ObjectStateType {
    if let Some(meta) = obj.get_metatable()? {
        let class = meta.get::<_, AnyUserData>("__class")?;
        let class_table = class.get_user_value::<Table>()?;
        let name = class_table.get::<_, String>("name")?;
        return Ok(format!("{}: {:p}", name, &*obj.state()?))
    }
    Err(rlua::Error::UserDataTypeMismatch)
}

fn connect_signal<S: ObjectStateType>(lua: &Lua,
                            (obj, signal, func): (Object<S>, String, Function))
                            -> rlua::Result<()> {
    signal::connect_signal(lua, obj.into(), signal, &[func])
}

fn disconnect_signal<S: ObjectStateType>(lua: &Lua,
                               (obj, signal): (Object<S>, String))
                               -> rlua::Result<()> {
    signal::disconnect_signal(lua, obj.into(), signal)
}

fn emit_signal<S: ObjectStateType>(lua: &Lua,
                        (obj, signal, args): (Object<S>, String, Value))
                        -> rlua::Result<()> {
    signal::emit_object_signal(lua, obj.into(), signal, args)
}
<|endoftext|>


<commit_before>//! This crate contains a single public function
//! [`get_path_for_executable`](fn.get_path_for_executable.html).
//! See docs there for more information.
use std::{env, iter, path::PathBuf};

pub fn cargo() -> PathBuf {
    get_path_for_executable("cargo")
}

pub fn rustc() -> PathBuf {
    get_path_for_executable("rustc")
}

pub fn rustup() -> PathBuf {
    get_path_for_executable("rustup")
}

pub fn rustfmt() -> PathBuf {
    get_path_for_executable("rustfmt")
}

/// Return a `PathBuf` to use for the given executable.
///
/// E.g., `get_path_for_executable("cargo")` may return just `cargo` if that
/// gives a valid Cargo executable; or it may return a full path to a valid
/// Cargo.
fn get_path_for_executable(executable_name: &'static str) -> PathBuf {
    // The current implementation checks three places for an executable to use:
    // 1) Appropriate environment variable (erroring if this is set but not a usable executable)
    //      example: for cargo, this checks $CARGO environment variable; for rustc, $RUSTC; etc
    // 2) `<executable_name>`
    //      example: for cargo, this tries just `cargo`, which will succeed if `cargo` is on the $PATH
    // 3) `~/.cargo/bin/<executable_name>`
    //      example: for cargo, this tries ~/.cargo/bin/cargo
    //      It seems that this is a reasonable place to try for cargo, rustc, and rustup
    let env_var = executable_name.to_ascii_uppercase();
    if let Some(path) = env::var_os(&env_var) {
        return path.into();
    }

    if lookup_in_path(executable_name) {
        return executable_name.into();
    }

    if let Some(mut path) = home::home_dir() {
        path.push(".cargo");
        path.push("bin");
        path.push(executable_name);
        if path.is_file() {
            return path;
        }
    }
    executable_name.into()
}

fn lookup_in_path(exec: &str) -> bool {
    let paths = env::var_os("PATH").unwrap_or_default();
    let mut candidates = env::split_paths(&paths).flat_map(|path| {
        let candidate = path.join(&exec);
        let with_exe = match env::consts::EXE_EXTENSION {
            "" => None,
            it => Some(candidate.with_extension(it)),
        };
        iter::once(candidate).chain(with_exe)
    });
    candidates.any(|it| it.is_file())
}
<commit_msg>Better exe probing<commit_after>//! This crate contains a single public function
//! [`get_path_for_executable`](fn.get_path_for_executable.html).
//! See docs there for more information.
use std::{env, iter, path::PathBuf};

pub fn cargo() -> PathBuf {
    get_path_for_executable("cargo")
}

pub fn rustc() -> PathBuf {
    get_path_for_executable("rustc")
}

pub fn rustup() -> PathBuf {
    get_path_for_executable("rustup")
}

pub fn rustfmt() -> PathBuf {
    get_path_for_executable("rustfmt")
}

/// Return a `PathBuf` to use for the given executable.
///
/// E.g., `get_path_for_executable("cargo")` may return just `cargo` if that
/// gives a valid Cargo executable; or it may return a full path to a valid
/// Cargo.
fn get_path_for_executable(executable_name: &'static str) -> PathBuf {
    // The current implementation checks three places for an executable to use:
    // 1) Appropriate environment variable (erroring if this is set but not a usable executable)
    //      example: for cargo, this checks $CARGO environment variable; for rustc, $RUSTC; etc
    // 2) `<executable_name>`
    //      example: for cargo, this tries just `cargo`, which will succeed if `cargo` is on the $PATH
    // 3) `~/.cargo/bin/<executable_name>`
    //      example: for cargo, this tries ~/.cargo/bin/cargo
    //      It seems that this is a reasonable place to try for cargo, rustc, and rustup
    let env_var = executable_name.to_ascii_uppercase();
    if let Some(path) = env::var_os(&env_var) {
        return path.into();
    }

    if lookup_in_path(executable_name) {
        return executable_name.into();
    }

    if let Some(mut path) = home::home_dir() {
        path.push(".cargo");
        path.push("bin");
        path.push(executable_name);
        if let Some(path) = probe(path) {
            return path;
        }
    }

    executable_name.into()
}

fn lookup_in_path(exec: &str) -> bool {
    let paths = env::var_os("PATH").unwrap_or_default();
    env::split_paths(&paths).map(|path| path.join(exec)).find_map(probe).is_some()
}

fn probe(path: PathBuf) -> Option<PathBuf> {
    let with_extension = match env::consts::EXE_EXTENSION {
        "" => None,
        it => Some(path.with_extension(it)),
    };
    iter::once(path).chain(with_extension).find(|it| it.is_file())
}
<|endoftext|>


<commit_before>use std::fmt;
use world::{HEX_INNER_RADIUS, HEX_OUTER_RADIUS};
use super::{AxialType, DefaultFloat, Point2f};
use std::ops::{Add, Div, Mul, Sub};

/// A 2-dimensional point in axial coordinates. See [here][hex-blog] for more
/// information.
///
/// [hex-blog]: http://www.redblobgames.com/grids/hexagons/#coordinates
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
#[repr(C, packed)]
pub struct AxialPoint {
    pub q: AxialType,
    pub r: AxialType,
}

// TODO: implement cgmath::Array
// TODO: implement cgmath::MatricSpace
// TODO: implement cgmath::EuclideanSpace
// TODO: implement ops::{ ... }
// For all of the above, see
// http://bjz.github.io/cgmath/cgmath/struct.Point2.html
//

impl AxialPoint {
    pub fn new(q: AxialType, r: AxialType) -> Self {
        AxialPoint { q: q, r: r }
    }

    /// Returns the position of the hexagons center in the standard coordinate
    /// system using `world::{HEX_INNER_RADIUS, HEX_OUTER_RADIUS}`.
    pub fn to_real(&self) -> Point2f {
        Point2f {
            x: ((2 * self.q + self.r) as DefaultFloat) * HEX_INNER_RADIUS,
            y: (self.r as DefaultFloat) * (3.0 / 2.0) * HEX_OUTER_RADIUS,
        }
    }

    /// Returns the `s` component of corresponding cube coordinates. In cube
    /// coordinates 'q + r + s = 0', so saving `s` is redundant and can be
    /// calculated on the fly when needed.
    pub fn s(&self) -> AxialType {
        -self.q - self.r
    }
}

impl fmt::Debug for AxialPoint {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_tuple("")
            .field(&self.q)
            .field(&self.r)
            .finish()
    }
}

impl Add<AxialPoint> for AxialPoint {
    type Output = AxialPoint;

    /// adds two Points together similar to vectors
    /// Returns an AxialPoint
    fn add(self, _rhs: AxialPoint) -> AxialPoint {
        AxialPoint {
            q: self.q + _rhs.q,
            r: self.r + _rhs.r,
        }
    }
}

impl Sub<AxialPoint> for AxialPoint {
    type Output = AxialPoint;

    /// substracts two Points similar to vectors
    /// Returns an AxialPoint
    fn sub(self, _rhs: AxialPoint) -> AxialPoint {
        AxialPoint {
            q: self.q - _rhs.q,
            r: self.r - _rhs.r,
        }
    }
}

impl Mul<AxialType> for AxialPoint {
    type Output = AxialPoint;

    /// Multiplies a point and a scalar
    /// Returns an AxialPoint
    fn mul(self, _rhs: AxialType) -> AxialPoint {
        AxialPoint {
            q: self.q * _rhs,
            r: self.r * _rhs,
        }
    }
}

impl Div<AxialType> for AxialPoint {
    type Output = AxialPoint;

    /// Divides a point and a scalar
    /// Returns an AxialPoint
    fn div(self, _rhs: AxialType) -> AxialPoint {
        AxialPoint {
            q: self.q / _rhs,
            r: self.r / _rhs,
        }
    }
}
<commit_msg>Basic functions for axial_point<commit_after>use std::fmt;
use world::{HEX_INNER_RADIUS, HEX_OUTER_RADIUS};
use super::{AxialType, DefaultFloat, Point2f};
use std::ops::{Add, Div, Index, IndexMut, Mul, Sub};
use math::cgmath::{Array, Zero};

/// A 2-dimensional point in axial coordinates. See [here][hex-blog] for more
/// information.
///
/// [hex-blog]: http://www.redblobgames.com/grids/hexagons/#coordinates
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
#[repr(C, packed)]
pub struct AxialPoint {
    pub q: AxialType,
    pub r: AxialType,
}

// TODO: implement cgmath::Array
// TODO: implement cgmath::MatricSpace
// TODO: implement cgmath::EuclideanSpace
// TODO: implement ops::{ ... }
// For all of the above, see
// http://bjz.github.io/cgmath/cgmath/struct.Point2.html
//

impl AxialPoint {
    pub fn new(q: AxialType, r: AxialType) -> Self {
        AxialPoint { q: q, r: r }
    }

    /// Returns the position of the hexagons center in the standard coordinate
    /// system using `world::{HEX_INNER_RADIUS, HEX_OUTER_RADIUS}`.
    pub fn to_real(&self) -> Point2f {
        Point2f {
            x: ((2 * self.q + self.r) as DefaultFloat) * HEX_INNER_RADIUS,
            y: (self.r as DefaultFloat) * (3.0 / 2.0) * HEX_OUTER_RADIUS,
        }
    }

    /// Returns the `s` component of corresponding cube coordinates. In cube
    /// coordinates 'q + r + s = 0', so saving `s` is redundant and can be
    /// calculated on the fly when needed.
    pub fn s(&self) -> AxialType {
        -self.q - self.r
    }
}

impl fmt::Debug for AxialPoint {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_tuple("")
            .field(&self.q)
            .field(&self.r)
            .finish()
    }
}

/// ********************Basic Arithmetics************

impl Add<AxialPoint> for AxialPoint {
    type Output = AxialPoint;

    /// adds two Points together similar to vectors
    /// Returns an AxialPoint
    fn add(self, _rhs: AxialPoint) -> AxialPoint {
        AxialPoint {
            q: self.q + _rhs.q,
            r: self.r + _rhs.r,
        }
    }
}

impl Sub<AxialPoint> for AxialPoint {
    type Output = AxialPoint;

    /// substracts two Points similar to vectors
    /// Returns an AxialPoint
    fn sub(self, _rhs: AxialPoint) -> AxialPoint {
        AxialPoint {
            q: self.q - _rhs.q,
            r: self.r - _rhs.r,
        }
    }
}

impl Mul<AxialType> for AxialPoint {
    type Output = AxialPoint;

    /// Multiplies a point and a scalar
    /// Returns an AxialPoint
    fn mul(self, _rhs: AxialType) -> AxialPoint {
        AxialPoint {
            q: self.q * _rhs,
            r: self.r * _rhs,
        }
    }
}

impl Div<AxialType> for AxialPoint {
    type Output = AxialPoint;

    /// Divides a point and a scalar
    /// Returns an AxialPoint
    fn div(self, _rhs: AxialType) -> AxialPoint {
        AxialPoint {
            q: self.q / _rhs,
            r: self.r / _rhs,
        }
    }
}
/// ********************Zero-Implementation************
impl Zero for AxialPoint {
    fn zero() -> AxialPoint {
        AxialPoint { q: 0, r: 0 }
    }
    fn is_zero(&self) -> bool {
        self.q == 0 && self.r == 0
    }
}

/// ********************Index************

impl Index<usize> for AxialPoint {
    type Output = AxialType;
    fn index<'a>(&'a self, index: usize) -> &'a AxialType {
        match index {
            0 => &self.q,
            1 => &self.r,
            _ => panic!("Index out of bounds!"),
        }
    }
}

impl IndexMut<usize> for AxialPoint {
    fn index_mut<'a>(&'a mut self, index: usize) -> &'a mut AxialType {
        match index {
            0 => &mut self.q,
            1 => &mut self.r,
            _ => panic!("Index out of bounds!"),
        }
    }
}

/// ********************Array************

impl Array for AxialPoint {
    type Element = AxialType;

    fn from_value(x: AxialType) -> AxialPoint {
        AxialPoint { q: x, r: x }
    }

    fn sum(self) -> AxialType {
        self.q + self.r
    }

    fn product(self) -> AxialType {
        self.q * self.r
    }

    fn min(self) -> AxialType {
        if self.q < self.r { self.q } else { self.r }
    }
    fn max(self) -> AxialType {
        if self.q < self.r { self.r } else { self.q }
    }
}
<|endoftext|>


<commit_before>// Copyright 2018 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use crate::proto_grpc::OctreeClient;
use futures::{Future, Stream};
use grpcio::{ChannelBuilder, EnvBuilder};
use nalgebra::Point3;
use point_viewer::color::Color;
use point_viewer::data_provider::{DataProvider, DataProviderFactoryResult};
use point_viewer::errors::*;
use point_viewer::geometry::Aabb;
use point_viewer::proto::Meta;
use point_viewer::Point;
pub use point_viewer_grpc_proto_rust::proto;
pub use point_viewer_grpc_proto_rust::proto_grpc;
use std::collections::HashMap;
use std::io::{Cursor, Read};
use std::sync::Arc;

pub mod service;

pub struct GrpcOctreeDataProvider {
    client: OctreeClient,
    octree_id: String,
}

impl GrpcOctreeDataProvider {
    pub fn from_address(addr: &str) -> Result<Self> {
        let mut addr_parts = addr.trim_matches('/').splitn(2, '/');
        let addr = addr_parts.next().ok_or_else(|| "Invalid address.")?;
        let octree_id = addr_parts.next().unwrap_or_default().to_string();
        let env = Arc::new(EnvBuilder::new().build());
        let ch = ChannelBuilder::new(env)
            .max_receive_message_len(::std::i32::MAX)
            .connect(addr);
        let client = OctreeClient::new(ch);

        Ok(GrpcOctreeDataProvider { client, octree_id })
    }

    pub fn get_points_in_box(
        &self,
        bounding_box: &Aabb,
        mut func: impl FnMut(&[Point]) -> bool,
    ) -> Result<()> {
        let mut req = proto::GetPointsInBoxRequest::new();
        req.set_octree_id(self.octree_id.clone());
        req.mut_bounding_box().mut_min().set_x(bounding_box.min().x);
        req.mut_bounding_box().mut_min().set_y(bounding_box.min().y);
        req.mut_bounding_box().mut_min().set_z(bounding_box.min().z);
        req.mut_bounding_box().mut_max().set_x(bounding_box.max().x);
        req.mut_bounding_box().mut_max().set_y(bounding_box.max().y);
        req.mut_bounding_box().mut_max().set_z(bounding_box.max().z);
        let replies = self
            .client
            .get_points_in_box(&req)
            .map_err(|_| point_viewer::errors::ErrorKind::Grpc)?;

        let mut points = Vec::new();
        let mut interrupted = false;
        let result = replies
            .for_each(|reply| {
                let last_num_points = points.len();
                for (p, color) in reply.positions.iter().zip(reply.colors.iter()) {
                    points.push(Point {
                        position: Point3::from(p),
                        color: Color {
                            red: color.red,
                            green: color.green,
                            blue: color.blue,
                            alpha: color.alpha,
                        }
                        .to_u8(),
                        intensity: None,
                    });
                }

                if reply.intensities.len() == reply.positions.len() {
                    for (i, p) in reply.intensities.iter().zip(&mut points[last_num_points..]) {
                        p.intensity = Some(*i);
                    }
                }

                if !func(&points) {
                    interrupted = true;
                    return Err(grpcio::Error::QueueShutdown);
                }
                points.clear();
                Ok(())
            })
            .wait()
            .map_err(|_| point_viewer::errors::ErrorKind::Grpc);
        if result.is_err() && !interrupted {
            result?;
        }
        Ok(())
    }
}

impl DataProvider for GrpcOctreeDataProvider {
    fn meta_proto(&self) -> Result<Meta> {
        let mut req = proto::GetMetaRequest::new();
        req.set_octree_id(self.octree_id.clone());
        let reply = self
            .client
            .get_meta(&req)
            .map_err(|_| point_viewer::errors::ErrorKind::Grpc)?;
        Ok(reply.meta.unwrap())
    }

    fn data(
        &self,
        node_id: &str,
        node_attributes: &[&str],
    ) -> Result<HashMap<String, Box<dyn Read + Send>>> {
        let mut req = proto::GetNodeDataRequest::new();
        req.set_octree_id(self.octree_id.clone());
        req.set_id(node_id.to_string());
        let reply = self
            .client
            .get_node_data(&req)
            .map_err(|_| point_viewer::errors::ErrorKind::Grpc)?;
        let mut readers = HashMap::<String, Box<dyn Read + Send>>::new();
        for node_attribute in node_attributes {
            let reader: Box<dyn Read + Send> = match *node_attribute {
                "position" => Box::new(Cursor::new(reply.position.clone())),
                "color" => Box::new(Cursor::new(reply.color.clone())),
                _ => {
                    return Err("Unsupported node extension.".into());
                }
            };
            readers.insert((*node_attribute).to_string(), reader);
        }
        Ok(readers)
    }
}

pub fn data_provider_from_grpc_address(addr: &str) -> DataProviderFactoryResult {
    let prefix = "grpc://";
    if !addr.starts_with(prefix) {
        return Err(format!("Invalid grpc address: it has to start with {}.", prefix).into());
    }
    let addr_no_prefix: &str = &addr[prefix.len()..];
    GrpcOctreeDataProvider::from_address(addr_no_prefix)
        .map(|provider| Box::new(provider) as Box<dyn DataProvider>)
}
<commit_msg>Fix clippy. (#470)<commit_after>// Copyright 2018 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use crate::proto_grpc::OctreeClient;
use futures::{Future, Stream};
use grpcio::{ChannelBuilder, EnvBuilder};
use nalgebra::Point3;
use point_viewer::color::Color;
use point_viewer::data_provider::{DataProvider, DataProviderFactoryResult};
use point_viewer::errors::*;
use point_viewer::geometry::Aabb;
use point_viewer::proto::Meta;
use point_viewer::Point;
pub use point_viewer_grpc_proto_rust::proto;
pub use point_viewer_grpc_proto_rust::proto_grpc;
use std::collections::HashMap;
use std::io::{Cursor, Read};
use std::sync::Arc;

pub mod service;

pub struct GrpcOctreeDataProvider {
    client: OctreeClient,
    octree_id: String,
}

impl GrpcOctreeDataProvider {
    pub fn from_address(addr: &str) -> Result<Self> {
        let mut addr_parts = addr.trim_matches('/').splitn(2, '/');
        let addr = addr_parts.next().ok_or("Invalid address.")?;
        let octree_id = addr_parts.next().unwrap_or_default().to_string();
        let env = Arc::new(EnvBuilder::new().build());
        let ch = ChannelBuilder::new(env)
            .max_receive_message_len(::std::i32::MAX)
            .connect(addr);
        let client = OctreeClient::new(ch);

        Ok(GrpcOctreeDataProvider { client, octree_id })
    }

    pub fn get_points_in_box(
        &self,
        bounding_box: &Aabb,
        mut func: impl FnMut(&[Point]) -> bool,
    ) -> Result<()> {
        let mut req = proto::GetPointsInBoxRequest::new();
        req.set_octree_id(self.octree_id.clone());
        req.mut_bounding_box().mut_min().set_x(bounding_box.min().x);
        req.mut_bounding_box().mut_min().set_y(bounding_box.min().y);
        req.mut_bounding_box().mut_min().set_z(bounding_box.min().z);
        req.mut_bounding_box().mut_max().set_x(bounding_box.max().x);
        req.mut_bounding_box().mut_max().set_y(bounding_box.max().y);
        req.mut_bounding_box().mut_max().set_z(bounding_box.max().z);
        let replies = self
            .client
            .get_points_in_box(&req)
            .map_err(|_| point_viewer::errors::ErrorKind::Grpc)?;

        let mut points = Vec::new();
        let mut interrupted = false;
        let result = replies
            .for_each(|reply| {
                let last_num_points = points.len();
                for (p, color) in reply.positions.iter().zip(reply.colors.iter()) {
                    points.push(Point {
                        position: Point3::from(p),
                        color: Color {
                            red: color.red,
                            green: color.green,
                            blue: color.blue,
                            alpha: color.alpha,
                        }
                        .to_u8(),
                        intensity: None,
                    });
                }

                if reply.intensities.len() == reply.positions.len() {
                    for (i, p) in reply.intensities.iter().zip(&mut points[last_num_points..]) {
                        p.intensity = Some(*i);
                    }
                }

                if !func(&points) {
                    interrupted = true;
                    return Err(grpcio::Error::QueueShutdown);
                }
                points.clear();
                Ok(())
            })
            .wait()
            .map_err(|_| point_viewer::errors::ErrorKind::Grpc);
        if result.is_err() && !interrupted {
            result?;
        }
        Ok(())
    }
}

impl DataProvider for GrpcOctreeDataProvider {
    fn meta_proto(&self) -> Result<Meta> {
        let mut req = proto::GetMetaRequest::new();
        req.set_octree_id(self.octree_id.clone());
        let reply = self
            .client
            .get_meta(&req)
            .map_err(|_| point_viewer::errors::ErrorKind::Grpc)?;
        Ok(reply.meta.unwrap())
    }

    fn data(
        &self,
        node_id: &str,
        node_attributes: &[&str],
    ) -> Result<HashMap<String, Box<dyn Read + Send>>> {
        let mut req = proto::GetNodeDataRequest::new();
        req.set_octree_id(self.octree_id.clone());
        req.set_id(node_id.to_string());
        let reply = self
            .client
            .get_node_data(&req)
            .map_err(|_| point_viewer::errors::ErrorKind::Grpc)?;
        let mut readers = HashMap::<String, Box<dyn Read + Send>>::new();
        for node_attribute in node_attributes {
            let reader: Box<dyn Read + Send> = match *node_attribute {
                "position" => Box::new(Cursor::new(reply.position.clone())),
                "color" => Box::new(Cursor::new(reply.color.clone())),
                _ => {
                    return Err("Unsupported node extension.".into());
                }
            };
            readers.insert((*node_attribute).to_string(), reader);
        }
        Ok(readers)
    }
}

pub fn data_provider_from_grpc_address(addr: &str) -> DataProviderFactoryResult {
    let prefix = "grpc://";
    if !addr.starts_with(prefix) {
        return Err(format!("Invalid grpc address: it has to start with {}.", prefix).into());
    }
    let addr_no_prefix: &str = &addr[prefix.len()..];
    GrpcOctreeDataProvider::from_address(addr_no_prefix)
        .map(|provider| Box::new(provider) as Box<dyn DataProvider>)
}
<|endoftext|>


<commit_before>extern crate structopt;
#[macro_use]
extern crate structopt_derive;

use structopt::StructOpt;
use std::collections::HashMap;
use std::error::Error;
use std::fs::File;
use std::io::Read;
use std::path::PathBuf;

type Literal = i64;
type Address = char;

#[derive(Debug)]
struct ParseError {
    bad_val: String,
    underlying: Option<Box<Error>>,
}

impl ParseError {
    fn new(
        bad_val: std::borrow::Cow<str>,
        underlying: Option<Box<Error>>,
    ) -> ParseError {
        ParseError {
            bad_val: bad_val.into_owned(),
            underlying: underlying,
        }
    }
}

impl std::fmt::Display for ParseError {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
        write!(f, "{}", self.description())
    }
}

impl Error for ParseError {
    fn description(&self) -> &str {
        "Could not parse the value as asked"
    }

    fn cause(&self) -> Option<&Error> {
        match self.underlying {
            Some(ref e) => Some(e.as_ref()),
            None => None,
        }
    }
}

#[derive(Debug, Clone, Copy)]
enum Value {
    Literal(Literal),
    Address(Address),
}

impl std::str::FromStr for Value {
    type Err = ParseError;
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        i64::from_str_radix(s, 10).map(Value::Literal).or_else(|_| {
            if s.len() == 1 {
                Ok(Value::Address(s.chars().next().unwrap()))
            } else {
                Err(ParseError::new(s.into(), None))
            }
        })
    }
}

enum Operation {
    Sound(Value),
    Set(Address, Value),
    Add(Address, Value),
    Mul(Address, Value),
    Mod(Address, Value),
    Recover(Value),
    Jgz(Value, Value),
}

impl std::str::FromStr for Operation {
    type Err = ParseError;
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        use Operation::*;
        let err = ParseError::new(s.into(), None);
        let parts = s.split_whitespace().collect::<Vec<_>>();
        let assert_len = |len: usize| {
            if parts.len() == len {
                Ok(())
            } else {
                Err(ParseError::new(s.into(), None))
            }
        };
        match parts.first() {
            Some(&"snd") => {
                assert_len(2)?;
                Ok(Sound(parts[1].parse()?))
            }
            Some(&"set") => {
                assert_len(3)?;
                Ok(Set(parts[1].chars().next().ok_or(err)?, parts[2].parse()?))
            }
            Some(&"add") => {
                assert_len(3)?;
                Ok(Add(parts[1].chars().next().ok_or(err)?, parts[2].parse()?))
            }
            Some(&"mul") => {
                assert_len(3)?;
                Ok(Mul(parts[1].chars().next().ok_or(err)?, parts[2].parse()?))
            }
            Some(&"mod") => {
                assert_len(3)?;
                Ok(Mod(parts[1].chars().next().ok_or(err)?, parts[2].parse()?))
            }
            Some(&"rcv") => {
                assert_len(2)?;
                Ok(Recover(parts[1].parse()?))
            }
            Some(&"jgz") => {
                assert_len(3)?;
                Ok(Jgz(parts[1].parse()?, parts[2].parse()?))
            }
            _ => Err(ParseError::new(s.into(), None)),
        }
    }
}

fn parse(input: &str) -> Result<Vec<Operation>, ParseError> {
    input.lines().map(|line| line.parse()).collect()
}

fn part1(instructions: &[Operation]) -> Option<Literal> {
    let mut computer = HashMap::new();
    let mut sounds = Vec::new();
    let mut instr = 0i64;
    let get = |v: Value, cpu: &HashMap<Address, Literal>| match v {
        Value::Literal(l) => l,
        Value::Address(a) => *cpu.get(&a).unwrap_or(&0),
    };
    while 0 <= instr && (instr as usize) < instructions.len() {
        use Operation::*;
        match instructions[instr as usize] {
            Sound(v) => sounds.push(get(v, &computer)),
            Set(addr, v) => {
                *computer.entry(addr).or_insert(0) = get(v, &computer)
            }
            Add(addr, v) => {
                *computer.entry(addr).or_insert(0) += get(v, &computer)
            }
            Mul(addr, v) => {
                *computer.entry(addr).or_insert(0) *= get(v, &computer)
            }
            Mod(addr, v) => {
                *computer.entry(addr).or_insert(0) %= get(v, &computer)
            }
            Recover(v) => {
                if get(v, &computer) != 0 {
                    return sounds.last().cloned();
                }
            }
            Jgz(v, jump) => {
                if get(v, &computer) > 0 {
                    instr += get(jump, &computer);
                    continue;
                }
            }
        }
        instr += 1;
    }
    None
}

fn main() {
    let opt = Opt::from_args();
    let mut contents = String::new();
    if opt.input.to_str() == Some("-") {
        std::io::stdin()
            .read_to_string(&mut contents)
            .expect("could not read stdin");
    } else {
        let mut file = File::open(&opt.input)
            .expect(&format!("file {} not found", opt.input.display()));
        file.read_to_string(&mut contents)
            .expect(&format!("could not read file {}", opt.input.display()));
    }
    let instructions = parse(&contents).expect("Could not parse instructions");
    println!(
        "Part 1: {}",
        part1(&instructions).expect("Could not recover a sound!")
    );
}

#[derive(StructOpt, Debug)]
#[structopt(name = "day13", about = "Advent of code 2017 day 13")]
struct Opt {
    #[structopt(help = "Input file", parse(from_os_str))] input: PathBuf,
}

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

    static INPUT: &str = "set a 1\n\
                          add a 2\n\
                          mul a a\n\
                          mod a 5\n\
                          snd a\n\
                          set a 0\n\
                          rcv a\n\
                          jgz a -1\n\
                          set a 1\n\
                          jgz a -2";

    #[test]
    fn part1_test() {
        let instructions = parse(INPUT).unwrap();
        assert_eq!(part1(&instructions), Some(4));
    }
}
<commit_msg>2017 day 18 part 2<commit_after>extern crate structopt;
#[macro_use]
extern crate structopt_derive;

use structopt::StructOpt;
use std::collections::HashMap;
use std::collections::VecDeque;
use std::error::Error;
use std::fs::File;
use std::io::Read;
use std::path::PathBuf;

type Literal = i64;
type Address = char;

#[derive(Debug)]
struct ParseError {
    bad_val: String,
    underlying: Option<Box<Error>>,
}

impl ParseError {
    fn new(
        bad_val: std::borrow::Cow<str>,
        underlying: Option<Box<Error>>,
    ) -> ParseError {
        ParseError {
            bad_val: bad_val.into_owned(),
            underlying: underlying,
        }
    }
}

impl std::fmt::Display for ParseError {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
        write!(f, "{}", self.description())
    }
}

impl Error for ParseError {
    fn description(&self) -> &str {
        "Could not parse the value as asked"
    }

    fn cause(&self) -> Option<&Error> {
        match self.underlying {
            Some(ref e) => Some(e.as_ref()),
            None => None,
        }
    }
}

#[derive(Debug, Clone, Copy)]
enum Value {
    Literal(Literal),
    Address(Address),
}

impl std::str::FromStr for Value {
    type Err = ParseError;
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        i64::from_str_radix(s, 10).map(Value::Literal).or_else(|_| {
            if s.len() == 1 {
                Ok(Value::Address(s.chars().next().unwrap()))
            } else {
                Err(ParseError::new(s.into(), None))
            }
        })
    }
}

#[derive(Debug, Clone, Copy)]
enum Operation {
    Snd(Value),
    Set(Address, Value),
    Add(Address, Value),
    Mul(Address, Value),
    Mod(Address, Value),
    Rcv(Address),
    Jgz(Value, Value),
}

impl std::str::FromStr for Operation {
    type Err = ParseError;
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        use Operation::*;
        let err = ParseError::new(s.into(), None);
        let parts = s.split_whitespace().collect::<Vec<_>>();
        let assert_len = |len: usize| {
            if parts.len() == len {
                Ok(())
            } else {
                Err(ParseError::new(s.into(), None))
            }
        };
        match parts.first() {
            Some(&"snd") => {
                assert_len(2)?;
                Ok(Snd(parts[1].parse()?))
            }
            Some(&"set") => {
                assert_len(3)?;
                Ok(Set(parts[1].chars().next().ok_or(err)?, parts[2].parse()?))
            }
            Some(&"add") => {
                assert_len(3)?;
                Ok(Add(parts[1].chars().next().ok_or(err)?, parts[2].parse()?))
            }
            Some(&"mul") => {
                assert_len(3)?;
                Ok(Mul(parts[1].chars().next().ok_or(err)?, parts[2].parse()?))
            }
            Some(&"mod") => {
                assert_len(3)?;
                Ok(Mod(parts[1].chars().next().ok_or(err)?, parts[2].parse()?))
            }
            Some(&"rcv") => {
                assert_len(2)?;
                Ok(Rcv(parts[1].chars().next().ok_or(err)?))
            }
            Some(&"jgz") => {
                assert_len(3)?;
                Ok(Jgz(parts[1].parse()?, parts[2].parse()?))
            }
            _ => Err(ParseError::new(s.into(), None)),
        }
    }
}

fn parse(input: &str) -> Result<Vec<Operation>, ParseError> {
    input.lines().map(|line| line.parse()).collect()
}

fn part1(instructions: &[Operation]) -> Option<Literal> {
    let mut computer = HashMap::new();
    let mut snds = Vec::new();
    let mut instr = 0i64;
    let get = |v: Value, cpu: &HashMap<Address, Literal>| match v {
        Value::Literal(l) => l,
        Value::Address(a) => *cpu.get(&a).unwrap_or(&0),
    };
    while 0 <= instr && (instr as usize) < instructions.len() {
        use Operation::*;
        match instructions[instr as usize] {
            Snd(v) => snds.push(get(v, &computer)),
            Set(addr, v) => {
                *computer.entry(addr).or_insert(0) = get(v, &computer)
            }
            Add(addr, v) => {
                *computer.entry(addr).or_insert(0) += get(v, &computer)
            }
            Mul(addr, v) => {
                *computer.entry(addr).or_insert(0) *= get(v, &computer)
            }
            Mod(addr, v) => {
                *computer.entry(addr).or_insert(0) %= get(v, &computer)
            }
            Rcv(v) => {
                if get(Value::Address(v), &computer) != 0 {
                    return snds.last().cloned();
                }
            }
            Jgz(v, jump) => {
                if get(v, &computer) > 0 {
                    instr += get(jump, &computer);
                    continue;
                }
            }
        }
        instr += 1;
    }
    None
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum Status {
    Running,
    Waiting,
    Terminated,
}

#[derive(Debug)]
struct Computer {
    id: u8,
    status: Status,
    instruction_ptr: usize,
    registers: HashMap<Address, Literal>,
    queue: VecDeque<Literal>,
}

impl Computer {
    fn new(id: u8) -> Computer {
        Computer {
            id: id,
            status: Status::Running,
            instruction_ptr: 0,
            registers: std::iter::once(('p', Literal::from(id))).collect(),
            queue: VecDeque::new(),
        }
    }
    fn lookup(&self, val: Value) -> Literal {
        match val {
            Value::Literal(l) => l,
            Value::Address(a) => *self.registers.get(&a).unwrap_or(&0),
        }
    }
    // returns Some(send) when sending a value
    fn perform(&mut self, op: Operation) -> Option<Literal> {
        //println!("{:?}", self);
        assert_eq!(self.status, Status::Running);
        use Operation::*;
        let mut ret = None;
        let mut incr = true;
        match op {
            Snd(v) => {
                let send = self.lookup(v);
                ret = Some(send)
            }
            Set(addr, v) => {
                *self.registers.entry(addr).or_insert(0) = self.lookup(v);
            }
            Add(addr, v) => {
                *self.registers.entry(addr).or_insert(0) += self.lookup(v);
            }
            Mul(addr, v) => {
                *self.registers.entry(addr).or_insert(0) *= self.lookup(v);
            }
            Mod(addr, v) => {
                *self.registers.entry(addr).or_insert(0) %= self.lookup(v)
            }
            Rcv(addr) => match self.queue.pop_front() {
                Some(lit) => *self.registers.entry(addr).or_insert(0) = lit,
                None => {
                    self.status = Status::Waiting;
                    incr = false;
                }
            },
            Jgz(v, jump) => {
                if self.lookup(v) > 0 {
                    let new_pos =
                        self.instruction_ptr as Literal + self.lookup(jump);
                    if new_pos < 0 {
                        self.status = Status::Terminated;
                    } else {
                        self.instruction_ptr = new_pos as usize;
                        incr = false;
                    }
                }
            }
        }
        if incr {
            self.instruction_ptr += 1;
        }
        ret
    }
}

fn part2(instructions: &[Operation]) -> usize {
    let mut send_count = 0;
    let mut computers = [Computer::new(0), Computer::new(1)];
    let mut current = 0;
    let mut other = if current == 0 { 1 } else { 0 };
    loop {
        let instr = instructions[computers[current].instruction_ptr];
        if let Some(rcv) = computers[current].perform(instr) {
            computers[other].queue.push_back(rcv);
            if current == 1 {
                send_count += 1;
            }
        }
        if computers[current].instruction_ptr > instructions.len() {
            computers[current].status = Status::Terminated;
        }
        if computers[current].status != Status::Running {
            std::mem::swap(&mut current, &mut other);
            match computers[current].status {
                Status::Running => {}
                Status::Waiting => if computers[current].queue.is_empty() {
                    break; // deadlock
                } else {
                    computers[current].status = Status::Running; // resume
                },
                Status::Terminated => break,
            }
        }
    }
    send_count
}

fn main() {
    let opt = Opt::from_args();
    let mut contents = String::new();
    if opt.input.to_str() == Some("-") {
        std::io::stdin()
            .read_to_string(&mut contents)
            .expect("could not read stdin");
    } else {
        let mut file = File::open(&opt.input)
            .expect(&format!("file {} not found", opt.input.display()));
        file.read_to_string(&mut contents)
            .expect(&format!("could not read file {}", opt.input.display()));
    }
    let instructions = parse(&contents).expect("Could not parse instructions");
    println!(
        "Part 1: {}",
        part1(&instructions).expect("Could not recover a sound!")
    );
    println!("Part 2: {}", part2(&instructions));
}

#[derive(StructOpt, Debug)]
#[structopt(name = "day13", about = "Advent of code 2017 day 13")]
struct Opt {
    #[structopt(help = "Input file", parse(from_os_str))] input: PathBuf,
}

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

    #[test]
    fn part1_test() {
        let input = "set a 1\n\
                     add a 2\n\
                     mul a a\n\
                     mod a 5\n\
                     snd a\n\
                     set a 0\n\
                     rcv a\n\
                     jgz a -1\n\
                     set a 1\n\
                     jgz a -2";
        let instructions = parse(input).unwrap();
        assert_eq!(part1(&instructions), Some(4));
    }

    #[test]
    fn part2_test() {
        let input = "snd 1\n\
                     snd 2\n\
                     snd p\n\
                     rcv a\n\
                     rcv b\n\
                     rcv c\n\
                     rcv d";
        let instructions = parse(input).unwrap();
        assert_eq!(part2(&instructions), 3);
    }

    #[test]
    fn part2_test2() {
        let input = "set a 1\n\
                     add a 2\n\
                     mul a a\n\
                     mod a 5\n\
                     snd a\n\
                     set a 0\n\
                     rcv a\n\
                     jgz a -1\n\
                     set a 1\n\
                     jgz a -2";
        let instructions = parse(input).unwrap();
        assert_eq!(part2(&instructions), 1);
    }
}
<|endoftext|>


<commit_before>// Third Party
#[cfg(feature = "yaml")]
use yaml_rust::Yaml;

// Internal
use App;
use ArgMatches;

/// The abstract representation of a command line subcommand.
///
/// This struct describes all the valid options of the subcommand for the program. Subcommands are
/// essentially "sub-[`App`]s" and contain all the same possibilities (such as their own
/// [arguments], subcommands, and settings).
///
/// # Examples
///
/// ```rust
/// # use clap::{App, Arg, SubCommand};
/// App::new("myprog")
///     .subcommand(
///         SubCommand::with_name("config")
///             .about("Used for configuration")
///             .arg(Arg::with_name("config_file")
///                 .help("The configuration file to use")
///                 .index(1)))
/// # ;
/// ```
/// [`App`]: ./struct.App.html
/// [arguments]: ./struct.Arg.html
#[derive(Debug, Clone)]
pub struct SubCommand<'a> {
    #[doc(hidden)]
    pub name: String,
    #[doc(hidden)]
    pub matches: ArgMatches<'a>,
}

impl<'a> SubCommand<'a> {
    /// Creates a new instance of a subcommand requiring a name. The name will be displayed
    /// to the user when they print version or help and usage information.
    ///
    /// # Examples
    ///
    /// ```rust
    /// # use clap::{App, Arg, SubCommand};
    /// App::new("myprog")
    ///     .subcommand(
    ///         SubCommand::with_name("config"))
    /// # ;
    /// ```
    pub fn with_name<'b>(name: &str) -> App<'a, 'b> { App::new(name) }

    /// Creates a new instance of a subcommand from a YAML (.yml) document
    ///
    /// # Examples
    ///
    /// ```ignore
    /// # #[macro_use]
    /// # extern crate clap;
    /// # use clap::Subcommand;
    /// # fn main() {
    /// let sc_yaml = load_yaml!("test_subcommand.yml");
    /// let sc = SubCommand::from_yaml(sc_yaml);
    /// # }
    /// ```
    #[cfg(feature = "yaml")]
    pub fn from_yaml(yaml: &Yaml) -> App { App::from_yaml(yaml) }
}
<commit_msg>depr(SubCommand::with_name): deprecates SubCommand facade to prefer App::new<commit_after>// Third Party
#[cfg(feature = "yaml")]
use yaml_rust::Yaml;

// Internal
use App;
use ArgMatches;

/// The abstract representation of a command line subcommand.
///
/// This struct describes all the valid options of the subcommand for the program. Subcommands are
/// essentially "sub-[`App`]s" and contain all the same possibilities (such as their own
/// [arguments], subcommands, and settings).
///
/// # Examples
///
/// ```rust
/// # use clap::{App, Arg, SubCommand};
/// App::new("myprog")
///     .subcommand(
///         SubCommand::with_name("config")
///             .about("Used for configuration")
///             .arg(Arg::with_name("config_file")
///                 .help("The configuration file to use")
///                 .index(1)))
/// # ;
/// ```
/// [`App`]: ./struct.App.html
/// [arguments]: ./struct.Arg.html
#[derive(Debug, Clone)]
pub struct SubCommand<'a> {
    #[doc(hidden)]
    pub name: String,
    #[doc(hidden)]
    pub matches: ArgMatches<'a>,
}

impl<'a> SubCommand<'a> {
    // @TODO-v3-beta: remove
    /// **Deprecated**
    #[deprecated(
        since = "2.32.0",
        note = "Use App::new instead. Will be removed in v3-beta"
    )]
    pub fn with_name<'b>(name: &str) -> App<'a, 'b> { App::new(name) }

    // @TODO-v3-beta: remove
    /// **Deprecated**
    #[cfg_attr(
        feature = "yaml",
        deprecated(
            since = "2.32.0",
            note = "Use App::from instead. Will be removed in v3-beta"
        )
    )]
    #[cfg(feature = "yaml")]
    pub fn from_yaml(yaml: &Yaml) -> App { App::from_yaml(yaml) }
}
<|endoftext|>


<commit_before>use nom::{
    self,
    bytes::streaming::{tag, take},
    character::streaming::digit1,
    sequence::tuple,
    IResult,
};

use std::str;

// list-wildcards = "%" / "*"
pub fn is_list_wildcards(c: u8) -> bool {
    c == b'%' || c == b'*'
}

// quoted-specials = DQUOTE / "\"
pub fn is_quoted_specials(c: u8) -> bool {
    c == b'"' || c == b'\\'
}

// resp-specials = "]"
pub fn is_resp_specials(c: u8) -> bool {
    c == b']'
}

// atom-specials = "(" / ")" / "{" / SP / CTL / list-wildcards / quoted-specials / resp-specials
pub fn is_atom_specials(c: u8) -> bool {
    c == b'('
        || c == b')'
        || c == b'{'
        || c == b' '
        || c < 32
        || is_list_wildcards(c)
        || is_quoted_specials(c)
        || is_resp_specials(c)
}

// ATOM-CHAR = <any CHAR except atom-specials>
pub fn is_atom_char(c: u8) -> bool {
    is_char(c) && !is_atom_specials(c)
}

// nil = "NIL"
named!(pub nil, tag_no_case!("NIL"));

// ASTRING-CHAR = ATOM-CHAR / resp-specials
pub fn is_astring_char(c: u8) -> bool {
    is_atom_char(c) || is_resp_specials(c)
}

// QUOTED-CHAR = <any TEXT-CHAR except quoted-specials> / "\" quoted-specials
pub fn quoted_data(i: &[u8]) -> IResult<&[u8], &[u8]> {
    // Ideally this should use nom's `escaped` macro, but it suffers from broken
    // type inference unless compiled with the verbose-errors feature enabled.
    let mut escape = false;
    let mut len = 0;
    for c in i {
        if *c == b'"' && !escape {
            break;
        }
        len += 1;
        if *c == b'\\' && !escape {
            escape = true
        } else if escape {
            escape = false;
        }
    }
    Ok((&i[len..], &i[..len]))
}

// quoted = DQUOTE *QUOTED-CHAR DQUOTE
named!(pub quoted<&[u8]>, delimited!(
    char!('"'),
    quoted_data,
    char!('"')
));

// quoted bytes as as utf8
named!(pub quoted_utf8<&str>, map_res!(quoted, str::from_utf8));

/// literal = "{" number "}" CRLF *CHAR8
///            ; Number represents the number of CHAR8s
pub fn literal(input: &[u8]) -> IResult<&[u8], &[u8]> {
    let parser = tuple((tag(b"{"), number, tag(b"}"), tag("\r\n")));

    let (remaining, (_, count, _, _)) = parser(input)?;

    let (remaining, data) = take(count)(remaining)?;

    if !data.iter().all(|byte| is_char8(*byte)) {
        // FIXME: what ErrorKind should this have?
        return Err(nom::Err::Error((remaining, nom::error::ErrorKind::Verify)));
    }

    Ok((remaining, data))
}

/// CHAR8 = %x01-ff ; any OCTET except NUL, %x00
pub fn is_char8(i: u8) -> bool {
    i != 0
}

// string = quoted / literal
named!(pub string<&[u8]>, alt!(quoted | literal));

// string bytes as as utf8
named!(pub string_utf8<&str>, map_res!(string, str::from_utf8));

// nstring = string / nil
named!(pub nstring<Option<&[u8]>>, alt!(
    map!(nil, |_| None) |
    map!(string, |s| Some(s))
));

// nstring bytes as utf8
named!(pub nstring_utf8<Option<&str>>, alt!(
    map!(nil, |_| None) |
    map!(string_utf8, |s| Some(s))
));

// number          = 1*DIGIT
//                    ; Unsigned 32-bit integer
//                    ; (0 <= n < 4,294,967,296)
named!(pub number<u32>, flat_map!(digit1, parse_to!(u32)));

// same as `number` but 64-bit
named!(pub number_64<u64>, flat_map!(digit1, parse_to!(u64)));

// atom = 1*ATOM-CHAR
named!(pub atom<&str>, map_res!(take_while1!(is_atom_char),
    str::from_utf8
));

// astring = 1*ASTRING-CHAR / string
named!(pub astring<&[u8]>, alt!(
    take_while1!(is_astring_char) |
    string
));

// astring bytes as as utf8
named!(pub astring_utf8<&str>, map_res!(astring, str::from_utf8));

// text = 1*TEXT-CHAR
named!(pub text<&str>, map_res!(take_while!(is_text_char),
    str::from_utf8
));

// TEXT-CHAR = <any CHAR except CR and LF>
pub fn is_text_char(c: u8) -> bool {
    is_char(c) && c != b'\r' && c != b'\n'
}

// CHAR = %x01-7F
//          ; any 7-bit US-ASCII character,
//          ;  excluding NUL
// From RFC5234
pub fn is_char(c: u8) -> bool {
    match c {
        0x01..=0x7F => true,
        _ => false,
    }
}

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

    #[test]
    fn test_string_literal() {
        match string(b"{3}\r\nXYZ") {
            Ok((_, value)) => {
                assert_eq!(value, b"XYZ");
            }
            rsp => panic!("unexpected response {:?}", rsp),
        }
    }

    #[test]
    fn test_astring() {
        match astring(b"text ") {
            Ok((_, value)) => {
                assert_eq!(value, b"text");
            }
            rsp => panic!("unexpected response {:?}", rsp),
        }
    }
}
<commit_msg>group number<commit_after>use nom::{
    self,
    bytes::streaming::{tag, take},
    character::streaming::digit1,
    sequence::tuple,
    IResult,
};

use std::str;

// ----- number -----

// number          = 1*DIGIT
//                    ; Unsigned 32-bit integer
//                    ; (0 <= n < 4,294,967,296)
named!(pub number<u32>, flat_map!(digit1, parse_to!(u32)));

// same as `number` but 64-bit
named!(pub number_64<u64>, flat_map!(digit1, parse_to!(u64)));

// list-wildcards = "%" / "*"
pub fn is_list_wildcards(c: u8) -> bool {
    c == b'%' || c == b'*'
}

// quoted-specials = DQUOTE / "\"
pub fn is_quoted_specials(c: u8) -> bool {
    c == b'"' || c == b'\\'
}

// resp-specials = "]"
pub fn is_resp_specials(c: u8) -> bool {
    c == b']'
}

// atom-specials = "(" / ")" / "{" / SP / CTL / list-wildcards / quoted-specials / resp-specials
pub fn is_atom_specials(c: u8) -> bool {
    c == b'('
        || c == b')'
        || c == b'{'
        || c == b' '
        || c < 32
        || is_list_wildcards(c)
        || is_quoted_specials(c)
        || is_resp_specials(c)
}

// ATOM-CHAR = <any CHAR except atom-specials>
pub fn is_atom_char(c: u8) -> bool {
    is_char(c) && !is_atom_specials(c)
}

// nil = "NIL"
named!(pub nil, tag_no_case!("NIL"));

// ASTRING-CHAR = ATOM-CHAR / resp-specials
pub fn is_astring_char(c: u8) -> bool {
    is_atom_char(c) || is_resp_specials(c)
}

// QUOTED-CHAR = <any TEXT-CHAR except quoted-specials> / "\" quoted-specials
pub fn quoted_data(i: &[u8]) -> IResult<&[u8], &[u8]> {
    // Ideally this should use nom's `escaped` macro, but it suffers from broken
    // type inference unless compiled with the verbose-errors feature enabled.
    let mut escape = false;
    let mut len = 0;
    for c in i {
        if *c == b'"' && !escape {
            break;
        }
        len += 1;
        if *c == b'\\' && !escape {
            escape = true
        } else if escape {
            escape = false;
        }
    }
    Ok((&i[len..], &i[..len]))
}

// quoted = DQUOTE *QUOTED-CHAR DQUOTE
named!(pub quoted<&[u8]>, delimited!(
    char!('"'),
    quoted_data,
    char!('"')
));

// quoted bytes as as utf8
named!(pub quoted_utf8<&str>, map_res!(quoted, str::from_utf8));

/// literal = "{" number "}" CRLF *CHAR8
///            ; Number represents the number of CHAR8s
pub fn literal(input: &[u8]) -> IResult<&[u8], &[u8]> {
    let parser = tuple((tag(b"{"), number, tag(b"}"), tag("\r\n")));

    let (remaining, (_, count, _, _)) = parser(input)?;

    let (remaining, data) = take(count)(remaining)?;

    if !data.iter().all(|byte| is_char8(*byte)) {
        // FIXME: what ErrorKind should this have?
        return Err(nom::Err::Error((remaining, nom::error::ErrorKind::Verify)));
    }

    Ok((remaining, data))
}

/// CHAR8 = %x01-ff ; any OCTET except NUL, %x00
pub fn is_char8(i: u8) -> bool {
    i != 0
}

// string = quoted / literal
named!(pub string<&[u8]>, alt!(quoted | literal));

// string bytes as as utf8
named!(pub string_utf8<&str>, map_res!(string, str::from_utf8));

// nstring = string / nil
named!(pub nstring<Option<&[u8]>>, alt!(
    map!(nil, |_| None) |
    map!(string, |s| Some(s))
));

// nstring bytes as utf8
named!(pub nstring_utf8<Option<&str>>, alt!(
    map!(nil, |_| None) |
    map!(string_utf8, |s| Some(s))
));

// atom = 1*ATOM-CHAR
named!(pub atom<&str>, map_res!(take_while1!(is_atom_char),
    str::from_utf8
));

// astring = 1*ASTRING-CHAR / string
named!(pub astring<&[u8]>, alt!(
    take_while1!(is_astring_char) |
    string
));

// astring bytes as as utf8
named!(pub astring_utf8<&str>, map_res!(astring, str::from_utf8));

// text = 1*TEXT-CHAR
named!(pub text<&str>, map_res!(take_while!(is_text_char),
    str::from_utf8
));

// TEXT-CHAR = <any CHAR except CR and LF>
pub fn is_text_char(c: u8) -> bool {
    is_char(c) && c != b'\r' && c != b'\n'
}

// CHAR = %x01-7F
//          ; any 7-bit US-ASCII character,
//          ;  excluding NUL
// From RFC5234
pub fn is_char(c: u8) -> bool {
    match c {
        0x01..=0x7F => true,
        _ => false,
    }
}

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

    #[test]
    fn test_string_literal() {
        match string(b"{3}\r\nXYZ") {
            Ok((_, value)) => {
                assert_eq!(value, b"XYZ");
            }
            rsp => panic!("unexpected response {:?}", rsp),
        }
    }

    #[test]
    fn test_astring() {
        match astring(b"text ") {
            Ok((_, value)) => {
                assert_eq!(value, b"text");
            }
            rsp => panic!("unexpected response {:?}", rsp),
        }
    }
}
<|endoftext|>


<commit_before>// min-version: 1.30.0

// === GDB TESTS ===================================================================================

// gdb-command:run

// gdb-command:print a
// gdbg-check:[...]$1 = enum::EnumA::Var3 = {Var3 = enum::EnumA::Var3 = {a = 5, b = enum::TestEnumB::Var2 = {Var2 = enum::TestEnumB::Var2 = {a = 5, b = "hello", c = enum::EnumC::Var1 = {Var1 = size=1 = {8}}}}}}

// gdb-command:print d
// gdbg-check:[...]$2 = enum::EnumD

enum EnumA {
    Var1 { a: u32 },
    Var2(u64),
    Var3 { a: u32, b: TestEnumB },
}

enum TestEnumB {
    Var1(u64),
    Var2 { a: u32, b: String, c: EnumC },
}

enum EnumC {
    Var1(u64),
}

enum EnumD {}

fn main() {
    let a = EnumA::Var3 {
        a: 5,
        b: TestEnumB::Var2 {
            a: 5,
            b: "hello".to_owned(),
            c: EnumC::Var1(8),
        },
    };
    let d: EnumD;
    print!(""); // #break
}
<commit_msg>T: disable pretty printer test for enum<commit_after>// min-version: 1.30.0
// Temporarily disable this test because it fails on 2021.1
// https://github.com/intellij-rust/intellij-rust/issues/6746
// max-version: 1.30.0

// === GDB TESTS ===================================================================================

// gdb-command:run

// gdb-command:print a
// gdbg-check:[...]$1 = enum::EnumA::Var3 = {Var3 = enum::EnumA::Var3 = {a = 5, b = enum::TestEnumB::Var2 = {Var2 = enum::TestEnumB::Var2 = {a = 5, b = "hello", c = enum::EnumC::Var1 = {Var1 = size=1 = {8}}}}}}

// gdb-command:print d
// gdbg-check:[...]$2 = enum::EnumD

enum EnumA {
    Var1 { a: u32 },
    Var2(u64),
    Var3 { a: u32, b: TestEnumB },
}

enum TestEnumB {
    Var1(u64),
    Var2 { a: u32, b: String, c: EnumC },
}

enum EnumC {
    Var1(u64),
}

enum EnumD {}

fn main() {
    let a = EnumA::Var3 {
        a: 5,
        b: TestEnumB::Var2 {
            a: 5,
            b: "hello".to_owned(),
            c: EnumC::Var1(8),
        },
    };
    let d: EnumD;
    print!(""); // #break
}
<|endoftext|>