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

use std::fmt::Display;
use std::convert::From;
use rlua::{self, Lua, Table, UserData, AnyUserData, Value,
           FromLua, ToLua, Function};
use super::signal;
use super::class::Class;
use super::property::Property;

/// All Lua objects can be cast to this.
#[derive(Clone, Debug)]
pub struct Object<'lua> {
    table: Table<'lua>
}

impl <'lua> From<Table<'lua>> for Object<'lua> {
    fn from(table: Table<'lua>) -> Self {
        Object { table }
    }
}

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

impl <'lua> ObjectBuilder<'lua> {
    #[allow(dead_code)]
    pub fn add_to_meta(self, new_meta: Table<'lua>) -> rlua::Result<Self> {
        let meta = self.object.table.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.table.set_metatable(Some(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 build(self) -> Object<'lua> {
        self.object
    }
}

/// Trait implemented by all objects that represent OO lua objects.
///
/// This trait allows casting an object gotten back from the Lua runtime
/// into a concrete object so that Rust can do things with it.
///
/// You can't do anything to the object until it has been converted into a
/// canonical form using this trait.
pub trait Objectable<'lua, T, S: UserData + Default + Display + Clone> {
    fn cast(obj: Object<'lua>) -> rlua::Result<T> {
        let data = obj.table.get::<_, Table>("data")?.get::<_, AnyUserData>("data")?;
        if data.is::<S>() {
            Ok(Self::_wrap(obj.table))
        } else {
            use rlua::Error::RuntimeError;
            Err(RuntimeError("Could not cast object to concrete type".into()))
        }
    }

    /// Given the internal object table, constructs a concrete object out
    /// of it.
    ///
    /// This is only used internally, which is why it's prefixed with a "_"
    /// Please do not use it outside of object.rs.
    fn _wrap(table: Table<'lua>) -> T;

    fn state(&self) -> rlua::Result<S> {
        self.get_table().get::<_, Table>("data")?.get::<_, S>("data")
    }

    fn set_state(&self, data: S) -> rlua::Result<()> {
        self.get_table().get::<_, Table>("data")?.set("data", data)
    }

    /// Gets the internal table for the concrete object.
    /// Used internally by cast, though there's nothing wrong with it being
    /// used outside of internal object use.
    fn get_table(&self) -> Table<'lua>;

    fn allocate(lua: &'lua Lua, class: Class) -> rlua::Result<ObjectBuilder<'lua>>
    {
        let object = S::default();
        // TODO FIXME
        // we put a wrapper table here,
        // but in awesome they use lua_setuservalue.
        // I don't think this is equivilent...it just forces things to "work"
        let wrapper_table = lua.create_table();
        wrapper_table.set("data", object)?;
        let object_table = lua.create_table();
        object_table.set("data", wrapper_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))?;
        meta.set("disconnect_signal",
                 lua.create_function(disconnect_signal))?;
        meta.set("emit_signal", lua.create_function(emit_signal))?;
        meta.set("__index", lua.create_function(default_index))?;
        meta.set("__newindex", lua.create_function(default_newindex))?;
        meta.set("__tostring", lua.create_function(|_, object_table: Table| {
            Ok(format!("{}", object_table.get::<_, Table>("data")?.get::<_, S>("data")?))
        }))?;
        object_table.set_metatable(Some(meta));
        let object = Object { table: object_table };
        Ok(ObjectBuilder { object, lua })
    }
}

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

impl <'lua> Object<'lua> {
    /// Coerces a concrete object into a generic object.
    ///
    /// This requires a check to ensure data integrity, and it's often useless.
    /// Please don't use this method unless you need to.
    #[allow(dead_code)]
    #[deprecated]
    pub fn to_object<T, S, O>(obj: O) -> Self
        where S: Default + Display + Clone + UserData,
              O: Objectable<'lua, T, S>
    {
        let table = obj.get_table();
        let has_data = table.contains_key("data")
            .expect("Could not get data field of object table");
        assert_eq!(has_data, true);
        Object { table }
    }

    pub fn signals(&self) -> rlua::Result<rlua::Table<'lua>> {
        self.table.get::<_, Table>("signals")
    }

    pub fn table(self) -> rlua::Table<'lua> {
        self.table
    }
}

/// 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>(lua: &'lua Lua,
                           (obj_table, index): (Table<'lua>, Value<'lua>))
                           -> rlua::Result<Value<'lua>> {
    // Look up in metatable first
    let meta = obj_table.get_metatable()
        .expect("Object had no metatable");
    if meta.get::<_, Table>("__class").is_ok() {
        if let Ok(val) = meta.raw_get::<_, Value>(index.clone()) {
            match val {
                Value::Nil => {},
                val => return Ok(val)
            }
        }
    }
    let index = String::from_lua(index, lua)?;
    match index.as_str() {
        "valid" => {
            Ok(Value::Boolean(
                if let Ok(class) = meta.get::<_, Table>("__class") {
                    let class: Class = class.into();
                    class.checker()?
                        .map(|checker| checker(obj_table.into()))
                        .unwrap_or(true)
                } else {
                    false
                }))
        },
        "data" => {
            obj_table.get("data")
        },
        index => {
            // Try see if there is a property of the class with the name
            if let Ok(class) = meta.get::<_, Table>("__class") {
                let props = class.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_table)
                        }
                    }
                }
                match class.get::<_, Function>("__index_miss_handler") {
                    Ok(function) => {
                        return function.bind(obj_table)?.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>(_: &'lua Lua,
                              (obj_table, index, val):
                              (Table<'lua>, String, Value<'lua>))
                              -> rlua::Result<Value<'lua>> {
    // Look up in metatable first
    if let Some(meta) = obj_table.get_metatable() {
        if let Ok(val) = meta.raw_get::<_, Value>(index.clone()) {
            match val {
                Value::Nil => {},
                val => return Ok(val)
            }
        }
        let class = meta.get::<_, Table>("__class")?;
        let props = class.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_table)?.call(val)
                }
            }
        }
        match class.get::<_, Function>("__newindex_miss_handler") {
            Ok(function) => {
                return function.bind(obj_table)?.call(index)
            },
            Err(_) => {}
        }
        // TODO property miss handler if index doesn't exst
    }
    Ok(Value::Nil)
}

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

fn disconnect_signal(lua: &Lua, (obj_table, signal): (Table, String))
                     -> rlua::Result<()> {
    signal::disconnect_signal(lua, obj_table.into(), signal)
}

fn emit_signal(lua: &Lua, (obj_table, signal, args): (Table, String, Value))
               -> rlua::Result<()> {
    signal::emit_signal(lua, obj_table.into(), signal, args)
}
<commit_msg>Removed dead code annotation on add_to_meta<commit_after>//! Utility methods and constructors for Lua objects

use std::fmt::Display;
use std::convert::From;
use rlua::{self, Lua, Table, UserData, AnyUserData, Value,
           FromLua, ToLua, Function};
use super::signal;
use super::class::Class;
use super::property::Property;

/// All Lua objects can be cast to this.
#[derive(Clone, Debug)]
pub struct Object<'lua> {
    table: Table<'lua>
}

impl <'lua> From<Table<'lua>> for Object<'lua> {
    fn from(table: Table<'lua>) -> Self {
        Object { table }
    }
}

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

impl <'lua> ObjectBuilder<'lua> {
    pub fn add_to_meta(self, new_meta: Table<'lua>) -> rlua::Result<Self> {
        let meta = self.object.table.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.table.set_metatable(Some(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 build(self) -> Object<'lua> {
        self.object
    }
}

/// Trait implemented by all objects that represent OO lua objects.
///
/// This trait allows casting an object gotten back from the Lua runtime
/// into a concrete object so that Rust can do things with it.
///
/// You can't do anything to the object until it has been converted into a
/// canonical form using this trait.
pub trait Objectable<'lua, T, S: UserData + Default + Display + Clone> {
    fn cast(obj: Object<'lua>) -> rlua::Result<T> {
        let data = obj.table.get::<_, Table>("data")?.get::<_, AnyUserData>("data")?;
        if data.is::<S>() {
            Ok(Self::_wrap(obj.table))
        } else {
            use rlua::Error::RuntimeError;
            Err(RuntimeError("Could not cast object to concrete type".into()))
        }
    }

    /// Given the internal object table, constructs a concrete object out
    /// of it.
    ///
    /// This is only used internally, which is why it's prefixed with a "_"
    /// Please do not use it outside of object.rs.
    fn _wrap(table: Table<'lua>) -> T;

    fn state(&self) -> rlua::Result<S> {
        self.get_table().get::<_, Table>("data")?.get::<_, S>("data")
    }

    fn set_state(&self, data: S) -> rlua::Result<()> {
        self.get_table().get::<_, Table>("data")?.set("data", data)
    }

    /// Gets the internal table for the concrete object.
    /// Used internally by cast, though there's nothing wrong with it being
    /// used outside of internal object use.
    fn get_table(&self) -> Table<'lua>;

    fn allocate(lua: &'lua Lua, class: Class) -> rlua::Result<ObjectBuilder<'lua>>
    {
        let object = S::default();
        // TODO FIXME
        // we put a wrapper table here,
        // but in awesome they use lua_setuservalue.
        // I don't think this is equivilent...it just forces things to "work"
        let wrapper_table = lua.create_table();
        wrapper_table.set("data", object)?;
        let object_table = lua.create_table();
        object_table.set("data", wrapper_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))?;
        meta.set("disconnect_signal",
                 lua.create_function(disconnect_signal))?;
        meta.set("emit_signal", lua.create_function(emit_signal))?;
        meta.set("__index", lua.create_function(default_index))?;
        meta.set("__newindex", lua.create_function(default_newindex))?;
        meta.set("__tostring", lua.create_function(|_, object_table: Table| {
            Ok(format!("{}", object_table.get::<_, Table>("data")?.get::<_, S>("data")?))
        }))?;
        object_table.set_metatable(Some(meta));
        let object = Object { table: object_table };
        Ok(ObjectBuilder { object, lua })
    }
}

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

impl <'lua> Object<'lua> {
    /// Coerces a concrete object into a generic object.
    ///
    /// This requires a check to ensure data integrity, and it's often useless.
    /// Please don't use this method unless you need to.
    #[allow(dead_code)]
    #[deprecated]
    pub fn to_object<T, S, O>(obj: O) -> Self
        where S: Default + Display + Clone + UserData,
              O: Objectable<'lua, T, S>
    {
        let table = obj.get_table();
        let has_data = table.contains_key("data")
            .expect("Could not get data field of object table");
        assert_eq!(has_data, true);
        Object { table }
    }

    pub fn signals(&self) -> rlua::Result<rlua::Table<'lua>> {
        self.table.get::<_, Table>("signals")
    }

    pub fn table(self) -> rlua::Table<'lua> {
        self.table
    }
}

