<commit_before>// Copyright 2015-2016, The Gtk-rs Project Developers.
// See the COPYRIGHT file at the top-level directory of this distribution.
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>

use ffi;
use translate::*;
use std;
use std::ffi::{OsStr, OsString};
use std::path::{Path, PathBuf};
use error::BoolError;
use Error;
use std::ptr;

/// Same as [`get_prgname()`].
///
/// [`get_prgname()`]: fn.get_prgname.html
pub fn get_program_name() -> Option<String> {
    get_prgname()
}

pub fn get_prgname() -> Option<String> {
    unsafe {
        from_glib_none(ffi::g_get_prgname())
    }
}

/// Same as [`set_prgname()`].
///
/// [`set_prgname()`]: fn.set_prgname.html
pub fn set_program_name(name: Option<&str>) {
    set_prgname(name)
}

pub fn set_prgname(name: Option<&str>) {
    unsafe {
        ffi::g_set_prgname(name.to_glib_none().0)
    }
}

pub fn getenv<K: AsRef<OsStr>>(variable_name: K) -> Option<OsString> {
    #[cfg(windows)]
    use ffi::g_getenv_utf8 as g_getenv;
    #[cfg(not(windows))]
    use ffi::g_getenv;

    unsafe {
        from_glib_none(g_getenv(variable_name.as_ref().to_glib_none().0))
    }
}

pub fn setenv<K: AsRef<OsStr>, V: AsRef<OsStr>>(variable_name: K, value: V, overwrite: bool) -> Result<(), BoolError> {
    #[cfg(windows)]
    use ffi::g_setenv_utf8 as g_setenv;
    #[cfg(not(windows))]
    use ffi::g_setenv;

    unsafe {
        BoolError::from_glib(g_setenv(variable_name.as_ref().to_glib_none().0,
                                value.as_ref().to_glib_none().0,
                                overwrite.to_glib()),
                             "Failed to set environment variable")
    }
}

pub fn unsetenv<K: AsRef<OsStr>>(variable_name: K) {
    #[cfg(windows)]
    use ffi::g_unsetenv_utf8 as g_unsetenv;
    #[cfg(not(windows))]
    use ffi::g_unsetenv;

    unsafe {
        g_unsetenv(variable_name.as_ref().to_glib_none().0)
    }
}

pub fn get_user_name() -> Option<String> {
    #[cfg(all(windows,target_arch="x86"))]
    use ffi::g_get_user_name_utf8 as g_get_user_name;
    #[cfg(not(all(windows,target_arch="x86")))]
    use ffi::g_get_user_name;

    unsafe {
        from_glib_none(g_get_user_name())
    }
}

pub fn get_real_name() -> Option<std::path::PathBuf> {
    #[cfg(all(windows,target_arch="x86"))]
    use ffi::g_get_real_name_utf8 as g_get_real_name;
    #[cfg(not(all(windows,target_arch="x86")))]
    use ffi::g_get_real_name;

    unsafe {
        from_glib_none(g_get_real_name())
    }
}

pub fn get_current_dir() -> Option<PathBuf> {
    #[cfg(windows)]
    use ffi::g_get_current_dir_utf8 as g_get_current_dir;
    #[cfg(not(windows))]
    use ffi::g_get_current_dir;

    unsafe {
        from_glib_full(g_get_current_dir())
    }
}

pub fn filename_to_uri<'a, P: AsRef<Path>, Q: Into<Option<&'a str>>>(filename: P, hostname: Q) -> Result<String, Error> {
    #[cfg(windows)]
    use ffi::g_filename_to_uri_utf8 as g_filename_to_uri;
    #[cfg(not(windows))]
    use ffi::g_filename_to_uri;

    let hostname = hostname.into();
    let hostname = hostname.to_glib_none();
    unsafe {
        let mut error = std::ptr::null_mut();
        let ret = g_filename_to_uri(filename.as_ref().to_glib_none().0, hostname.0, &mut error);
        if error.is_null() { Ok(from_glib_full(ret)) } else { Err(from_glib_full(error)) }
    }
}

pub fn filename_from_uri(uri: &str) -> Result<(std::path::PathBuf, Option<String>), Error> {
    #[cfg(windows)]
    use ffi::g_filename_from_uri_utf8 as g_filename_from_uri;
    #[cfg(not(windows))]
    use ffi::g_filename_from_uri;

    unsafe {
        let mut hostname = ptr::null_mut();
        let mut error = ptr::null_mut();
        let ret = g_filename_from_uri(uri.to_glib_none().0, &mut hostname, &mut error);
        if error.is_null() { Ok((from_glib_full(ret), from_glib_full(hostname))) } else { Err(from_glib_full(error)) }
    }
}

pub fn find_program_in_path<P: AsRef<Path>>(program: P) -> Option<PathBuf> {
    #[cfg(all(windows,target_arch="x86"))]
    use ffi::g_find_program_in_path_utf8 as g_find_program_in_path;
    #[cfg(not(all(windows,target_arch="x86")))]
    use ffi::g_find_program_in_path;

    unsafe {
        from_glib_full(g_find_program_in_path(program.as_ref().to_glib_none().0))
    }
}

pub fn get_home_dir() -> Option<std::path::PathBuf> {
    #[cfg(all(windows,target_arch="x86"))]
    use ffi::g_get_home_dir_utf8 as g_get_home_dir;
    #[cfg(not(all(windows,target_arch="x86")))]
    use ffi::g_get_home_dir;

    unsafe {
        from_glib_none(g_get_home_dir())
    }
}

pub fn get_tmp_dir() -> Option<std::path::PathBuf> {
    #[cfg(all(windows,target_arch="x86"))]
    use ffi::g_get_tmp_dir_utf8 as g_get_tmp_dir;
    #[cfg(not(all(windows,target_arch="x86")))]
    use ffi::g_get_tmp_dir;

    unsafe {
        from_glib_none(g_get_tmp_dir())
    }
}

pub fn mkstemp<P: AsRef<std::path::Path>>(tmpl: P) -> i32 {
    #[cfg(windows)]
    use ffi::g_mkstemp_utf8 as g_mkstemp;
    #[cfg(not(windows))]
    use ffi::g_mkstemp;

    unsafe {
        g_mkstemp(tmpl.as_ref().to_glib_none().0)
    }
}

#[cfg(test)]
mod tests {
    use std::env;
    use std::sync::Mutex;

    //Mutex to prevent run environment tests parallel
    lazy_static! { static ref LOCK: Mutex<()> = Mutex::new(()); }

    const VAR_NAME: &str = "function_environment_test";

    fn check_getenv(val: &str) {
        let _data = LOCK.lock().unwrap();

        env::set_var(VAR_NAME, val);
        assert_eq!(env::var_os(VAR_NAME), Some(val.into()));
        assert_eq!(::getenv(VAR_NAME), Some(val.into()));

        let environ = ::get_environ();
        assert_eq!(::environ_getenv(&environ, VAR_NAME), Some(val.into()));
    }

    fn check_setenv(val: &str) {
        let _data = LOCK.lock().unwrap();

        ::setenv(VAR_NAME, val, true).unwrap();
        assert_eq!(env::var_os(VAR_NAME), Some(val.into()));
    }

    #[test]
    fn getenv() {
        check_getenv("Test");
        check_getenv("Тест"); // "Test" in Russian
    }

    #[test]
    fn setenv() {
        check_setenv("Test");
        check_setenv("Тест"); // "Test" in Russian
    }
}
<commit_msg>Add manual environ_getenv<commit_after>// Copyright 2015-2016, The Gtk-rs Project Developers.
// See the COPYRIGHT file at the top-level directory of this distribution.
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>

use ffi;
use translate::*;
use std;
use std::ffi::{OsStr, OsString};
use std::path::{Path, PathBuf};
use error::BoolError;
use Error;
use std::ptr;

/// Same as [`get_prgname()`].
///
/// [`get_prgname()`]: fn.get_prgname.html
pub fn get_program_name() -> Option<String> {
    get_prgname()
}

pub fn get_prgname() -> Option<String> {
    unsafe {
        from_glib_none(ffi::g_get_prgname())
    }
}

/// Same as [`set_prgname()`].
///
/// [`set_prgname()`]: fn.set_prgname.html
pub fn set_program_name(name: Option<&str>) {
    set_prgname(name)
}

pub fn set_prgname(name: Option<&str>) {
    unsafe {
        ffi::g_set_prgname(name.to_glib_none().0)
    }
}

pub fn getenv<K: AsRef<OsStr>>(variable_name: K) -> Option<OsString> {
    #[cfg(windows)]
    use ffi::g_getenv_utf8 as g_getenv;
    #[cfg(not(windows))]
    use ffi::g_getenv;

    unsafe {
        from_glib_none(g_getenv(variable_name.as_ref().to_glib_none().0))
    }
}

pub fn setenv<K: AsRef<OsStr>, V: AsRef<OsStr>>(variable_name: K, value: V, overwrite: bool) -> Result<(), BoolError> {
    #[cfg(windows)]
    use ffi::g_setenv_utf8 as g_setenv;
    #[cfg(not(windows))]
    use ffi::g_setenv;

    unsafe {
        BoolError::from_glib(g_setenv(variable_name.as_ref().to_glib_none().0,
                                value.as_ref().to_glib_none().0,
                                overwrite.to_glib()),
                             "Failed to set environment variable")
    }
}

pub fn unsetenv<K: AsRef<OsStr>>(variable_name: K) {
    #[cfg(windows)]
    use ffi::g_unsetenv_utf8 as g_unsetenv;
    #[cfg(not(windows))]
    use ffi::g_unsetenv;

    unsafe {
        g_unsetenv(variable_name.as_ref().to_glib_none().0)
    }
}

pub fn environ_getenv<K: AsRef<OsStr>>(envp: &[OsString], variable: K) -> Option<OsString> {
    unsafe {
        from_glib_none(ffi::g_environ_getenv(envp.to_glib_none().0, variable.as_ref().to_glib_none().0))
    }
}

pub fn get_user_name() -> Option<String> {
    #[cfg(all(windows,target_arch="x86"))]
    use ffi::g_get_user_name_utf8 as g_get_user_name;
    #[cfg(not(all(windows,target_arch="x86")))]
    use ffi::g_get_user_name;

    unsafe {
        from_glib_none(g_get_user_name())
    }
}

pub fn get_real_name() -> Option<std::path::PathBuf> {
    #[cfg(all(windows,target_arch="x86"))]
    use ffi::g_get_real_name_utf8 as g_get_real_name;
    #[cfg(not(all(windows,target_arch="x86")))]
    use ffi::g_get_real_name;

    unsafe {
        from_glib_none(g_get_real_name())
    }
}

pub fn get_current_dir() -> Option<PathBuf> {
    #[cfg(windows)]
    use ffi::g_get_current_dir_utf8 as g_get_current_dir;
    #[cfg(not(windows))]
    use ffi::g_get_current_dir;

    unsafe {
        from_glib_full(g_get_current_dir())
    }
}

pub fn filename_to_uri<'a, P: AsRef<Path>, Q: Into<Option<&'a str>>>(filename: P, hostname: Q) -> Result<String, Error> {
    #[cfg(windows)]
    use ffi::g_filename_to_uri_utf8 as g_filename_to_uri;
    #[cfg(not(windows))]
    use ffi::g_filename_to_uri;

    let hostname = hostname.into();
    let hostname = hostname.to_glib_none();
    unsafe {
        let mut error = std::ptr::null_mut();
        let ret = g_filename_to_uri(filename.as_ref().to_glib_none().0, hostname.0, &mut error);
        if error.is_null() { Ok(from_glib_full(ret)) } else { Err(from_glib_full(error)) }
    }
}

pub fn filename_from_uri(uri: &str) -> Result<(std::path::PathBuf, Option<String>), Error> {
    #[cfg(windows)]
    use ffi::g_filename_from_uri_utf8 as g_filename_from_uri;
    #[cfg(not(windows))]
    use ffi::g_filename_from_uri;

    unsafe {
        let mut hostname = ptr::null_mut();
        let mut error = ptr::null_mut();
        let ret = g_filename_from_uri(uri.to_glib_none().0, &mut hostname, &mut error);
        if error.is_null() { Ok((from_glib_full(ret), from_glib_full(hostname))) } else { Err(from_glib_full(error)) }
    }
}

