<commit_before>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![unstable(feature = "reentrant_mutex", reason = "new API")]

use prelude::v1::*;

use fmt;
use marker;
use ops::Deref;
use sys_common::poison::{self, TryLockError, TryLockResult, LockResult};
use sys::mutex as sys;

/// A re-entrant mutual exclusion
///
/// This mutex will block *other* threads waiting for the lock to become
/// available. The thread which has already locked the mutex can lock it
/// multiple times without blocking, preventing a common source of deadlocks.
pub struct ReentrantMutex<T> {
    inner: Box<sys::ReentrantMutex>,
    poison: poison::Flag,
    data: T,
}

unsafe impl<T: Send> Send for ReentrantMutex<T> {}
unsafe impl<T: Send> Sync for ReentrantMutex<T> {}

/// An RAII implementation of a "scoped lock" of a mutex. When this structure is
/// dropped (falls out of scope), the lock will be unlocked.
///
/// The data protected by the mutex can be accessed through this guard via its
/// Deref and DerefMut implementations
#[must_use]
pub struct ReentrantMutexGuard<'a, T: 'a> {
    // funny underscores due to how Deref/DerefMut currently work (they
    // disregard field privacy).
    __lock: &'a ReentrantMutex<T>,
    __poison: poison::Guard,
}

impl<'a, T> !marker::Send for ReentrantMutexGuard<'a, T> {}

impl<T> ReentrantMutex<T> {
    /// Creates a new reentrant mutex in an unlocked state.
    pub fn new(t: T) -> ReentrantMutex<T> {
        unsafe {
            let mut mutex = ReentrantMutex {
                inner: box sys::ReentrantMutex::uninitialized(),
                poison: poison::Flag::new(),
                data: t,
            };
            mutex.inner.init();
            return mutex
        }
    }

    /// Acquires a mutex, blocking the current thread until it is able to do so.
    ///
    /// This function will block the caller until it is available to acquire the mutex.
    /// Upon returning, the thread is the only thread with the mutex held. When the thread
    /// calling this method already holds the lock, the call shall succeed without
    /// blocking.
    ///
    /// # Failure
    ///
    /// If another user of this mutex panicked while holding the mutex, then
    /// this call will return failure if the mutex would otherwise be
    /// acquired.
    pub fn lock(&self) -> LockResult<ReentrantMutexGuard<T>> {
        unsafe { self.inner.lock() }
        ReentrantMutexGuard::new(&self)
    }

    /// Attempts to acquire this lock.
    ///
    /// If the lock could not be acquired at this time, then `Err` is returned.
    /// Otherwise, an RAII guard is returned.
    ///
    /// This function does not block.
    ///
    /// # Failure
    ///
    /// If another user of this mutex panicked while holding the mutex, then
    /// this call will return failure if the mutex would otherwise be
    /// acquired.
    pub fn try_lock(&self) -> TryLockResult<ReentrantMutexGuard<T>> {
        if unsafe { self.inner.try_lock() } {
            Ok(try!(ReentrantMutexGuard::new(&self)))
        } else {
            Err(TryLockError::WouldBlock)
        }
    }
}

impl<T> Drop for ReentrantMutex<T> {
    fn drop(&mut self) {
        // This is actually safe b/c we know that there is no further usage of
        // this mutex (it's up to the user to arrange for a mutex to get
        // dropped, that's not our job)
        unsafe { self.inner.destroy() }
    }
}

impl<T: fmt::Debug + 'static> fmt::Debug for ReentrantMutex<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self.try_lock() {
            Ok(guard) => write!(f, "ReentrantMutex {{ data: {:?} }}", &*guard),
            Err(TryLockError::Poisoned(err)) => {
                write!(f, "ReentrantMutex {{ data: Poisoned({:?}) }}", &**err.get_ref())
            },
            Err(TryLockError::WouldBlock) => write!(f, "ReentrantMutex {{ <locked> }}")
        }
    }
}

impl<'mutex, T> ReentrantMutexGuard<'mutex, T> {
    fn new(lock: &'mutex ReentrantMutex<T>)
            -> LockResult<ReentrantMutexGuard<'mutex, T>> {
        poison::map_result(lock.poison.borrow(), |guard| {
            ReentrantMutexGuard {
                __lock: lock,
                __poison: guard,
            }
        })
    }
}

impl<'mutex, T> Deref for ReentrantMutexGuard<'mutex, T> {
    type Target = T;

    fn deref<'a>(&'a self) -> &'a T {
        &self.__lock.data
    }
}

impl<'a, T> Drop for ReentrantMutexGuard<'a, T> {
    #[inline]
    fn drop(&mut self) {
        unsafe {
            self.__lock.poison.done(&self.__poison);
            self.__lock.inner.unlock();
        }
    }
}

#[cfg(test)]
mod tests {
    use prelude::v1::*;
    use sys_common::remutex::{ReentrantMutex, ReentrantMutexGuard};
    use cell::RefCell;
    use sync::Arc;
    use boxed;
    use thread;

    #[test]
    fn smoke() {
        let m = ReentrantMutex::new(());
        {
            let a = m.lock().unwrap();
            {
                let b = m.lock().unwrap();
                {
                    let c = m.lock().unwrap();
                    assert_eq!(*c, ());
                }
                assert_eq!(*b, ());
            }
            assert_eq!(*a, ());
        }
    }

    #[test]
    fn is_mutex() {
        let m = ReentrantMutex::new(RefCell::new(0));
        let lock = m.lock().unwrap();
        let handle = thread::scoped(|| {
            let lock = m.lock().unwrap();
            assert_eq!(*lock.borrow(), 4950);
        });
        for i in 0..100 {
            let lock = m.lock().unwrap();
            *lock.borrow_mut() += i;
        }
        drop(lock);
        drop(handle);
    }

    #[test]
    fn trylock_works() {
        let m = ReentrantMutex::new(());
        let lock = m.try_lock().unwrap();
        let lock2 = m.try_lock().unwrap();
        {
            thread::scoped(|| {
                let lock = m.try_lock();
                assert!(lock.is_err());
            });
        }
        let lock3 = m.try_lock().unwrap();
    }

    pub struct Answer<'a>(pub ReentrantMutexGuard<'a, RefCell<u32>>);
    impl<'a> Drop for Answer<'a> {
        fn drop(&mut self) {
            *self.0.borrow_mut() = 42;
        }
    }

    #[test]
    fn poison_works() {
        let m = Arc::new(ReentrantMutex::new(RefCell::new(0)));
        let mc = m.clone();
        let result = thread::spawn(move ||{
            let lock = mc.lock().unwrap();
            *lock.borrow_mut() = 1;
            let lock2 = mc.lock().unwrap();
            *lock.borrow_mut() = 2;
            let answer = Answer(lock2);
            panic!("What the answer to my lifetimes dilemma is?");
            drop(answer);
        }).join();
        assert!(result.is_err());
        let r = m.lock().err().unwrap().into_inner();
        assert_eq!(*r.borrow(), 42);
    }
}
<commit_msg>Fix ReentrantMutex documentation wrt DerefMut<commit_after>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![unstable(feature = "reentrant_mutex", reason = "new API")]

use prelude::v1::*;

use fmt;
use marker;
use ops::Deref;
use sys_common::poison::{self, TryLockError, TryLockResult, LockResult};
use sys::mutex as sys;

/// A re-entrant mutual exclusion
///
/// This mutex will block *other* threads waiting for the lock to become
/// available. The thread which has already locked the mutex can lock it
/// multiple times without blocking, preventing a common source of deadlocks.
pub struct ReentrantMutex<T> {
    inner: Box<sys::ReentrantMutex>,
    poison: poison::Flag,
    data: T,
}

unsafe impl<T: Send> Send for ReentrantMutex<T> {}
unsafe impl<T: Send> Sync for ReentrantMutex<T> {}

/// An RAII implementation of a "scoped lock" of a mutex. When this structure is
/// dropped (falls out of scope), the lock will be unlocked.
///
/// The data protected by the mutex can be accessed through this guard via its
/// Deref implementation.
///
/// # Mutability
///
/// Unlike `MutexGuard`, `ReentrantMutexGuard` does not implement `DerefMut`,
/// because implementation of the trait would violate Rust’s reference aliasing
/// rules. Use interior mutability (usually `RefCell`) in order to mutate the
/// guarded data.
#[must_use]
pub struct ReentrantMutexGuard<'a, T: 'a> {
    // funny underscores due to how Deref currently works (it disregards field
    // privacy).
    __lock: &'a ReentrantMutex<T>,
    __poison: poison::Guard,
}

impl<'a, T> !marker::Send for ReentrantMutexGuard<'a, T> {}

impl<T> ReentrantMutex<T> {
    /// Creates a new reentrant mutex in an unlocked state.
    pub fn new(t: T) -> ReentrantMutex<T> {
        unsafe {
            let mut mutex = ReentrantMutex {
                inner: box sys::ReentrantMutex::uninitialized(),
                poison: poison::Flag::new(),
                data: t,
            };
            mutex.inner.init();
            return mutex
        }
    }

    /// Acquires a mutex, blocking the current thread until it is able to do so.
    ///
    /// This function will block the caller until it is available to acquire the mutex.
    /// Upon returning, the thread is the only thread with the mutex held. When the thread
    /// calling this method already holds the lock, the call shall succeed without
    /// blocking.
    ///
    /// # Failure
    ///
    /// If another user of this mutex panicked while holding the mutex, then
    /// this call will return failure if the mutex would otherwise be
    /// acquired.
    pub fn lock(&self) -> LockResult<ReentrantMutexGuard<T>> {
        unsafe { self.inner.lock() }
        ReentrantMutexGuard::new(&self)
    }

    /// Attempts to acquire this lock.
    ///
    /// If the lock could not be acquired at this time, then `Err` is returned.
    /// Otherwise, an RAII guard is returned.
    ///
    /// This function does not block.
    ///
    /// # Failure
    ///
    /// If another user of this mutex panicked while holding the mutex, then
    /// this call will return failure if the mutex would otherwise be
    /// acquired.
    pub fn try_lock(&self) -> TryLockResult<ReentrantMutexGuard<T>> {
        if unsafe { self.inner.try_lock() } {
            Ok(try!(ReentrantMutexGuard::new(&self)))
        } else {
            Err(TryLockError::WouldBlock)
        }
    }
}

impl<T> Drop for ReentrantMutex<T> {
    fn drop(&mut self) {
        // This is actually safe b/c we know that there is no further usage of
        // this mutex (it's up to the user to arrange for a mutex to get
        // dropped, that's not our job)
        unsafe { self.inner.destroy() }
    }
}

impl<T: fmt::Debug + 'static> fmt::Debug for ReentrantMutex<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self.try_lock() {
            Ok(guard) => write!(f, "ReentrantMutex {{ data: {:?} }}", &*guard),
            Err(TryLockError::Poisoned(err)) => {
                write!(f, "ReentrantMutex {{ data: Poisoned({:?}) }}", &**err.get_ref())
            },
            Err(TryLockError::WouldBlock) => write!(f, "ReentrantMutex {{ <locked> }}")
        }
    }
}