/// 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>(lua: &'lua Lua,
                           (obj_table, index): (Table<'lua>, Value<'lua>))
                           -> rlua::Result<Value<'lua>> {
    // Look up in metatable first
    let meta = obj_table.get_metatable()
        .expect("Object had no metatable");
    if meta.get::<_, Table>("__class").is_ok() {
        if let Ok(val) = meta.raw_get::<_, Value>(index.clone()) {
            match val {
                Value::Nil => {},
                val => return Ok(val)
            }
        }
    }
    let index = String::from_lua(index, lua)?;
    match index.as_str() {
        "valid" => {
            Ok(Value::Boolean(
                if let Ok(class) = meta.get::<_, Table>("__class") {
                    let class: Class = class.into();
                    class.checker()?
                        .map(|checker| checker(obj_table.into()))
                        .unwrap_or(true)
                } else {
                    false
                }))
        },
        "data" => {
            obj_table.get("data")
        },
        index => {
            // Try see if there is a property of the class with the name
            if let Ok(class) = meta.get::<_, Table>("__class") {
                let props = class.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_table)
                        }
                    }
                }
                match class.get::<_, Function>("__index_miss_handler") {
                    Ok(function) => {
                        return function.bind(obj_table)?.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>(_: &'lua Lua,
                              (obj_table, index, val):
                              (Table<'lua>, String, Value<'lua>))
                              -> rlua::Result<Value<'lua>> {
    // Look up in metatable first
    if let Some(meta) = obj_table.get_metatable() {
        if let Ok(val) = meta.raw_get::<_, Value>(index.clone()) {
            match val {
                Value::Nil => {},
                val => return Ok(val)
            }
        }
        let class = meta.get::<_, Table>("__class")?;
        let props = class.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_table)?.call(val)
                }
            }
        }
        match class.get::<_, Function>("__newindex_miss_handler") {
            Ok(function) => {
                return function.bind(obj_table)?.call(index)
            },
            Err(_) => {}
        }
        // TODO property miss handler if index doesn't exst
    }
    Ok(Value::Nil)
}

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

fn disconnect_signal(lua: &Lua, (obj_table, signal): (Table, String))
                     -> rlua::Result<()> {
    signal::disconnect_signal(lua, obj_table.into(), signal)
}

fn emit_signal(lua: &Lua, (obj_table, signal, args): (Table, String, Value))
               -> rlua::Result<()> {
    signal::emit_signal(lua, obj_table.into(), signal, args)
}
<|endoftext|>


<commit_before>#![feature(phase, macro_rules, if_let)]

extern crate serialize;
extern crate libc;
#[phase(plugin, link)] extern crate log;

extern crate argparse;
extern crate quire;
#[phase(plugin, link)] extern crate lithos;
#[phase(plugin)] extern crate regex_macros;
extern crate regex;

use std::rc::Rc;
use std::os::{set_exit_status, self_exe_path, getenv};
use std::io::stderr;
use std::time::Duration;
use std::default::Default;
use serialize::json;
use libc::funcs::posix88::unistd::getpid;

use argparse::{ArgumentParser, Store, List};
use quire::parse_config;

use lithos::master_config::{MasterConfig, create_master_dirs};
use lithos::tree_config::TreeConfig;
use lithos::container_config::{Command};
use lithos::child_config::ChildConfig;
use lithos::container::{Command};
use lithos::monitor::{Monitor, Executor};
use lithos::signal;

struct Child {
    name: Rc<String>,
    master_file: Path,
    child_config_serialized: String,
    root_binary: Path,
    args: Vec<String>,
}

impl Executor for Child {
    fn command(&self) -> Command
    {
        let mut cmd = Command::new((*self.name).clone(), &self.root_binary);
        cmd.keep_sigmask();

        // Name is first here, so it's easily visible in ps
        cmd.arg("--name");
        cmd.arg(self.name.as_slice());

        cmd.arg("--master");
        cmd.arg(&self.master_file);
        cmd.arg("--config");
        cmd.arg(self.child_config_serialized.as_slice());
        cmd.set_env("TERM".to_string(),
                    getenv("TERM").unwrap_or("dumb".to_string()));
        if let Some(x) = getenv("RUST_LOG") {
            cmd.set_env("RUST_LOG".to_string(), x);
        }
        if let Some(x) = getenv("RUST_BACKTRACE") {
            cmd.set_env("RUST_BACKTRACE".to_string(), x);
        }
        cmd.args(self.args.as_slice());
        cmd.container();
        return cmd;
    }
    fn finish(&self) -> bool {
        return false;  // Do not restart
    }
}

fn run(master_cfg: Path, tree_name: String,
    command_name: String, args: Vec<String>)
    -> Result<(), String>
{
    let master: MasterConfig = try_str!(parse_config(&master_cfg,
        &*MasterConfig::validator(), Default::default()));
    try!(create_master_dirs(&master));

    if !regex!(r"^\w+$").is_match(tree_name.as_slice()) {
        return Err(format!("Wrong tree name: {}", tree_name));
    }
    if !regex!(r"^\w+$").is_match(command_name.as_slice()) {
        return Err(format!("Wrong tree name: {}", command_name));
    }

    let tree: TreeConfig = try_str!(parse_config(
        &master.config_dir.join(tree_name + ".yaml"),
        &*TreeConfig::validator(), Default::default()));

    let child_fn = tree.config_dir.join(command_name + ".yaml".to_string());
    let child_cfg: ChildConfig = try_str!(parse_config(&child_fn,
        &*ChildConfig::validator(), Default::default()));

    debug!("Child fn: {}", child_fn.display());

    if child_cfg.kind != Command {
        return Err(format!("The target container is: {}", child_cfg.kind));
    }

    let name = Rc::new(format!("{}/cmd.{}.{}", tree_name,
        command_name, unsafe { getpid() }));
    info!("[{}] Running command with args {}", name, args);
    let mut mon = Monitor::new((*name).clone());
    let timeo = Duration::milliseconds(0);
    let mut args = args;
    args.insert(0, "--".to_string());
    mon.add(name.clone(), box Child {
        name: name,
        master_file: master_cfg,
        child_config_serialized: json::encode(&child_cfg),
        root_binary: self_exe_path().unwrap().join("lithos_knot"),
        args: args,
    }, timeo, None);
    mon.run();

    return Ok(());
}

fn main() {

    signal::block_all();

    let mut master_config = Path::new("/etc/lithos.yaml");
    let mut command_name = "".to_string();
    let mut tree_name = "".to_string();
    let mut args = vec!();
    {
        let mut ap = ArgumentParser::new();
        ap.set_description("Runs tree of processes");
        ap.refer(&mut master_config)
          .add_option(["--master"], box Store::<Path>,
            "Name of the master configuration file (default /etc/lithos.yaml)")
          .metavar("FILE");
        ap.refer(&mut tree_name)
          .add_argument("subtree", box Store::<String>,
            "Name of the tree to run command for")
          .required();
        ap.refer(&mut command_name)
          .add_argument("name", box Store::<String>,
            "Name of the command to run")
          .required();
        ap.refer(&mut args)
          .add_argument("argument", box List::<String>,
            "Arguments for the command");
        ap.stop_on_first_argument(true);
        match ap.parse_args() {
            Ok(()) => {}
            Err(x) => {
                set_exit_status(x);
                return;
            }
        }
    }
    match run(master_config, tree_name, command_name, args) {
        Ok(()) => {
            set_exit_status(0);
        }
        Err(e) => {
            (write!(stderr(), "Fatal error: {}\n", e)).ok();
            set_exit_status(1);
        }
    }
}
<commit_msg>Allow dash in command name<commit_after>#![feature(phase, macro_rules, if_let)]

extern crate serialize;
extern crate libc;
#[phase(plugin, link)] extern crate log;

extern crate argparse;
extern crate quire;
#[phase(plugin, link)] extern crate lithos;
#[phase(plugin)] extern crate regex_macros;
extern crate regex;

use std::rc::Rc;
use std::os::{set_exit_status, self_exe_path, getenv};
use std::io::stderr;
use std::time::Duration;
use std::default::Default;
use serialize::json;
use libc::funcs::posix88::unistd::getpid;

use argparse::{ArgumentParser, Store, List};
use quire::parse_config;

use lithos::master_config::{MasterConfig, create_master_dirs};
use lithos::tree_config::TreeConfig;
use lithos::container_config::{Command};
use lithos::child_config::ChildConfig;
use lithos::container::{Command};
use lithos::monitor::{Monitor, Executor};
use lithos::signal;

struct Child {
    name: Rc<String>,
    master_file: Path,
    child_config_serialized: String,
    root_binary: Path,
    args: Vec<String>,
}

impl Executor for Child {
    fn command(&self) -> Command
    {
        let mut cmd = Command::new((*self.name).clone(), &self.root_binary);
        cmd.keep_sigmask();

        // Name is first here, so it's easily visible in ps
        cmd.arg("--name");
        cmd.arg(self.name.as_slice());

        cmd.arg("--master");
        cmd.arg(&self.master_file);
        cmd.arg("--config");
        cmd.arg(self.child_config_serialized.as_slice());
        cmd.set_env("TERM".to_string(),
                    getenv("TERM").unwrap_or("dumb".to_string()));
        if let Some(x) = getenv("RUST_LOG") {
            cmd.set_env("RUST_LOG".to_string(), x);
        }
        if let Some(x) = getenv("RUST_BACKTRACE") {
            cmd.set_env("RUST_BACKTRACE".to_string(), x);
        }
        cmd.args(self.args.as_slice());
        cmd.container();
        return cmd;
    }
    fn finish(&self) -> bool {
        return false;  // Do not restart
    }
}

fn run(master_cfg: Path, tree_name: String,
    command_name: String, args: Vec<String>)
    -> Result<(), String>
{
    let master: MasterConfig = try_str!(parse_config(&master_cfg,
        &*MasterConfig::validator(), Default::default()));
    try!(create_master_dirs(&master));

    if !regex!(r"^[\w-]+$").is_match(tree_name.as_slice()) {
        return Err(format!("Wrong tree name: {}", tree_name));
    }
    if !regex!(r"^[\w-]+$").is_match(command_name.as_slice()) {
        return Err(format!("Wrong ommand name: {}", command_name));
    }

    let tree: TreeConfig = try_str!(parse_config(
        &master.config_dir.join(tree_name + ".yaml"),
        &*TreeConfig::validator(), Default::default()));

    let child_fn = tree.config_dir.join(command_name + ".yaml".to_string());
    let child_cfg: ChildConfig = try_str!(parse_config(&child_fn,
        &*ChildConfig::validator(), Default::default()));

    debug!("Child fn: {}", child_fn.display());

    if child_cfg.kind != Command {
        return Err(format!("The target container is: {}", child_cfg.kind));
    }

    let name = Rc::new(format!("{}/cmd.{}.{}", tree_name,
        command_name, unsafe { getpid() }));
    info!("[{}] Running command with args {}", name, args);
    let mut mon = Monitor::new((*name).clone());
    let timeo = Duration::milliseconds(0);
    let mut args = args;
    args.insert(0, "--".to_string());
    mon.add(name.clone(), box Child {
        name: name,
        master_file: master_cfg,
        child_config_serialized: json::encode(&child_cfg),
        root_binary: self_exe_path().unwrap().join("lithos_knot"),
        args: args,
    }, timeo, None);
    mon.run();

    return Ok(());
}