pub fn find_program_in_path<P: AsRef<Path>>(program: P) -> Option<PathBuf> {
    #[cfg(all(windows,target_arch="x86"))]
    use ffi::g_find_program_in_path_utf8 as g_find_program_in_path;
    #[cfg(not(all(windows,target_arch="x86")))]
    use ffi::g_find_program_in_path;

    unsafe {
        from_glib_full(g_find_program_in_path(program.as_ref().to_glib_none().0))
    }
}

pub fn get_home_dir() -> Option<std::path::PathBuf> {
    #[cfg(all(windows,target_arch="x86"))]
    use ffi::g_get_home_dir_utf8 as g_get_home_dir;
    #[cfg(not(all(windows,target_arch="x86")))]
    use ffi::g_get_home_dir;

    unsafe {
        from_glib_none(g_get_home_dir())
    }
}

pub fn get_tmp_dir() -> Option<std::path::PathBuf> {
    #[cfg(all(windows,target_arch="x86"))]
    use ffi::g_get_tmp_dir_utf8 as g_get_tmp_dir;
    #[cfg(not(all(windows,target_arch="x86")))]
    use ffi::g_get_tmp_dir;

    unsafe {
        from_glib_none(g_get_tmp_dir())
    }
}

pub fn mkstemp<P: AsRef<std::path::Path>>(tmpl: P) -> i32 {
    #[cfg(windows)]
    use ffi::g_mkstemp_utf8 as g_mkstemp;
    #[cfg(not(windows))]
    use ffi::g_mkstemp;

    unsafe {
        g_mkstemp(tmpl.as_ref().to_glib_none().0)
    }
}

#[cfg(test)]
mod tests {
    use std::env;
    use std::sync::Mutex;

    //Mutex to prevent run environment tests parallel
    lazy_static! { static ref LOCK: Mutex<()> = Mutex::new(()); }

    const VAR_NAME: &str = "function_environment_test";

    fn check_getenv(val: &str) {
        let _data = LOCK.lock().unwrap();

        env::set_var(VAR_NAME, val);
        assert_eq!(env::var_os(VAR_NAME), Some(val.into()));
        assert_eq!(::getenv(VAR_NAME), Some(val.into()));

        let environ = ::get_environ();
        assert_eq!(::environ_getenv(&environ, VAR_NAME), Some(val.into()));
    }

    fn check_setenv(val: &str) {
        let _data = LOCK.lock().unwrap();

        ::setenv(VAR_NAME, val, true).unwrap();
        assert_eq!(env::var_os(VAR_NAME), Some(val.into()));
    }

    #[test]
    fn getenv() {
        check_getenv("Test");
        check_getenv("Тест"); // "Test" in Russian
    }

    #[test]
    fn setenv() {
        check_setenv("Test");
        check_setenv("Тест"); // "Test" in Russian
    }
}
<|endoftext|>


<commit_before>use std::io;

use crate::{
    Command, Header, IdCode, ReferenceIndex, Scope, ScopeItem, ScopeType, SimulationCommand,
    TimescaleUnit, Value, Var, VarType,
};

/// Struct wrapping an `io::Write` with methods for writing VCD commands and data.
pub struct Writer<'w> {
    writer: &'w mut dyn io::Write,
    next_id_code: IdCode,
    scope_depth: usize,
}

impl<'s> Writer<'s> {
    /// Creates a Writer, wrapping an io::Write.
    ///
    /// ```
    /// let mut buf = Vec::new();
    /// let mut vcd = vcd::Writer::new(&mut buf);
    /// ```
    pub fn new(writer: &mut dyn io::Write) -> Writer<'_> {
        Writer {
            writer,
            next_id_code: IdCode::FIRST,
            scope_depth: 0,
        }
    }

    /// Writes a complete header with the fields from a `Header` struct from the parser.
    pub fn header(&mut self, h: &Header) -> io::Result<()> {
        if let Some(ref s) = h.date {
            self.date(s)?;
        }
        if let Some(ref s) = h.version {
            self.version(s)?;
        }
        if let Some(ref s) = h.comment {
            self.comment(s)?;
        }
        if let Some((v, u)) = h.timescale {
            self.timescale(v, u)?;
        }
        for i in &h.items {
            match *i {
                ScopeItem::Var(ref v) => self.var(v)?,
                ScopeItem::Scope(ref s) => self.scope(s)?,
            }
        }
        self.enddefinitions()
    }

    /// Writes a `$comment` command.
    pub fn comment(&mut self, v: &str) -> io::Result<()> {
        writeln!(self.writer, "$comment\n    {}\n$end", v)
    }

    /// Writes a `$date` command.
    pub fn date(&mut self, v: &str) -> io::Result<()> {
        writeln!(self.writer, "$date\n    {}\n$end", v)
    }

    /// Writes a `$version` command.
    pub fn version(&mut self, v: &str) -> io::Result<()> {
        writeln!(self.writer, "$version\n    {}\n$end", v)
    }

    /// Writes a `$timescale` command.
    pub fn timescale(&mut self, ts: u32, unit: TimescaleUnit) -> io::Result<()> {
        writeln!(self.writer, "$timescale {} {} $end", ts, unit)
    }

    /// Writes a `$scope` command.
    pub fn scope_def(&mut self, t: ScopeType, i: &str) -> io::Result<()> {
        self.scope_depth += 1;
        writeln!(self.writer, "$scope {} {} $end", t, i)
    }

    /// Writes a `$scope` command for a module.
    ///
    /// Convenience wrapper around `scope_def`.
    pub fn add_module(&mut self, identifier: &str) -> io::Result<()> {
        self.scope_def(ScopeType::Module, identifier)
    }

    /// Writes an `$upscope` command.
    pub fn upscope(&mut self) -> io::Result<()> {
        debug_assert!(
            self.scope_depth > 0,
            "Generating invalid VCD: upscope without a matching scope"
        );
        self.scope_depth -= 1;
        writeln!(self.writer, "$upscope $end")
    }

    /// Writes a `$scope` command, a series of `$var` commands, and an `$upscope` commands from
    /// a `Scope` structure from the parser.
    pub fn scope(&mut self, s: &Scope) -> io::Result<()> {
        self.scope_def(s.scope_type, &s.identifier[..])?;
        for i in &s.children {
            match *i {
                ScopeItem::Var(ref v) => self.var(v)?,
                ScopeItem::Scope(ref s) => self.scope(s)?,
            }
        }
        self.upscope()
    }

    /// Writes a `$var` command with a specified id.
    pub fn var_def(
        &mut self,
        var_type: VarType,
        width: u32,
        id: IdCode,
        reference: &str,
        index: Option<ReferenceIndex>,
    ) -> io::Result<()> {
        debug_assert!(
            self.scope_depth > 0,
            "Generating invalid VCD: variable must be in a scope"
        );
        if id >= self.next_id_code {
            self.next_id_code = id.next();
        }
        match index {
            Some(idx) => writeln!(
                self.writer,
                "$var {} {} {} {} {} $end",
                var_type, width, id, reference, idx
            ),
            None => writeln!(
                self.writer,
                "$var {} {} {} {} $end",
                var_type, width, id, reference
            ),
        }
    }

    /// Writes a `$var` command with the next available ID, returning the assigned ID.
    ///
    /// Convenience wrapper around `var_def`.
    pub fn add_var(
        &mut self,
        var_type: VarType,
        width: u32,
        reference: &str,
        index: Option<ReferenceIndex>,
    ) -> io::Result<IdCode> {
        let id = self.next_id_code;
        self.var_def(var_type, width, id, reference, index)?;
        Ok(id)
    }

    /// Adds a `$var` for a wire with the next available ID, returning the assigned ID.
    ///
    /// Convenience wrapper around `add_var`.
    pub fn add_wire(&mut self, width: u32, reference: &str) -> io::Result<IdCode> {
        self.add_var(VarType::Wire, width, reference, None)
    }

    /// Writes a `$var` command from a `Var` structure from the parser.
    pub fn var(&mut self, v: &Var) -> io::Result<()> {
        self.var_def(v.var_type, v.size, v.code, &v.reference[..], v.index)
    }

    /// Writes a `$enddefinitions` command to end the header.
    pub fn enddefinitions(&mut self) -> io::Result<()> {
        debug_assert!(
            self.scope_depth == 0,
            "Generating invalid VCD: {} scopes must be closed with $upscope before $enddefinitions"
        );
        writeln!(self.writer, "$enddefinitions $end")
    }

    /// Writes a `#xxx` timestamp.
    pub fn timestamp(&mut self, ts: u64) -> io::Result<()> {
        writeln!(self.writer, "#{}", ts)
    }

    /// Writes a change to a scalar variable.
    pub fn change_scalar<V: Into<Value>>(&mut self, id: IdCode, v: V) -> io::Result<()> {
        writeln!(self.writer, "{}{}", v.into(), id)
    }

    /// Writes a change to a vector variable.
    pub fn change_vector(&mut self, id: IdCode, v: &[Value]) -> io::Result<()> {
        write!(self.writer, "b")?;
        for i in v {
            write!(self.writer, "{}", i)?
        }
        writeln!(self.writer, " {}", id)
    }

    /// Writes a change to a real variable.
    pub fn change_real(&mut self, id: IdCode, v: f64) -> io::Result<()> {
        writeln!(self.writer, "r{} {}", v, id)
    }

    /// Writes a change to a string variable.
    pub fn change_string(&mut self, id: IdCode, v: &str) -> io::Result<()> {
        writeln!(self.writer, "s{} {}", v, id)
    }

    /// Writes the beginning of a simulation command.
    pub fn begin(&mut self, c: SimulationCommand) -> io::Result<()> {
        writeln!(self.writer, "${}", c)
    }

    /// Writes an `$end` to end a simulation command.
    pub fn end(&mut self) -> io::Result<()> {
        writeln!(self.writer, "$end")
    }

    /// Writes a command from a `Command` enum as parsed by the parser.
    pub fn command(&mut self, c: &Command) -> io::Result<()> {
        use Command::*;
        match *c {
            Comment(ref c) => self.comment(&c[..]),
            Date(ref c) => self.date(&c[..]),
            Version(ref c) => self.version(&c[..]),
            Timescale(v, u) => self.timescale(v, u),
            ScopeDef(t, ref i) => self.scope_def(t, &i[..]),
            Upscope => self.upscope(),
            VarDef(t, s, i, ref r, idx) => self.var_def(t, s, i, &r[..], idx),
            Enddefinitions => self.enddefinitions(),
            Timestamp(t) => self.timestamp(t),
            ChangeScalar(i, v) => self.change_scalar(i, v),
            ChangeVector(i, ref v) => self.change_vector(i, &v[..]),
            ChangeReal(i, v) => self.change_real(i, v),
            ChangeString(i, ref v) => self.change_string(i, v),
            Begin(c) => self.begin(c),
            End(_) => self.end(),
        }
    }
}
<commit_msg>Writer: Take io::Write directly, not a mutable reference<commit_after>use std::io;

use crate::{
    Command, Header, IdCode, ReferenceIndex, Scope, ScopeItem, ScopeType, SimulationCommand,
    TimescaleUnit, Value, Var, VarType,
};

/// Struct wrapping an `io::Write` with methods for writing VCD commands and data.
pub struct Writer<W: io::Write> {
    writer: W,
    next_id_code: IdCode,
    scope_depth: usize,
}

impl<W: io::Write> Writer<W> {
    /// Creates a Writer, wrapping an io::Write.
    ///
    /// ```
    /// let mut buf = Vec::new();
    /// let mut vcd = vcd::Writer::new(&mut buf);
    /// ```
    pub fn new(writer: W) -> Writer<W> {
        Writer {
            writer,
            next_id_code: IdCode::FIRST,
            scope_depth: 0,
        }
    }