impl<'mutex, T> ReentrantMutexGuard<'mutex, T> {
    fn new(lock: &'mutex ReentrantMutex<T>)
            -> LockResult<ReentrantMutexGuard<'mutex, T>> {
        poison::map_result(lock.poison.borrow(), |guard| {
            ReentrantMutexGuard {
                __lock: lock,
                __poison: guard,
            }
        })
    }
}

impl<'mutex, T> Deref for ReentrantMutexGuard<'mutex, T> {
    type Target = T;

    fn deref<'a>(&'a self) -> &'a T {
        &self.__lock.data
    }
}

impl<'a, T> Drop for ReentrantMutexGuard<'a, T> {
    #[inline]
    fn drop(&mut self) {
        unsafe {
            self.__lock.poison.done(&self.__poison);
            self.__lock.inner.unlock();
        }
    }
}

#[cfg(test)]
mod tests {
    use prelude::v1::*;
    use sys_common::remutex::{ReentrantMutex, ReentrantMutexGuard};
    use cell::RefCell;
    use sync::Arc;
    use boxed;
    use thread;

    #[test]
    fn smoke() {
        let m = ReentrantMutex::new(());
        {
            let a = m.lock().unwrap();
            {
                let b = m.lock().unwrap();
                {
                    let c = m.lock().unwrap();
                    assert_eq!(*c, ());
                }
                assert_eq!(*b, ());
            }
            assert_eq!(*a, ());
        }
    }

    #[test]
    fn is_mutex() {
        let m = ReentrantMutex::new(RefCell::new(0));
        let lock = m.lock().unwrap();
        let handle = thread::scoped(|| {
            let lock = m.lock().unwrap();
            assert_eq!(*lock.borrow(), 4950);
        });
        for i in 0..100 {
            let lock = m.lock().unwrap();
            *lock.borrow_mut() += i;
        }
        drop(lock);
        drop(handle);
    }

    #[test]
    fn trylock_works() {
        let m = ReentrantMutex::new(());
        let lock = m.try_lock().unwrap();
        let lock2 = m.try_lock().unwrap();
        {
            thread::scoped(|| {
                let lock = m.try_lock();
                assert!(lock.is_err());
            });
        }
        let lock3 = m.try_lock().unwrap();
    }

    pub struct Answer<'a>(pub ReentrantMutexGuard<'a, RefCell<u32>>);
    impl<'a> Drop for Answer<'a> {
        fn drop(&mut self) {
            *self.0.borrow_mut() = 42;
        }
    }

    #[test]
    fn poison_works() {
        let m = Arc::new(ReentrantMutex::new(RefCell::new(0)));
        let mc = m.clone();
        let result = thread::spawn(move ||{
            let lock = mc.lock().unwrap();
            *lock.borrow_mut() = 1;
            let lock2 = mc.lock().unwrap();
            *lock.borrow_mut() = 2;
            let answer = Answer(lock2);
            panic!("What the answer to my lifetimes dilemma is?");
            drop(answer);
        }).join();
        assert!(result.is_err());
        let r = m.lock().err().unwrap().into_inner();
        assert_eq!(*r.borrow(), 42);
    }
}
<|endoftext|>


<commit_before>use imgui::{Ui};
use lichen::parse::Env;

pub struct AppState {
    pub exit: bool,
    pub open_file: bool,
    pub env: Option<Env>,
}
impl Default for AppState {
    fn default() -> Self {
        AppState {
            exit: false,
            open_file: true,
            env: None,
        }
    }
}

impl AppState {
    pub fn render (&mut self, ui: &Ui) {
        ui.main_menu_bar(|| {
            ui.menu(im_str!("File"))
                .build(|| {
                    ui.menu_item(im_str!("Open"))
                        .selected(&mut self.open_file)
                        .build();

                    ui.menu_item(im_str!("Exit"))
                        .selected(&mut self.exit)
                        .build();
                });
        });

        if let Some(ref env) = self.env {
            ui.window(im_str!("Environment Parsed"))
                .build(||{
                    ui.text(im_str!("Def Blocks"));
                    ui.separator();

                    for def in env.def.keys() {
                        ui.text(im_str!("{:?}",def));
                    }

                    ui.separator();
                    ui.separator();

                    ui.text(im_str!("Src Blocks"));
                    ui.separator();

                    for src in env.src.keys() {
                        ui.text(im_str!("{:?}",src));
                    }
                });
        }
    }
}
<commit_msg>display src data<commit_after>use imgui::{Ui,ImGuiSetCond_Once};
use lichen::parse::Env;

pub struct AppState {
    pub exit: bool,
    pub open_file: bool,
    pub env: Option<Env>,
}
impl Default for AppState {
    fn default() -> Self {
        AppState {
            exit: false,
            open_file: true,
            env: None,
        }
    }
}

impl AppState {
    pub fn render (&mut self, ui: &Ui) {
        ui.main_menu_bar(|| {
            ui.menu(im_str!("File"))
                .build(|| {
                    ui.menu_item(im_str!("Open"))
                        .selected(&mut self.open_file)
                        .build();

                    ui.menu_item(im_str!("Exit"))
                        .selected(&mut self.exit)
                        .build();
                });
        });

        if let Some(ref env) = self.env {
            ui.window(im_str!("Environment Parsed"))
                .build(||{
                    ui.tree_node(im_str!("Def Blocks"))
                        .opened(true, ImGuiSetCond_Once)
                        .build(|| {
                            for k in env.def.keys() {
                                if ui.collapsing_header(im_str!("{:?}",k))
                                    .build() {
                                        let block = env.def.get(k).unwrap();
                                        for (k,v) in block.def.iter() {
                                            let info = im_str!("{:}: {:?}",k,v);
                                            if ui.small_button(info) {

                                            }
                                        }
                                    }
                            }
                        });

                    ui.tree_node(im_str!("Src Blocks"))
                        .opened(true, ImGuiSetCond_Once)
                        .build(|| {
                            for k in env.src.keys() {
                                if ui.collapsing_header(im_str!("{:?}",k))
                                    .build() {
                                        let block = env.src.get(k).unwrap();
                                        for src in block.src.iter() {
                                            let info = im_str!("{:?}",src);
                                            if ui.small_button(info) {

                                            }
                                        }
                                    }
                            }
                        });
                });

        }

    }
}
<|endoftext|>


<commit_before>use std::cell::RefCell;
use std::collections::HashMap;
use std::io::{BufferedReader, BufferedWriter, IoResult, TcpStream};
use {Bot, process};
use conn::Connection;
use data::{Config, IrcReader, IrcWriter, Message};

pub struct IrcBot<'a, T, U> where T: IrcWriter, U: IrcReader {
    pub conn: Connection<T, U>,
    pub config: Config,
    process: RefCell<|&IrcBot<T, U>, &str, &str, &[&str]|:'a -> IoResult<()>>,
    pub chanlists: RefCell<HashMap<String, Vec<String>>>,
}

impl<'a> IrcBot<'a, BufferedWriter<TcpStream>, BufferedReader<TcpStream>> {
    pub fn new(process: |&IrcBot<BufferedWriter<TcpStream>, BufferedReader<TcpStream>>, &str, &str, &[&str]|:'a -> IoResult<()>) -> IoResult<IrcBot<'a, BufferedWriter<TcpStream>, BufferedReader<TcpStream>>> {
        let config = try!(Config::load());
        let conn = try!(Connection::connect(config.server.as_slice(), config.port));
        Ok(IrcBot {
            conn: conn,
            config: config,
            process: RefCell::new(process),
            chanlists: RefCell::new(HashMap::new()),
        })
    }
}

impl<'a, T, U> Bot<'a> for IrcBot<'a, T, U> where T: IrcWriter, U: IrcReader {
    fn send_nick(&self, nick: &str) -> IoResult<()> {
        self.conn.send(Message::new(None, "NICK", [nick]))
    }

    fn send_user(&self, username: &str, real_name: &str) -> IoResult<()> {
        self.conn.send(Message::new(None, "USER", [username, "0", "*", real_name]))
    }

    fn send_join(&self, chan: &str) -> IoResult<()> {
        self.conn.send(Message::new(None, "JOIN", [chan.as_slice()]))
    }

    fn send_mode(&self, chan: &str, mode: &str) -> IoResult<()> {
        self.conn.send(Message::new(None, "MODE", [chan.as_slice(), mode.as_slice()]))
    }

    fn send_topic(&self, chan: &str, topic: &str) -> IoResult<()> {
        self.conn.send(Message::new(None, "TOPIC", [chan.as_slice(), topic.as_slice()]))
    }

    fn send_invite(&self, person: &str, chan: &str) -> IoResult<()> {
        self.conn.send(Message::new(None, "INVITE", [person.as_slice(), chan.as_slice()]))
    }

    fn send_privmsg(&self, chan: &str, msg: &str) -> IoResult<()> {
        self.conn.send(Message::new(None, "PRIVMSG", [chan.as_slice(), msg.as_slice()]))
    }

    fn identify(&self) -> IoResult<()> {
        try!(self.send_nick(self.config.nickname.as_slice()));
        self.send_user(self.config.username.as_slice(), self.config.realname.as_slice())
    }

    fn output(&mut self) -> IoResult<()> {
        let mut reader = self.conn.reader();
        for line in reader.lines() {
            match line {
                Ok(ln) => {
                    let (source, command, args) = try!(process(ln.as_slice()));
                    try!(self.handle_command(source, command, args.as_slice()));
                    println!("{}", ln)
                },
                Err(e) => {
                    println!("Shit, you're fucked! {}", e);
                    return Err(e)
                },
            }
        }
        Ok(())
    }

    fn config(&self) -> &Config {
        &self.config
    }
}