fn main() {

    signal::block_all();

    let mut master_config = Path::new("/etc/lithos.yaml");
    let mut command_name = "".to_string();
    let mut tree_name = "".to_string();
    let mut args = vec!();
    {
        let mut ap = ArgumentParser::new();
        ap.set_description("Runs tree of processes");
        ap.refer(&mut master_config)
          .add_option(["--master"], box Store::<Path>,
            "Name of the master configuration file (default /etc/lithos.yaml)")
          .metavar("FILE");
        ap.refer(&mut tree_name)
          .add_argument("subtree", box Store::<String>,
            "Name of the tree to run command for")
          .required();
        ap.refer(&mut command_name)
          .add_argument("name", box Store::<String>,
            "Name of the command to run")
          .required();
        ap.refer(&mut args)
          .add_argument("argument", box List::<String>,
            "Arguments for the command");
        ap.stop_on_first_argument(true);
        match ap.parse_args() {
            Ok(()) => {}
            Err(x) => {
                set_exit_status(x);
                return;
            }
        }
    }
    match run(master_config, tree_name, command_name, args) {
        Ok(()) => {
            set_exit_status(0);
        }
        Err(e) => {
            (write!(stderr(), "Fatal error: {}\n", e)).ok();
            set_exit_status(1);
        }
    }
}
<|endoftext|>


<commit_before>extern crate cairo;
extern crate cairo_sys;

#[repr(C)]
pub struct RsvgPathBuilder {
    path_segments: Vec<cairo::PathSegment>,
    last_move_to_index: Option<usize>
}

impl RsvgPathBuilder {
    pub fn new () -> RsvgPathBuilder {
        let builder = RsvgPathBuilder {
            path_segments: Vec::new (),
            last_move_to_index: None
        };

        builder
    }

    pub fn move_to (&mut self, x: f64, y: f64) {
        self.path_segments.push (cairo::PathSegment::MoveTo ((x, y)));
        self.last_move_to_index = Some (self.path_segments.len () - 1);
    }

    pub fn line_to (&mut self, x: f64, y: f64) {
        self.path_segments.push (cairo::PathSegment::LineTo ((x, y)));
    }

    pub fn curve_to (&mut self, x2: f64, y2: f64, x3: f64, y3: f64, x4: f64, y4: f64) {
        self.path_segments.push (cairo::PathSegment::CurveTo ((x2, y2), (x3, y3), (x4, y4)));
    }

    pub fn close_path (&mut self) {
        if let Some (idx) = self.last_move_to_index {
            let segment = self.path_segments[idx];

            if let cairo::PathSegment::MoveTo ((x, y)) = segment {
                self.move_to (x, y);
            } else {
                unreachable! ();
            }
        }
    }

    pub fn get_path_segments (&self) -> &Vec<cairo::PathSegment> {
        &self.path_segments
    }
}

#[no_mangle]
pub unsafe extern fn rsvg_path_builder_new () -> *mut RsvgPathBuilder {
    let builder = RsvgPathBuilder::new ();

    let boxed_builder = Box::new (builder);

    Box::into_raw (boxed_builder)
}

#[no_mangle]
pub unsafe extern fn rsvg_path_builder_destroy (raw_builder: *mut RsvgPathBuilder) {
    assert! (!raw_builder.is_null ());

    let _ = Box::from_raw (raw_builder);
}

#[no_mangle]
pub extern fn rsvg_path_builder_move_to (raw_builder: *mut RsvgPathBuilder,
                                         x: f64,
                                         y: f64) {
    assert! (!raw_builder.is_null ());

    let builder: &mut RsvgPathBuilder = unsafe { &mut (*raw_builder) };

    builder.move_to (x, y);
}

#[no_mangle]
pub extern fn rsvg_path_builder_line_to (raw_builder: *mut RsvgPathBuilder,
                                         x: f64,
                                         y: f64) {
    assert! (!raw_builder.is_null ());

    let builder: &mut RsvgPathBuilder = unsafe { &mut (*raw_builder) };

    builder.line_to (x, y);
}

#[no_mangle]
pub extern fn rsvg_path_builder_curve_to (raw_builder: *mut RsvgPathBuilder,
                                          x2: f64, y2: f64,
                                          x3: f64, y3: f64,
                                          x4: f64, y4: f64) {
    assert! (!raw_builder.is_null ());

    let builder: &mut RsvgPathBuilder = unsafe { &mut (*raw_builder) };

    builder.curve_to (x2, y2, x3, y3, x4, y4);
}

#[no_mangle]
pub extern fn rsvg_path_builder_close_path (raw_builder: *mut RsvgPathBuilder) {
    assert! (!raw_builder.is_null ());

    let builder: &mut RsvgPathBuilder = unsafe { &mut (*raw_builder) };

    builder.close_path ();
}

#[no_mangle]
pub extern fn rsvg_path_builder_add_to_cairo_context (raw_builder: *mut RsvgPathBuilder, cr: *mut cairo_sys::cairo_t) {
    assert! (!raw_builder.is_null ());

    let builder: &mut RsvgPathBuilder = unsafe { &mut (*raw_builder) };

    unsafe {
        let path_segments = builder.get_path_segments ();

        for s in path_segments {
            match *s {
                cairo::PathSegment::MoveTo ((x, y)) => {
                    cairo_sys::cairo_move_to (cr, x, y);
                },

                cairo::PathSegment::LineTo ((x, y)) => {
                    cairo_sys::cairo_line_to (cr, x, y);
                },

                cairo::PathSegment::CurveTo ((x2, y2), (x3, y3), (x4, y4)) => {
                    cairo_sys::cairo_curve_to (cr, x2, y2, x3, y3, x4, y4);
                },

                cairo::PathSegment::ClosePath => {
                    cairo_sys::cairo_close_path (cr);
                    /* FIXME: we'll get a MoveTo from the path builder.  Do we need to omit it
                     * if Cairo will add a similar Moveto by itself?
                     */
                }
            }
        }
    }
}
<commit_msg>path_builder.rs: Actually put a ClosePath in our array of cairo::PathSegment<commit_after>extern crate cairo;
extern crate cairo_sys;

#[repr(C)]
pub struct RsvgPathBuilder {
    path_segments: Vec<cairo::PathSegment>,
}

impl RsvgPathBuilder {
    pub fn new () -> RsvgPathBuilder {
        let builder = RsvgPathBuilder {
            path_segments: Vec::new ()
        };

        builder
    }

    pub fn move_to (&mut self, x: f64, y: f64) {
        self.path_segments.push (cairo::PathSegment::MoveTo ((x, y)));
    }

    pub fn line_to (&mut self, x: f64, y: f64) {
        self.path_segments.push (cairo::PathSegment::LineTo ((x, y)));
    }

    pub fn curve_to (&mut self, x2: f64, y2: f64, x3: f64, y3: f64, x4: f64, y4: f64) {
        self.path_segments.push (cairo::PathSegment::CurveTo ((x2, y2), (x3, y3), (x4, y4)));
    }

    pub fn close_path (&mut self) {
        self.path_segments.push (cairo::PathSegment::ClosePath);
    }

    pub fn get_path_segments (&self) -> &Vec<cairo::PathSegment> {
        &self.path_segments
    }
}

#[no_mangle]
pub unsafe extern fn rsvg_path_builder_new () -> *mut RsvgPathBuilder {
    let builder = RsvgPathBuilder::new ();

    let boxed_builder = Box::new (builder);

    Box::into_raw (boxed_builder)
}

#[no_mangle]
pub unsafe extern fn rsvg_path_builder_destroy (raw_builder: *mut RsvgPathBuilder) {
    assert! (!raw_builder.is_null ());

    let _ = Box::from_raw (raw_builder);
}

#[no_mangle]
pub extern fn rsvg_path_builder_move_to (raw_builder: *mut RsvgPathBuilder,
                                         x: f64,
                                         y: f64) {
    assert! (!raw_builder.is_null ());

    let builder: &mut RsvgPathBuilder = unsafe { &mut (*raw_builder) };

    builder.move_to (x, y);
}

#[no_mangle]
pub extern fn rsvg_path_builder_line_to (raw_builder: *mut RsvgPathBuilder,
                                         x: f64,
                                         y: f64) {
    assert! (!raw_builder.is_null ());

    let builder: &mut RsvgPathBuilder = unsafe { &mut (*raw_builder) };

    builder.line_to (x, y);
}

#[no_mangle]
pub extern fn rsvg_path_builder_curve_to (raw_builder: *mut RsvgPathBuilder,
                                          x2: f64, y2: f64,
                                          x3: f64, y3: f64,
                                          x4: f64, y4: f64) {
    assert! (!raw_builder.is_null ());

    let builder: &mut RsvgPathBuilder = unsafe { &mut (*raw_builder) };

    builder.curve_to (x2, y2, x3, y3, x4, y4);
}

#[no_mangle]
pub extern fn rsvg_path_builder_close_path (raw_builder: *mut RsvgPathBuilder) {
    assert! (!raw_builder.is_null ());

    let builder: &mut RsvgPathBuilder = unsafe { &mut (*raw_builder) };

    builder.close_path ();
}