    /// Writes a complete header with the fields from a `Header` struct from the parser.
    pub fn header(&mut self, h: &Header) -> io::Result<()> {
        if let Some(ref s) = h.date {
            self.date(s)?;
        }
        if let Some(ref s) = h.version {
            self.version(s)?;
        }
        if let Some(ref s) = h.comment {
            self.comment(s)?;
        }
        if let Some((v, u)) = h.timescale {
            self.timescale(v, u)?;
        }
        for i in &h.items {
            match *i {
                ScopeItem::Var(ref v) => self.var(v)?,
                ScopeItem::Scope(ref s) => self.scope(s)?,
            }
        }
        self.enddefinitions()
    }

    /// Writes a `$comment` command.
    pub fn comment(&mut self, v: &str) -> io::Result<()> {
        writeln!(self.writer, "$comment\n    {}\n$end", v)
    }

    /// Writes a `$date` command.
    pub fn date(&mut self, v: &str) -> io::Result<()> {
        writeln!(self.writer, "$date\n    {}\n$end", v)
    }

    /// Writes a `$version` command.
    pub fn version(&mut self, v: &str) -> io::Result<()> {
        writeln!(self.writer, "$version\n    {}\n$end", v)
    }

    /// Writes a `$timescale` command.
    pub fn timescale(&mut self, ts: u32, unit: TimescaleUnit) -> io::Result<()> {
        writeln!(self.writer, "$timescale {} {} $end", ts, unit)
    }

    /// Writes a `$scope` command.
    pub fn scope_def(&mut self, t: ScopeType, i: &str) -> io::Result<()> {
        self.scope_depth += 1;
        writeln!(self.writer, "$scope {} {} $end", t, i)
    }

    /// Writes a `$scope` command for a module.
    ///
    /// Convenience wrapper around `scope_def`.
    pub fn add_module(&mut self, identifier: &str) -> io::Result<()> {
        self.scope_def(ScopeType::Module, identifier)
    }

    /// Writes an `$upscope` command.
    pub fn upscope(&mut self) -> io::Result<()> {
        debug_assert!(
            self.scope_depth > 0,
            "Generating invalid VCD: upscope without a matching scope"
        );
        self.scope_depth -= 1;
        writeln!(self.writer, "$upscope $end")
    }

    /// Writes a `$scope` command, a series of `$var` commands, and an `$upscope` commands from
    /// a `Scope` structure from the parser.
    pub fn scope(&mut self, s: &Scope) -> io::Result<()> {
        self.scope_def(s.scope_type, &s.identifier[..])?;
        for i in &s.children {
            match *i {
                ScopeItem::Var(ref v) => self.var(v)?,
                ScopeItem::Scope(ref s) => self.scope(s)?,
            }
        }
        self.upscope()
    }

    /// Writes a `$var` command with a specified id.
    pub fn var_def(
        &mut self,
        var_type: VarType,
        width: u32,
        id: IdCode,
        reference: &str,
        index: Option<ReferenceIndex>,
    ) -> io::Result<()> {
        debug_assert!(
            self.scope_depth > 0,
            "Generating invalid VCD: variable must be in a scope"
        );
        if id >= self.next_id_code {
            self.next_id_code = id.next();
        }
        match index {
            Some(idx) => writeln!(
                self.writer,
                "$var {} {} {} {} {} $end",
                var_type, width, id, reference, idx
            ),
            None => writeln!(
                self.writer,
                "$var {} {} {} {} $end",
                var_type, width, id, reference
            ),
        }
    }

    /// Writes a `$var` command with the next available ID, returning the assigned ID.
    ///
    /// Convenience wrapper around `var_def`.
    pub fn add_var(
        &mut self,
        var_type: VarType,
        width: u32,
        reference: &str,
        index: Option<ReferenceIndex>,
    ) -> io::Result<IdCode> {
        let id = self.next_id_code;
        self.var_def(var_type, width, id, reference, index)?;
        Ok(id)
    }

    /// Adds a `$var` for a wire with the next available ID, returning the assigned ID.
    ///
    /// Convenience wrapper around `add_var`.
    pub fn add_wire(&mut self, width: u32, reference: &str) -> io::Result<IdCode> {
        self.add_var(VarType::Wire, width, reference, None)
    }

    /// Writes a `$var` command from a `Var` structure from the parser.
    pub fn var(&mut self, v: &Var) -> io::Result<()> {
        self.var_def(v.var_type, v.size, v.code, &v.reference[..], v.index)
    }

    /// Writes a `$enddefinitions` command to end the header.
    pub fn enddefinitions(&mut self) -> io::Result<()> {
        debug_assert!(
            self.scope_depth == 0,
            "Generating invalid VCD: {} scopes must be closed with $upscope before $enddefinitions"
        );
        writeln!(self.writer, "$enddefinitions $end")
    }

    /// Writes a `#xxx` timestamp.
    pub fn timestamp(&mut self, ts: u64) -> io::Result<()> {
        writeln!(self.writer, "#{}", ts)
    }

    /// Writes a change to a scalar variable.
    pub fn change_scalar<V: Into<Value>>(&mut self, id: IdCode, v: V) -> io::Result<()> {
        writeln!(self.writer, "{}{}", v.into(), id)
    }

    /// Writes a change to a vector variable.
    pub fn change_vector(&mut self, id: IdCode, v: &[Value]) -> io::Result<()> {
        write!(self.writer, "b")?;
        for i in v {
            write!(self.writer, "{}", i)?
        }
        writeln!(self.writer, " {}", id)
    }

    /// Writes a change to a real variable.
    pub fn change_real(&mut self, id: IdCode, v: f64) -> io::Result<()> {
        writeln!(self.writer, "r{} {}", v, id)
    }

    /// Writes a change to a string variable.
    pub fn change_string(&mut self, id: IdCode, v: &str) -> io::Result<()> {
        writeln!(self.writer, "s{} {}", v, id)
    }

    /// Writes the beginning of a simulation command.
    pub fn begin(&mut self, c: SimulationCommand) -> io::Result<()> {
        writeln!(self.writer, "${}", c)
    }

    /// Writes an `$end` to end a simulation command.
    pub fn end(&mut self) -> io::Result<()> {
        writeln!(self.writer, "$end")
    }

    /// Writes a command from a `Command` enum as parsed by the parser.
    pub fn command(&mut self, c: &Command) -> io::Result<()> {
        use Command::*;
        match *c {
            Comment(ref c) => self.comment(&c[..]),
            Date(ref c) => self.date(&c[..]),
            Version(ref c) => self.version(&c[..]),
            Timescale(v, u) => self.timescale(v, u),
            ScopeDef(t, ref i) => self.scope_def(t, &i[..]),
            Upscope => self.upscope(),
            VarDef(t, s, i, ref r, idx) => self.var_def(t, s, i, &r[..], idx),
            Enddefinitions => self.enddefinitions(),
            Timestamp(t) => self.timestamp(t),
            ChangeScalar(i, v) => self.change_scalar(i, v),
            ChangeVector(i, ref v) => self.change_vector(i, &v[..]),
            ChangeReal(i, v) => self.change_real(i, v),
            ChangeString(i, ref v) => self.change_string(i, v),
            Begin(c) => self.begin(c),
            End(_) => self.end(),
        }
    }
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::boxed::Box;

use to_javascript::ToJavaScript;

/// Create a type alias for the table containing the symbols
/// All items are acccessible via their name
/// The `T` is the value inherited from `Table`
pub type Container<T> = HashMap<&'static str, T>;

/// This is the generic container for all symbol tables
/// `T` must implement `ToJavaScript`
pub struct Table<T: ToJavaScript> {
    /// This is the optional parent struct.
    /// The parent will most likely have a value unless the scope is global
    parent: Option<Box<Table<T>>>,
    /// The container is the contents of th table
    container: Box<Container<T>>,
}

impl<T: ToJavaScript> Table<T> {
    pub fn new(table: Option<Box<Table<T>>>) -> Table<T> {
        Table {
            parent: table,
            container: Box::new(Container::new()),
        }
    }

    /// Insert a value into the table
    pub fn insert(&mut self, key: &'static str, value: T) {
        self.container.insert(key, value);
    }

    /// Attempt to get a value from the table
    /// If the value can't be found within this scope. try the parent.
    /// After descending through all the scopes, return an undefiend error
    pub fn get(&self, key: &'static str) -> Option<&T> {
        // First we get from the local scope
        match self.container.get(key) {
            Some(value) => Some(value),
            None => self.parent.as_ref().and_then(|i| i.get(key)),
        }
    }
}
<commit_msg>Derive Debug from table.rs<commit_after>use std::collections::HashMap;
use std::boxed::Box;

use to_javascript::ToJavaScript;

/// Create a type alias for the table containing the symbols
/// All items are acccessible via their name
/// The `T` is the value inherited from `Table`
pub type Container<T> = HashMap<&'static str, T>;

/// This is the generic container for all symbol tables
/// `T` must implement `ToJavaScript`
#[derive(Debug)]
pub struct Table<T: ToJavaScript> {
    /// This is the optional parent struct.
    /// The parent will most likely have a value unless the scope is global
    parent: Option<Box<Table<T>>>,
    /// The container is the contents of th table
    container: Box<Container<T>>,
}

impl<T: ToJavaScript> Table<T> {
    pub fn new(table: Option<Box<Table<T>>>) -> Table<T> {
        Table {
            parent: table,
            container: Box::new(Container::new()),
        }
    }

    /// Insert a value into the table
    pub fn insert(&mut self, key: &'static str, value: T) {
        self.container.insert(key, value);
    }