impl<'a, T, U> IrcBot<'a, T, U> where T: IrcWriter, U: IrcReader {
    pub fn from_connection(conn: Connection<T, U>, process: |&IrcBot<T, U>, &str, &str, &[&str]|:'a -> IoResult<()>) -> IoResult<IrcBot<'a, T, U>> {
        Ok(IrcBot {
            conn: conn,
            config: try!(Config::load()),
            process: RefCell::new(process),
            chanlists: RefCell::new(HashMap::new()),
        })
    }

    fn handle_command(&self, source: &str, command: &str, args: &[&str]) -> IoResult<()> {
        match (command, args) {
            ("PING", [msg]) => {
                try!(self.conn.send(Message::new(None, "PONG", [msg])));
            },
            ("376", _) => { // End of MOTD
                for chan in self.config.channels.iter() {
                    try!(self.send_join(chan.as_slice()));
                }
            },
            ("422", _) => { // Missing MOTD
                for chan in self.config.channels.iter() {
                    try!(self.send_join(chan.as_slice()));
                }
            },
            ("353", [_, _, chan, users]) => { // /NAMES
                for user in users.split_str(" ") {
                    if !match self.chanlists.borrow_mut().find_mut(&String::from_str(chan)) {
                        Some(vec) => {
                            vec.push(String::from_str(user));
                            true
                        },
                        None => false,
                    } {
                        self.chanlists.borrow_mut().insert(String::from_str(chan), vec!(String::from_str(user)));
                    }
                }
            },
            ("JOIN", [chan]) => {
                match self.chanlists.borrow_mut().find_mut(&String::from_str(chan)) {
                    Some(vec) => {
                        match source.find('!') {
                            Some(i) => vec.push(String::from_str(source.slice_to(i))),
                            None => (),
                        };
                    },
                    None => (),
                }
            },
            ("PART", [chan, _]) => {
                match self.chanlists.borrow_mut().find_mut(&String::from_str(chan)) {
                    Some(vec) => {
                        match source.find('!') {
                            Some(i) => {
                                match vec.as_slice().position_elem(&String::from_str(source.slice_to(i))) {
                                    Some(n) => {
                                        vec.swap_remove(n);
                                    },
                                    None => (),
                                };
                            },
                            None => (),
                        };
                    },
                    None => (),
                }
            },
            _ => {
                try!((*self.process.borrow_mut().deref_mut())(self, source, command, args));
            },
        };
        Ok(())
    }
}

#[cfg(test)]
mod test {
    use Bot;
    use super::IrcBot;
    use std::io::{BufReader, MemWriter};
    use std::io::util::NullReader;
    use conn::Connection;

    #[test]
    fn from_connection() {
        let w = MemWriter::new();
        let c = Connection::new(w, NullReader).unwrap();
        assert!(IrcBot::from_connection(c, |_, _, _, _| { Ok(()) }).is_ok());
    }

    #[test]
    fn send_nick() {
        let w = MemWriter::new();
        let c = Connection::new(w, NullReader).unwrap();
        let b = IrcBot::from_connection(c, |_, _, _, _| { Ok(()) }).unwrap();
        b.send_nick("test").unwrap();
        assert_eq!(b.conn.writer().deref_mut().get_ref(), "NICK :test\r\n".as_bytes());
    }

    #[test]
    fn send_user() {
        let w = MemWriter::new();
        let c = Connection::new(w, NullReader).unwrap();
        let b = IrcBot::from_connection(c, |_, _, _, _| { Ok(()) }).unwrap();
        b.send_user("test", "Test").unwrap();
        assert_eq!(b.conn.writer().deref_mut().get_ref(), "USER test 0 * :Test\r\n".as_bytes());
    }

    #[test]
    fn send_join() {
        let w = MemWriter::new();
        let c = Connection::new(w, NullReader).unwrap();
        let b = IrcBot::from_connection(c, |_, _, _, _| { Ok(()) }).unwrap();
        b.send_join("#test").unwrap();
        assert_eq!(b.conn.writer().deref_mut().get_ref(), "JOIN :#test\r\n".as_bytes());
    }

    #[test]
    fn send_mode() {
        let w = MemWriter::new();
        let c = Connection::new(w, NullReader).unwrap();
        let b = IrcBot::from_connection(c, |_, _, _, _| { Ok(()) }).unwrap();
        b.send_mode("#test", "+i").unwrap();
        assert_eq!(b.conn.writer().deref_mut().get_ref(), "MODE #test :+i\r\n".as_bytes());
    }

    #[test]
    fn send_topic() {
        let w = MemWriter::new();
        let c = Connection::new(w, NullReader).unwrap();
        let b = IrcBot::from_connection(c, |_, _, _, _| { Ok(()) }).unwrap();
        b.send_topic("#test", "This is a test topic.").unwrap();
        assert_eq!(b.conn.writer().deref_mut().get_ref(), "TOPIC #test :This is a test topic.\r\n".as_bytes());
    }

    #[test]
    fn send_invite() {
        let w = MemWriter::new();
        let c = Connection::new(w, NullReader).unwrap();
        let b = IrcBot::from_connection(c, |_, _, _, _| { Ok(()) }).unwrap();
        b.send_invite("test2", "#test").unwrap();
        assert_eq!(b.conn.writer().deref_mut().get_ref(), "INVITE test2 :#test\r\n".as_bytes());
    }

    #[test]
    fn send_privmsg() {
        let w = MemWriter::new();
        let c = Connection::new(w, NullReader).unwrap();
        let b = IrcBot::from_connection(c, |_, _, _, _| { Ok(()) }).unwrap();
        b.send_privmsg("#test", "This is a test message.").unwrap();
        assert_eq!(b.conn.writer().deref_mut().get_ref(), "PRIVMSG #test :This is a test message.\r\n".as_bytes());
    }

    #[test]
    fn identify() {
        let w = MemWriter::new();
        let c = Connection::new(w, NullReader).unwrap();
        let b = IrcBot::from_connection(c, |_, _, _, _| { Ok(()) }).unwrap();
        b.identify().unwrap();
        assert_eq!(b.conn.writer().deref_mut().get_ref(), "NICK :test\r\nUSER test 0 * :test\r\n".as_bytes());
    }

    #[test]
    fn ping_response() {
        let r = BufReader::new(":embyr.tx.us.fyrechat.net PING :01R6\r\n".as_bytes());
        let w = MemWriter::new();
        let c = Connection::new(w, r).unwrap();
        let mut b = IrcBot::from_connection(c, |_, _, _, _| { Ok(()) }).unwrap();
        b.output().unwrap();
        assert_eq!(b.conn.writer().deref_mut().get_ref(), "PONG :01R6\r\n".as_bytes());
    }

    #[test]
    fn end_of_motd_response() {
        let r = BufReader::new(":embyr.tx.us.fyrechat.net 376 test :End of /MOTD command.\r\n".as_bytes());
        let w = MemWriter::new();
        let c = Connection::new(w, r).unwrap();
        let mut b = IrcBot::from_connection(c, |_, _, _, _| { Ok(()) }).unwrap();
        b.output().unwrap();
        assert_eq!(b.conn.writer().deref_mut().get_ref(), "JOIN :#test\r\nJOIN :#test2\r\n".as_bytes());
    }

    #[test]
    fn missing_motd_response() {
        let r = BufReader::new(":flare.to.ca.fyrechat.net 422 pickles :MOTD File is missing\r\n".as_bytes());
        let w = MemWriter::new();
        let c = Connection::new(w, r).unwrap();
        let mut b = IrcBot::from_connection(c, |_, _, _, _| { Ok(()) }).unwrap();
        b.output().unwrap();
        assert_eq!(b.conn.writer().deref_mut().get_ref(), "JOIN :#test\r\nJOIN :#test2\r\n".as_bytes());
    }

    #[test]
    fn generate_user_list() {
        let r = BufReader::new(":flare.to.ca.fyrechat.net 353 test @ #test :test test2 test3\r\n".as_bytes());
        let w = MemWriter::new();
        let c = Connection::new(w, r).unwrap();
        let mut b = IrcBot::from_connection(c, |_, _, _, _| { Ok(()) }).unwrap();
        b.output().unwrap();
        let vec_res = match b.chanlists.borrow_mut().find_mut(&String::from_str("#test")) {
                Some(v) => Ok(v.clone()),
                None => Err("Could not find vec for channel."),
        };
        assert!(vec_res.is_ok());
        let vec = vec_res.unwrap();
        assert_eq!(vec, vec![String::from_str("test"), String::from_str("test2"), String::from_str("test3")]);
    }

    #[test]
    fn add_to_user_list() {
        let r = BufReader::new(":flare.to.ca.fyrechat.net 353 test @ #test :test test2\r\n:test3!test@test JOIN :#test\r\n".as_bytes());
        let w = MemWriter::new();
        let c = Connection::new(w, r).unwrap();
        let mut b = IrcBot::from_connection(c, |_, _, _, _| { Ok(()) }).unwrap();
        b.output().unwrap();
        let vec_res = match b.chanlists.borrow_mut().find_mut(&String::from_str("#test")) {
                Some(v) => Ok(v.clone()),
                None => Err("Could not find vec for channel."),
        };
        assert!(vec_res.is_ok());
        let vec = vec_res.unwrap();
        assert_eq!(vec, vec![String::from_str("test"), String::from_str("test2"), String::from_str("test3")]);
    }

    #[test]
    fn remove_from_user_list() {
        let r = BufReader::new(":flare.to.ca.fyrechat.net 353 test @ #test :test test2 test3\r\n:test3!test@test PART #test :\r\n".as_bytes());
        let w = MemWriter::new();
        let c = Connection::new(w, r).unwrap();
        let mut b = IrcBot::from_connection(c, |_, _, _, _| { Ok(()) }).unwrap();
        b.output().unwrap();
        let vec_res = match b.chanlists.borrow_mut().find_mut(&String::from_str("#test")) {
                Some(v) => Ok(v.clone()),
                None => Err("Could not find vec for channel."),
        };
        assert!(vec_res.is_ok());
        let vec = vec_res.unwrap();
        // n.b. ordering is not guaranteed, this only ought to hold because we're removing the last user
        assert_eq!(vec, vec![String::from_str("test"), String::from_str("test2")]);
    }
}
<commit_msg>Simplified bot unit tests where possible.<commit_after>use std::cell::RefCell;
use std::collections::HashMap;
use std::io::{BufferedReader, BufferedWriter, IoResult, TcpStream};
use {Bot, process};
use conn::Connection;
use data::{Config, IrcReader, IrcWriter, Message};

pub struct IrcBot<'a, T, U> where T: IrcWriter, U: IrcReader {
    pub conn: Connection<T, U>,
    pub config: Config,
    process: RefCell<|&IrcBot<T, U>, &str, &str, &[&str]|:'a -> IoResult<()>>,
    pub chanlists: RefCell<HashMap<String, Vec<String>>>,
}

impl<'a> IrcBot<'a, BufferedWriter<TcpStream>, BufferedReader<TcpStream>> {
    pub fn new(process: |&IrcBot<BufferedWriter<TcpStream>, BufferedReader<TcpStream>>, &str, &str, &[&str]|:'a -> IoResult<()>) -> IoResult<IrcBot<'a, BufferedWriter<TcpStream>, BufferedReader<TcpStream>>> {
        let config = try!(Config::load());
        let conn = try!(Connection::connect(config.server.as_slice(), config.port));
        Ok(IrcBot {
            conn: conn,
            config: config,
            process: RefCell::new(process),
            chanlists: RefCell::new(HashMap::new()),
        })
    }
}

impl<'a, T, U> Bot<'a> for IrcBot<'a, T, U> where T: IrcWriter, U: IrcReader {
    fn send_nick(&self, nick: &str) -> IoResult<()> {
        self.conn.send(Message::new(None, "NICK", [nick]))
    }