#[no_mangle]
pub extern fn rsvg_path_builder_add_to_cairo_context (raw_builder: *mut RsvgPathBuilder, cr: *mut cairo_sys::cairo_t) {
    assert! (!raw_builder.is_null ());

    let builder: &mut RsvgPathBuilder = unsafe { &mut (*raw_builder) };

    unsafe {
        let path_segments = builder.get_path_segments ();

        for s in path_segments {
            match *s {
                cairo::PathSegment::MoveTo ((x, y)) => {
                    cairo_sys::cairo_move_to (cr, x, y);
                },

                cairo::PathSegment::LineTo ((x, y)) => {
                    cairo_sys::cairo_line_to (cr, x, y);
                },

                cairo::PathSegment::CurveTo ((x2, y2), (x3, y3), (x4, y4)) => {
                    cairo_sys::cairo_curve_to (cr, x2, y2, x3, y3, x4, y4);
                },

                cairo::PathSegment::ClosePath => {
                    cairo_sys::cairo_close_path (cr);
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>use clippy_dev::clippy_project_root;
use std::fs::{File, OpenOptions};
use std::io;
use std::io::prelude::*;
use std::io::ErrorKind;
use std::path::Path;

pub fn create(pass: Option<&str>, lint_name: Option<&str>, category: Option<&str>) -> Result<(), io::Error> {
    let pass = pass.expect("`pass` argument is validated by clap");
    let lint_name = lint_name.expect("`name` argument is validated by clap");
    let category = category.expect("`category` argument is validated by clap");

    match open_files(lint_name) {
        Ok((mut test_file, mut lint_file)) => {
            let (pass_type, pass_lifetimes, pass_import, context_import) = match pass {
                "early" => ("EarlyLintPass", "", "use rustc_ast::ast::*;", "EarlyContext"),
                "late" => ("LateLintPass", "<'_, '_>", "use rustc_hir::*;", "LateContext"),
                _ => {
                    unreachable!("`pass_type` should only ever be `early` or `late`!");
                },
            };

            let camel_case_name = to_camel_case(lint_name);

            if let Err(e) = test_file.write_all(get_test_file_contents(lint_name).as_bytes()) {
                return Err(io::Error::new(
                    ErrorKind::Other,
                    format!("Could not write to test file: {}", e),
                ));
            };

            if let Err(e) = lint_file.write_all(
                get_lint_file_contents(
                    pass_type,
                    pass_lifetimes,
                    lint_name,
                    &camel_case_name,
                    category,
                    pass_import,
                    context_import,
                )
                .as_bytes(),
            ) {
                return Err(io::Error::new(
                    ErrorKind::Other,
                    format!("Could not write to lint file: {}", e),
                ));
            }
            Ok(())
        },
        Err(e) => Err(io::Error::new(
            ErrorKind::Other,
            format!("Unable to create lint: {}", e),
        )),
    }
}

fn open_files(lint_name: &str) -> Result<(File, File), io::Error> {
    let project_root = clippy_project_root();

    let test_file_path = project_root.join("tests").join("ui").join(format!("{}.rs", lint_name));
    let lint_file_path = project_root
        .join("clippy_lints")
        .join("src")
        .join(format!("{}.rs", lint_name));

    if Path::new(&test_file_path).exists() {
        return Err(io::Error::new(
            ErrorKind::AlreadyExists,
            format!("test file {:?} already exists", test_file_path),
        ));
    }
    if Path::new(&lint_file_path).exists() {
        return Err(io::Error::new(
            ErrorKind::AlreadyExists,
            format!("lint file {:?} already exists", lint_file_path),
        ));
    }

    let test_file = OpenOptions::new().write(true).create_new(true).open(test_file_path)?;
    let lint_file = OpenOptions::new().write(true).create_new(true).open(lint_file_path)?;

    Ok((test_file, lint_file))
}

fn to_camel_case(name: &str) -> String {
    name.split('_')
        .map(|s| {
            if s.is_empty() {
                String::from("")
            } else {
                [&s[0..1].to_uppercase(), &s[1..]].concat()
            }
        })
        .collect()
}

fn get_test_file_contents(lint_name: &str) -> String {
    format!(
        "#![warn(clippy::{})]

fn main() {{
    // test code goes here
}}
",
        lint_name
    )
}

fn get_lint_file_contents(
    pass_type: &str,
    pass_lifetimes: &str,
    lint_name: &str,
    camel_case_name: &str,
    category: &str,
    pass_import: &str,
    context_import: &str,
) -> String {
    format!(
        "use rustc_lint::{{{type}, {context_import}}};
use rustc_session::{{declare_lint_pass, declare_tool_lint}};
{pass_import}

declare_clippy_lint! {{
    /// **What it does:**
    ///
    /// **Why is this bad?**
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    ///
    /// ```rust
    /// // example code
    /// ```
    pub {name_upper},
    {category},
    \"default lint description\"
}}

declare_lint_pass!({name_camel} => [{name_upper}]);

impl {type}{lifetimes} for {name_camel} {{}}
",
        type=pass_type,
        lifetimes=pass_lifetimes,
        name_upper=lint_name.to_uppercase(),
        name_camel=camel_case_name,
        category=category,
        pass_import=pass_import,
        context_import=context_import
    )
}

#[test]
fn test_camel_case() {
    let s = "a_lint";
    let s2 = to_camel_case(s);
    assert_eq!(s2, "ALint");

    let name = "a_really_long_new_lint";
    let name2 = to_camel_case(name);
    assert_eq!(name2, "AReallyLongNewLint");

    let name3 = "lint__name";
    let name4 = to_camel_case(name3);
    assert_eq!(name4, "LintName");
}
<commit_msg>Auto merge of #5330 - matthiaskrgr:newlint_expl, r=flip1995<commit_after>use clippy_dev::clippy_project_root;
use std::fs::{File, OpenOptions};
use std::io;
use std::io::prelude::*;
use std::io::ErrorKind;
use std::path::Path;

pub fn create(pass: Option<&str>, lint_name: Option<&str>, category: Option<&str>) -> Result<(), io::Error> {
    let pass = pass.expect("`pass` argument is validated by clap");
    let lint_name = lint_name.expect("`name` argument is validated by clap");
    let category = category.expect("`category` argument is validated by clap");

    match open_files(lint_name) {
        Ok((mut test_file, mut lint_file)) => {
            let (pass_type, pass_lifetimes, pass_import, context_import) = match pass {
                "early" => ("EarlyLintPass", "", "use rustc_ast::ast::*;", "EarlyContext"),
                "late" => ("LateLintPass", "<'_, '_>", "use rustc_hir::*;", "LateContext"),
                _ => {
                    unreachable!("`pass_type` should only ever be `early` or `late`!");
                },
            };

            let camel_case_name = to_camel_case(lint_name);

            if let Err(e) = test_file.write_all(get_test_file_contents(lint_name).as_bytes()) {
                return Err(io::Error::new(
                    ErrorKind::Other,
                    format!("Could not write to test file: {}", e),
                ));
            };

            if let Err(e) = lint_file.write_all(
                get_lint_file_contents(
                    pass_type,
                    pass_lifetimes,
                    lint_name,
                    &camel_case_name,
                    category,
                    pass_import,
                    context_import,
                )
                .as_bytes(),
            ) {
                return Err(io::Error::new(
                    ErrorKind::Other,
                    format!("Could not write to lint file: {}", e),
                ));
            }
            Ok(())
        },
        Err(e) => Err(io::Error::new(
            ErrorKind::Other,
            format!("Unable to create lint: {}", e),
        )),
    }
}

fn open_files(lint_name: &str) -> Result<(File, File), io::Error> {
    let project_root = clippy_project_root();

    let test_file_path = project_root.join("tests").join("ui").join(format!("{}.rs", lint_name));
    let lint_file_path = project_root
        .join("clippy_lints")
        .join("src")
        .join(format!("{}.rs", lint_name));

    if Path::new(&test_file_path).exists() {
        return Err(io::Error::new(
            ErrorKind::AlreadyExists,
            format!("test file {:?} already exists", test_file_path),
        ));
    }
    if Path::new(&lint_file_path).exists() {
        return Err(io::Error::new(
            ErrorKind::AlreadyExists,
            format!("lint file {:?} already exists", lint_file_path),
        ));
    }

    let test_file = OpenOptions::new().write(true).create_new(true).open(test_file_path)?;
    let lint_file = OpenOptions::new().write(true).create_new(true).open(lint_file_path)?;

    Ok((test_file, lint_file))
}

fn to_camel_case(name: &str) -> String {
    name.split('_')
        .map(|s| {
            if s.is_empty() {
                String::from("")
            } else {
                [&s[0..1].to_uppercase(), &s[1..]].concat()
            }
        })
        .collect()
}

fn get_test_file_contents(lint_name: &str) -> String {
    format!(
        "#![warn(clippy::{})]

fn main() {{
    // test code goes here
}}
",
        lint_name
    )
}

fn get_lint_file_contents(
    pass_type: &str,
    pass_lifetimes: &str,
    lint_name: &str,
    camel_case_name: &str,
    category: &str,
    pass_import: &str,
    context_import: &str,
) -> String {
    format!(
        "use rustc_lint::{{{type}, {context_import}}};
use rustc_session::{{declare_lint_pass, declare_tool_lint}};
{pass_import}

declare_clippy_lint! {{
    /// **What it does:**
    ///
    /// **Why is this bad?**
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    ///
    /// ```rust
    /// // example code where clippy issues a warning
    /// ```
    /// Use instead:
    /// ```rust
    /// // example code which does not raise clippy warning
    /// ```
    pub {name_upper},
    {category},
    \"default lint description\"
}}

declare_lint_pass!({name_camel} => [{name_upper}]);

impl {type}{lifetimes} for {name_camel} {{}}
",
        type=pass_type,
        lifetimes=pass_lifetimes,
        name_upper=lint_name.to_uppercase(),
        name_camel=camel_case_name,
        category=category,
        pass_import=pass_import,
        context_import=context_import
    )
}

#[test]
fn test_camel_case() {
    let s = "a_lint";
    let s2 = to_camel_case(s);
    assert_eq!(s2, "ALint");

    let name = "a_really_long_new_lint";
    let name2 = to_camel_case(name);
    assert_eq!(name2, "AReallyLongNewLint");

    let name3 = "lint__name";
    let name4 = to_camel_case(name3);
    assert_eq!(name4, "LintName");
}
<|endoftext|>


<commit_before>use std::f32;

use na::{Isometry3, Translation3, UnitQuaternion, Vector3, Point3};
use ncollide3d::{
    query::{Ray,RayCast},
    shape::{Ball, ShapeHandle},
    world::{CollisionGroups, CollisionWorld, GeometricQueryType},
};

#[test]
fn interferences_with_ray() {
    let mut world = CollisionWorld::new(0.01);

    let ball = Ball::new(0.5f32);
    let groups = CollisionGroups::new();
    let query = GeometricQueryType::Contacts(0.0, 0.0);

    let tra = Translation3::new(1.0, 1.0, 1.0);
    let rot = UnitQuaternion::from_scaled_axis(Vector3::y() * f32::consts::PI);
    let iso = Isometry3::from_parts(tra, rot);

    let ray = Ray::new(Point3::new(0.0, 0.0, 0.0), Vector3::new(1.0, 1.0, 1.0));

    assert!(ball.toi_with_ray(
        &iso,
        &ray,
        true,
    ).is_some());

    let shape = ShapeHandle::new(ball);
    world.add(iso, shape.clone(), groups, query, ());
    world.update();

    let num_collision_objects = world.collision_objects().into_iter().collect::<Vec<_>>().len();
    assert!(
        num_collision_objects  == 1,
        format!("Expected 1 collision object, got {}", num_collision_objects),
    );

    let interferences = world.interferences_with_ray(&ray, &groups);
    let num_collisions = interferences.into_iter().collect::<Vec<_>>().len();
    assert!(
        num_collisions  == 1,
        format!("Expected 1 collision, got {}", num_collisions),
    );
}
<commit_msg>rustfmt<commit_after>use std::f32;

use na::{Isometry3, Point3, Translation3, UnitQuaternion, Vector3};
use ncollide3d::{
    query::{Ray, RayCast},
    shape::{Ball, ShapeHandle},
    world::{CollisionGroups, CollisionWorld, GeometricQueryType},
};

#[test]
fn interferences_with_ray() {
    let mut world = CollisionWorld::new(0.01);

    let ball = Ball::new(0.5f32);
    let groups = CollisionGroups::new();
    let query = GeometricQueryType::Contacts(0.0, 0.0);

    let tra = Translation3::new(1.0, 1.0, 1.0);
    let rot = UnitQuaternion::from_scaled_axis(Vector3::y() * f32::consts::PI);
    let iso = Isometry3::from_parts(tra, rot);

    let ray = Ray::new(Point3::new(0.0, 0.0, 0.0), Vector3::new(1.0, 1.0, 1.0));

    assert!(ball.toi_with_ray(&iso, &ray, true,).is_some());

    let shape = ShapeHandle::new(ball);
    world.add(iso, shape.clone(), groups, query, ());
    world.update();

    let num_collision_objects = world
        .collision_objects()
        .into_iter()
        .collect::<Vec<_>>()
        .len();
    assert!(
        num_collision_objects == 1,
        format!("Expected 1 collision object, got {}", num_collision_objects),
    );

    let interferences = world.interferences_with_ray(&ray, &groups);
    let num_collisions = interferences.into_iter().collect::<Vec<_>>().len();
    assert!(
        num_collisions == 1,
        format!("Expected 1 collision, got {}", num_collisions),
    );
}
<|endoftext|>


<commit_before>#![doc(html_root_url = "https://docs.rs/tokio-macros/0.2.3")]
#![allow(clippy::needless_doctest_main)]
#![warn(
    missing_debug_implementations,
    missing_docs,
    rust_2018_idioms,
    unreachable_pub
)]
use proc_macro::TokenStream;
use quote::quote;
use std::num::NonZeroUsize;

#[derive(Clone, Copy, PartialEq)]
enum Runtime {
    Basic,
    Threaded,
}

fn parse_knobs(
    input: syn::ItemFn,
    args: syn::AttributeArgs,
    is_test: bool,
    rt_threaded: bool,
) -> Result<TokenStream, syn::Error> {
    let ret = &input.sig.output;
    let name = &input.sig.ident;
    let inputs = &input.sig.inputs;
    let body = &input.block;
    let attrs = &input.attrs;
    let vis = input.vis;

    if input.sig.asyncness.is_none() {
        let msg = "the async keyword is missing from the function declaration";
        return Err(syn::Error::new_spanned(input.sig.fn_token, msg));
    }

    let mut runtime = None;
    let mut core_threads = None;
    let mut max_threads = None;

    for arg in args {
        match arg {
            syn::NestedMeta::Meta(syn::Meta::NameValue(namevalue)) => {
                let ident = namevalue.path.get_ident();
                if ident.is_none() {
                    let msg = "Must have specified ident";
                    return Err(syn::Error::new_spanned(namevalue, msg));
                }
                match ident.unwrap().to_string().to_lowercase().as_str() {
                    "core_threads" => {
                        if rt_threaded {
                            match &namevalue.lit {
                                syn::Lit::Int(expr) => {
                                    let num = expr.base10_parse::<NonZeroUsize>().unwrap();
                                    if num.get() > 1 {
                                        runtime = Some(Runtime::Threaded);
                                    } else {
                                        runtime = Some(Runtime::Basic);
                                    }

                                    if let Some(v) = max_threads {
                                        if v < num {
                                            return Err(syn::Error::new_spanned(
                                                namevalue,
                                                "max_threads cannot be less than core_threads",
                                            ));
                                        }
                                    }

                                    core_threads = Some(num);
                                }
                                _ => {
                                    return Err(syn::Error::new_spanned(
                                        namevalue,
                                        "core_threads argument must be an int",
                                    ))
                                }
                            }
                        } else {
                            return Err(syn::Error::new_spanned(
                                namevalue,
                                "core_threads can only be set with rt-threaded feature flag enabled",
                            ));
                        }
                    }
                    "max_threads" => match &namevalue.lit {
                        syn::Lit::Int(expr) => {
                            let num = expr.base10_parse::<NonZeroUsize>().unwrap();

                            if let Some(v) = core_threads {
                                if num < v {
                                    return Err(syn::Error::new_spanned(
                                        namevalue,
                                        "max_threads cannot be less than core_threads",
                                    ));
                                }
                            }
                            max_threads = Some(num);
                        }
                        _ => {
                            return Err(syn::Error::new_spanned(
                                namevalue,
                                "max_threads argument must be an int",
                            ))
                        }
                    },
                    name => {
                        let msg = format!("Unknown attribute pair {} is specified; expected one of: `core_threads`, `max_threads`", name);
                        return Err(syn::Error::new_spanned(namevalue, msg));
                    }
                }
            }
            syn::NestedMeta::Meta(syn::Meta::Path(path)) => {
                let ident = path.get_ident();
                if ident.is_none() {
                    let msg = "Must have specified ident";
                    return Err(syn::Error::new_spanned(path, msg));
                }
                match ident.unwrap().to_string().to_lowercase().as_str() {
                    "threaded_scheduler" => {
                        runtime = Some(runtime.unwrap_or_else(|| Runtime::Threaded))
                    }
                    "basic_scheduler" => runtime = Some(runtime.unwrap_or_else(|| Runtime::Basic)),
                    name => {
                        let msg = format!("Unknown attribute {} is specified; expected `basic_scheduler` or `threaded_scheduler`", name);
                        return Err(syn::Error::new_spanned(path, msg));
                    }
                }
            }
            other => {
                return Err(syn::Error::new_spanned(
                    other,
                    "Unknown attribute inside the macro",
                ));
            }
        }
    }

    let mut rt = quote! { tokio::runtime::Builder::new().basic_scheduler() };
    if rt_threaded && (runtime == Some(Runtime::Threaded) || (runtime.is_none() && !is_test)) {
        rt = quote! { #rt.threaded_scheduler() };
    }
    if let Some(v) = core_threads.map(|v| v.get()) {
        rt = quote! { #rt.core_threads(#v) };
    }
    if let Some(v) = max_threads.map(|v| v.get()) {
        rt = quote! { #rt.max_threads(#v) };
    }

    let header = {
        if is_test {
            quote! {
                #[test]
            }
        } else {
            quote! {}
        }
    };

    let result = quote! {
        #header
        #(#attrs)*
        #vis fn #name(#inputs) #ret {
            #rt
                .enable_all()
                .build()
                .unwrap()
                .block_on(async { #body })
        }
    };

    Ok(result.into())
}

#[cfg(not(test))] // Work around for rust-lang/rust#62127
pub(crate) fn main(args: TokenStream, item: TokenStream, rt_threaded: bool) -> TokenStream {
    let input = syn::parse_macro_input!(item as syn::ItemFn);
    let args = syn::parse_macro_input!(args as syn::AttributeArgs);

    if input.sig.ident == "main" && !input.sig.inputs.is_empty() {
        let msg = "the main function cannot accept arguments";
        return syn::Error::new_spanned(&input.sig.inputs, msg)
            .to_compile_error()
            .into();
    }

    parse_knobs(input, args, false, rt_threaded).unwrap_or_else(|e| e.to_compile_error().into())
}

pub(crate) fn test(args: TokenStream, item: TokenStream, rt_threaded: bool) -> TokenStream {
    let input = syn::parse_macro_input!(item as syn::ItemFn);
    let args = syn::parse_macro_input!(args as syn::AttributeArgs);

    for attr in &input.attrs {
        if attr.path.is_ident("test") {
            let msg = "second test attribute is supplied";
            return syn::Error::new_spanned(&attr, msg)
                .to_compile_error()
                .into();
        }
    }

    if !input.sig.inputs.is_empty() {
        let msg = "the test function cannot accept arguments";
        return syn::Error::new_spanned(&input.sig.inputs, msg)
            .to_compile_error()
            .into();
    }

    parse_knobs(input, args, true, rt_threaded).unwrap_or_else(|e| e.to_compile_error().into())
}

pub(crate) mod old {
    use proc_macro::TokenStream;
    use quote::quote;

    enum Runtime {
        Basic,
        Threaded,
        Auto,
    }

    #[cfg(not(test))] // Work around for rust-lang/rust#62127
    pub(crate) fn main(args: TokenStream, item: TokenStream) -> TokenStream {
        let input = syn::parse_macro_input!(item as syn::ItemFn);
        let args = syn::parse_macro_input!(args as syn::AttributeArgs);

        let ret = &input.sig.output;
        let name = &input.sig.ident;
        let inputs = &input.sig.inputs;
        let body = &input.block;
        let attrs = &input.attrs;
        let vis = input.vis;

        if input.sig.asyncness.is_none() {
            let msg = "the async keyword is missing from the function declaration";
            return syn::Error::new_spanned(input.sig.fn_token, msg)
                .to_compile_error()
                .into();
        } else if name == "main" && !inputs.is_empty() {
            let msg = "the main function cannot accept arguments";
            return syn::Error::new_spanned(&input.sig.inputs, msg)
                .to_compile_error()
                .into();
        }

        let mut runtime = Runtime::Auto;

        for arg in args {
            if let syn::NestedMeta::Meta(syn::Meta::Path(path)) = arg {
                let ident = path.get_ident();
                if ident.is_none() {
                    let msg = "Must have specified ident";
                    return syn::Error::new_spanned(path, msg).to_compile_error().into();
                }
                match ident.unwrap().to_string().to_lowercase().as_str() {
                    "threaded_scheduler" => runtime = Runtime::Threaded,
                    "basic_scheduler" => runtime = Runtime::Basic,
                    name => {
                        let msg = format!("Unknown attribute {} is specified; expected `basic_scheduler` or `threaded_scheduler`", name);
                        return syn::Error::new_spanned(path, msg).to_compile_error().into();
                    }
                }
            }
        }

        let result = match runtime {
            Runtime::Threaded | Runtime::Auto => quote! {
                #(#attrs)*
                #vis fn #name(#inputs) #ret {
                    tokio::runtime::Runtime::new().unwrap().block_on(async { #body })
                }
            },
            Runtime::Basic => quote! {
                #(#attrs)*
                #vis fn #name(#inputs) #ret {
                    tokio::runtime::Builder::new()
                        .basic_scheduler()
                        .enable_all()
                        .build()
                        .unwrap()
                        .block_on(async { #body })
                }
            },
        };

        result.into()
    }

    pub(crate) fn test(args: TokenStream, item: TokenStream) -> TokenStream {
        let input = syn::parse_macro_input!(item as syn::ItemFn);
        let args = syn::parse_macro_input!(args as syn::AttributeArgs);

        let ret = &input.sig.output;
        let name = &input.sig.ident;
        let body = &input.block;
        let attrs = &input.attrs;
        let vis = input.vis;

        for attr in attrs {
            if attr.path.is_ident("test") {
                let msg = "second test attribute is supplied";
                return syn::Error::new_spanned(&attr, msg)
                    .to_compile_error()
                    .into();
            }
        }

        if input.sig.asyncness.is_none() {
            let msg = "the async keyword is missing from the function declaration";
            return syn::Error::new_spanned(&input.sig.fn_token, msg)
                .to_compile_error()
                .into();
        } else if !input.sig.inputs.is_empty() {
            let msg = "the test function cannot accept arguments";
            return syn::Error::new_spanned(&input.sig.inputs, msg)
                .to_compile_error()
                .into();
        }

        let mut runtime = Runtime::Auto;

        for arg in args {
            if let syn::NestedMeta::Meta(syn::Meta::Path(path)) = arg {
                let ident = path.get_ident();
                if ident.is_none() {
                    let msg = "Must have specified ident";
                    return syn::Error::new_spanned(path, msg).to_compile_error().into();
                }
                match ident.unwrap().to_string().to_lowercase().as_str() {
                    "threaded_scheduler" => runtime = Runtime::Threaded,
                    "basic_scheduler" => runtime = Runtime::Basic,
                    name => {
                        let msg = format!("Unknown attribute {} is specified; expected `basic_scheduler` or `threaded_scheduler`", name);
                        return syn::Error::new_spanned(path, msg).to_compile_error().into();
                    }
                }
            }
        }

        let result = match runtime {
            Runtime::Threaded => quote! {
                #[test]
                #(#attrs)*
                #vis fn #name() #ret {
                    tokio::runtime::Runtime::new().unwrap().block_on(async { #body })
                }
            },
            Runtime::Basic | Runtime::Auto => quote! {
                #[test]
                #(#attrs)*
                #vis fn #name() #ret {
                    tokio::runtime::Builder::new()
                        .basic_scheduler()
                        .enable_all()
                        .build()
                        .unwrap()
                        .block_on(async { #body })
                }
            },
        };

        result.into()
    }
}
<commit_msg>macros: remove unused attributes (#2147)<commit_after>use proc_macro::TokenStream;
use quote::quote;
use std::num::NonZeroUsize;

#[derive(Clone, Copy, PartialEq)]
enum Runtime {
    Basic,
    Threaded,
}

fn parse_knobs(
    input: syn::ItemFn,
    args: syn::AttributeArgs,
    is_test: bool,
    rt_threaded: bool,
) -> Result<TokenStream, syn::Error> {
    let ret = &input.sig.output;
    let name = &input.sig.ident;
    let inputs = &input.sig.inputs;
    let body = &input.block;
    let attrs = &input.attrs;
    let vis = input.vis;

    if input.sig.asyncness.is_none() {
        let msg = "the async keyword is missing from the function declaration";
        return Err(syn::Error::new_spanned(input.sig.fn_token, msg));
    }

    let mut runtime = None;
    let mut core_threads = None;
    let mut max_threads = None;

    for arg in args {
        match arg {
            syn::NestedMeta::Meta(syn::Meta::NameValue(namevalue)) => {
                let ident = namevalue.path.get_ident();
                if ident.is_none() {
                    let msg = "Must have specified ident";
                    return Err(syn::Error::new_spanned(namevalue, msg));
                }
                match ident.unwrap().to_string().to_lowercase().as_str() {
                    "core_threads" => {
                        if rt_threaded {
                            match &namevalue.lit {
                                syn::Lit::Int(expr) => {
                                    let num = expr.base10_parse::<NonZeroUsize>().unwrap();
                                    if num.get() > 1 {
                                        runtime = Some(Runtime::Threaded);
                                    } else {
                                        runtime = Some(Runtime::Basic);
                                    }

                                    if let Some(v) = max_threads {
                                        if v < num {
                                            return Err(syn::Error::new_spanned(
                                                namevalue,
                                                "max_threads cannot be less than core_threads",
                                            ));
                                        }
                                    }

                                    core_threads = Some(num);
                                }
                                _ => {
                                    return Err(syn::Error::new_spanned(
                                        namevalue,
                                        "core_threads argument must be an int",
                                    ))
                                }
                            }
                        } else {
                            return Err(syn::Error::new_spanned(
                                namevalue,
                                "core_threads can only be set with rt-threaded feature flag enabled",
                            ));
                        }
                    }
                    "max_threads" => match &namevalue.lit {
                        syn::Lit::Int(expr) => {
                            let num = expr.base10_parse::<NonZeroUsize>().unwrap();

                            if let Some(v) = core_threads {
                                if num < v {
                                    return Err(syn::Error::new_spanned(
                                        namevalue,
                                        "max_threads cannot be less than core_threads",
                                    ));
                                }
                            }
                            max_threads = Some(num);
                        }
                        _ => {
                            return Err(syn::Error::new_spanned(
                                namevalue,
                                "max_threads argument must be an int",
                            ))
                        }
                    },
                    name => {
                        let msg = format!("Unknown attribute pair {} is specified; expected one of: `core_threads`, `max_threads`", name);
                        return Err(syn::Error::new_spanned(namevalue, msg));
                    }
                }
            }
            syn::NestedMeta::Meta(syn::Meta::Path(path)) => {
                let ident = path.get_ident();
                if ident.is_none() {
                    let msg = "Must have specified ident";
                    return Err(syn::Error::new_spanned(path, msg));
                }
                match ident.unwrap().to_string().to_lowercase().as_str() {
                    "threaded_scheduler" => {
                        runtime = Some(runtime.unwrap_or_else(|| Runtime::Threaded))
                    }
                    "basic_scheduler" => runtime = Some(runtime.unwrap_or_else(|| Runtime::Basic)),
                    name => {
                        let msg = format!("Unknown attribute {} is specified; expected `basic_scheduler` or `threaded_scheduler`", name);
                        return Err(syn::Error::new_spanned(path, msg));
                    }
                }
            }
            other => {
                return Err(syn::Error::new_spanned(
                    other,
                    "Unknown attribute inside the macro",
                ));
            }
        }
    }

    let mut rt = quote! { tokio::runtime::Builder::new().basic_scheduler() };
    if rt_threaded && (runtime == Some(Runtime::Threaded) || (runtime.is_none() && !is_test)) {
        rt = quote! { #rt.threaded_scheduler() };
    }
    if let Some(v) = core_threads.map(|v| v.get()) {
        rt = quote! { #rt.core_threads(#v) };
    }
    if let Some(v) = max_threads.map(|v| v.get()) {
        rt = quote! { #rt.max_threads(#v) };
    }

    let header = {
        if is_test {
            quote! {
                #[test]
            }
        } else {
            quote! {}
        }
    };

    let result = quote! {
        #header
        #(#attrs)*
        #vis fn #name(#inputs) #ret {
            #rt
                .enable_all()
                .build()
                .unwrap()
                .block_on(async { #body })
        }
    };

    Ok(result.into())
}

#[cfg(not(test))] // Work around for rust-lang/rust#62127
pub(crate) fn main(args: TokenStream, item: TokenStream, rt_threaded: bool) -> TokenStream {
    let input = syn::parse_macro_input!(item as syn::ItemFn);
    let args = syn::parse_macro_input!(args as syn::AttributeArgs);

    if input.sig.ident == "main" && !input.sig.inputs.is_empty() {
        let msg = "the main function cannot accept arguments";
        return syn::Error::new_spanned(&input.sig.inputs, msg)
            .to_compile_error()
            .into();
    }

    parse_knobs(input, args, false, rt_threaded).unwrap_or_else(|e| e.to_compile_error().into())
}

pub(crate) fn test(args: TokenStream, item: TokenStream, rt_threaded: bool) -> TokenStream {
    let input = syn::parse_macro_input!(item as syn::ItemFn);
    let args = syn::parse_macro_input!(args as syn::AttributeArgs);

    for attr in &input.attrs {
        if attr.path.is_ident("test") {
            let msg = "second test attribute is supplied";
            return syn::Error::new_spanned(&attr, msg)
                .to_compile_error()
                .into();
        }
    }

    if !input.sig.inputs.is_empty() {
        let msg = "the test function cannot accept arguments";
        return syn::Error::new_spanned(&input.sig.inputs, msg)
            .to_compile_error()
            .into();
    }

    parse_knobs(input, args, true, rt_threaded).unwrap_or_else(|e| e.to_compile_error().into())
}

pub(crate) mod old {
    use proc_macro::TokenStream;
    use quote::quote;

    enum Runtime {
        Basic,
        Threaded,
        Auto,
    }

    #[cfg(not(test))] // Work around for rust-lang/rust#62127
    pub(crate) fn main(args: TokenStream, item: TokenStream) -> TokenStream {
        let input = syn::parse_macro_input!(item as syn::ItemFn);
        let args = syn::parse_macro_input!(args as syn::AttributeArgs);

        let ret = &input.sig.output;
        let name = &input.sig.ident;
        let inputs = &input.sig.inputs;
        let body = &input.block;
        let attrs = &input.attrs;
        let vis = input.vis;

        if input.sig.asyncness.is_none() {
            let msg = "the async keyword is missing from the function declaration";
            return syn::Error::new_spanned(input.sig.fn_token, msg)
                .to_compile_error()
                .into();
        } else if name == "main" && !inputs.is_empty() {
            let msg = "the main function cannot accept arguments";
            return syn::Error::new_spanned(&input.sig.inputs, msg)
                .to_compile_error()
                .into();
        }

        let mut runtime = Runtime::Auto;

        for arg in args {
            if let syn::NestedMeta::Meta(syn::Meta::Path(path)) = arg {
                let ident = path.get_ident();
                if ident.is_none() {
                    let msg = "Must have specified ident";
                    return syn::Error::new_spanned(path, msg).to_compile_error().into();
                }
                match ident.unwrap().to_string().to_lowercase().as_str() {
                    "threaded_scheduler" => runtime = Runtime::Threaded,
                    "basic_scheduler" => runtime = Runtime::Basic,
                    name => {
                        let msg = format!("Unknown attribute {} is specified; expected `basic_scheduler` or `threaded_scheduler`", name);
                        return syn::Error::new_spanned(path, msg).to_compile_error().into();
                    }
                }
            }
        }

        let result = match runtime {
            Runtime::Threaded | Runtime::Auto => quote! {
                #(#attrs)*
                #vis fn #name(#inputs) #ret {
                    tokio::runtime::Runtime::new().unwrap().block_on(async { #body })
                }
            },
            Runtime::Basic => quote! {
                #(#attrs)*
                #vis fn #name(#inputs) #ret {
                    tokio::runtime::Builder::new()
                        .basic_scheduler()
                        .enable_all()
                        .build()
                        .unwrap()
                        .block_on(async { #body })
                }
            },
        };

        result.into()
    }

    pub(crate) fn test(args: TokenStream, item: TokenStream) -> TokenStream {
        let input = syn::parse_macro_input!(item as syn::ItemFn);
        let args = syn::parse_macro_input!(args as syn::AttributeArgs);

        let ret = &input.sig.output;
        let name = &input.sig.ident;
        let body = &input.block;
        let attrs = &input.attrs;
        let vis = input.vis;

        for attr in attrs {
            if attr.path.is_ident("test") {
                let msg = "second test attribute is supplied";
                return syn::Error::new_spanned(&attr, msg)
                    .to_compile_error()
                    .into();
            }
        }

        if input.sig.asyncness.is_none() {
            let msg = "the async keyword is missing from the function declaration";
            return syn::Error::new_spanned(&input.sig.fn_token, msg)
                .to_compile_error()
                .into();
        } else if !input.sig.inputs.is_empty() {
            let msg = "the test function cannot accept arguments";
            return syn::Error::new_spanned(&input.sig.inputs, msg)
                .to_compile_error()
                .into();
        }

        let mut runtime = Runtime::Auto;

        for arg in args {
            if let syn::NestedMeta::Meta(syn::Meta::Path(path)) = arg {
                let ident = path.get_ident();
                if ident.is_none() {
                    let msg = "Must have specified ident";
                    return syn::Error::new_spanned(path, msg).to_compile_error().into();
                }
                match ident.unwrap().to_string().to_lowercase().as_str() {
                    "threaded_scheduler" => runtime = Runtime::Threaded,
                    "basic_scheduler" => runtime = Runtime::Basic,
                    name => {
                        let msg = format!("Unknown attribute {} is specified; expected `basic_scheduler` or `threaded_scheduler`", name);
                        return syn::Error::new_spanned(path, msg).to_compile_error().into();
                    }
                }
            }
        }

        let result = match runtime {
            Runtime::Threaded => quote! {
                #[test]
                #(#attrs)*
                #vis fn #name() #ret {
                    tokio::runtime::Runtime::new().unwrap().block_on(async { #body })
                }
            },
            Runtime::Basic | Runtime::Auto => quote! {
                #[test]
                #(#attrs)*
                #vis fn #name() #ret {
                    tokio::runtime::Builder::new()
                        .basic_scheduler()
                        .enable_all()
                        .build()
                        .unwrap()
                        .block_on(async { #body })
                }
            },
        };

        result.into()
    }
}
<|endoftext|>


<commit_before>
pub struct Task {
        id: int,
        todo: ~str,
        priority: char,
        finished: bool,
        raw_todo: ~str,
        create_date: ~str,
        finish_date: ~str,
        contexts: ~[~str],
        projects: ~[~str]
}

impl Task {
        pub fn to_str(&self) -> ~str {
                return format!("{:d} {:b} |{:s}| ({:c}) |{:s}| '{:s}' \"{:s}\"",
                                self.id, self.finished, self.finish_date, self.priority,
                                self.create_date, self.todo, self.raw_todo)
        }

        pub fn create(text: ~str, id: int) -> Task {
                let mut task = Task{id: id, raw_todo: text.clone(), todo: text.clone(),
                                        finished: false, priority: '^',
                                        create_date: ~"", finish_date: ~"",
                                        contexts: ~[], projects: ~[]};

                let mut todo = text.clone();

                if (todo.slice(0, 2) == "x ") {
                        task.finished = true;
                        todo = todo.slice(2, todo.len()).to_owned();
                }

                let mut chars = todo.chars().to_owned_vec();

                if (chars[10] == ' ' && chars[4] == '-' &&
                    chars[7] == '-' && task.finished) {
                        task.finish_date = todo.slice(0, 10).to_owned();
                        todo = todo.slice(11, todo.len()).to_owned();
                }

                chars = todo.chars().to_owned_vec();
                if (chars[0] == '(' && chars[2] == ')' &&
                    chars[1].is_uppercase() && chars[3] == ' ') {

                        task.priority = chars[1];
                        todo = todo.slice(4, todo.len()).to_owned();
                }

                chars = todo.chars().to_owned_vec();
                if (chars[10] == ' ' && chars[4] == '-' && chars[7] == '-') {
                        task.create_date = todo.slice(0, 10).to_owned();
                        todo = todo.slice(11, todo.len()).to_owned();
                }

                task.todo = todo;

                return task;
        }
}

pub struct Tasks {
        list: ~[Task]
}

impl Tasks {
        pub fn create() -> Tasks {
                let tasks = Tasks{list: ~[]};

                return tasks;
        }

        pub fn add(&mut self, task: Task) {
                self.list.push(task);
        }

        pub fn add_task_from_string(&mut self, text: ~str) {
                let id = self.len();
                self.list.push(Task::create(text, id));
        }

        pub fn len(&self) -> int {
                return self.list.len() as int;
        }
}

#[test]
fn simple_todo_create_test() {
        let t = Task::create(~"some important task", 1);

        assert_eq!(t.id , 1);
        assert_eq!(t.priority , '^');
        assert_eq!(t.finished , false);
        assert_eq!(t.todo , ~"some important task");
        assert_eq!(t.raw_todo , ~"some important task");
}

#[test]
fn simple_todo_with_priority_test() {
        let t = Task::create(~"(A) some important task with priority", 1);

        assert_eq!(t.id , 1);
        assert_eq!(t.priority , 'A');
        assert_eq!(t.finished , false);
        assert_eq!(t.todo , ~"some important task with priority");
        assert_eq!(t.raw_todo , ~"(A) some important task with priority");

        let ts = Task::create(~"(a) some important task with priority", 1);

        assert_eq!(ts.id , 1);
        assert_eq!(ts.priority , '^');
        assert_eq!(ts.finished , false);
        assert_eq!(ts.todo , ~"(a) some important task with priority");
        assert_eq!(ts.raw_todo , ~"(a) some important task with priority");

}

#[test]
fn simple_todo_with_date_test() {
        let t = Task::create(~"(A) 2014-03-02 some important task with priority", 1);

        assert_eq!(t.id , 1);
        assert_eq!(t.priority , 'A');
        assert_eq!(t.finished , false);
        assert_eq!(t.todo , ~"some important task with priority");
        assert_eq!(t.raw_todo , ~"(A) 2014-03-02 some important task with priority");
        assert_eq!(t.create_date, ~"2014-03-02");

        let ft = Task::create(~"x 2014-03-03 (A) 2014-03-02 some finished important task", 1);

        assert_eq!(ft.id , 1);
        assert_eq!(ft.priority , 'A');
        assert_eq!(ft.finished , true);
        assert_eq!(ft.todo , ~"some finished important task");
        assert_eq!(ft.raw_todo , ~"x 2014-03-03 (A) 2014-03-02 some finished important task");
        assert_eq!(ft.create_date, ~"2014-03-02");
        assert_eq!(ft.finish_date, ~"2014-03-03");

}

#[test]
fn todo_to_str_test() {
        let t = Task::create(~"some important task", 1);

        assert_eq!(t.to_str(), ~"1 false || (^) || 'some important task' \"some important task\"")

        let x = Task::create(~"x some important task", 1);
        assert_eq!(x.to_str(), ~"1 true || (^) || 'some important task' \"x some important task\"")
}
<commit_msg>contexts<commit_after>
pub struct Task {
        id: int,
        todo: ~str,
        priority: char,
        finished: bool,
        raw_todo: ~str,
        create_date: ~str,
        finish_date: ~str,
        contexts: ~[~str],
        projects: ~[~str]
}

impl Task {
        pub fn to_str(&self) -> ~str {
                return format!("{:d} {:b} |{:s}| ({:c}) |{:s}| '{:s}' \"{:s}\"",
                                self.id, self.finished, self.finish_date, self.priority,
                                self.create_date, self.todo, self.raw_todo)
        }

        pub fn create(text: ~str, id: int) -> Task {
                let mut task = Task{id: id, raw_todo: text.clone(), todo: text.clone(),
                                        finished: false, priority: '^',
                                        create_date: ~"", finish_date: ~"",
                                        contexts: ~[], projects: ~[]};

                let mut todo = text.clone();

                if (todo.slice(0, 2) == "x ") {
                        task.finished = true;
                        todo = todo.slice(2, todo.len()).to_owned();
                }

                let mut chars = todo.chars().to_owned_vec();

                if (chars[10] == ' ' && chars[4] == '-' &&
                    chars[7] == '-' && task.finished) {
                        task.finish_date = todo.slice(0, 10).to_owned();
                        todo = todo.slice(11, todo.len()).to_owned();
                }

                chars = todo.chars().to_owned_vec();
                if (chars[0] == '(' && chars[2] == ')' &&
                    chars[1].is_uppercase() && chars[3] == ' ') {

                        task.priority = chars[1];
                        todo = todo.slice(4, todo.len()).to_owned();
                }

                chars = todo.chars().to_owned_vec();
                if (chars[10] == ' ' && chars[4] == '-' && chars[7] == '-') {
                        task.create_date = todo.slice(0, 10).to_owned();
                        todo = todo.slice(11, todo.len()).to_owned();
                }

                for item in todo.split(' ') {
                        if (item[0] == '@' as u8) {
                                task.contexts.push(item.to_owned());
                        }
                }

                task.todo = todo;

                return task;
        }
}

pub struct Tasks {
        list: ~[Task]
}

impl Tasks {
        pub fn create() -> Tasks {
                let tasks = Tasks{list: ~[]};

                return tasks;
        }

        pub fn add(&mut self, task: Task) {
                self.list.push(task);
        }

        pub fn add_task_from_string(&mut self, text: ~str) {
                let id = self.len();
                self.list.push(Task::create(text, id));
        }

        pub fn len(&self) -> int {
                return self.list.len() as int;
        }
}

#[test]
fn simple_todo_create_test() {
        let t = Task::create(~"some important task", 1);

        assert_eq!(t.id , 1);
        assert_eq!(t.priority , '^');
        assert_eq!(t.finished , false);
        assert_eq!(t.todo , ~"some important task");
        assert_eq!(t.raw_todo , ~"some important task");
}

#[test]
fn simple_todo_with_priority_test() {
        let t = Task::create(~"(A) some important task with priority", 1);

        assert_eq!(t.id , 1);
        assert_eq!(t.priority , 'A');
        assert_eq!(t.finished , false);
        assert_eq!(t.todo , ~"some important task with priority");
        assert_eq!(t.raw_todo , ~"(A) some important task with priority");

        let ts = Task::create(~"(a) some important task with priority", 1);

        assert_eq!(ts.id , 1);
        assert_eq!(ts.priority , '^');
        assert_eq!(ts.finished , false);
        assert_eq!(ts.todo , ~"(a) some important task with priority");
        assert_eq!(ts.raw_todo , ~"(a) some important task with priority");

}

#[test]
fn simple_todo_with_context_test() {
        let t = Task::create(~"(A) some @important task with priority", 1);

        assert_eq!(t.id , 1);
        assert_eq!(t.priority , 'A');
        assert_eq!(t.finished , false);
        assert_eq!(t.todo , ~"some @important task with priority");
        assert_eq!(t.raw_todo , ~"(A) some @important task with priority");

        assert_eq!(t.contexts, ~[~"@important"]);
}

#[test]
fn simple_todo_with_date_test() {
        let t = Task::create(~"(A) 2014-03-02 some important task with priority", 1);

        assert_eq!(t.id , 1);
        assert_eq!(t.priority , 'A');
        assert_eq!(t.finished , false);
        assert_eq!(t.todo , ~"some important task with priority");
        assert_eq!(t.raw_todo , ~"(A) 2014-03-02 some important task with priority");
        assert_eq!(t.create_date, ~"2014-03-02");

        let ft = Task::create(~"x 2014-03-03 (A) 2014-03-02 some finished important task", 1);

        assert_eq!(ft.id , 1);
        assert_eq!(ft.priority , 'A');
        assert_eq!(ft.finished , true);
        assert_eq!(ft.todo , ~"some finished important task");
        assert_eq!(ft.raw_todo , ~"x 2014-03-03 (A) 2014-03-02 some finished important task");
        assert_eq!(ft.create_date, ~"2014-03-02");
        assert_eq!(ft.finish_date, ~"2014-03-03");

}

#[test]
fn todo_to_str_test() {
        let t = Task::create(~"some important task", 1);

        assert_eq!(t.to_str(), ~"1 false || (^) || 'some important task' \"some important task\"")

        let x = Task::create(~"x some important task", 1);
        assert_eq!(x.to_str(), ~"1 true || (^) || 'some important task' \"x some important task\"")
}
<|endoftext|>


<commit_before>// Copyright (C) 2020 O.S. Systems Sofware LTDA
//
// SPDX-License-Identifier: Apache-2.0

use serde::Serialize;
use std::{collections::BTreeMap, fs, path::Path};

#[derive(Debug)]
pub enum ProbeResponse {
    NoUpdate,
    Update(UpdatePackage, Option<Signature>),
    ExtraPoll(i64),
}

#[derive(Debug, PartialEq)]
pub struct UpdatePackage {
    pub inner: pkg_schema::UpdatePackage,
    pub raw: Vec<u8>,
}

#[derive(Debug, PartialEq)]
pub struct Signature(Vec<u8>);

#[derive(Serialize)]
#[serde(rename_all = "kebab-case")]
pub struct FirmwareMetadata<'a> {
    pub product_uid: &'a str,
    pub version: &'a str,
    pub hardware: &'a str,
    pub device_identity: MetadataValue<'a>,
    pub device_attributes: MetadataValue<'a>,
}

pub struct MetadataValue<'a>(pub &'a BTreeMap<String, Vec<String>>);

impl<'a> serde::ser::Serialize for MetadataValue<'a> {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: serde::ser::Serializer,
    {
        use serde::ser::SerializeMap;

        let mut map = serializer.serialize_map(Some(self.0.len()))?;
        for (k, v) in self.0 {
            if v.len() == 1 {
                map.serialize_entry(k, &v[0])?;
            } else {
                map.serialize_entry(k, v)?;
            }
        }
        map.end()
    }
}

impl UpdatePackage {
    pub fn parse(content: &[u8]) -> crate::Result<Self> {
        let update_package = serde_json::from_slice(content)?;
        Ok(UpdatePackage { inner: update_package, raw: content.to_vec() })
    }

    pub fn package_uid(&self) -> String {
        openssl::sha::sha256(&self.raw).iter().map(|c| format!("{:02x}", c)).collect()
    }
}

impl Signature {
    pub fn from_base64_str(bytes: &str) -> crate::Result<Self> {
        Ok(Signature(openssl::base64::decode_block(bytes)?.to_vec()))
    }

    pub fn validate(&self, key: &Path, package: &UpdatePackage) -> crate::Result<()> {
        use openssl::{hash::MessageDigest, pkey::PKey, rsa::Rsa, sign::Verifier};
        let key = PKey::from_rsa(Rsa::public_key_from_pem(&fs::read(key)?)?)?;
        if Verifier::new(MessageDigest::sha256(), &key)?.verify_oneshot(&self.0, &package.raw)? {
            return Ok(());
        }
        Err(crate::Error::InvalidSignature)
    }
}
<commit_msg>cloud-sdk: Add version getter for update pacakge<commit_after>// Copyright (C) 2020 O.S. Systems Sofware LTDA
//
// SPDX-License-Identifier: Apache-2.0

use serde::Serialize;
use std::{collections::BTreeMap, fs, path::Path};

#[derive(Debug)]
pub enum ProbeResponse {
    NoUpdate,
    Update(UpdatePackage, Option<Signature>),
    ExtraPoll(i64),
}

#[derive(Debug, PartialEq)]
pub struct UpdatePackage {
    pub inner: pkg_schema::UpdatePackage,
    pub raw: Vec<u8>,
}

#[derive(Debug, PartialEq)]
pub struct Signature(Vec<u8>);

#[derive(Serialize)]
#[serde(rename_all = "kebab-case")]
pub struct FirmwareMetadata<'a> {
    pub product_uid: &'a str,
    pub version: &'a str,
    pub hardware: &'a str,
    pub device_identity: MetadataValue<'a>,
    pub device_attributes: MetadataValue<'a>,
}

pub struct MetadataValue<'a>(pub &'a BTreeMap<String, Vec<String>>);

impl<'a> serde::ser::Serialize for MetadataValue<'a> {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: serde::ser::Serializer,
    {
        use serde::ser::SerializeMap;

        let mut map = serializer.serialize_map(Some(self.0.len()))?;
        for (k, v) in self.0 {
            if v.len() == 1 {
                map.serialize_entry(k, &v[0])?;
            } else {
                map.serialize_entry(k, v)?;
            }
        }
        map.end()
    }
}

impl UpdatePackage {
    pub fn parse(content: &[u8]) -> crate::Result<Self> {
        let update_package = serde_json::from_slice(content)?;
        Ok(UpdatePackage { inner: update_package, raw: content.to_vec() })
    }

    pub fn package_uid(&self) -> String {
        openssl::sha::sha256(&self.raw).iter().map(|c| format!("{:02x}", c)).collect()
    }

    pub fn version(&self) -> &str {
        &self.inner.version
    }
}

impl Signature {
    pub fn from_base64_str(bytes: &str) -> crate::Result<Self> {
        Ok(Signature(openssl::base64::decode_block(bytes)?.to_vec()))
    }

    pub fn validate(&self, key: &Path, package: &UpdatePackage) -> crate::Result<()> {
        use openssl::{hash::MessageDigest, pkey::PKey, rsa::Rsa, sign::Verifier};
        let key = PKey::from_rsa(Rsa::public_key_from_pem(&fs::read(key)?)?)?;
        if Verifier::new(MessageDigest::sha256(), &key)?.verify_oneshot(&self.0, &package.raw)? {
            return Ok(());
        }
        Err(crate::Error::InvalidSignature)
    }
}
<|endoftext|>


<commit_before>use crate::cdsl::settings::{PredicateNode, SettingGroup, SettingGroupBuilder};

pub fn define(shared: &SettingGroup) -> SettingGroup {
    let mut settings = SettingGroupBuilder::new("x86");

    // CPUID.01H:ECX
    let has_sse3 = settings.add_bool("has_sse3", "SSE3: CPUID.01H:ECX.SSE3[bit 0]", false);
    let has_ssse3 = settings.add_bool("has_ssse3", "SSSE3: CPUID.01H:ECX.SSSE3[bit 9]", false);
    let has_sse41 = settings.add_bool("has_sse41", "SSE4.1: CPUID.01H:ECX.SSE4_1[bit 19]", false);
    let has_sse42 = settings.add_bool("has_sse42", "SSE4.2: CPUID.01H:ECX.SSE4_2[bit 20]", false);
    let has_popcnt = settings.add_bool("has_popcnt", "POPCNT: CPUID.01H:ECX.POPCNT[bit 23]", false);
    settings.add_bool("has_avx", "AVX: CPUID.01H:ECX.AVX[bit 28]", false);

    // CPUID.(EAX=07H, ECX=0H):EBX
    let has_bmi1 = settings.add_bool(
        "has_bmi1",
        "BMI1: CPUID.(EAX=07H, ECX=0H):EBX.BMI1[bit 3]",
        false,
    );
    let has_bmi2 = settings.add_bool(
        "has_bmi2",
        "BMI2: CPUID.(EAX=07H, ECX=0H):EBX.BMI2[bit 8]",
        false,
    );

    // CPUID.EAX=80000001H:ECX
    let has_lzcnt = settings.add_bool(
        "has_lzcnt",
        "LZCNT: CPUID.EAX=80000001H:ECX.LZCNT[bit 5]",
        false,
    );

    settings.add_predicate("use_sse41", predicate!(has_sse41));
    settings.add_predicate("use_sse42", predicate!(has_sse41 && has_sse42));
    settings.add_predicate("use_popcnt", predicate!(has_popcnt && has_sse42));
    settings.add_predicate("use_bmi1", predicate!(has_bmi1));
    settings.add_predicate("use_lznct", predicate!(has_lzcnt));

    // Some shared boolean values are used in x86 instruction predicates, so we need to group them
    // in the same TargetIsa, for compabitibity with code generated by meta-python.
    // TODO Once all the meta generation code has been migrated from Python to Rust, we can put it
    // back in the shared SettingGroup, and use it in x86 instruction predicates.

    let is_pic = shared.get_bool("is_pic");
    let allones_funcaddrs = shared.get_bool("allones_funcaddrs");
    settings.add_predicate("is_pic", predicate!(is_pic));
    settings.add_predicate("not_is_pic", predicate!(!is_pic));
    settings.add_predicate(
        "all_ones_funcaddrs_and_not_is_pic",
        predicate!(allones_funcaddrs && !is_pic),
    );
    settings.add_predicate(
        "not_all_ones_funcaddrs_and_not_is_pic",
        predicate!(!allones_funcaddrs && !is_pic),
    );

    // Presets corresponding to x86 CPUs.

    settings.add_preset("baseline", preset!());
    let nehalem = settings.add_preset(
        "nehalem",
        preset!(has_sse3 && has_ssse3 && has_sse41 && has_sse42 && has_popcnt),
    );
    let haswell = settings.add_preset(
        "haswell",
        preset!(nehalem && has_bmi1 && has_bmi2 && has_lzcnt),
    );
    let broadwell = settings.add_preset("broadwell", preset!(haswell));
    let skylake = settings.add_preset("skylake", preset!(broadwell));
    let cannonlake = settings.add_preset("cannonlake", preset!(skylake));
    settings.add_preset("icelake", preset!(cannonlake));
    settings.add_preset(
        "znver1",
        preset!(
            has_sse3
                && has_ssse3
                && has_sse41
                && has_sse42
                && has_popcnt
                && has_bmi1
                && has_bmi2
                && has_lzcnt
        ),
    );

    settings.build()
}
<commit_msg>[meta] Fix typo in x86 setting name use_lzcnt;<commit_after>use crate::cdsl::settings::{PredicateNode, SettingGroup, SettingGroupBuilder};

pub fn define(shared: &SettingGroup) -> SettingGroup {
    let mut settings = SettingGroupBuilder::new("x86");

    // CPUID.01H:ECX
    let has_sse3 = settings.add_bool("has_sse3", "SSE3: CPUID.01H:ECX.SSE3[bit 0]", false);
    let has_ssse3 = settings.add_bool("has_ssse3", "SSSE3: CPUID.01H:ECX.SSSE3[bit 9]", false);
    let has_sse41 = settings.add_bool("has_sse41", "SSE4.1: CPUID.01H:ECX.SSE4_1[bit 19]", false);
    let has_sse42 = settings.add_bool("has_sse42", "SSE4.2: CPUID.01H:ECX.SSE4_2[bit 20]", false);
    let has_popcnt = settings.add_bool("has_popcnt", "POPCNT: CPUID.01H:ECX.POPCNT[bit 23]", false);
    settings.add_bool("has_avx", "AVX: CPUID.01H:ECX.AVX[bit 28]", false);

    // CPUID.(EAX=07H, ECX=0H):EBX
    let has_bmi1 = settings.add_bool(
        "has_bmi1",
        "BMI1: CPUID.(EAX=07H, ECX=0H):EBX.BMI1[bit 3]",
        false,
    );
    let has_bmi2 = settings.add_bool(
        "has_bmi2",
        "BMI2: CPUID.(EAX=07H, ECX=0H):EBX.BMI2[bit 8]",
        false,
    );

    // CPUID.EAX=80000001H:ECX
    let has_lzcnt = settings.add_bool(
        "has_lzcnt",
        "LZCNT: CPUID.EAX=80000001H:ECX.LZCNT[bit 5]",
        false,
    );

    settings.add_predicate("use_sse41", predicate!(has_sse41));
    settings.add_predicate("use_sse42", predicate!(has_sse41 && has_sse42));
    settings.add_predicate("use_popcnt", predicate!(has_popcnt && has_sse42));
    settings.add_predicate("use_bmi1", predicate!(has_bmi1));
    settings.add_predicate("use_lzcnt", predicate!(has_lzcnt));

    // Some shared boolean values are used in x86 instruction predicates, so we need to group them
    // in the same TargetIsa, for compabitibity with code generated by meta-python.
    // TODO Once all the meta generation code has been migrated from Python to Rust, we can put it
    // back in the shared SettingGroup, and use it in x86 instruction predicates.

    let is_pic = shared.get_bool("is_pic");
    let allones_funcaddrs = shared.get_bool("allones_funcaddrs");
    settings.add_predicate("is_pic", predicate!(is_pic));
    settings.add_predicate("not_is_pic", predicate!(!is_pic));
    settings.add_predicate(
        "all_ones_funcaddrs_and_not_is_pic",
        predicate!(allones_funcaddrs && !is_pic),
    );
    settings.add_predicate(
        "not_all_ones_funcaddrs_and_not_is_pic",
        predicate!(!allones_funcaddrs && !is_pic),
    );

    // Presets corresponding to x86 CPUs.

    settings.add_preset("baseline", preset!());
    let nehalem = settings.add_preset(
        "nehalem",
        preset!(has_sse3 && has_ssse3 && has_sse41 && has_sse42 && has_popcnt),
    );
    let haswell = settings.add_preset(
        "haswell",
        preset!(nehalem && has_bmi1 && has_bmi2 && has_lzcnt),
    );
    let broadwell = settings.add_preset("broadwell", preset!(haswell));
    let skylake = settings.add_preset("skylake", preset!(broadwell));
    let cannonlake = settings.add_preset("cannonlake", preset!(skylake));
    settings.add_preset("icelake", preset!(cannonlake));
    settings.add_preset(
        "znver1",
        preset!(
            has_sse3
                && has_ssse3
                && has_sse41
                && has_sse42
                && has_popcnt
                && has_bmi1
                && has_bmi2
                && has_lzcnt
        ),
    );

    settings.build()
}
<|endoftext|>