    /// Attempt to get a value from the table
    /// If the value can't be found within this scope. try the parent.
    /// After descending through all the scopes, return an undefiend error
    pub fn get(&self, key: &'static str) -> Option<&T> {
        // First we get from the local scope
        match self.container.get(key) {
            Some(value) => Some(value),
            None => self.parent.as_ref().and_then(|i| i.get(key)),
        }
    }
}
<|endoftext|>


<commit_before>use ll::stylesheet::css_fixed;

pub fn css_fixed_to_float(f: css_fixed) -> float {
    const before: i32 = 10;
    f as float * 1.0f / ((1i32 << before) as float)
}
<commit_msg>Add VoidPtrLike trait for converting between *c_void<commit_after>use ll::stylesheet::css_fixed;
use core::libc::c_void;

pub fn css_fixed_to_float(f: css_fixed) -> float {
    const before: i32 = 10;
    f as float * 1.0f / ((1i32 << before) as float)
}

pub trait VoidPtrLike {
    static fn from_void_ptr(*c_void) -> self;
    fn to_void_ptr(&self) -> *c_void;
}<|endoftext|>


<commit_before>use ll::stylesheet::css_fixed;
use types::CssQName;
use core::libc::c_void;
use lwcstr_from_rust_str = wapcaplet::from_rust_string;

pub fn css_fixed_to_float(f: css_fixed) -> float {
    const before: i32 = 10;
    f as float * 1.0f / ((1i32 << before) as float)
}

pub fn float_to_css_fixed(f: float) -> css_fixed {
    const before: i32 = 10;
    (f as i32 << before) * (f as i32)
}

pub fn rust_str_to_net_qname(s: &str) -> CssQName {
    CssQName {
        ns: None,
        name: lwcstr_from_rust_str(s)
    }
}

pub fn net_qname_to_rust_str(qname: &CssQName) -> ~str {
    qname.name.to_str()
}

// FIXME: These methods should be unsafe
pub trait VoidPtrLike {
    static fn from_void_ptr(*c_void) -> self;
    fn to_void_ptr(&self) -> *c_void;
}<commit_msg>Fix float-to-fixed calculation<commit_after>use ll::stylesheet::css_fixed;
use types::CssQName;
use core::libc::c_void;
use lwcstr_from_rust_str = wapcaplet::from_rust_string;

pub fn css_fixed_to_float(f: css_fixed) -> float {
    const before: i32 = 10;
    f as float * 1.0f / ((1i32 << before) as float)
}

pub fn float_to_css_fixed(f: float) -> css_fixed {
    const before: i32 = 10;
    (f * ((1 << before) as float)) as css_fixed
}

pub fn rust_str_to_net_qname(s: &str) -> CssQName {
    CssQName {
        ns: None,
        name: lwcstr_from_rust_str(s)
    }
}

pub fn net_qname_to_rust_str(qname: &CssQName) -> ~str {
    qname.name.to_str()
}

// FIXME: These methods should be unsafe
pub trait VoidPtrLike {
    static fn from_void_ptr(*c_void) -> self;
    fn to_void_ptr(&self) -> *c_void;
}
<|endoftext|>


<commit_before>// Copyright (c) 2006-2009 Graydon Hoare
// Copyright (c) 2009-2013 Mozilla Foundation

// Permission is hereby granted, free of charge, to any
// person obtaining a copy of this software and associated
// documentation files (the "Software"), to deal in the
// Software without restriction, including without
// limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software
// is furnished to do so, subject to the following
// conditions:

// The above copyright notice and this permission notice
// shall be included in all copies or substantial portions
// of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
// ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
// SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
// IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.

//
// zero.rs
//
// Minimal definitions of the core primitives in Rust. Include this file with
// your project to create a freestanding Rust program that can run on bare
// metal.
//

#[allow(ctypes)];

// Built-in traits

#[lang="copy"]
pub trait Copy {}

#[lang="owned"]
pub trait Owned {}

#[lang="freeze"]
pub trait Freeze {}

#[lang="opaque"]
pub enum Opaque {}

#[lang="ty_desc"]
pub struct TyDesc;

#[lang="ty_visitor"]
pub trait TyVisitor {}

#[lang="closure_exchange_malloc"]
pub trait ClosureExchangeMalloc {}

#[lang="send"]
pub trait Send {}

#[lang="sized"]
pub trait Sized {}

#[lang="drop"]
pub trait Drop {
    fn finalize(&self);
}

// Operator overloading

#[lang="eq"]
pub trait Eq {
    fn eq(&self, other: &Self) -> bool;
    fn ne(&self, other: &Self) -> bool;
}

#[lang="ord"]
pub trait Ord {
    fn lt(&self, other: &Self) -> bool;
    fn le(&self, other: &Self) -> bool;
    fn ge(&self, other: &Self) -> bool;
    fn gt(&self, other: &Self) -> bool;
}

#[lang="add"]
pub trait Add<Rhs,Result> {
    fn add(&self, rhs: &Rhs) -> Result;
}

#[lang="sub"]
pub trait Sub<Rhs,Result> {
    fn sub(&self, rhs: &Rhs) -> Result;
}

#[lang="mul"]
pub trait Mul<Rhs,Result> {
    fn mul(&self, rhs: &Rhs) -> Result;
}

#[lang="div"]
pub trait Div<Rhs,Result> {
    fn div(&self, rhs: &Rhs) -> Result;
}

#[lang="rem"]
pub trait Rem<Rhs,Result> {
    fn rem(&self, rhs: &Rhs) -> Result;
}

#[lang="neg"]
pub trait Neg<Rhs,Result> {
    fn neg(&self) -> Result;
}

#[lang="not"]
pub trait Not<Rhs,Result> {
    fn not(&self) -> Result;
}

#[lang="bitand"]
pub trait BitAnd<Rhs,Result> {
    fn bitand(&self, rhs: &Rhs) -> Result;
}

#[lang="bitor"]
pub trait BitOr<Rhs,Result> {
    fn bitor(&self, rhs: &Rhs) -> Result;
}

#[lang="bitxor"]
pub trait BitXor<Rhs,Result> {
    fn bitxor(&self, rhs: &Rhs) -> Result;
}

#[lang="shl"]
pub trait Shl<Rhs,Result> {
    fn shl(&self, rhs: &Rhs) -> Result;
}

#[lang="shr"]
pub trait Shr<Rhs,Result> {
    fn shr(&self, rhs: &Rhs) -> Result;
}

#[lang="index"]
pub trait Index<Index,Result> {
    fn index(&self, rhs: &Index) -> Result;
}

// String utilities

#[lang="str_eq"]
pub fn str_eq(a: &str, b: &str) -> bool {
    unsafe {
        let (aptr, alen): (*u8, uint) = transmute(a);
        let (bptr, blen): (*u8, uint) = transmute(b);
        if alen != blen {
            return false
        }
        memcmp(aptr, bptr, alen - 1) == 0
    }
}

// FIXME(pcwalton): This function is legacy junk.
#[lang="uniq_str_eq"]
pub fn uniq_str_eq(a: &~str, b: &~str) -> bool {
    str_eq(*a, *b)
}

struct StringRepr {
    fill: uint,
    alloc: uint,
}

// FIXME(pcwalton): This function should not be necessary, I don't think.
#[lang="strdup_uniq"]
pub unsafe fn strdup_uniq(ptr: *u8, len: uint) -> ~str {
    let size = size_of::<StringRepr>() + len + 1;
    let string: *mut StringRepr = transmute(exchange_malloc(transmute(0),
                                                            size));
    (*string).fill = len + 1;
    (*string).alloc = len + 1;

    let mut data_ptr: uint = transmute(string);
    data_ptr += size_of::<StringRepr>();
    let data_ptr: *mut u8 = transmute(data_ptr);
    memcpy(data_ptr, ptr, len + 1);

    transmute(string)
}

// Legacy junk

#[lang="log_type"]
pub fn log_type<T>(_: u32, _: &T) {
    // FIXME: This function should not be a lang item.
}

#[lang="annihilate"]
pub unsafe fn annihilate() {}

// Failure

#[lang="fail_"]
pub fn fail(_: *i8, _: *i8, _: uint) -> ! {
    unsafe {
        abort()
    }
}

#[lang="fail_bounds_check"]
pub fn fail_bounds_check(_: *i8, _: uint, _: uint, _: uint) {
    unsafe {
        abort()
    }
}

// Memory allocation

// FIXME: So grotesquely inefficient.
struct Header {
    minus_one: uint,    // Must be -1.
    type_desc: *i8,
    null_0: uint,       // Must be null.
    null_1: uint,       // Must be null.
}

// FIXME: This is horrendously inefficient.
#[lang="exchange_malloc"]
pub unsafe fn exchange_malloc(type_desc: *i8, size: uint) -> *i8 {
    let alloc: *mut Header = transmute(malloc(size_of::<Header>() + size));
    (*alloc).minus_one = -1;
    (*alloc).type_desc = type_desc;
    (*alloc).null_0 = 0;
    (*alloc).null_1 = 0;
    transmute(alloc)
}

#[lang="exchange_free"]
pub unsafe fn exchange_free(alloc: *i8) {
    free(transmute(alloc))
}

// Entry point

// TODO(pcwalton): Stash argc and argv somewhere. Probably needs to wait on
// global variables.
#[lang="start"]
pub fn start(main: *u8, _: int, _: **i8, _: *u8) -> int {
    unsafe {
        let main: extern "Rust" fn() = transmute(main);
        main();
        0
    }
}

// The nonexistent garbage collector

#[lang="malloc"]
pub unsafe fn gc_malloc(_: *i8, _: uint) -> *i8 {
    abort()
}

#[lang="free"]
pub unsafe fn gc_free(_: *i8) {
    abort()
}

#[lang="borrow_as_imm"]
pub unsafe fn borrow_as_imm(_: *u8, _: *i8, _: uint) -> uint {
    abort()
}

#[lang="borrow_as_mut"]
pub unsafe fn borrow_as_mut(_: *u8, _: *i8, _: uint) -> uint {
    abort()
}

#[lang="record_borrow"]
pub unsafe fn record_borrow(_: *u8, _: uint, _: *i8, _: uint) {
    abort()
}

#[lang="unrecord_borrow"]
pub unsafe fn unrecord_borrow(_: *u8, _: uint, _: *i8, _: uint) {
    abort()
}

#[lang="return_to_mut"]
pub unsafe fn return_to_mut(_: *u8, _: uint, _: *i8, _: uint) {
    abort()
}

#[lang="check_not_borrowed"]
pub unsafe fn check_not_borrowed(_: *u8, _: *i8, _: uint) {
    abort()
}

// libc dependencies

extern {
    #[fast_ffi]
    pub fn malloc(size: uint) -> *u8;
    #[fast_ffi]
    pub fn free(ptr: *u8);
    #[fast_ffi]
    pub fn abort() -> !;
    #[fast_ffi]
    pub fn memcpy(dest: *mut u8, src: *u8, size: uint) -> *u8;
    #[fast_ffi]
    pub fn memcmp(a: *u8, b: *u8, size: uint) -> i32;
}

// Rust intrinsic dependencies

extern "rust-intrinsic" {
    pub fn transmute<T,U>(val: T) -> U;
    pub fn size_of<T>() -> uint;
}

<commit_msg>Add vector_exchange_malloc lang item<commit_after>// Copyright (c) 2006-2009 Graydon Hoare
// Copyright (c) 2009-2013 Mozilla Foundation

// Permission is hereby granted, free of charge, to any
// person obtaining a copy of this software and associated
// documentation files (the "Software"), to deal in the
// Software without restriction, including without
// limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software
// is furnished to do so, subject to the following
// conditions:

// The above copyright notice and this permission notice
// shall be included in all copies or substantial portions
// of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
// ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
// SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
// IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.

//
// zero.rs
//
// Minimal definitions of the core primitives in Rust. Include this file with
// your project to create a freestanding Rust program that can run on bare
// metal.
//

#[allow(ctypes)];

// Built-in traits

#[lang="copy"]
pub trait Copy {}

#[lang="owned"]
pub trait Owned {}

#[lang="freeze"]
pub trait Freeze {}

#[lang="opaque"]
pub enum Opaque {}

#[lang="ty_desc"]
pub struct TyDesc;

#[lang="ty_visitor"]
pub trait TyVisitor {}

#[lang="closure_exchange_malloc"]
pub trait ClosureExchangeMalloc {}

#[lang="vector_exchange_malloc"]

#[lang="send"]
pub trait Send {}

#[lang="sized"]
pub trait Sized {}

#[lang="drop"]
pub trait Drop {
    fn finalize(&self);
}

// Operator overloading

#[lang="eq"]
pub trait Eq {
    fn eq(&self, other: &Self) -> bool;
    fn ne(&self, other: &Self) -> bool;
}

#[lang="ord"]
pub trait Ord {
    fn lt(&self, other: &Self) -> bool;
    fn le(&self, other: &Self) -> bool;
    fn ge(&self, other: &Self) -> bool;
    fn gt(&self, other: &Self) -> bool;
}

#[lang="add"]
pub trait Add<Rhs,Result> {
    fn add(&self, rhs: &Rhs) -> Result;
}

#[lang="sub"]
pub trait Sub<Rhs,Result> {
    fn sub(&self, rhs: &Rhs) -> Result;
}

#[lang="mul"]
pub trait Mul<Rhs,Result> {
    fn mul(&self, rhs: &Rhs) -> Result;
}

#[lang="div"]
pub trait Div<Rhs,Result> {
    fn div(&self, rhs: &Rhs) -> Result;
}

#[lang="rem"]
pub trait Rem<Rhs,Result> {
    fn rem(&self, rhs: &Rhs) -> Result;
}

#[lang="neg"]
pub trait Neg<Rhs,Result> {
    fn neg(&self) -> Result;
}

#[lang="not"]
pub trait Not<Rhs,Result> {
    fn not(&self) -> Result;
}

#[lang="bitand"]
pub trait BitAnd<Rhs,Result> {
    fn bitand(&self, rhs: &Rhs) -> Result;
}

#[lang="bitor"]
pub trait BitOr<Rhs,Result> {
    fn bitor(&self, rhs: &Rhs) -> Result;
}

#[lang="bitxor"]
pub trait BitXor<Rhs,Result> {
    fn bitxor(&self, rhs: &Rhs) -> Result;
}

#[lang="shl"]
pub trait Shl<Rhs,Result> {
    fn shl(&self, rhs: &Rhs) -> Result;
}

#[lang="shr"]
pub trait Shr<Rhs,Result> {
    fn shr(&self, rhs: &Rhs) -> Result;
}

#[lang="index"]
pub trait Index<Index,Result> {
    fn index(&self, rhs: &Index) -> Result;
}

// String utilities

#[lang="str_eq"]
pub fn str_eq(a: &str, b: &str) -> bool {
    unsafe {
        let (aptr, alen): (*u8, uint) = transmute(a);
        let (bptr, blen): (*u8, uint) = transmute(b);
        if alen != blen {
            return false
        }
        memcmp(aptr, bptr, alen - 1) == 0
    }
}

// FIXME(pcwalton): This function is legacy junk.
#[lang="uniq_str_eq"]
pub fn uniq_str_eq(a: &~str, b: &~str) -> bool {
    str_eq(*a, *b)
}

struct StringRepr {
    fill: uint,
    alloc: uint,
}

// FIXME(pcwalton): This function should not be necessary, I don't think.
#[lang="strdup_uniq"]
pub unsafe fn strdup_uniq(ptr: *u8, len: uint) -> ~str {
    let size = size_of::<StringRepr>() + len + 1;
    let string: *mut StringRepr = transmute(exchange_malloc(transmute(0),
                                                            size));
    (*string).fill = len + 1;
    (*string).alloc = len + 1;

    let mut data_ptr: uint = transmute(string);
    data_ptr += size_of::<StringRepr>();
    let data_ptr: *mut u8 = transmute(data_ptr);
    memcpy(data_ptr, ptr, len + 1);

    transmute(string)
}

// Legacy junk

#[lang="log_type"]
pub fn log_type<T>(_: u32, _: &T) {
    // FIXME: This function should not be a lang item.
}

#[lang="annihilate"]
pub unsafe fn annihilate() {}

// Failure

#[lang="fail_"]
pub fn fail(_: *i8, _: *i8, _: uint) -> ! {
    unsafe {
        abort()
    }
}

#[lang="fail_bounds_check"]
pub fn fail_bounds_check(_: *i8, _: uint, _: uint, _: uint) {
    unsafe {
        abort()
    }
}

// Memory allocation

// FIXME: So grotesquely inefficient.
struct Header {
    minus_one: uint,    // Must be -1.
    type_desc: *i8,
    null_0: uint,       // Must be null.
    null_1: uint,       // Must be null.
}

// FIXME: This is horrendously inefficient.
#[lang="exchange_malloc"]
pub unsafe fn exchange_malloc(type_desc: *i8, size: uint) -> *i8 {
    let alloc: *mut Header = transmute(malloc(size_of::<Header>() + size));
    (*alloc).minus_one = -1;
    (*alloc).type_desc = type_desc;
    (*alloc).null_0 = 0;
    (*alloc).null_1 = 0;
    transmute(alloc)
}

#[lang="exchange_free"]
pub unsafe fn exchange_free(alloc: *i8) {
    free(transmute(alloc))
}

// Entry point

// TODO(pcwalton): Stash argc and argv somewhere. Probably needs to wait on
// global variables.
#[lang="start"]
pub fn start(main: *u8, _: int, _: **i8, _: *u8) -> int {
    unsafe {
        let main: extern "Rust" fn() = transmute(main);
        main();
        0
    }
}

// The nonexistent garbage collector

#[lang="malloc"]
pub unsafe fn gc_malloc(_: *i8, _: uint) -> *i8 {
    abort()
}

#[lang="free"]
pub unsafe fn gc_free(_: *i8) {
    abort()
}

#[lang="borrow_as_imm"]
pub unsafe fn borrow_as_imm(_: *u8, _: *i8, _: uint) -> uint {
    abort()
}

#[lang="borrow_as_mut"]
pub unsafe fn borrow_as_mut(_: *u8, _: *i8, _: uint) -> uint {
    abort()
}

#[lang="record_borrow"]
pub unsafe fn record_borrow(_: *u8, _: uint, _: *i8, _: uint) {
    abort()
}

#[lang="unrecord_borrow"]
pub unsafe fn unrecord_borrow(_: *u8, _: uint, _: *i8, _: uint) {
    abort()
}

#[lang="return_to_mut"]
pub unsafe fn return_to_mut(_: *u8, _: uint, _: *i8, _: uint) {
    abort()
}

#[lang="check_not_borrowed"]
pub unsafe fn check_not_borrowed(_: *u8, _: *i8, _: uint) {
    abort()
}

// libc dependencies

extern {
    #[fast_ffi]
    pub fn malloc(size: uint) -> *u8;
    #[fast_ffi]
    pub fn free(ptr: *u8);
    #[fast_ffi]
    pub fn abort() -> !;
    #[fast_ffi]
    pub fn memcpy(dest: *mut u8, src: *u8, size: uint) -> *u8;
    #[fast_ffi]
    pub fn memcmp(a: *u8, b: *u8, size: uint) -> i32;
}

// Rust intrinsic dependencies

extern "rust-intrinsic" {
    pub fn transmute<T,U>(val: T) -> U;
    pub fn size_of<T>() -> uint;
}

<|endoftext|>


<commit_before>
#![allow(unused_variables)]
#![allow(dead_code)]

/// Basic structure of a Monitor (aka Server App, aka wtttttt)
///
/// Monitors are designed so that the FoxBox can offer a simple
/// IFTTT-style Web UX to let users write their own scripts. More
/// complex monitors can installed from the web from a master device
/// (i.e. the user's cellphone or smart tv).

use dependencies::{DeviceKind, InputCapability, OutputCapability, Device, Range, Watcher, Witness};

use std::time::Duration;
use std::collections::HashMap;
use std::sync::Arc;
use std::sync::mpsc::{channel, Receiver, Sender};
use std::thread;

extern crate rustc_serialize;
use self::rustc_serialize::json::Json;

extern crate itertools;
use self::itertools::Zip;

/// A Monitor Application, i.e. an application (or a component of an
/// application) executed on the server.
///
/// Monitor applications are typically used for triggering an action
/// in reaction to an event: changing temperature when night falls,
/// ringing an alarm when a door is opened, etc.
///
/// Monitor applications are installed from a paired device. They may
/// either be part of a broader application (which can install them
/// through a web/REST API) or live on their own.
#[derive(Clone)]
struct MonitorApp {
    metadata: (), // FIXME: Authorizations, author, description, update url, version, ...