    fn send_user(&self, username: &str, real_name: &str) -> IoResult<()> {
        self.conn.send(Message::new(None, "USER", [username, "0", "*", real_name]))
    }

    fn send_join(&self, chan: &str) -> IoResult<()> {
        self.conn.send(Message::new(None, "JOIN", [chan.as_slice()]))
    }

    fn send_mode(&self, chan: &str, mode: &str) -> IoResult<()> {
        self.conn.send(Message::new(None, "MODE", [chan.as_slice(), mode.as_slice()]))
    }

    fn send_topic(&self, chan: &str, topic: &str) -> IoResult<()> {
        self.conn.send(Message::new(None, "TOPIC", [chan.as_slice(), topic.as_slice()]))
    }

    fn send_invite(&self, person: &str, chan: &str) -> IoResult<()> {
        self.conn.send(Message::new(None, "INVITE", [person.as_slice(), chan.as_slice()]))
    }

    fn send_privmsg(&self, chan: &str, msg: &str) -> IoResult<()> {
        self.conn.send(Message::new(None, "PRIVMSG", [chan.as_slice(), msg.as_slice()]))
    }

    fn identify(&self) -> IoResult<()> {
        try!(self.send_nick(self.config.nickname.as_slice()));
        self.send_user(self.config.username.as_slice(), self.config.realname.as_slice())
    }

    fn output(&mut self) -> IoResult<()> {
        let mut reader = self.conn.reader();
        for line in reader.lines() {
            match line {
                Ok(ln) => {
                    let (source, command, args) = try!(process(ln.as_slice()));
                    try!(self.handle_command(source, command, args.as_slice()));
                    println!("{}", ln)
                },
                Err(e) => {
                    println!("Shit, you're fucked! {}", e);
                    return Err(e)
                },
            }
        }
        Ok(())
    }

    fn config(&self) -> &Config {
        &self.config
    }
}

impl<'a, T, U> IrcBot<'a, T, U> where T: IrcWriter, U: IrcReader {
    pub fn from_connection(conn: Connection<T, U>, process: |&IrcBot<T, U>, &str, &str, &[&str]|:'a -> IoResult<()>) -> IoResult<IrcBot<'a, T, U>> {
        Ok(IrcBot {
            conn: conn,
            config: try!(Config::load()),
            process: RefCell::new(process),
            chanlists: RefCell::new(HashMap::new()),
        })
    }

    fn handle_command(&self, source: &str, command: &str, args: &[&str]) -> IoResult<()> {
        match (command, args) {
            ("PING", [msg]) => {
                try!(self.conn.send(Message::new(None, "PONG", [msg])));
            },
            ("376", _) => { // End of MOTD
                for chan in self.config.channels.iter() {
                    try!(self.send_join(chan.as_slice()));
                }
            },
            ("422", _) => { // Missing MOTD
                for chan in self.config.channels.iter() {
                    try!(self.send_join(chan.as_slice()));
                }
            },
            ("353", [_, _, chan, users]) => { // /NAMES
                for user in users.split_str(" ") {
                    if !match self.chanlists.borrow_mut().find_mut(&String::from_str(chan)) {
                        Some(vec) => {
                            vec.push(String::from_str(user));
                            true
                        },
                        None => false,
                    } {
                        self.chanlists.borrow_mut().insert(String::from_str(chan), vec!(String::from_str(user)));
                    }
                }
            },
            ("JOIN", [chan]) => {
                match self.chanlists.borrow_mut().find_mut(&String::from_str(chan)) {
                    Some(vec) => {
                        match source.find('!') {
                            Some(i) => vec.push(String::from_str(source.slice_to(i))),
                            None => (),
                        };
                    },
                    None => (),
                }
            },
            ("PART", [chan, _]) => {
                match self.chanlists.borrow_mut().find_mut(&String::from_str(chan)) {
                    Some(vec) => {
                        match source.find('!') {
                            Some(i) => {
                                match vec.as_slice().position_elem(&String::from_str(source.slice_to(i))) {
                                    Some(n) => {
                                        vec.swap_remove(n);
                                    },
                                    None => (),
                                };
                            },
                            None => (),
                        };
                    },
                    None => (),
                }
            },
            _ => {
                try!((*self.process.borrow_mut().deref_mut())(self, source, command, args));
            },
        };
        Ok(())
    }
}

#[cfg(test)]
mod test {
    use Bot;
    use super::IrcBot;
    use std::io::{BufReader, MemWriter};
    use std::io::util::{NullReader, NullWriter};
    use conn::Connection;

    #[test]
    fn from_connection() {
        let c = Connection::new(MemWriter::new(), NullReader).unwrap();
        assert!(IrcBot::from_connection(c, |_, _, _, _| { Ok(()) }).is_ok());
    }

    #[test]
    fn send_nick() {
        let c = Connection::new(MemWriter::new(), NullReader).unwrap();
        let b = IrcBot::from_connection(c, |_, _, _, _| { Ok(()) }).unwrap();
        b.send_nick("test").unwrap();
        assert_eq!(b.conn.writer().deref_mut().get_ref(), "NICK :test\r\n".as_bytes());
    }

    #[test]
    fn send_user() {
        let c = Connection::new(MemWriter::new(), NullReader).unwrap();
        let b = IrcBot::from_connection(c, |_, _, _, _| { Ok(()) }).unwrap();
        b.send_user("test", "Test").unwrap();
        assert_eq!(b.conn.writer().deref_mut().get_ref(), "USER test 0 * :Test\r\n".as_bytes());
    }

    #[test]
    fn send_join() {
        let c = Connection::new(MemWriter::new(), NullReader).unwrap();
        let b = IrcBot::from_connection(c, |_, _, _, _| { Ok(()) }).unwrap();
        b.send_join("#test").unwrap();
        assert_eq!(b.conn.writer().deref_mut().get_ref(), "JOIN :#test\r\n".as_bytes());
    }

    #[test]
    fn send_mode() {
        let c = Connection::new(MemWriter::new(), NullReader).unwrap();
        let b = IrcBot::from_connection(c, |_, _, _, _| { Ok(()) }).unwrap();
        b.send_mode("#test", "+i").unwrap();
        assert_eq!(b.conn.writer().deref_mut().get_ref(), "MODE #test :+i\r\n".as_bytes());
    }

    #[test]
    fn send_topic() {
        let c = Connection::new(MemWriter::new(), NullReader).unwrap();
        let b = IrcBot::from_connection(c, |_, _, _, _| { Ok(()) }).unwrap();
        b.send_topic("#test", "This is a test topic.").unwrap();
        assert_eq!(b.conn.writer().deref_mut().get_ref(), "TOPIC #test :This is a test topic.\r\n".as_bytes());
    }

    #[test]
    fn send_invite() {
        let c = Connection::new(MemWriter::new(), NullReader).unwrap();
        let b = IrcBot::from_connection(c, |_, _, _, _| { Ok(()) }).unwrap();
        b.send_invite("test2", "#test").unwrap();
        assert_eq!(b.conn.writer().deref_mut().get_ref(), "INVITE test2 :#test\r\n".as_bytes());
    }

    #[test]
    fn send_privmsg() {
        let c = Connection::new(MemWriter::new(), NullReader).unwrap();
        let b = IrcBot::from_connection(c, |_, _, _, _| { Ok(()) }).unwrap();
        b.send_privmsg("#test", "This is a test message.").unwrap();
        assert_eq!(b.conn.writer().deref_mut().get_ref(), "PRIVMSG #test :This is a test message.\r\n".as_bytes());
    }

    #[test]
    fn identify() {
        let c = Connection::new(MemWriter::new(), NullReader).unwrap();
        let b = IrcBot::from_connection(c, |_, _, _, _| { Ok(()) }).unwrap();
        b.identify().unwrap();
        assert_eq!(b.conn.writer().deref_mut().get_ref(), "NICK :test\r\nUSER test 0 * :test\r\n".as_bytes());
    }

    #[test]
    fn ping_response() {
        let r = BufReader::new(":embyr.tx.us.fyrechat.net PING :01R6\r\n".as_bytes());
        let c = Connection::new(MemWriter::new(), r).unwrap();
        let mut b = IrcBot::from_connection(c, |_, _, _, _| { Ok(()) }).unwrap();
        b.output().unwrap();
        assert_eq!(b.conn.writer().deref_mut().get_ref(), "PONG :01R6\r\n".as_bytes());
    }

    #[test]
    fn end_of_motd_response() {
        let r = BufReader::new(":embyr.tx.us.fyrechat.net 376 test :End of /MOTD command.\r\n".as_bytes());
        let c = Connection::new(MemWriter::new(), r).unwrap();
        let mut b = IrcBot::from_connection(c, |_, _, _, _| { Ok(()) }).unwrap();
        b.output().unwrap();
        assert_eq!(b.conn.writer().deref_mut().get_ref(), "JOIN :#test\r\nJOIN :#test2\r\n".as_bytes());
    }

    #[test]
    fn missing_motd_response() {
        let r = BufReader::new(":flare.to.ca.fyrechat.net 422 pickles :MOTD File is missing\r\n".as_bytes());
        let c = Connection::new(MemWriter::new(), r).unwrap();
        let mut b = IrcBot::from_connection(c, |_, _, _, _| { Ok(()) }).unwrap();
        b.output().unwrap();
        assert_eq!(b.conn.writer().deref_mut().get_ref(), "JOIN :#test\r\nJOIN :#test2\r\n".as_bytes());
    }

    #[test]
    fn generate_user_list() {
        let r = BufReader::new(":flare.to.ca.fyrechat.net 353 test @ #test :test test2 test3\r\n".as_bytes());
        let c = Connection::new(NullWriter, r).unwrap();
        let mut b = IrcBot::from_connection(c, |_, _, _, _| { Ok(()) }).unwrap();
        b.output().unwrap();
        let vec_res = match b.chanlists.borrow_mut().find_mut(&String::from_str("#test")) {
                Some(v) => Ok(v.clone()),
                None => Err("Could not find vec for channel."),
        };
        assert!(vec_res.is_ok());
        let vec = vec_res.unwrap();
        assert_eq!(vec, vec![String::from_str("test"), String::from_str("test2"), String::from_str("test3")]);
    }

    #[test]
    fn add_to_user_list() {
        let r = BufReader::new(":flare.to.ca.fyrechat.net 353 test @ #test :test test2\r\n:test3!test@test JOIN :#test\r\n".as_bytes());
        let c = Connection::new(NullWriter, r).unwrap();
        let mut b = IrcBot::from_connection(c, |_, _, _, _| { Ok(()) }).unwrap();
        b.output().unwrap();
        let vec_res = match b.chanlists.borrow_mut().find_mut(&String::from_str("#test")) {
                Some(v) => Ok(v.clone()),
                None => Err("Could not find vec for channel."),
        };
        assert!(vec_res.is_ok());
        let vec = vec_res.unwrap();
        assert_eq!(vec, vec![String::from_str("test"), String::from_str("test2"), String::from_str("test3")]);
    }