    /// `true` if the app is on, `false` otherwise.
    is_active: bool,

    /// Monitor applications have sets of requirements (e.g. "I need a
    /// camera"), which are allocated to actual resources through the
    /// UX. Re-allocating resources may be requested by the user, the
    /// foxbox, or an application, e.g. when replacing a device or
    /// upgrading the app.
    ///
    /// The position in the vector is important, as it is used to
    /// represent the instances of resources in the script.
    ///
    /// FIXME: Turn this `Vec` (and others) into a data structure in
    /// which this indexing property is built-in.
    requirements: Vec<Named<Requirement>>,

    /// For each requirement, the resources actually allocated to
    /// match the requirements. This may be 1 or more individual
    /// devices.
    ///
    /// Allocations can be done in several ways:
    ///
    /// - when entering the script through a UX (either the script or
    ///   the UX can suggest allocations);
    /// - when installing an application with a web front-end.
    allocations: Vec<Vec<Named<Arc<Device>>>>,

    /// A set of rules, stating what must be done in which circumstance.
    rules: Vec<Trigger>,

    /// Either `None` if the application is not launched, or `Some(tx)`,
    /// where `tx` is a channel used to communicate with the thread
    /// running the application.
    command_sender: Option<Sender<MonitorOp>>,
}

impl<'a> MonitorApp {
    /// Index-safe iteration through all the possible
    /// allocations/individual devices/inputs.
    fn iter_state_index(&self) -> Vec<InputBinding>
    {
        // FIXME: Several possible optimizations here, including
        // caching the vector.
        let mut vec = Vec::new();
        for (req, allocation, allocation_index) in Zip::new((&self.requirements, &self.allocations, 0..)) {
            for (individual_device, individual_device_index) in Zip::new((allocation, 0..)) {
                for (input, individual_input_index) in Zip::new((&req.data.inputs, 0..)) {
                    vec.push(InputBinding {
                        allocation: allocation_index,
                        device: individual_device_index,
                        input: individual_input_index
                    })
                }
            }
        }
        vec
    }
}

/// The binding of an input capability to a specific device set.
struct InputBinding {
    /// The device set holding this input capability.
    /// Index in `app.allocations`.
    allocation: usize,

    /// The individual device holding this input capability.
    /// Index in `app.allocations[self.allocation]`.
    device: usize,

    /// The specific input holding this input capability.
    /// Index in `app.allocations[self.allocation][self.device]`.
    input: usize,
}

impl InputBinding {
    /// Get the device providing the InputBinding.
    fn get_individual_device(&self, app: &MonitorApp) -> Arc<Device> {
        app.allocations[self.allocation][self.device].data.clone()
    }

    /// Get the input capability for this binding.
    fn get_input(&self, app: &MonitorApp) -> InputCapability {
        app.requirements[self.allocation].data.inputs[self.input].data.clone()
    }

    /// Update the state attached to this input binding.
    fn set_state(&self, state: &mut MonitorTaskState, value: Option<Json>) {
        state.input_state[self.allocation][self.device][self.input] = value;
    }
}

/// The state of a given condition.
struct ConditionState {
    /// `true` if the conditions were met last time the state of the
    /// inputs changed. We use this to trigger an action only when
    /// conditions were previously unmet and are now met.
    are_conditions_met: bool,
    // FIXME: In the future, the cooldown should go here.
}

type InputState = Vec<Vec<Vec<Option<Json>>>>;
struct MonitorTaskState {
    /// The state of each trigger.
    ///
    /// Invariant: len() is the same as that of `self.app.rule`s
    trigger_condition_state: Vec<ConditionState>,

    /// For each device set allocated, for each individual device
    /// allocated, for each input watched by the app, the latest state
    /// received.
    ///
    /// Use `InputBinding` to access the data.
    input_state: InputState,

    witnesses: Vec<Witness>,

    /// A clone of the code being executed.
    app: MonitorApp,
}

/// The part of the monitor used to communicate between threads.
///
/// Kept separate to help the borrow checker understand what we're
/// accessing at any time.
struct MonitorComm {
    tx: Sender<MonitorOp>,
    rx: Receiver<MonitorOp>,
}

/// A MonitorApp currently being executed.
///
/// Each MonitorTask runs on its own thread.
struct MonitorTask {
    state: MonitorTaskState,
    comm: MonitorComm,
}

impl MonitorTask {
    /// Create a new MonitorTask.
    ///
    /// This creates the data structures and initializes watching,
    /// but the task is not launched
    fn start(app: MonitorApp) -> Sender<MonitorOp> {
        // Initialize condition state.
        let mut trigger_condition_state = Vec::with_capacity(app.rules.len());
        for _ in &app.rules {
            trigger_condition_state.push(ConditionState {
                are_conditions_met: false,
            });
        }
        assert_eq!(trigger_condition_state.len(), app.rules.len());

        // Initialize input state.
        let mut full_input_state = Vec::with_capacity(app.requirements.len());
        for (req, allocation) in app.requirements.iter().zip(&app.allocations) {

            // State for this allocation. A single allocation may map
            // to a number of inputs (e.g. "all fire alarms").
            let mut allocation_state = Vec::with_capacity(allocation.len());
            for individual_device in allocation {
                let mut individual_device_state = Vec::with_capacity(req.data.inputs.len());
                for _ in 0 .. req.data.inputs.len() {
                    individual_device_state.push(None);
                }
                allocation_state.push(individual_device_state);
            }
            assert_eq!(allocation_state.len(), allocation.len());
            full_input_state.push(allocation_state);
        }
        assert_eq!(full_input_state.len(), app.requirements.len());

        // Start watching
        let mut watcher = Watcher::new();
        let mut witnesses = Vec::new();
        let (tx, rx) = channel();

        for state_index in app.iter_state_index() {
            // FIXME: We currently use `Range::any()` for simplicity.
            // However, in most cases, we should be able to look inside
            // the condition to build a better `Range`.

            // FIXME: We currently monitor all the inputs that are
            // used by this rule, even if they are not part of the
            // condition (e.g. we monitor the camera all the time even
            // if we only need to trigger when an intruder enters).
            witnesses.push(
                watcher.add(
                    &state_index.get_individual_device(&app),
                    &state_index.get_input(&app),
                    &Range::any(),
                    |data| {
                        let _ignored = tx.send(MonitorOp::Update {
                            data: data,
                            index: state_index,
                        });
                        // Ignore errors. If the thread is shutting
                        // down, it's ok to lose messages.
                    }));
        }

        let result = tx.clone();

        let mut task = MonitorTask {
            state: MonitorTaskState {
                trigger_condition_state: trigger_condition_state,
                input_state: full_input_state,
                witnesses: witnesses,
                app: app,
            },
            comm: MonitorComm {
                tx: tx,
                rx: rx,
            }
        };

        thread::spawn(move || {
            task.run();
        });

        result
    }

    /// Execute the monitoring task.
    /// This currently expects to be executed in its own thread.
    fn run(&mut self) {
        for msg in &self.comm.rx {
            use self::MonitorOp::*;
            match msg {
                Update {
                    data,
                    index,
                } => {
                    // Update the state
                    index.set_state(&mut self.state, Some(data));

                    // Find out if we should execute triggers.
                    // FIXME: We could optimize this by finding out which triggers
                    // are tainted by the update and only rechecking these.
                    for (trigger, trigger_condition_state) in Zip::new((&self.state.app.rules, &mut self.state.trigger_condition_state)) {
                        let is_met = trigger.condition.is_met(&self.state.input_state);
                        if is_met == trigger_condition_state.are_conditions_met {
                            // No change in conditions. Nothing to do.
                            continue;
                        }
                        trigger_condition_state.are_conditions_met = is_met;
                        if !is_met {
                            // Conditions were met, now they are not anymore.
                            // The next time they are met, we can trigger
                            // a new execution.
                            continue;
                        }
                        // Conditions were not met, now they are, so it is
                        // time to start executing. We copy the inputs
                        // and dispatch to a background thread

                        // FIXME: Handle cooldown.

                        trigger_condition_state.are_conditions_met = true;
                        let _ignored = self.comm.tx.send(MonitorOp::Execute {
                            state: self.state.input_state.clone(),
                            commands: trigger.execute.clone()
                        });
                        // Ignore errors. If the thread is shutting down, it's ok to lose messages.
                    }
                },
                Execute {..} => {
                    panic!("Not implemented");
                }
                Stop => {
                    // Clean up watcher, stop the thread.
                    self.state.witnesses.clear();
                    return;
                }
            }
        }
    }
}

enum MonitorOp {
    Update{data: Json, index: InputBinding},
    Execute{state: InputState, commands: Vec<Command>},
    Stop
}

impl MonitorApp {
    ///
    /// Start executing the application.
    ///
    pub fn start(&mut self) {
        if self.command_sender.is_some() {
            return;
        }
        self.command_sender = Some(MonitorTask::start(self.clone()));
    }

    ///
    /// Stop the execution of the application.
    ///
    pub fn stop(&mut self) {
        match self.command_sender {
            None => {
                /* Nothing to stop */
                return;
            },
            Some(ref tx) => {
                // Shutdown the application, asynchronously.
                let _ignored = tx.send(MonitorOp::Stop);
                // Do not return.
            }
        }
        self.command_sender = None;
    }
}

/// Data labelled with a user-readable name.
#[derive(Clone)]
struct Named<T> where T: Clone {
    /// User-readable name.
    name: String,

    data: T,
}

/// A resource needed by this application. Typically, a definition of
/// device with some input our output capabilities.
#[derive(Clone)]
struct Requirement {
    /// The kind of resource, e.g. "a flashbulb".
    kind: DeviceKind,

    /// Input capabilities we need from the device, e.g. "the time of
    /// day", "the current temperature".
    inputs: Vec<Named<InputCapability>>,

    /// Output capabilities we need from the device, e.g. "play a
    /// sound", "set luminosity".
    outputs: Vec<Named<OutputCapability>>,

    /// Minimal number of resources required. If unspecified in the
    /// script, this is 1.
    min: u32,

    /// Maximal number of resources that may be handled. If
    /// unspecified in the script, this is the same as `min`.
    max: u32,

    // FIXME: We may need cooldown properties.
}

/// A single trigger, i.e. "when some condition becomes true, do
/// something".
#[derive(Clone)]
struct Trigger {
    /// The condition in which to execute the trigger.
    condition: Disjunction,

    /// Stuff to do once `condition` is met.
    execute: Vec<Command>,

    /// Minimal duration between two executions of the trigger.  If a
    /// duration was not picked by the developer, a reasonable default
    /// duration should be picked (e.g. 10 minutes).
    cooldown: Duration,
}

/// A disjunction (e.g. a "or") of conditions.
///
/// # Example
///
/// Door alarm #1 OR door alarm #2
#[derive(Clone)]
struct Disjunction {
    /// The disjunction is true iff any of the following conjunctions is true.
    any: Vec<Conjunction>
}

impl Disjunction {
    fn is_met(&self, input_state: &InputState) -> bool {
        panic!("Not implemented");
    }
}

/// A conjunction (e.g. a "and") of conditions.
#[derive(Clone)]
struct Conjunction {
    /// The conjunction is true iff all of the following expressions evaluate to true.
    all: Vec<Expression>
}

#[derive(Clone)]
enum Value {
    Json(Json),
    Blob{data: Arc<Vec<u8>>, mime_type: String},
}

/// An expression in the language.  Note that expressions may contain
/// inputs, which are typically asynchronous. Consequently,
/// expressions are evaluated asynchronously.
#[derive(Clone)]
enum Expression {
    Const {
        value: Value,

        /// We are dealing with real-world values, so physical units
        /// will prevent real-world accidents.
        unit: (), // FIXME: An actual unit

        /// The source for this value.  Used whenever we need to find
        /// out which sensor triggered the trigger (e.g. "where is the
        /// fire?").
        sources: Vec<usize>,
    },

    /// Dynamic values, including both actual sensors and higher-level values.
    ///
    /// # Example
    ///
    /// "Is there movement on motion detector" (may be true/false)
    ///
    /// # Example
    ///
    /// "Date of the latest motion on motion detector" (a Date)
    Input {
        /// A reference to the device used for input.
        /// This is an index in `requirements` and `allocations`.
        index: usize, // FIXME: We should use a custom type.

        /// A property to fetch (e.g. "luminosity" or "meta/latest-on").
        property: InputCapability,
    },

    /// Pure functions on values. The fact that they are pure
    /// functions is important, as it lets us find out automatically
    /// which subexpressions (including inputs) do not need to be
    /// re-evaluated.
    Function {
        function: Function,
        // FIXME: use a Box<> for now to avoid recursive type.
        arguments: Vec<Box<Expression>>
    },
}

#[derive(Clone)]
enum Function {
    // Operations on all values.
    InRange,
    OutOfRange,
    // Operations on strings
    Contains,
    NotContains,
}

/*
enum Function {
    // Operations on all values.
    Equals,
    NotEquals,

    // Operations on numbers, dates, durations.
    GreaterEq,
    Greater,
    LowerEq,
    Lower,
    Plus,
    Minus,

    // Operations on strings
    Contains,
    NotContains,

    // Etc.  FIXME: We'll need operations on dates, extracting name
    // from device, etc.
}
 */

/// Stuff to actually do. In practice, this is always a REST call.
// FIXME: Need to decide how much we wish to sandbox apps.
#[derive(Clone)]
struct Command {
    /// The resource to which this command applies,
    /// as an index in Trigger.requirements/allocations.
    destination: usize,  // FIXME: Use custom type.

    action: OutputCapability,

    arguments: HashMap<String, Option<Expression>>
}

<commit_msg>[fxbox/thinkerbell] Refactored the MonitorTask to make sure that watching takes places off main thread<commit_after>
#![allow(unused_variables)]
#![allow(dead_code)]

/// Basic structure of a Monitor (aka Server App, aka wtttttt)
///
/// Monitors are designed so that the FoxBox can offer a simple
/// IFTTT-style Web UX to let users write their own scripts. More
/// complex monitors can installed from the web from a master device
/// (i.e. the user's cellphone or smart tv).

use dependencies::{DeviceKind, InputCapability, OutputCapability, Device, Range, Watcher};

use std::time::Duration;
use std::collections::HashMap;
use std::sync::Arc;
use std::sync::mpsc::{channel, Receiver, Sender};
use std::thread;

extern crate rustc_serialize;
use self::rustc_serialize::json::Json;

extern crate itertools;
use self::itertools::Zip;

/// A Monitor Application, i.e. an application (or a component of an
/// application) executed on the server.
///
/// Monitor applications are typically used for triggering an action
/// in reaction to an event: changing temperature when night falls,
/// ringing an alarm when a door is opened, etc.
///
/// Monitor applications are installed from a paired device. They may
/// either be part of a broader application (which can install them
/// through a web/REST API) or live on their own.
#[derive(Clone)]
struct MonitorApp {
    metadata: (), // FIXME: Authorizations, author, description, update url, version, ...

    /// `true` if the app is on, `false` otherwise.
    is_active: bool,

    /// Monitor applications have sets of requirements (e.g. "I need a
    /// camera"), which are allocated to actual resources through the
    /// UX. Re-allocating resources may be requested by the user, the
    /// foxbox, or an application, e.g. when replacing a device or
    /// upgrading the app.
    ///
    /// The position in the vector is important, as it is used to
    /// represent the instances of resources in the script.
    ///
    /// FIXME: Turn this `Vec` (and others) into a data structure in
    /// which this indexing property is built-in.
    requirements: Vec<Named<Requirement>>,

    /// For each requirement, the resources actually allocated to
    /// match the requirements. This may be 1 or more individual
    /// devices.
    ///
    /// Allocations can be done in several ways:
    ///
    /// - when entering the script through a UX (either the script or
    ///   the UX can suggest allocations);
    /// - when installing an application with a web front-end.
    allocations: Vec<Vec<Named<Arc<Device>>>>,

    /// A set of rules, stating what must be done in which circumstance.
    rules: Vec<Trigger>,

    /// Either `None` if the application is not launched, or `Some(tx)`,
    /// where `tx` is a channel used to communicate with the thread
    /// running the application.
    command_sender: Option<Sender<MonitorOp>>,
}

impl<'a> MonitorApp {
    /// Index-safe iteration through all the possible
    /// allocations/individual devices/inputs.
    fn iter_state_index(&self) -> Vec<InputBinding>
    {
        // FIXME: Several possible optimizations here, including
        // caching the vector.
        let mut vec = Vec::new();
        for (req, allocation, allocation_index) in Zip::new((&self.requirements, &self.allocations, 0..)) {
            for (individual_device, individual_device_index) in Zip::new((allocation, 0..)) {
                for (input, individual_input_index) in Zip::new((&req.data.inputs, 0..)) {
                    vec.push(InputBinding {
                        allocation: allocation_index,
                        device: individual_device_index,
                        input: individual_input_index
                    })
                }
            }
        }
        vec
    }
}

/// The binding of an input capability to a specific device set.
struct InputBinding {
    /// The device set holding this input capability.
    /// Index in `app.allocations`.
    allocation: usize,

    /// The individual device holding this input capability.
    /// Index in `app.allocations[self.allocation]`.
    device: usize,

    /// The specific input holding this input capability.
    /// Index in `app.allocations[self.allocation][self.device]`.
    input: usize,
}

impl InputBinding {
    /// Get the device providing the InputBinding.
    fn get_individual_device(&self, app: &MonitorApp) -> Arc<Device> {
        app.allocations[self.allocation][self.device].data.clone()
    }

    /// Get the input capability for this binding.
    fn get_input(&self, app: &MonitorApp) -> InputCapability {
        app.requirements[self.allocation].data.inputs[self.input].data.clone()
    }

    /// Update the state attached to this input binding.
    fn set_state(&self, state: &mut MonitorTaskState, value: Option<Json>) {
        state.input_state[self.allocation][self.device][self.input] = value;
    }
}

/// The state of a given condition.
struct ConditionState {
    /// `true` if the conditions were met last time the state of the
    /// inputs changed. We use this to trigger an action only when
    /// conditions were previously unmet and are now met.
    are_conditions_met: bool,
    // FIXME: In the future, the cooldown should go here.
}

type InputState = Vec<Vec<Vec<Option<Json>>>>;
struct MonitorTaskState {
    /// The state of each trigger.
    ///
    /// Invariant: len() is the same as that of `self.app.rule`s
    trigger_condition_state: Vec<ConditionState>,