    #[test]
    fn remove_from_user_list() {
        let r = BufReader::new(":flare.to.ca.fyrechat.net 353 test @ #test :test test2 test3\r\n:test3!test@test PART #test :\r\n".as_bytes());
        let c = Connection::new(NullWriter, r).unwrap();
        let mut b = IrcBot::from_connection(c, |_, _, _, _| { Ok(()) }).unwrap();
        b.output().unwrap();
        let vec_res = match b.chanlists.borrow_mut().find_mut(&String::from_str("#test")) {
                Some(v) => Ok(v.clone()),
                None => Err("Could not find vec for channel."),
        };
        assert!(vec_res.is_ok());
        let vec = vec_res.unwrap();
        // n.b. ordering is not guaranteed, this only ought to hold because we're removing the last user
        assert_eq!(vec, vec![String::from_str("test"), String::from_str("test2")]);
    }
}
<|endoftext|>


<commit_before>use std::fmt;

use indoc::formatdoc;

use super::{FormattedBody, MessageType, OriginalRoomMessageEvent};

pub fn get_plain_quote_fallback(original_message: &OriginalRoomMessageEvent) -> String {
    let sender = &original_message.sender;

    match &original_message.content.msgtype {
        MessageType::Audio(_) => {
            format!("> <{}> sent an audio file.", sender)
        }
        MessageType::Emote(content) => {
            format!("> * <{}> {}", sender, content.body)
        }
        MessageType::File(_) => {
            format!("> <{}> sent a file.", sender)
        }
        MessageType::Image(_) => {
            format!("> <{}> sent an image.", sender)
        }
        MessageType::Location(content) => {
            format!("> <{}> {}", sender, content.body)
        }
        MessageType::Notice(content) => {
            format!("> <{}> {}", sender, content.body)
        }
        MessageType::ServerNotice(content) => {
            format!("> <{}> {}", sender, content.body)
        }
        MessageType::Text(content) => {
            format!("> <{}> {}", sender, content.body)
        }
        MessageType::Video(_) => {
            format!("> <{}> sent a video.", sender)
        }
        MessageType::_Custom(content) => {
            format!("> <{}> {}", sender, content.body)
        }
        MessageType::VerificationRequest(content) => {
            format!("> <{}> {}", sender, content.body)
        }
    }
    .replace('\n', "\n> ")
}

#[allow(clippy::nonstandard_macro_braces)]
pub fn get_html_quote_fallback(original_message: &OriginalRoomMessageEvent) -> String {
    match &original_message.content.msgtype {
        MessageType::Audio(_) => {
            formatdoc!(
                "
                <mx-reply>

                        In reply to
                        {sender}

                        sent an audio file.

                </mx-reply>
                ",
                room_id = original_message.room_id,
                event_id = original_message.event_id,
                sender = original_message.sender,
            )
        }
        MessageType::Emote(content) => {
            formatdoc!(
                "
                <mx-reply>

                        In reply to
                        * {sender}

                        {body}

                </mx-reply>
                ",
                room_id = original_message.room_id,
                event_id = original_message.event_id,
                sender = original_message.sender,
                body = formatted_or_plain_body(&content.formatted, &content.body),
            )
        }
        MessageType::File(_) => {
            formatdoc!(
                "
                <mx-reply>

                        In reply to
                        {sender}

                        sent a file.

                </mx-reply>
                ",
                room_id = original_message.room_id,
                event_id = original_message.event_id,
                sender = original_message.sender,
            )
        }
        MessageType::Image(_) => {
            formatdoc!(
                "
                <mx-reply>

                        In reply to
                        {sender}

                        sent an image.

                </mx-reply>
                ",
                room_id = original_message.room_id,
                event_id = original_message.event_id,
                sender = original_message.sender,
            )
        }
        MessageType::Location(_) => {
            formatdoc!(
                "
                <mx-reply>

                        In reply to
                        {sender}

                        sent a location.

                </mx-reply>
                ",
                room_id = original_message.room_id,
                event_id = original_message.event_id,
                sender = original_message.sender,
            )
        }
        MessageType::Notice(content) => {
            formatdoc!(
                "
                <mx-reply>

                        In reply to
                        {sender}

                        {body}

                </mx-reply>
                ",
                room_id = original_message.room_id,
                event_id = original_message.event_id,
                sender = original_message.sender,
                body = formatted_or_plain_body(&content.formatted, &content.body),
            )
        }
        MessageType::ServerNotice(content) => {
            formatdoc!(
                "
                <mx-reply>

                        In reply to
                        {sender}

                        {body}

                </mx-reply>
                ",
                room_id = original_message.room_id,
                event_id = original_message.event_id,
                sender = original_message.sender,
                body = content.body,
            )
        }
        MessageType::Text(content) => {
            formatdoc!(
                "
                <mx-reply>

                        In reply to
                        {sender}

                        {body}

                </mx-reply>
                ",
                room_id = original_message.room_id,
                event_id = original_message.event_id,
                sender = original_message.sender,
                body = formatted_or_plain_body(&content.formatted, &content.body),
            )
        }
        MessageType::Video(_) => {
            formatdoc!(
                "
                <mx-reply>

                        In reply to
                        {sender}

                        sent a video.

                </mx-reply>
                ",
                room_id = original_message.room_id,
                event_id = original_message.event_id,
                sender = original_message.sender,
            )
        }
        MessageType::_Custom(content) => {
            formatdoc!(
                "
                <mx-reply>

                        In reply to
                        {sender}

                        {body}

                </mx-reply>
                ",
                room_id = original_message.room_id,
                event_id = original_message.event_id,
                sender = original_message.sender,
                body = content.body,
            )
        }
        MessageType::VerificationRequest(content) => {
            formatdoc!(
                "
                <mx-reply>

                        In reply to
                        {sender}

                        {body}

                </mx-reply>
                ",
                server_name = original_message.room_id,
                event_id = original_message.event_id,
                sender = original_message.sender,
                body = content.body,
            )
        }
    }
}

fn formatted_or_plain_body<'a>(formatted: &'a Option<FormattedBody>, body: &'a str) -> &'a str {
    if let Some(formatted_body) = formatted {
        &formatted_body.body
    } else {
        body
    }
}

/// Get the plain and formatted body for a rich reply.
///
/// Returns a `(plain, html)` tuple.
pub fn plain_and_formatted_reply_body(
    body: impl fmt::Display,
    formatted: Option<impl fmt::Display>,
    original_message: &OriginalRoomMessageEvent,
) -> (String, String) {
    let quoted = get_plain_quote_fallback(original_message);
    let quoted_html = get_html_quote_fallback(original_message);

    let plain = format!("{}\n\n{}", quoted, body);
    let html = if let Some(formatted) = formatted {
        format!("{}\n\n{}", quoted_html, formatted)
    } else {
        format!("{}\n\n{}", quoted_html, body)
    };

    (plain, html)
}

#[cfg(test)]
mod tests {
    use crate::{
        event_id,
        events::{room::message::RoomMessageEventContent, MessageLikeUnsigned},
        room_id, user_id, MilliSecondsSinceUnixEpoch,
    };

    use super::OriginalRoomMessageEvent;

    #[test]
    fn plain_quote_fallback_multiline() {
        assert_eq!(
            super::get_plain_quote_fallback(&OriginalRoomMessageEvent {
                content: RoomMessageEventContent::text_plain("multi\nline"),
                event_id: event_id!("$1598361704261elfgc:localhost").to_owned(),
                sender: user_id!("@alice:example.com").to_owned(),
                origin_server_ts: MilliSecondsSinceUnixEpoch::now(),
                room_id: room_id!("!n8f893n9:example.com").to_owned(),
                unsigned: MessageLikeUnsigned::new(),
            }),
            "> <@alice:example.com> multi\n> line"
        );
    }
}
<commit_msg>events: Refactor reply code<commit_after>use std::fmt;

use indoc::formatdoc;

use super::{FormattedBody, MessageType, OriginalRoomMessageEvent};

pub fn get_message_quote_fallbacks(
    original_message: &OriginalRoomMessageEvent,
) -> (String, String) {
    match &original_message.content.msgtype {
        MessageType::Audio(_) => get_quotes("sent an audio file.", None, original_message, false),
        MessageType::Emote(content) => {
            get_quotes(&content.body, content.formatted.as_ref(), original_message, true)
        }
        MessageType::File(_) => get_quotes("sent a file.", None, original_message, false),
        MessageType::Image(_) => get_quotes("sent an image.", None, original_message, false),
        MessageType::Location(_) => get_quotes("sent a location.", None, original_message, false),
        MessageType::Notice(content) => {
            get_quotes(&content.body, content.formatted.as_ref(), original_message, false)
        }
        MessageType::ServerNotice(content) => {
            get_quotes(&content.body, None, original_message, false)
        }
        MessageType::Text(content) => {
            get_quotes(&content.body, content.formatted.as_ref(), original_message, false)
        }
        MessageType::Video(_) => get_quotes("sent a video.", None, original_message, false),
        MessageType::_Custom(content) => get_quotes(&content.body, None, original_message, false),
        MessageType::VerificationRequest(content) => {
            get_quotes(&content.body, None, original_message, false)
        }
    }
}

fn get_quotes(
    body: &str,
    formatted: Option<&FormattedBody>,
    original_message: &OriginalRoomMessageEvent,
    is_emote: bool,
) -> (String, String) {
    let OriginalRoomMessageEvent { room_id, event_id, sender, .. } = original_message;
    let emote_sign = is_emote.then(|| "* ").unwrap_or_default();
    let html_body = formatted_or_plain_body(formatted, body);

    (
        format!("> {emote_sign}<{sender}> {body}").replace('\n', "\n> "),
        formatdoc!(
            "
            <mx-reply>

                    In reply to
                    {emote_sign}{sender}

                    {html_body}

            </mx-reply>
            "
        ),
    )
}

fn formatted_or_plain_body<'a>(formatted: Option<&'a FormattedBody>, body: &'a str) -> &'a str {
    if let Some(formatted_body) = formatted {
        &formatted_body.body
    } else {
        body
    }
}

/// Get the plain and formatted body for a rich reply.
///
/// Returns a `(plain, html)` tuple.
pub fn plain_and_formatted_reply_body(
    body: impl fmt::Display,
    formatted: Option<impl fmt::Display>,
    original_message: &OriginalRoomMessageEvent,
) -> (String, String) {
    let (quoted, quoted_html) = get_message_quote_fallbacks(original_message);

    let plain = format!("{quoted}\n{body}");
    let html = if let Some(formatted) = formatted {
        format!("{quoted_html}{formatted}")
    } else {
        format!("{quoted_html}{body}")
    };

    (plain, html)
}

#[cfg(test)]
mod tests {
    use crate::{
        event_id,
        events::{room::message::RoomMessageEventContent, MessageLikeUnsigned},
        room_id, user_id, MilliSecondsSinceUnixEpoch,
    };