    /// For each device set allocated, for each individual device
    /// allocated, for each input watched by the app, the latest state
    /// received.
    ///
    /// Use `InputBinding` to access the data.
    input_state: InputState,

    /// A clone of the code being executed.
    app: MonitorApp,
}

/// The part of the monitor used to communicate between threads.
///
/// Kept separate to help the borrow checker understand what we're
/// accessing at any time.
struct MonitorComm {
    tx: Sender<MonitorOp>,
    rx: Receiver<MonitorOp>,
}

/// A MonitorApp currently being executed.
///
/// Each MonitorTask runs on its own thread.
struct MonitorTask {
    state: MonitorTaskState,
    comm: MonitorComm,
}

impl MonitorTask {

    /// Create a new MonitorTask.
    ///
    /// To initiate watching, use method `run()`.
    fn new(app: MonitorApp) -> Self {
        // Initialize condition state.
        let mut trigger_condition_state = Vec::with_capacity(app.rules.len());
        for _ in &app.rules {
            trigger_condition_state.push(ConditionState {
                are_conditions_met: false,
            });
        }
        assert_eq!(trigger_condition_state.len(), app.rules.len());

        // Initialize input state.
        let mut full_input_state = Vec::with_capacity(app.requirements.len());
        for (req, allocation) in app.requirements.iter().zip(&app.allocations) {

            // State for this allocation. A single allocation may map
            // to a number of inputs (e.g. "all fire alarms").
            let mut allocation_state = Vec::with_capacity(allocation.len());
            for individual_device in allocation {
                let mut individual_device_state = Vec::with_capacity(req.data.inputs.len());
                for _ in 0 .. req.data.inputs.len() {
                    individual_device_state.push(None);
                }
                allocation_state.push(individual_device_state);
            }
            assert_eq!(allocation_state.len(), allocation.len());
            full_input_state.push(allocation_state);
        }
        assert_eq!(full_input_state.len(), app.requirements.len());

        // Start watching
        let (tx, rx) = channel();

        MonitorTask {
            state: MonitorTaskState {
                trigger_condition_state: trigger_condition_state,
                input_state: full_input_state,
                app: app,
            },
            comm: MonitorComm {
                tx: tx,
                rx: rx,
            }
        }
    }

    /// Get a channel that may be used to send commands to the task.
    fn get_command_sender(&self) -> Sender<MonitorOp> {
        self.comm.tx.clone()
    }

    /// Execute the monitoring task.
    /// This currently expects to be executed in its own thread.
    fn run(&mut self) {
        let mut watcher = Watcher::new();
        let mut witnesses = Vec::new();

        for state_index in self.state.app.iter_state_index() {
            // FIXME: We currently use `Range::any()` for simplicity.
            // However, in most cases, we should be able to look inside
            // the condition to build a better `Range`.

            // FIXME: We currently monitor all the inputs that are
            // used by this rule, even if they are not part of the
            // condition (e.g. we monitor the camera all the time even
            // if we only need to trigger when an intruder enters).
            witnesses.push(
                watcher.add(
                    &state_index.get_individual_device(&self.state.app),
                    &state_index.get_input(&self.state.app),
                    &Range::any(),
                    |data| {
                        let _ignored = self.comm.tx.send(MonitorOp::Update {
                            data: data,
                            index: state_index,
                        });
                        // Ignore errors. If the thread is shutting
                        // down, it's ok to lose messages.
                    }));
        }

        for msg in &self.comm.rx {
            use self::MonitorOp::*;
            match msg {
                Update {
                    data,
                    index,
                } => {
                    // Update the state
                    index.set_state(&mut self.state, Some(data));

                    // Find out if we should execute triggers.
                    // FIXME: We could optimize this by finding out which triggers
                    // are tainted by the update and only rechecking these.
                    for (trigger, trigger_condition_state) in Zip::new((&self.state.app.rules, &mut self.state.trigger_condition_state)) {
                        let is_met = trigger.condition.is_met(&self.state.input_state);
                        if is_met == trigger_condition_state.are_conditions_met {
                            // No change in conditions. Nothing to do.
                            continue;
                        }
                        trigger_condition_state.are_conditions_met = is_met;
                        if !is_met {
                            // Conditions were met, now they are not anymore.
                            // The next time they are met, we can trigger
                            // a new execution.
                            continue;
                        }
                        // Conditions were not met, now they are, so it is
                        // time to start executing. We copy the inputs
                        // and dispatch to a background thread

                        // FIXME: Handle cooldown.

                        trigger_condition_state.are_conditions_met = true;
                        let _ignored = self.comm.tx.send(MonitorOp::Execute {
                            state: self.state.input_state.clone(),
                            commands: trigger.execute.clone()
                        });
                        // Ignore errors. If the thread is shutting down, it's ok to lose messages.
                    }
                },
                Execute {..} => {
                    panic!("Not implemented");
                }
                Stop => {
                    // Clean up watcher, stop the thread.
                    return;
                }
            }
        }
    }
}

enum MonitorOp {
    Update{data: Json, index: InputBinding},
    Execute{state: InputState, commands: Vec<Command>},
    Stop
}

impl MonitorApp {
    ///
    /// Start executing the application.
    ///
    pub fn start(&mut self) {
        if self.command_sender.is_some() {
            return;
        }
        let mut task = MonitorTask::new(self.clone());
        self.command_sender = Some(task.get_command_sender());
        thread::spawn(move || {
            task.run();
        });
    }

    ///
    /// Stop the execution of the application.
    ///
    pub fn stop(&mut self) {
        match self.command_sender {
            None => {
                /* Nothing to stop */
                return;
            },
            Some(ref tx) => {
                // Shutdown the application, asynchronously.
                let _ignored = tx.send(MonitorOp::Stop);
                // Do not return.
            }
        }
        self.command_sender = None;
    }
}

/// Data labelled with a user-readable name.
#[derive(Clone)]
struct Named<T> where T: Clone {
    /// User-readable name.
    name: String,

    data: T,
}

/// A resource needed by this application. Typically, a definition of
/// device with some input our output capabilities.
#[derive(Clone)]
struct Requirement {
    /// The kind of resource, e.g. "a flashbulb".
    kind: DeviceKind,

    /// Input capabilities we need from the device, e.g. "the time of
    /// day", "the current temperature".
    inputs: Vec<Named<InputCapability>>,

    /// Output capabilities we need from the device, e.g. "play a
    /// sound", "set luminosity".
    outputs: Vec<Named<OutputCapability>>,

    /// Minimal number of resources required. If unspecified in the
    /// script, this is 1.
    min: u32,

    /// Maximal number of resources that may be handled. If
    /// unspecified in the script, this is the same as `min`.
    max: u32,

    // FIXME: We may need cooldown properties.
}

/// A single trigger, i.e. "when some condition becomes true, do
/// something".
#[derive(Clone)]
struct Trigger {
    /// The condition in which to execute the trigger.
    condition: Disjunction,

    /// Stuff to do once `condition` is met.
    execute: Vec<Command>,

    /// Minimal duration between two executions of the trigger.  If a
    /// duration was not picked by the developer, a reasonable default
    /// duration should be picked (e.g. 10 minutes).
    cooldown: Duration,
}

/// A disjunction (e.g. a "or") of conditions.
///
/// # Example
///
/// Door alarm #1 OR door alarm #2
#[derive(Clone)]
struct Disjunction {
    /// The disjunction is true iff any of the following conjunctions is true.
    any: Vec<Conjunction>
}

impl Disjunction {
    fn is_met(&self, input_state: &InputState) -> bool {
        panic!("Not implemented");
    }
}

/// A conjunction (e.g. a "and") of conditions.
#[derive(Clone)]
struct Conjunction {
    /// The conjunction is true iff all of the following expressions evaluate to true.
    all: Vec<Expression>
}

#[derive(Clone)]
enum Value {
    Json(Json),
    Blob{data: Arc<Vec<u8>>, mime_type: String},
}

/// An expression in the language.  Note that expressions may contain
/// inputs, which are typically asynchronous. Consequently,
/// expressions are evaluated asynchronously.
#[derive(Clone)]
enum Expression {
    Const {
        value: Value,

        /// We are dealing with real-world values, so physical units
        /// will prevent real-world accidents.
        unit: (), // FIXME: An actual unit

        /// The source for this value.  Used whenever we need to find
        /// out which sensor triggered the trigger (e.g. "where is the
        /// fire?").
        sources: Vec<usize>,
    },

    /// Dynamic values, including both actual sensors and higher-level values.
    ///
    /// # Example
    ///
    /// "Is there movement on motion detector" (may be true/false)
    ///
    /// # Example
    ///
    /// "Date of the latest motion on motion detector" (a Date)
    Input {
        /// A reference to the device used for input.
        /// This is an index in `requirements` and `allocations`.
        index: usize, // FIXME: We should use a custom type.

        /// A property to fetch (e.g. "luminosity" or "meta/latest-on").
        property: InputCapability,
    },

    /// Pure functions on values. The fact that they are pure
    /// functions is important, as it lets us find out automatically
    /// which subexpressions (including inputs) do not need to be
    /// re-evaluated.
    Function {
        function: Function,
        // FIXME: use a Box<> for now to avoid recursive type.
        arguments: Vec<Box<Expression>>
    },
}

#[derive(Clone)]
enum Function {
    // Operations on all values.
    InRange,
    OutOfRange,
    // Operations on strings
    Contains,
    NotContains,
}

/*
enum Function {
    // Operations on all values.
    Equals,
    NotEquals,

    // Operations on numbers, dates, durations.
    GreaterEq,
    Greater,
    LowerEq,
    Lower,
    Plus,
    Minus,

    // Operations on strings
    Contains,
    NotContains,

    // Etc.  FIXME: We'll need operations on dates, extracting name
    // from device, etc.
}
 */

/// Stuff to actually do. In practice, this is always a REST call.
// FIXME: Need to decide how much we wish to sandbox apps.
#[derive(Clone)]
struct Command {
    /// The resource to which this command applies,
    /// as an index in Trigger.requirements/allocations.
    destination: usize,  // FIXME: Use custom type.

    action: OutputCapability,

    arguments: HashMap<String, Option<Expression>>
}

<|endoftext|>


<commit_before>extern crate concurrent;

pub use self::concurrent::collections::BoundedBlockingQueue;
pub use self::concurrent::collections::UnboundedBlockingQueue;

pub use std::sync::Arc;
pub use std::sync::atomic::{AtomicBool, Ordering};
pub use std::time::Duration;

pub use std::thread;
pub use std::sync::mpsc;