    use super::OriginalRoomMessageEvent;

    #[test]
    fn plain_quote_fallback_multiline() {
        let (plain_quote, _html_quote) =
            super::get_message_quote_fallbacks(&OriginalRoomMessageEvent {
                content: RoomMessageEventContent::text_plain("multi\nline"),
                event_id: event_id!("$1598361704261elfgc:localhost").to_owned(),
                sender: user_id!("@alice:example.com").to_owned(),
                origin_server_ts: MilliSecondsSinceUnixEpoch::now(),
                room_id: room_id!("!n8f893n9:example.com").to_owned(),
                unsigned: MessageLikeUnsigned::new(),
            });

        assert_eq!(plain_quote, "> <@alice:example.com> multi\n> line");
    }
}
<|endoftext|>


<commit_before>//! An operator which captures the streams of records and notifications to play back later.
//!
//! Not yet tested; please be careful using!

use std::rc::Rc;
use std::cell::RefCell;

use ::Data;
use dataflow::{Scope, Stream};
use dataflow::channels::pact::{ParallelizationContract, Pipeline};
use dataflow::channels::pullers::Counter as PullCounter;
use dataflow::channels::pushers::Counter as PushCounter;
use dataflow::channels::pushers::buffer::Buffer as PushBuffer;
use dataflow::channels::pushers::Tee;
use dataflow::channels::message::Content;

use progress::count_map::CountMap;
use progress::nested::subgraph::Source::ChildOutput;
use progress::nested::subgraph::Target::ChildInput;
use progress::{Timestamp, Operate, Antichain};

pub trait Capture<T: Timestamp, D: Data> {
    ///
    ///
    /// #Examples
    /// ```
    /// use timely::dataflow::Scope;
    /// use timely::dataflow::operators::{Capture, ToStream, Inspect};
    ///
    /// timely::execute(timely::Configuration::Thread, |computation| {
    ///     let handle = computation.scoped::<u64,_,_>(|builder|
    ///         (0..10).to_stream(builder)
    ///                .capture()
    ///     );
    ///
    ///     computation.scoped(|builder| {
    ///         handle.replay(builder)
    ///               .inspect(|x| println!("replayed: {:?}", x));
    ///     })
    /// });
    /// ```
    fn capture(&self) -> Handle<T, D>;
}

impl<S: Scope, D: Data> Capture<S::Timestamp, D> for Stream<S, D> {
    fn capture(&self) -> Handle<S::Timestamp, D> {

        let events = Rc::new(RefCell::new(EventLink { event: Event::Start, next: None }));
        let handle = Handle { events: events.clone() };

        let mut scope = self.scope();   // clones the scope
        let channel_id = scope.new_identifier();

        let (sender, receiver) = Pipeline.connect(&mut scope, channel_id);
        let operator = CaptureOperator {
            input: PullCounter::new(receiver),
            events: events,
        };

        let index = scope.add_operator(operator);
        self.connect_to(ChildInput(index, 0), sender, channel_id);
        handle
    }
}

/// Possible events that the captured stream may provide.
pub enum Event<T, D> {
    Start,
    /// Progress received via `push_external_progress`.
    Progress(Vec<(T, i64)>),
    /// Messages received via the data stream.
    Messages(T, Content<D>),
}

pub struct EventLink<T, D> {
    event: Event<T, D>,
    next: Option<Rc<RefCell<EventLink<T, D>>>>,
}

// TODO : No notion of streaming garbage collection, which is probably a bug.
// TODO : The whole list will be collected when everyone is done, but perhaps a linked list would
// TODO : be better / have better properties?

/// A handle to the captured data, shared with the capture operator itself.
pub struct Handle<T: Timestamp, D: Data> {
    pub events: Rc<RefCell<EventLink<T, D>>>,
}

impl<T: Timestamp, D: Data> Handle<T, D> {
    pub fn replay<S: Scope<Timestamp=T>>(&self, scope: &mut S) -> Stream<S, D> {

        let (targets, registrar) = Tee::<S::Timestamp, D>::new();
        let operator = ReplayOperator {
            output: PushBuffer::new(PushCounter::new(targets, Rc::new(RefCell::new(CountMap::new())))),
            events: self.events.clone(),
        };

        let index = scope.add_operator(operator);
        Stream::new(ChildOutput(index, 0), registrar, scope.clone())
    }
}

struct CaptureOperator<T: Timestamp, D: Data> {
    input: PullCounter<T, D>,
    events: Rc<RefCell<EventLink<T, D>>>,
}

impl<T:Timestamp, D: Data> Operate<T> for CaptureOperator<T, D> {
    fn name(&self) -> &str { "Capture" }
    fn inputs(&self) -> usize { 1 }
    fn outputs(&self) -> usize { 0 }

    // we need to set the initial value of the frontier
    fn set_external_summary(&mut self, _: Vec<Vec<Antichain<T::Summary>>>, counts: &mut [CountMap<T>]) {
        self.events.borrow_mut().next = Some(Rc::new(RefCell::new(EventLink { event: Event::Progress(counts[0].updates.clone()), next: None })));
        let next = self.events.borrow().next.as_ref().unwrap().clone();
        self.events = next;
        counts[0].updates.clear();
    }

    // each change to the frontier should be shared
    fn push_external_progress(&mut self, counts: &mut [CountMap<T>]) {
        self.events.borrow_mut().next = Some(Rc::new(RefCell::new(EventLink { event: Event::Progress(counts[0].updates.clone()), next: None })));
        let next = self.events.borrow().next.as_ref().unwrap().clone();
        self.events = next;
        counts[0].updates.clear();
    }

    fn pull_internal_progress(&mut self, _: &mut [CountMap<T>], consumed: &mut [CountMap<T>], _: &mut [CountMap<T>]) -> bool {
        let events = &mut self.events;
        self.input.for_each(|&time, data| {
            events.borrow_mut().next = Some(Rc::new(RefCell::new(EventLink { event: Event::Messages(time, data.clone()), next: None })));
            let next = events.borrow().next.as_ref().unwrap().clone();
            *events = next;
        });
        self.input.pull_progress(&mut consumed[0]);
        false
    }
}

struct ReplayOperator<T:Timestamp, D: Data> {
    events: Rc<RefCell<EventLink<T, D>>>,
    output: PushBuffer<T, D, PushCounter<T, D, Tee<T, D>>>,
}

impl<T:Timestamp, D: Data> Operate<T> for ReplayOperator<T, D> {
    fn name(&self) -> &str { "Replay" }
    fn inputs(&self) -> usize { 0 }
    fn outputs(&self) -> usize { 1 }

    fn get_internal_summary(&mut self) -> (Vec<Vec<Antichain<T::Summary>>>, Vec<CountMap<T>>) {

        // panics if the event link has not been initialized; should only happen if no one has
        // called set_external_summary on the `CaptureOperator`. So, please don't use this in the
        // same graph as the `CaptureOperator`.

        // TODO : use Default::default() as the initial time, and in the first Event we dequeue,
        // TODO : announce that we've moved beyond Default::default().
        let mut result = CountMap::new();
        let next = self.events.borrow().next.as_ref().unwrap().clone();
        self.events = next;
        if let Event::Progress(ref vec) = self.events.borrow().event {
            for &(ref time, delta) in vec {
                result.update(time, delta);
            }
        }
        (vec![], vec![result])
    }

    fn pull_internal_progress(&mut self, internal: &mut [CountMap<T>], _: &mut [CountMap<T>], produced: &mut [CountMap<T>]) -> bool {

        while self.events.borrow().next.is_some() {
            let next = self.events.borrow().next.as_ref().unwrap().clone();
            self.events = next;
            match self.events.borrow().event {
                Event::Start => { },
                Event::Progress(ref vec) => {
                    for &(ref time, delta) in vec {
                        internal[0].update(time, delta);
                    }
                },
                Event::Messages(ref time, ref data) => {
                    let mut data = data.clone();
                    self.output.session(time).give_content(&mut data);
                }
            }
        }

        self.output.cease();
        self.output.inner().pull_progress(&mut produced[0]);

        false
    }
}

#[cfg(test)]
mod tests {

    use ::Configuration;
    use dataflow::*;
    use dataflow::operators::{Capture, ToStream, Inspect};

    #[test]
    fn probe() {

        // initializes and runs a timely dataflow computation
        ::execute(Configuration::Thread, |computation| {
            let handle = computation.scoped::<u64,_,_>(|builder|
                (0..10).to_stream(builder)
                       .capture()
            );

            // computation.step();
            // computation.step();
            // computation.step();

            computation.scoped(|builder| {
                handle.replay(builder)
                      .inspect(|x| println!("replayed: {:?}", x));
            })
        });
    }

}
<commit_msg>documentation/test update for capture<commit_after>//! An operator which captures the streams of records and notifications to play back later.
//!
//! Not yet tested; please be careful using!

use std::rc::Rc;
use std::cell::RefCell;

use ::Data;
use dataflow::{Scope, Stream};
use dataflow::channels::pact::{ParallelizationContract, Pipeline};
use dataflow::channels::pullers::Counter as PullCounter;
use dataflow::channels::pushers::Counter as PushCounter;
use dataflow::channels::pushers::buffer::Buffer as PushBuffer;
use dataflow::channels::pushers::Tee;
use dataflow::channels::message::Content;

use progress::count_map::CountMap;
use progress::nested::subgraph::Source::ChildOutput;
use progress::nested::subgraph::Target::ChildInput;
use progress::{Timestamp, Operate, Antichain};

/// Capture a stream of timestamped data for later replay.
pub trait Capture<T: Timestamp, D: Data> {
    /// Captures a stream of timestamped data for later replay.
    ///
    /// #Examples
    /// ```
    /// use timely::dataflow::Scope;
    /// use timely::dataflow::operators::{Capture, ToStream, Inspect};
    ///
    /// timely::execute(timely::Configuration::Thread, |computation| {
    ///     let handle = computation.scoped::<u64,_,_>(|builder|
    ///         (0..10).to_stream(builder)
    ///                .capture()
    ///     );
    ///
    ///     computation.scoped(|builder| {
    ///         handle.replay(builder)
    ///               .inspect(|x| println!("replayed: {:?}", x));
    ///     })
    /// });
    /// ```
    fn capture(&self) -> Handle<T, D>;
}

impl<S: Scope, D: Data> Capture<S::Timestamp, D> for Stream<S, D> {
    fn capture(&self) -> Handle<S::Timestamp, D> {

        let events = Rc::new(RefCell::new(EventLink { event: Event::Start, next: None }));
        let handle = Handle { events: events.clone() };

        let mut scope = self.scope();   // clones the scope
        let channel_id = scope.new_identifier();

        let (sender, receiver) = Pipeline.connect(&mut scope, channel_id);
        let operator = CaptureOperator {
            input: PullCounter::new(receiver),
            events: events,
        };

        let index = scope.add_operator(operator);
        self.connect_to(ChildInput(index, 0), sender, channel_id);
        handle
    }
}

/// Possible events that the captured stream may provide.
pub enum Event<T, D> {
    Start,
    /// Progress received via `push_external_progress`.
    Progress(Vec<(T, i64)>),
    /// Messages received via the data stream.
    Messages(T, Content<D>),
}

/// Linked list of events.
pub struct EventLink<T, D> {
    /// An event.
    pub event: Event<T, D>,
    /// The next event, if it exists.
    pub next: Option<Rc<RefCell<EventLink<T, D>>>>,
}

// TODO : No notion of streaming garbage collection, which is probably a bug.
// TODO : The whole list will be collected when everyone is done, but perhaps a linked list would
// TODO : be better / have better properties?

/// A handle to the captured data, shared with the capture operator itself.
pub struct Handle<T: Timestamp, D: Data> {
    /// A linked list of events.
    pub events: Rc<RefCell<EventLink<T, D>>>,
}

impl<T: Timestamp, D: Data> Handle<T, D> {
    pub fn replay<S: Scope<Timestamp=T>>(&self, scope: &mut S) -> Stream<S, D> {

        let (targets, registrar) = Tee::<S::Timestamp, D>::new();
        let operator = ReplayOperator {
            output: PushBuffer::new(PushCounter::new(targets, Rc::new(RefCell::new(CountMap::new())))),
            events: self.events.clone(),
        };

        let index = scope.add_operator(operator);
        Stream::new(ChildOutput(index, 0), registrar, scope.clone())
    }
}

struct CaptureOperator<T: Timestamp, D: Data> {
    input: PullCounter<T, D>,
    events: Rc<RefCell<EventLink<T, D>>>,
}

impl<T:Timestamp, D: Data> Operate<T> for CaptureOperator<T, D> {
    fn name(&self) -> &str { "Capture" }
    fn inputs(&self) -> usize { 1 }
    fn outputs(&self) -> usize { 0 }