describe! bounded_blocking_queue_test {

    before_each {
        const CAPACITY : usize = 16;
        let queue: BoundedBlockingQueue<i32> = BoundedBlockingQueue::with_capacity(CAPACITY);
    }

    it "should create a new queue with default capacity" {
        let queue: BoundedBlockingQueue<i32> = BoundedBlockingQueue::new();
        assert_eq!(queue.remaning_capacity(), 15);
    }

    it "should create a new empty queue" {
        assert!(queue.is_empty());
        assert_eq!(queue.size(), 0);
    }

    it "should capacity be always highest power of two" {
        let queue: BoundedBlockingQueue<i32> = BoundedBlockingQueue::with_capacity(6);
        assert_eq!(queue.remaning_capacity(), 7);

        let queue: BoundedBlockingQueue<i32> = BoundedBlockingQueue::with_capacity(10);
        assert_eq!(queue.remaning_capacity(), 15);

        let queue: BoundedBlockingQueue<i32> = BoundedBlockingQueue::with_capacity(20);
        assert_eq!(queue.remaning_capacity(), 31);

        let queue: BoundedBlockingQueue<i32> = BoundedBlockingQueue::with_capacity(40);
        assert_eq!(queue.remaning_capacity(), 63);
    }

    it "should increase size when insert into queue" {
        let old_size = queue.size();
        queue.enqueue(1);

        assert_eq!(queue.size(), old_size + 1);
    }

    it "should contains value that was equeued" {
        queue.enqueue(1);

        assert!(queue.contains(1));
        assert!(!queue.contains(2));
    }

    it "should decrise size when remove from queue" {
        queue.enqueue(1);
        let old_size = queue.size();

        queue.dequeue();
        assert_eq!(queue.size(), old_size - 1);
    }

    it "should dequeue first enqueued value" {
        queue.enqueue(10);
        queue.enqueue(20);
        queue.enqueue(30);

        assert_eq!(queue.dequeue(), 10);
        assert_eq!(queue.dequeue(), 20);
        assert_eq!(queue.dequeue(), 30);
    }

    it "should insert offered value if queue not full" {
        assert!(queue.offer(1));
        assert!(queue.contains(1));
    }

    it "should peek first element but not delete from queue" {
        queue.enqueue(1);
        queue.enqueue(2);
        queue.enqueue(3);

        assert_eq!(queue.peek(), Some(1));
        assert_eq!(queue.peek(), Some(1));
    }

    it "should calculate correct size when alot insertions and deletions" {
        let size = queue.size();
        for i in 1..8 {
            queue.enqueue(i);
            assert_eq!(queue.size(), size + (i as usize));
        }

        let size = queue.size();
        for i in 1..6 {
            queue.dequeue();
            assert_eq!(queue.size(), size - (i as usize));
        }

        let size = queue.size();
        for i in 1..8 {
            queue.enqueue(i);
            assert_eq!(queue.size(), size + (i as usize));
        }

        let size = queue.size();
        for i in 1..6 {
            queue.dequeue();
            assert_eq!(queue.size(), size - (i as usize));
        }

        let size = queue.size();
        for i in 1..8 {
            queue.enqueue(i);
            assert_eq!(queue.size(), size + (i as usize));
        }

        let size = queue.size();
        for i in 1..6 {
            queue.dequeue();
            assert_eq!(queue.size(), size - (i as usize));
        }

        let size = queue.size();
        for i in 1..8 {
            queue.enqueue(i);
            assert_eq!(queue.size(), size + (i as usize));
        }

        let size = queue.size();
        for i in 1..6 {
            queue.dequeue();
            assert_eq!(queue.size(), size - (i as usize));
        }
    }

    //FAILED test
    //some times threads get stuck
    /*
    it "should threads wait each other when queue is empty or full" {
        let arc = Arc::new(queue);
        let flag = Arc::new(AtomicBool::new(false));

        let data = arc.clone();
        let ready = flag.clone();
        let jh = thread::spawn(
            move || {
                let mut counter = 0;
                let mut sum = 0;
                while !data.is_empty() || !ready.load(Ordering::Relaxed) {
                    let datum = data.dequeue();
                    assert_eq!(datum, counter);
                    counter += 1;
                    sum += datum;
                }
                assert_eq!(sum, 4950);
            }
        );

        for i in 0..100 {
            arc.enqueue(i);
        }

        flag.store(true, Ordering::Relaxed);

        assert!(jh.join().is_ok());
    }
    */
}

describe! unbounded_blocking_queue_test {

    before_each {
        let mut queue = UnboundedBlockingQueue::new();
    }

    it "should create new empty unbounded queue" {
        assert_eq!(queue.size(), 0);
        assert!(queue.is_empty());
    }

    it "should increase queue size when enqueue value" {
        let old_size = queue.size();
        queue.enqueue(1);

        assert_eq!(queue.size(), old_size + 1);
    }

    it "should decrease queue size when dequeue value" {
        queue.enqueue(1);
        let old_size = queue.size();
        queue.dequeue();

        assert_eq!(queue.size(), old_size - 1);
    }

    it "should contain values that were enqueued" {
        queue.enqueue(1);
        assert!(queue.contains(1));
        assert!(!queue.contains(2));

        queue.enqueue(2);
        assert!(queue.contains(1));
        assert!(queue.contains(2));
    }
}
<commit_msg>add triangulation test cases<commit_after>extern crate concurrent;

pub use self::concurrent::collections::BoundedBlockingQueue;
pub use self::concurrent::collections::UnboundedBlockingQueue;

pub use std::sync::Arc;
pub use std::sync::atomic::{AtomicBool, Ordering};
pub use std::time::Duration;

pub use std::thread;
pub use std::sync::mpsc;

describe! bounded_blocking_queue_test {

    before_each {
        const CAPACITY : usize = 16;
        let queue: BoundedBlockingQueue<i32> = BoundedBlockingQueue::with_capacity(CAPACITY);
    }

    it "should create a new queue with default capacity" {
        let queue: BoundedBlockingQueue<i32> = BoundedBlockingQueue::new();
        assert_eq!(queue.remaning_capacity(), 15);
    }

    it "should create a new empty queue" {
        assert!(queue.is_empty());
        assert_eq!(queue.size(), 0);
    }

    it "should have capacity that is always highest power of two minus one" {
        let queue: BoundedBlockingQueue<i32> = BoundedBlockingQueue::with_capacity(6);
        assert_eq!(queue.remaning_capacity(), 7);

        let queue: BoundedBlockingQueue<i32> = BoundedBlockingQueue::with_capacity(10);
        assert_eq!(queue.remaning_capacity(), 15);

        let queue: BoundedBlockingQueue<i32> = BoundedBlockingQueue::with_capacity(20);
        assert_eq!(queue.remaning_capacity(), 31);

        let queue: BoundedBlockingQueue<i32> = BoundedBlockingQueue::with_capacity(40);
        assert_eq!(queue.remaning_capacity(), 63);
    }

    it "should increase size when insert into queue" {
        let old_size = queue.size();
        queue.enqueue(1);

        assert_eq!(queue.size(), old_size + 1);
    }

    it "should contain value that was equeued" {
        queue.enqueue(1);

        assert!(queue.contains(1));
    }

    it "should contain values that were enqueued" {
        queue.enqueue(10);
        queue.enqueue(20);
        queue.enqueue(30);
        queue.enqueue(40);

        assert!(queue.contains(10));
        assert!(queue.contains(20));
        assert!(queue.contains(30));
        assert!(queue.contains(40));
    }

    it "should not contain value that was not enqueued" {
        assert!(!queue.contains(10));
    }

    it "should decrise size when remove from queue" {
        queue.enqueue(1);
        let old_size = queue.size();

        queue.dequeue();
        assert_eq!(queue.size(), old_size - 1);
    }

    it "should dequeue first enqueued value" {
        queue.enqueue(10);
        queue.enqueue(20);
        queue.enqueue(30);

        assert_eq!(queue.dequeue(), 10);
        assert_eq!(queue.dequeue(), 20);
        assert_eq!(queue.dequeue(), 30);
    }

    it "should insert offered value if queue not full" {
        assert!(queue.offer(1));
        assert!(queue.contains(1));
    }

    it "should peek first element but not delete" {
        queue.enqueue(1);
        queue.enqueue(2);
        queue.enqueue(3);

        assert_eq!(queue.peek(), Some(1));
        assert_eq!(queue.peek(), Some(1));
    }

    it "should calculate correct size when alot insertions and deletions" {
        let size = queue.size();
        for i in 1..8 {
            queue.enqueue(i);
            assert_eq!(queue.size(), size + (i as usize));
        }

        let size = queue.size();
        for i in 1..6 {
            queue.dequeue();
            assert_eq!(queue.size(), size - (i as usize));
        }

        let size = queue.size();
        for i in 1..8 {
            queue.enqueue(i);
            assert_eq!(queue.size(), size + (i as usize));
        }

        let size = queue.size();
        for i in 1..6 {
            queue.dequeue();
            assert_eq!(queue.size(), size - (i as usize));
        }

        let size = queue.size();
        for i in 1..8 {
            queue.enqueue(i);
            assert_eq!(queue.size(), size + (i as usize));
        }

        let size = queue.size();
        for i in 1..6 {
            queue.dequeue();
            assert_eq!(queue.size(), size - (i as usize));
        }

        let size = queue.size();
        for i in 1..8 {
            queue.enqueue(i);
            assert_eq!(queue.size(), size + (i as usize));
        }

        let size = queue.size();
        for i in 1..6 {
            queue.dequeue();
            assert_eq!(queue.size(), size - (i as usize));
        }
    }

    //FAILED test
    //some times threads get stuck
    /*
    it "should threads wait each other when queue is empty or full" {
        let arc = Arc::new(queue);
        let flag = Arc::new(AtomicBool::new(false));

        let data = arc.clone();
        let ready = flag.clone();
        let jh = thread::spawn(
            move || {
                let mut counter = 0;
                let mut sum = 0;
                while !data.is_empty() || !ready.load(Ordering::Relaxed) {
                    let datum = data.dequeue();
                    assert_eq!(datum, counter);
                    counter += 1;
                    sum += datum;
                }
                assert_eq!(sum, 4950);
            }
        );

        for i in 0..100 {
            arc.enqueue(i);
        }

        flag.store(true, Ordering::Relaxed);

        assert!(jh.join().is_ok());
    }
    */
}

describe! unbounded_blocking_queue_test {

    before_each {
        let mut queue = UnboundedBlockingQueue::new();
    }

    it "should create new empty unbounded queue" {
        assert_eq!(queue.size(), 0);
        assert!(queue.is_empty());
    }

    it "should increase queue size when enqueue value" {
        let old_size = queue.size();
        queue.enqueue(1);

        assert_eq!(queue.size(), old_size + 1);
    }

    it "should decrease queue size when dequeue value" {
        queue.enqueue(1);
        let old_size = queue.size();
        queue.dequeue();

        assert_eq!(queue.size(), old_size - 1);
    }

    it "should contain value that was enqueued" {
        queue.enqueue(1);
        assert!(queue.contains(1));
    }

    it "should contain values that were enqueued" {
        queue.enqueue(10);
        queue.enqueue(20);
        queue.enqueue(30);
        queue.enqueue(40);

        assert!(queue.contains(10));
        assert!(queue.contains(20));
        assert!(queue.contains(30));
        assert!(queue.contains(40));
    }

    it "should not contain value that was not enqueued" {
        assert!(!queue.contains(10));
    }
}
<|endoftext|>


<commit_before>#![cfg(feature = "compat")]

use matches::assert_matches;
use ruma_events::room::topic::{TopicEvent, TopicEventContent};
use serde_json::{from_value as from_json_value, json};

#[test]
fn deserialize_unsigned_prev_content() {
    let res = from_json_value::<TopicEvent>(json!({
        "content": {
            "topic": "New room topic",
        },
        "event_id": "$143273582443PhrSn:example.org",
        "origin_server_ts": 1432735824653_u64,
        "room_id": "!jEsUZKDJdhlrceRyVU:example.org",
        "sender": "@example:example.org",
        "state_key": "",
        "type": "m.room.topic",
        "unsigned": {
            "age": 1234,
            "prev_content": {
                "topic": "Old room topic",
            },
        },
    }));

    assert_matches!(
        res,
        Ok(TopicEvent {
            content: TopicEventContent { topic: new_topic, .. },
            prev_content: Some(TopicEventContent { topic: old_topic, .. }),
            ..
        }) if new_topic == "New room topic"
            && old_topic == "Old room topic"
    );
}
<commit_msg>events: Truly appease clippy<commit_after>#![cfg(feature = "compat")]

use matches::assert_matches;
use ruma_events::room::topic::{TopicEvent, TopicEventContent};
use serde_json::{from_value as from_json_value, json};

#[test]
fn deserialize_unsigned_prev_content() {
    let res = from_json_value::<TopicEvent>(json!({
        "content": {
            "topic": "New room topic",
        },
        "event_id": "$143273582443PhrSn:example.org",
        "origin_server_ts": 1_432_735_824_653_u64,
        "room_id": "!jEsUZKDJdhlrceRyVU:example.org",
        "sender": "@example:example.org",
        "state_key": "",
        "type": "m.room.topic",
        "unsigned": {
            "age": 1234,
            "prev_content": {
                "topic": "Old room topic",
            },
        },
    }));

    assert_matches!(
        res,
        Ok(TopicEvent {
            content: TopicEventContent { topic: new_topic, .. },
            prev_content: Some(TopicEventContent { topic: old_topic, .. }),
            ..
        }) if new_topic == "New room topic"
            && old_topic == "Old room topic"
    );
}
<|endoftext|>