    // we need to set the initial value of the frontier
    fn set_external_summary(&mut self, _: Vec<Vec<Antichain<T::Summary>>>, counts: &mut [CountMap<T>]) {
        self.events.borrow_mut().next = Some(Rc::new(RefCell::new(EventLink { event: Event::Progress(counts[0].updates.clone()), next: None })));
        let next = self.events.borrow().next.as_ref().unwrap().clone();
        self.events = next;
        counts[0].updates.clear();
    }

    // each change to the frontier should be shared
    fn push_external_progress(&mut self, counts: &mut [CountMap<T>]) {
        self.events.borrow_mut().next = Some(Rc::new(RefCell::new(EventLink { event: Event::Progress(counts[0].updates.clone()), next: None })));
        let next = self.events.borrow().next.as_ref().unwrap().clone();
        self.events = next;
        counts[0].updates.clear();
    }

    fn pull_internal_progress(&mut self, _: &mut [CountMap<T>], consumed: &mut [CountMap<T>], _: &mut [CountMap<T>]) -> bool {
        let events = &mut self.events;
        self.input.for_each(|&time, data| {
            events.borrow_mut().next = Some(Rc::new(RefCell::new(EventLink { event: Event::Messages(time, data.clone()), next: None })));
            let next = events.borrow().next.as_ref().unwrap().clone();
            *events = next;
        });
        self.input.pull_progress(&mut consumed[0]);
        false
    }
}

struct ReplayOperator<T:Timestamp, D: Data> {
    events: Rc<RefCell<EventLink<T, D>>>,
    output: PushBuffer<T, D, PushCounter<T, D, Tee<T, D>>>,
}

impl<T:Timestamp, D: Data> Operate<T> for ReplayOperator<T, D> {
    fn name(&self) -> &str { "Replay" }
    fn inputs(&self) -> usize { 0 }
    fn outputs(&self) -> usize { 1 }

    fn get_internal_summary(&mut self) -> (Vec<Vec<Antichain<T::Summary>>>, Vec<CountMap<T>>) {

        // panics if the event link has not been initialized; should only happen if no one has
        // called set_external_summary on the `CaptureOperator`. So, please don't use this in the
        // same graph as the `CaptureOperator`.

        // TODO : use Default::default() as the initial time, and in the first Event we dequeue,
        // TODO : announce that we've moved beyond Default::default().
        let mut result = CountMap::new();
        let next = self.events.borrow().next.as_ref().unwrap().clone();
        self.events = next;
        if let Event::Progress(ref vec) = self.events.borrow().event {
            for &(ref time, delta) in vec {
                result.update(time, delta);
            }
        }
        (vec![], vec![result])
    }

    fn pull_internal_progress(&mut self, internal: &mut [CountMap<T>], _: &mut [CountMap<T>], produced: &mut [CountMap<T>]) -> bool {

        while self.events.borrow().next.is_some() {
            let next = self.events.borrow().next.as_ref().unwrap().clone();
            self.events = next;
            match self.events.borrow().event {
                Event::Start => { },
                Event::Progress(ref vec) => {
                    for &(ref time, delta) in vec {
                        internal[0].update(time, delta);
                    }
                },
                Event::Messages(ref time, ref data) => {
                    let mut data = data.clone();
                    self.output.session(time).give_content(&mut data);
                }
            }
        }

        self.output.cease();
        self.output.inner().pull_progress(&mut produced[0]);

        false
    }
}

#[cfg(test)]
mod tests {

    use ::Configuration;
    use dataflow::*;
    use dataflow::operators::{Capture, ToStream, Inspect};

    #[test]
    fn probe() {

        // initializes and runs a timely dataflow computation
        ::execute(Configuration::Thread, |computation| {
            let handle = computation.scoped::<u64,_,_>(|builder|
                (0..10).to_stream(builder)
                       .capture()
            );

            computation.scoped(|builder| {
                handle.replay(builder)
                      .inspect(|x| println!("replayed: {:?}", x));
            })
        });
    }

}
<|endoftext|>


<commit_before>use core::ops;
use vmx;
use cpu;
use core::sync::atomic::{AtomicUsize, AtomicBool, ATOMIC_BOOL_INIT, Ordering};

lazy_static! {
    static ref CLI_COUNT: cpu::PerCoreVariable<AtomicUsize> = Default::default();
}

pub fn are_interrupts_enabled() -> bool {
    (vmx::read_flags() & 0x200) != 0
}

#[cfg(not(test))]
pub fn cli() {
    unsafe {
        asm!("cli" : : :);
    }
}

#[cfg(test)]
pub fn cli() {}

#[cfg(not(test))]
pub fn sti() {
    unsafe {
        asm!("sti" : : :);
    }
}

#[cfg(test)]
pub fn sti() {}

#[derive(Default)]
pub struct ClearLocalInterrupts<T> {
    guarded: T,
}

pub struct ClearLocalInterruptsGuard<'a, T: 'a> {
    guarded: &'a T,
    acquired: AtomicBool,
}

pub struct ClearLocalInterruptsGuardMut<'a, T: 'a> {
    guarded: &'a mut T,
    acquired: AtomicBool,
}

impl<T> ClearLocalInterrupts<T> {
    pub fn new(guarded: T) -> Self {
        ClearLocalInterrupts { guarded: guarded }
    }

    pub fn cli_mut(&mut self) -> ClearLocalInterruptsGuardMut<T> {
        ClearLocalInterruptsGuardMut {
            guarded: &mut self.guarded,
            acquired: ATOMIC_BOOL_INIT,
        }
    }

    pub fn cli(&self) -> ClearLocalInterruptsGuard<T> {
        ClearLocalInterruptsGuard {
            guarded: &self.guarded,
            acquired: ATOMIC_BOOL_INIT,
        }
    }
}

impl<'a, T> ops::Deref for ClearLocalInterruptsGuard<'a, T> {
    type Target = T;
    fn deref(&self) -> &T {
        if !self.acquired.compare_and_swap(false, true, Ordering::AcqRel) &&
            CLI_COUNT.get().fetch_add(1, Ordering::AcqRel) == 0 {
            cli();
        }
        self.guarded
    }
}

impl<'a, T> ops::Deref for ClearLocalInterruptsGuardMut<'a, T> {
    type Target = T;
    fn deref(&self) -> &T {
        if !self.acquired.compare_and_swap(false, true, Ordering::AcqRel) &&
            CLI_COUNT.get().fetch_add(1, Ordering::AcqRel) == 0 {
            cli();
        }
        self.guarded
    }
}

impl<'a, T> ops::DerefMut for ClearLocalInterruptsGuardMut<'a, T> {
    fn deref_mut(&mut self) -> &mut T {
        if !self.acquired.compare_and_swap(false, true, Ordering::AcqRel) &&
            CLI_COUNT.get().fetch_add(1, Ordering::AcqRel) == 0 {
            cli();
        }
        self.guarded
    }
}

impl<'a, T> Drop for ClearLocalInterruptsGuard<'a, T> {
    fn drop(&mut self) {
        if CLI_COUNT.get().fetch_sub(1, Ordering::AcqRel) == 1 {
            sti();
        }
    }
}

impl<'a, T> Drop for ClearLocalInterruptsGuardMut<'a, T> {
    fn drop(&mut self) {
        if CLI_COUNT.get().fetch_sub(1, Ordering::AcqRel) == 1 {
            sti();
        }
    }
}

#[cfg(feature = "runtime_tests")]
pub mod runtime_tests {
    use super::are_interrupts_enabled;
    use super::ClearLocalInterrupts;

    struct Guardee {
        data: u16,
    }

    lazy_static! {
        static ref STATIC_GUARDEE: ClearLocalInterrupts<Guardee> =
            ClearLocalInterrupts::new(Guardee { data: 0 });
    }

    impl Guardee {
        fn do_work(&self) {}
    }

    pub fn run() {
        info!("Running CLI tests...");
        test_clear_local_interrupts_guard_borrow();
        test_clear_local_interrupts_guard_mut_borrow();
        test_clear_local_interrupts_guard_static_borrow();
        info!("CLI tests succeeded");
    }

    fn test_clear_local_interrupts_guard_mut_borrow() {
        assert!(are_interrupts_enabled());
        {
            let mut g: ClearLocalInterrupts<Guardee> =
                ClearLocalInterrupts::new(Guardee { data: 0 });
            assert!(are_interrupts_enabled());
            g.cli_mut().data += 1;
            assert!(are_interrupts_enabled());
            assert_eq!(g.cli().data, 1);
            assert!(are_interrupts_enabled());
        }
        assert!(are_interrupts_enabled());
    }

    fn test_clear_local_interrupts_guard_borrow() {
        assert!(are_interrupts_enabled());
        {
            let g: ClearLocalInterrupts<Guardee> = ClearLocalInterrupts::new(Guardee { data: 0 });
            assert!(are_interrupts_enabled());
            let borrowed = g.cli();
            assert!(are_interrupts_enabled());
            borrowed.do_work();
            assert!(!are_interrupts_enabled());
        }
        assert!(are_interrupts_enabled());
    }

    fn test_clear_local_interrupts_guard_static_borrow() {
        assert!(are_interrupts_enabled());
        {
            assert!(are_interrupts_enabled());
            STATIC_GUARDEE.cli().do_work();
            assert!(are_interrupts_enabled());
            assert_eq!(STATIC_GUARDEE.cli().data, 0);
            assert!(are_interrupts_enabled());
        }
        assert!(are_interrupts_enabled());
    }
}
<commit_msg>Cargo fmt<commit_after>use core::ops;
use vmx;
use cpu;
use core::sync::atomic::{AtomicUsize, AtomicBool, ATOMIC_BOOL_INIT, Ordering};

lazy_static! {
    static ref CLI_COUNT: cpu::PerCoreVariable<AtomicUsize> = Default::default();
}

pub fn are_interrupts_enabled() -> bool {
    (vmx::read_flags() & 0x200) != 0
}

#[cfg(not(test))]
pub fn cli() {
    unsafe {
        asm!("cli" : : :);
    }
}

#[cfg(test)]
pub fn cli() {}

#[cfg(not(test))]
pub fn sti() {
    unsafe {
        asm!("sti" : : :);
    }
}

#[cfg(test)]
pub fn sti() {}

#[derive(Default)]
pub struct ClearLocalInterrupts<T> {
    guarded: T,
}

pub struct ClearLocalInterruptsGuard<'a, T: 'a> {
    guarded: &'a T,
    acquired: AtomicBool,
}

pub struct ClearLocalInterruptsGuardMut<'a, T: 'a> {
    guarded: &'a mut T,
    acquired: AtomicBool,
}

impl<T> ClearLocalInterrupts<T> {
    pub fn new(guarded: T) -> Self {
        ClearLocalInterrupts { guarded: guarded }
    }

    pub fn cli_mut(&mut self) -> ClearLocalInterruptsGuardMut<T> {
        ClearLocalInterruptsGuardMut {
            guarded: &mut self.guarded,
            acquired: ATOMIC_BOOL_INIT,
        }
    }

    pub fn cli(&self) -> ClearLocalInterruptsGuard<T> {
        ClearLocalInterruptsGuard {
            guarded: &self.guarded,
            acquired: ATOMIC_BOOL_INIT,
        }
    }
}

impl<'a, T> ops::Deref for ClearLocalInterruptsGuard<'a, T> {
    type Target = T;
    fn deref(&self) -> &T {
        if !self.acquired.compare_and_swap(false, true, Ordering::AcqRel) &&
           CLI_COUNT.get().fetch_add(1, Ordering::AcqRel) == 0 {
            cli();
        }
        self.guarded
    }
}

impl<'a, T> ops::Deref for ClearLocalInterruptsGuardMut<'a, T> {
    type Target = T;
    fn deref(&self) -> &T {
        if !self.acquired.compare_and_swap(false, true, Ordering::AcqRel) &&
           CLI_COUNT.get().fetch_add(1, Ordering::AcqRel) == 0 {
            cli();
        }
        self.guarded
    }
}

impl<'a, T> ops::DerefMut for ClearLocalInterruptsGuardMut<'a, T> {
    fn deref_mut(&mut self) -> &mut T {
        if !self.acquired.compare_and_swap(false, true, Ordering::AcqRel) &&
           CLI_COUNT.get().fetch_add(1, Ordering::AcqRel) == 0 {
            cli();
        }
        self.guarded
    }
}

impl<'a, T> Drop for ClearLocalInterruptsGuard<'a, T> {
    fn drop(&mut self) {
        if CLI_COUNT.get().fetch_sub(1, Ordering::AcqRel) == 1 {
            sti();
        }
    }
}

impl<'a, T> Drop for ClearLocalInterruptsGuardMut<'a, T> {
    fn drop(&mut self) {
        if CLI_COUNT.get().fetch_sub(1, Ordering::AcqRel) == 1 {
            sti();
        }
    }
}

#[cfg(feature = "runtime_tests")]
pub mod runtime_tests {
    use super::are_interrupts_enabled;
    use super::ClearLocalInterrupts;

    struct Guardee {
        data: u16,
    }

    lazy_static! {
        static ref STATIC_GUARDEE: ClearLocalInterrupts<Guardee> =
            ClearLocalInterrupts::new(Guardee { data: 0 });
    }

    impl Guardee {
        fn do_work(&self) {}
    }

    pub fn run() {
        info!("Running CLI tests...");
        test_clear_local_interrupts_guard_borrow();
        test_clear_local_interrupts_guard_mut_borrow();
        test_clear_local_interrupts_guard_static_borrow();
        info!("CLI tests succeeded");
    }

    fn test_clear_local_interrupts_guard_mut_borrow() {
        assert!(are_interrupts_enabled());
        {
            let mut g: ClearLocalInterrupts<Guardee> =
                ClearLocalInterrupts::new(Guardee { data: 0 });
            assert!(are_interrupts_enabled());
            g.cli_mut().data += 1;
            assert!(are_interrupts_enabled());
            assert_eq!(g.cli().data, 1);
            assert!(are_interrupts_enabled());
        }
        assert!(are_interrupts_enabled());
    }

    fn test_clear_local_interrupts_guard_borrow() {
        assert!(are_interrupts_enabled());
        {
            let g: ClearLocalInterrupts<Guardee> = ClearLocalInterrupts::new(Guardee { data: 0 });
            assert!(are_interrupts_enabled());
            let borrowed = g.cli();
            assert!(are_interrupts_enabled());
            borrowed.do_work();
            assert!(!are_interrupts_enabled());
        }
        assert!(are_interrupts_enabled());
    }

    fn test_clear_local_interrupts_guard_static_borrow() {
        assert!(are_interrupts_enabled());
        {
            assert!(are_interrupts_enabled());
            STATIC_GUARDEE.cli().do_work();
            assert!(are_interrupts_enabled());
            assert_eq!(STATIC_GUARDEE.cli().data, 0);
            assert!(are_interrupts_enabled());
        }
        assert!(are_interrupts_enabled());
    }
}
<|endoftext|>


<commit_before>//! cli: command line parsing for git-global

use std::io::{Write, stderr};

use clap::{Arg, App, SubCommand};

use core::GitGlobalResult;
use errors::GitGlobalError;
use subcommands;

fn get_clap_app<'a, 'b>() -> App<'a, 'b> {
    App::new("git-global")
        .version(crate_version!())
        .author("Eric Petersen <eric@huskers.unl.edu>")
        .about("git subcommand for working with all git repos on a machine")
        .arg(Arg::with_name("json")
            .long("json")
            .help("Output results in JSON."))
        .subcommand(SubCommand::with_name("info")
            .about("show meta-information about git-global"))
        .subcommand(SubCommand::with_name("list")
            .about("lists all git repos on your machine [the default]"))
        .subcommand(SubCommand::with_name("scan")
            .about("update cache of git repos on your machine"))
        .subcommand(SubCommand::with_name("status")
            .about("shows status of all git repos"))
}

/// Entry point for the `git-global` git subcommand. Returns an exit code.
pub fn run_from_command_line() -> i32 {
    let clap_app = get_clap_app();
    let matches = clap_app.get_matches();
    let use_json = matches.is_present("json");
    let results = match matches.subcommand_name() {
        Some("info") => subcommands::info::get_results(),
        Some("list") => subcommands::list::get_results(),
        Some("scan") => subcommands::scan::get_results(),
        Some("status") => subcommands::status::get_results(),
        Some(cmd) => Err(GitGlobalError::BadSubcommand(cmd.to_string())),
        None => subcommands::scan::get_results(),
    };
    match results {
        Ok(res) => show_results(res, use_json),
        Err(err) => show_error(err, use_json),
    }
}

/// Print out the subcommand results.
fn show_results(results: GitGlobalResult, use_json: bool) -> i32 {
    if use_json {
        results.print_json();
    } else {
        results.print();
    }
    0
}

/// Print out an error.
fn show_error(error: GitGlobalError, use_json: bool) -> i32 {
    if use_json {
        let json = object!{
            "error" => true,
            "message" => format!("{}", error)
        };
        writeln!(&mut stderr(), "{:#}", json).expect("failed write to STDERR");
    } else {
        writeln!(&mut stderr(), "{}", error).expect("failed write to STDERR");
    }
    1
}
<commit_msg>*Actually* make `status` the default subcommand<commit_after>//! cli: command line parsing for git-global

use std::io::{Write, stderr};

use clap::{Arg, App, SubCommand};

use core::GitGlobalResult;
use errors::GitGlobalError;
use subcommands;

fn get_clap_app<'a, 'b>() -> App<'a, 'b> {
    App::new("git-global")
        .version(crate_version!())
        .author("Eric Petersen <eric@huskers.unl.edu>")
        .about("git subcommand for working with all git repos on a machine")
        .arg(Arg::with_name("json")
            .long("json")
            .help("Output results in JSON."))
        .subcommand(SubCommand::with_name("info")
            .about("show meta-information about git-global"))
        .subcommand(SubCommand::with_name("list")
            .about("lists all git repos on your machine [the default]"))
        .subcommand(SubCommand::with_name("scan")
            .about("update cache of git repos on your machine"))
        .subcommand(SubCommand::with_name("status")
            .about("shows status of all git repos"))
}

/// Entry point for the `git-global` git subcommand. Returns an exit code.
pub fn run_from_command_line() -> i32 {
    let clap_app = get_clap_app();
    let matches = clap_app.get_matches();
    let use_json = matches.is_present("json");
    let results = match matches.subcommand_name() {
        Some("info") => subcommands::info::get_results(),
        Some("list") => subcommands::list::get_results(),
        Some("scan") => subcommands::scan::get_results(),
        Some("status") => subcommands::status::get_results(),
        Some(cmd) => Err(GitGlobalError::BadSubcommand(cmd.to_string())),
        None => subcommands::status::get_results(),
    };
    match results {
        Ok(res) => show_results(res, use_json),
        Err(err) => show_error(err, use_json),
    }
}

/// Print out the subcommand results.
fn show_results(results: GitGlobalResult, use_json: bool) -> i32 {
    if use_json {
        results.print_json();
    } else {
        results.print();
    }
    0
}

/// Print out an error.
fn show_error(error: GitGlobalError, use_json: bool) -> i32 {
    if use_json {
        let json = object!{
            "error" => true,
            "message" => format!("{}", error)
        };
        writeln!(&mut stderr(), "{:#}", json).expect("failed write to STDERR");
    } else {
        writeln!(&mut stderr(), "{}", error).expect("failed write to STDERR");
    }
    1
}
<|endoftext|>