<commit_before>use std::path::PathBuf;
use std::collections::BTreeMap;
use std::collections::btree_map::Iter;
use std::fs::{File, OpenOptions};
use std::io;
use std::io::{BufReader, BufWriter};
use bincode::{deserialize_from, serialize_into, Infinite};

use errors::*;

#[derive(Serialize, Deserialize, PartialEq, Debug)]
pub struct Bookmark {
    pub name: String,
    pub directory: PathBuf,
    created_at: u64,
    pub updated_at: u64,
    pub last_access: Option<u64>,
    pub count: i64,
}

pub type Bookmarks = BTreeMap<String, Bookmark>;

impl Bookmark {
    pub fn new(name: String, directory: PathBuf) -> Bookmark {
        Bookmark {
            name: name,
            directory: directory,
            created_at: ::now(),
            updated_at: ::now(),
            last_access: None,
            count: 0,
        }
    }
}

#[derive(Debug)]
pub struct Database {
    pub location: PathBuf,
    bookmarks: Bookmarks,
}

impl Database {
    pub fn open(mut path: PathBuf) -> Result<Database> {
        if !path.ends_with("db") {
            path.push("db");
        }

        let bookmarks = match File::open(&path) {
            Ok(file) => try!(hydrate(file)),
            Err(ref err) if notfound(err) => Bookmarks::new(),
            Err(_) => bail!(ErrorKind::DBOpenError(path)),
        };

        let db = Database::new(path, bookmarks);
        Ok(db)
    }

    fn new(location: PathBuf, bookmarks: Bookmarks) -> Database {
        Database {
            location: location,
            bookmarks: bookmarks,
        }
    }

    pub fn get(&self, key: &str) -> Option<&Bookmark> {
        self.bookmarks.get(key)
    }

    pub fn get_path(&mut self, key: &str) -> Result<PathBuf> {
        let path: PathBuf;
        match self.bookmarks.get_mut(key) {
            Some(bookmark) => {
                bookmark.last_access = Some(::now());
                path = bookmark.directory.clone();
            }
            None => bail!(ErrorKind::BookmarkNotFound(key.to_string())),
        };

        try!(self.close());
        Ok(path)
    }

    // TODO: add a check to verify the db is open.
    // TODO: add check to verify value is a valid directory.
    pub fn put(&mut self, key: String, value: PathBuf) -> Result<()> {
        if self.bookmarks.contains_key(&key) {
            self.update(key, value)
        } else {
            self.create(key, value)
        }
    }

    pub fn delete(&mut self, key: String) -> Result<()> {
        if self.bookmarks.remove(&key).is_none() {
            bail!(ErrorKind::BookmarkNotFound(key));
        }

        try!(self.close());
        Ok(())
    }

    fn update(&mut self, key: String, path: PathBuf) -> Result<()> {
        match self.bookmarks.get_mut(&key) {
            Some(bookmark) => {
                bookmark.directory = path;
                bookmark.updated_at = ::now();
            }
            None => bail!(ErrorKind::BookmarkNotFound(key)),
        }

        try!(self.close());
        Ok(())
    }

    fn create(&mut self, key: String, value: PathBuf) -> Result<()> {
        let bookmark = Bookmark::new(key.clone(), value);
        self.bookmarks.insert(key, bookmark);

        try!(self.close());
        Ok(())
    }

    pub fn list(&self) -> Iter<String, Bookmark> {
        self.bookmarks.iter()
    }

    fn close(&self) -> Result<()> {
        let path = PathBuf::from(&self.location);

        let file = OpenOptions::new()
            .read(true)
            .write(true)
            .create(true)
            .open(&path)
            .chain_err(|| ErrorKind::DBOpenError(path))?;

        try!(dehydrate(file, &self.bookmarks));
        Ok(())
    }
}

fn notfound(err: &io::Error) -> bool {
    err.kind() == io::ErrorKind::NotFound
}

fn hydrate(file: File) -> Result<Bookmarks> {
    let mut reader = BufReader::new(file);
    let bookmarks: Bookmarks = try!(deserialize_from(&mut reader, Infinite));
    Ok(bookmarks)
}

fn dehydrate(file: File, bookmarks: &Bookmarks) -> Result<()> {
    let mut writer = BufWriter::new(file);

    try!(serialize_into(&mut writer, &bookmarks, Infinite));
    Ok(())
}
<commit_msg>Add a test for bookmark<commit_after>use std::path::PathBuf;
use std::collections::BTreeMap;
use std::collections::btree_map::Iter;
use std::fs::{File, OpenOptions};
use std::io;
use std::io::{BufReader, BufWriter};
use bincode::{deserialize_from, serialize_into, Infinite};

use errors::*;

#[derive(Serialize, Deserialize, PartialEq, Debug)]
pub struct Bookmark {
    pub name: String,
    pub directory: PathBuf,
    pub created_at: u64,
    pub updated_at: u64,
    pub last_access: Option<u64>,
    pub count: i64,
}

pub type Bookmarks = BTreeMap<String, Bookmark>;

impl Bookmark {
    pub fn new(name: String, directory: PathBuf) -> Bookmark {
        let timestamp = ::now();

        Bookmark {
            name: name,
            directory: directory,
            created_at: timestamp,
            updated_at: timestamp,
            last_access: None,
            count: 0,
        }
    }
}

#[derive(Debug)]
pub struct Database {
    pub location: PathBuf,
    bookmarks: Bookmarks,
}

impl Database {
    pub fn open(mut path: PathBuf) -> Result<Database> {
        if !path.ends_with("db") {
            path.push("db");
        }

        let bookmarks = match File::open(&path) {
            Ok(file) => try!(hydrate(file)),
            Err(ref err) if notfound(err) => Bookmarks::new(),
            Err(_) => bail!(ErrorKind::DBOpenError(path)),
        };

        let db = Database::new(path, bookmarks);
        Ok(db)
    }

    fn new(location: PathBuf, bookmarks: Bookmarks) -> Database {
        Database {
            location: location,
            bookmarks: bookmarks,
        }
    }

    pub fn get(&self, key: &str) -> Option<&Bookmark> {
        self.bookmarks.get(key)
    }

    pub fn get_path(&mut self, key: &str) -> Result<PathBuf> {
        let path: PathBuf;
        match self.bookmarks.get_mut(key) {
            Some(bookmark) => {
                bookmark.last_access = Some(::now());
                path = bookmark.directory.clone();
            }
            None => bail!(ErrorKind::BookmarkNotFound(key.to_string())),
        };

        try!(self.close());
        Ok(path)
    }

    // TODO: add a check to verify the db is open.
    // TODO: add check to verify value is a valid directory.
    pub fn put(&mut self, key: String, value: PathBuf) -> Result<()> {
        if self.bookmarks.contains_key(&key) {
            self.update(key, value)
        } else {
            self.create(key, value)
        }
    }

    pub fn delete(&mut self, key: String) -> Result<()> {
        if self.bookmarks.remove(&key).is_none() {
            bail!(ErrorKind::BookmarkNotFound(key));
        }

        try!(self.close());
        Ok(())
    }

    fn update(&mut self, key: String, path: PathBuf) -> Result<()> {
        match self.bookmarks.get_mut(&key) {
            Some(bookmark) => {
                bookmark.directory = path;
                bookmark.updated_at = ::now();
            }
            None => bail!(ErrorKind::BookmarkNotFound(key)),
        }

        try!(self.close());
        Ok(())
    }

    fn create(&mut self, key: String, value: PathBuf) -> Result<()> {
        let bookmark = Bookmark::new(key.clone(), value);
        self.bookmarks.insert(key, bookmark);

        try!(self.close());
        Ok(())
    }

    pub fn list(&self) -> Iter<String, Bookmark> {
        self.bookmarks.iter()
    }

    fn close(&self) -> Result<()> {
        let path = PathBuf::from(&self.location);

        let file = OpenOptions::new()
            .read(true)
            .write(true)
            .create(true)
            .open(&path)
            .chain_err(|| ErrorKind::DBOpenError(path))?;

        try!(dehydrate(file, &self.bookmarks));
        Ok(())
    }
}

fn notfound(err: &io::Error) -> bool {
    err.kind() == io::ErrorKind::NotFound
}

fn hydrate(file: File) -> Result<Bookmarks> {
    let mut reader = BufReader::new(file);
    let bookmarks: Bookmarks = try!(deserialize_from(&mut reader, Infinite));
    Ok(bookmarks)
}

fn dehydrate(file: File, bookmarks: &Bookmarks) -> Result<()> {
    let mut writer = BufWriter::new(file);

    try!(serialize_into(&mut writer, &bookmarks, Infinite));
    Ok(())
}

#[cfg(test)]
mod tests {
    use super::{Bookmark};
    use std::path::PathBuf;

    #[test]
    fn bookmark_values() {
        let name = String::from("hello");
        let path = PathBuf::from("/tmp/hello");
        let bookmark = Bookmark::new(name, path);

        assert_eq!(bookmark.name, String::from("hello"));
        assert_eq!(bookmark.directory, PathBuf::from("/tmp/hello"));
        assert!(bookmark.last_access.is_none());
        assert_eq!(bookmark.count, 0);
    }
}
<|endoftext|>


<commit_before>extern crate debugserver_types;
extern crate env_logger;
extern crate futures;
extern crate jsonrpc_core;
extern crate serde;
extern crate serde_json;

extern crate gluon_language_server;
extern crate gluon;

use std::error::Error as StdError;
use std::fs::File;
use std::io::{BufReader, Read};
use std::net::{TcpListener, TcpStream};
use std::sync::{Arc, Condvar, Mutex};
use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
use std::thread::spawn;
use std::collections::{HashMap, HashSet};

use futures::{Async, BoxFuture, Future, IntoFuture};

use jsonrpc_core::IoHandler;

use serde_json::Value;

use debugserver_types::*;

use gluon::base::pos::Line;
use gluon::vm::api::{OpaqueValue, Hole};
use gluon::vm::Error as VmError;
use gluon::vm::thread::{RootedThread, ThreadInternal, LINE_FLAG};
use gluon::{Compiler, filename_to_module};

use gluon_language_server::rpc::{LanguageServerCommand, ServerCommand, ServerError, main_loop,
                                 write_message};

pub struct InitializeHandler {
    stream: Arc<TcpStream>,
    seq: Arc<AtomicUsize>,
}

impl LanguageServerCommand<InitializeRequestArguments> for InitializeHandler {
    type Output = Option<Capabilities>;
    type Error = ();
    fn execute(&self,
               _args: InitializeRequestArguments)
               -> BoxFuture<Option<Capabilities>, ServerError<Self::Error>> {

        let initialized = InitializedEvent {
            body: None,
            event: "initialized".into(),
            seq: self.seq.fetch_add(1, Ordering::SeqCst) as i64,
            type_: "event".into(),
        };
        write_message(&*self.stream, &initialized)
            .map_err(|err| {
                ServerError {
                    message: format!("Unable to write result to initialize: {}", err),
                    data: None,
                }
            })
            .map(|_| None)
            .into_future()
            .boxed()
    }
}

pub struct LaunchHandler {
    debugger: Arc<Debugger>,
    thread: RootedThread,
    stream: Arc<TcpStream>,
    seq: Arc<AtomicUsize>,
}

impl LanguageServerCommand<Value> for LaunchHandler {
    type Output = Option<Value>;
    type Error = ();
    fn execute(&self, args: Value) -> BoxFuture<Option<Value>, ServerError<()>> {
        self.execute_launch(args).into_future().boxed()
    }
}

impl LaunchHandler {
    fn execute_launch(&self, args: Value) -> Result<Option<Value>, ServerError<()>> {
        let program = args.get("program")
            .and_then(|s| s.as_str())
            .ok_or_else(|| {
                ServerError {
                    message: "No program argument found".into(),
                    data: None,
                }
            })?;
        let module = filename_to_module(program);
        let expr = {
            let mut file = File::open(program).map_err(|_| {
                    ServerError {
                        message: format!("Program does not exit: `{}`", program),
                        data: None,
                    }
                })?;
            let mut expr = String::new();
            file.read_to_string(&mut expr).expect("Could not read from file");
            expr
        };

        let debugger = self.debugger.clone();
        self.thread.context().set_hook(Some(Box::new(move |_, debug_info| {
            let stack_info = debug_info.stack_info(0).unwrap();
            if let Some(line) = stack_info.line() {
                if debugger.should_break(stack_info.source_name(), line) {
                    let mut continue_exection = debugger.continue_mutex.lock().unwrap();
                    *continue_exection = false;
                    write_message(&*debugger.stream,
                                  &StoppedEvent {
                                      body: StoppedEventBody {
                                          all_threads_stopped: Some(true),
                                          reason: "breakpoint".into(),
                                          text: None,
                                          thread_id: None,
                                      },
                                      event: "stopped".to_string(),
                                      seq: debugger.seq(),
                                      type_: "event".to_string(),
                                  }).map_err(|err| VmError::Message(format!("{}", err)))?;
                    while !*continue_exection {
                        continue_exection = debugger.continue_var.wait(continue_exection).unwrap();
                    }
                }
            }
            Ok(Async::Ready(()))
        })));
        self.thread.context().set_hook_mask(LINE_FLAG);

        let thread = self.thread.clone();
        let seq = self.seq.clone();
        let stream = self.stream.clone();
        spawn(move || {
            let _result = Compiler::new()
                .run_expr::<OpaqueValue<RootedThread, Hole>>(&thread, &module, &expr);
            let seq = seq.fetch_add(1, Ordering::SeqCst) as i64;
            let terminated = TerminatedEvent {
                body: None,
                event: "terminated".into(),
                seq: seq,
                type_: "event".into(),
            };
            write_message(&*stream, &terminated).unwrap();
        });
        Ok(None)
    }
}

pub struct DisconnectHandler {
    exit_token: Arc<AtomicBool>,
}

impl LanguageServerCommand<DisconnectArguments> for DisconnectHandler {
    type Output = Option<Value>;
    type Error = ();
    fn execute(&self, _args: Value) -> BoxFuture<Option<Value>, ServerError<()>> {
        self.exit_token.store(true, Ordering::SeqCst);
        Ok(None).into_future().boxed()
    }
}

// Translate debug server messages into jsonrpc-2.0
fn translate_request(message: String) -> Result<String, Box<StdError>> {
    use serde_json::Value;
    let mut data: Value = try!(serde_json::from_str(&message));
    if data.is_object() {
        let data = data.as_object_mut().unwrap();
        let command = data.get("command").and_then(|c| c.as_str()).expect("command").to_string();
        let seq = data.get("seq")
            .and_then(|c| {
                c.as_str()
                    .map(|s| Value::String(s.to_string()))
                    .or_else(|| c.as_i64().map(Value::from))
            })
            .expect("seq");
        let arguments = data.remove("arguments").unwrap_or(Value::Object(Default::default()));
        let map = vec![("method".to_string(), Value::String(command)),
                       ("id".to_string(), seq),
                       ("params".to_string(), arguments),
                       ("jsonrpc".to_owned(), Value::String("2.0".to_string()))]
            .into_iter()
            .collect();
        return Ok(try!(serde_json::to_string(&Value::Object(map))));
    }
    Ok(message)
}

fn translate_response(message: String) -> Result<String, Box<StdError>> {
    use serde_json::Value;
    let mut data: Value = try!(serde_json::from_str(&message));
    if data.is_object() {
        let data = data.as_object_mut().unwrap();
        let seq = data.get("id")
            .and_then(|c| {
                c.as_str()
                    .map(|s| Value::String(s.to_string()))
                    .or_else(|| c.as_i64().map(Value::from))
            })
            .expect("id");
        let result = data.remove("result");
        let error = data.remove("error");

        let mut map = vec![("success".to_string(), Value::Bool(result.is_some())),
                           ("request_seq".to_string(), seq.clone()),
                           ("seq".to_string(), seq),
                           ("type".to_owned(), Value::String("response".to_string()))];

        if let Some(result) = result {
            map.push(("body".to_string(), result));
        }
        if let Some(mut error) = error {
            map.push(("message".to_string(),
                      error.as_object_mut().unwrap().remove("message").expect("error message")));
        }

        let map = map.into_iter().collect();
        return Ok(try!(serde_json::to_string(&Value::Object(map))));
    }
    Ok(message)
}

pub struct Debugger {
    stream: Arc<TcpStream>,
    breakpoints: Mutex<HashMap<String, HashSet<Line>>>,
    continue_mutex: Mutex<bool>,
    continue_var: Condvar,
    seq: Arc<AtomicUsize>,
}

impl Debugger {
    fn seq(&self) -> i64 {
        self.seq.fetch_add(1, Ordering::SeqCst) as i64
    }

    fn should_break(&self, source_name: &str, line: Line) -> bool {
        let breakpoints = self.breakpoints.lock().expect("breakpoints mutex is poisoned");
        breakpoints.get(source_name)
            .map_or(false, |lines| lines.contains(&line))
    }
}

pub fn main() {
    env_logger::init().unwrap();

    let listener = TcpListener::bind("127.0.0.1:4711").unwrap();
    for stream in listener.incoming() {
        let stream = Arc::new(stream.unwrap());

        let exit_token = Arc::new(AtomicBool::new(false));
        let seq = Arc::new(AtomicUsize::new(0));

        let thread = gluon::new_vm();

        let debugger = Arc::new(Debugger {
            stream: stream.clone(),
            breakpoints: Mutex::new(HashMap::new()),
            continue_mutex: Mutex::new(false),
            continue_var: Condvar::new(),
            seq: seq.clone(),
        });

        let mut io = IoHandler::new();
        io.add_async_method("initialize",
                      ServerCommand::new(InitializeHandler {
                          stream: stream.clone(),
                          seq: seq.clone(),
                      }));
        io.add_async_method("launch",
                      ServerCommand::new(LaunchHandler {
                          debugger: debugger.clone(),
                          thread: thread,
                          stream: stream.clone(),
                          seq: seq.clone(),
                      }));
        io.add_async_method("disconnect",
                            ServerCommand::new(DisconnectHandler {
                                exit_token: exit_token.clone(),
                            }));
        {
            let debugger = debugger.clone();
            let set_break =
                move |args: SetBreakpointsArguments| -> BoxFuture<_, ServerError<()>> {
                let mut breakpoint_map = debugger.breakpoints.lock().unwrap();
                let breakpoints = args.breakpoints
                    .iter()
                    .flat_map(|bs| bs.iter().map(|breakpoint| Line::from(breakpoint.line as usize)))
                    .collect();
                if let Some(path) = args.source.path {
                    breakpoint_map.insert(filename_to_module(path.trim_right_matches(".glu")),
                                          breakpoints);
                }
                Ok(SetBreakpointsResponseBody {
                    breakpoints: args.breakpoints
                        .into_iter()
                        .flat_map(|bs| bs)
                        .map(|breakpoint| {
                            Breakpoint {
                                column: None,
                                end_column: None,
                                end_line: None,
                                id: None,
                                line: Some(breakpoint.line),
                                message: None,
                                source: None,
                                verified: true,
                            }
                        })
                        .collect(),
                }).into_future().boxed()
            };

            io.add_async_method("setBreakpoints", ServerCommand::new(set_break));
        }

        let threads = move |_: Value| -> Result<ThreadsResponseBody, ServerError<()>> {
            Ok(ThreadsResponseBody {
                threads: vec![Thread {
                                  id: 0,
                                  name: "main".to_string(),
                              }],
            })
        };

        io.add_method("threads", ServerCommand::new(threads));

        {
            let debugger = debugger.clone();
            let cont = move |_: ContinueArguments| -> BoxFuture<Option<Value>, ServerError<()>> {
                *debugger.continue_mutex.lock().unwrap() = true;
                debugger.continue_var.notify_one();
                Ok(None).into_future().boxed()
            };
            io.add_async_method("continue", ServerCommand::new(cont));
        }

        spawn(move || {
            let read = BufReader::new(&*stream);
            main_loop(read,
                      &*stream,
                      &io,
                      exit_token,
                      translate_request,
                      translate_response)
                .unwrap()
        });
    }
}
<commit_msg>fix: Fill in stub methods visual code expects to exist after the 'stopped' event<commit_after>extern crate debugserver_types;
extern crate env_logger;
extern crate futures;
extern crate jsonrpc_core;
extern crate serde;
extern crate serde_json;

extern crate gluon_language_server;
extern crate gluon;

use std::error::Error as StdError;
use std::fs::File;
use std::io::{BufReader, Read};
use std::net::{TcpListener, TcpStream};
use std::sync::{Arc, Condvar, Mutex};
use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
use std::thread::spawn;
use std::collections::{HashMap, HashSet};

use futures::{Async, BoxFuture, Future, IntoFuture};

use jsonrpc_core::IoHandler;

use serde_json::Value;

use debugserver_types::*;

use gluon::base::pos::Line;
use gluon::vm::api::{OpaqueValue, Hole};
use gluon::vm::Error as VmError;
use gluon::vm::thread::{RootedThread, ThreadInternal, LINE_FLAG};
use gluon::{Compiler, filename_to_module};

use gluon_language_server::rpc::{LanguageServerCommand, ServerCommand, ServerError, main_loop,
                                 write_message};

pub struct InitializeHandler {
    stream: Arc<TcpStream>,
    seq: Arc<AtomicUsize>,
}

impl LanguageServerCommand<InitializeRequestArguments> for InitializeHandler {
    type Output = Option<Capabilities>;
    type Error = ();
    fn execute(&self,
               _args: InitializeRequestArguments)
               -> BoxFuture<Option<Capabilities>, ServerError<Self::Error>> {

        let initialized = InitializedEvent {
            body: None,
            event: "initialized".into(),
            seq: self.seq.fetch_add(1, Ordering::SeqCst) as i64,
            type_: "event".into(),
        };
        write_message(&*self.stream, &initialized)
            .map_err(|err| {
                ServerError {
                    message: format!("Unable to write result to initialize: {}", err),
                    data: None,
                }
            })
            .map(|_| {
                Some(Capabilities {
                    supports_configuration_done_request: Some(true),
                    ..Capabilities::default()
                })
            })
            .into_future()
            .boxed()
    }
}

pub struct LaunchHandler {
    debugger: Arc<Debugger>,
    thread: RootedThread,
    stream: Arc<TcpStream>,
    seq: Arc<AtomicUsize>,
}

impl LanguageServerCommand<Value> for LaunchHandler {
    type Output = Option<Value>;
    type Error = ();
    fn execute(&self, args: Value) -> BoxFuture<Option<Value>, ServerError<()>> {
        self.execute_launch(args).into_future().boxed()
    }
}

impl LaunchHandler {
    fn execute_launch(&self, args: Value) -> Result<Option<Value>, ServerError<()>> {
        let program = args.get("program")
            .and_then(|s| s.as_str())
            .ok_or_else(|| {
                ServerError {
                    message: "No program argument found".into(),
                    data: None,
                }
            })?;
        let module = filename_to_module(program);
        let expr = {
            let mut file = File::open(program).map_err(|_| {
                    ServerError {
                        message: format!("Program does not exit: `{}`", program),
                        data: None,
                    }
                })?;
            let mut expr = String::new();
            file.read_to_string(&mut expr).expect("Could not read from file");
            expr
        };

        let debugger = self.debugger.clone();
        self.thread.context().set_hook(Some(Box::new(move |_, debug_info| {
            let stack_info = debug_info.stack_info(0).unwrap();
            if let Some(line) = stack_info.line() {
                if debugger.should_break(stack_info.source_name(), line) {
                    let mut continue_exection = debugger.continue_mutex.lock().unwrap();
                    *continue_exection = false;
                    write_message(&*debugger.stream,
                                  &StoppedEvent {
                                      body: StoppedEventBody {
                                          all_threads_stopped: Some(true),
                                          reason: "breakpoint".into(),
                                          text: None,
                                          thread_id: Some(1),
                                      },
                                      event: "stopped".to_string(),
                                      seq: debugger.seq(),
                                      type_: "event".to_string(),
                                  }).map_err(|err| VmError::Message(format!("{}", err)))?;
                    while !*continue_exection {
                        continue_exection = debugger.continue_var.wait(continue_exection).unwrap();
                    }
                }
            }
            Ok(Async::Ready(()))
        })));
        self.thread.context().set_hook_mask(LINE_FLAG);

        let thread = self.thread.clone();
        let seq = self.seq.clone();
        let stream = self.stream.clone();
        spawn(move || {
            let _result = Compiler::new()
                .run_expr::<OpaqueValue<RootedThread, Hole>>(&thread, &module, &expr);
            let seq = seq.fetch_add(1, Ordering::SeqCst) as i64;
            let terminated = TerminatedEvent {
                body: None,
                event: "terminated".into(),
                seq: seq,
                type_: "event".into(),
            };
            write_message(&*stream, &terminated).unwrap();
        });
        Ok(None)
    }
}

pub struct DisconnectHandler {
    exit_token: Arc<AtomicBool>,
}

impl LanguageServerCommand<DisconnectArguments> for DisconnectHandler {
    type Output = Option<Value>;
    type Error = ();
    fn execute(&self, _args: Value) -> BoxFuture<Option<Value>, ServerError<()>> {
        self.exit_token.store(true, Ordering::SeqCst);
        Ok(None).into_future().boxed()
    }
}

// Translate debug server messages into jsonrpc-2.0
fn translate_request(message: String) -> Result<String, Box<StdError>> {
    use serde_json::Value;
    let mut data: Value = try!(serde_json::from_str(&message));
    if data.is_object() {
        let data = data.as_object_mut().unwrap();
        let command = data.get("command").and_then(|c| c.as_str()).expect("command").to_string();
        let seq = data.get("seq")
            .and_then(|c| {
                c.as_str()
                    .map(|s| Value::String(s.to_string()))
                    .or_else(|| c.as_i64().map(Value::from))
            })
            .expect("seq");
        let arguments = data.remove("arguments").unwrap_or(Value::Object(Default::default()));
        let map = vec![("method".to_string(), Value::String(command)),
                       ("id".to_string(), seq),
                       ("params".to_string(), arguments),
                       ("jsonrpc".to_owned(), Value::String("2.0".to_string()))]
            .into_iter()
            .collect();
        return Ok(try!(serde_json::to_string(&Value::Object(map))));
    }
    Ok(message)
}

fn translate_response(debugger: &Debugger, message: String) -> Result<String, Box<StdError>> {
    use serde_json::Value;
    let mut data: Value = try!(serde_json::from_str(&message));
    if data.is_object() {
        let data = data.as_object_mut().unwrap();
        let seq = data.get("id")
            .and_then(|c| {
                c.as_str()
                    .map(|s| Value::String(s.to_string()))
                    .or_else(|| c.as_i64().map(Value::from))
            })
            .expect("id");
        let result = data.remove("result");
        let error = data.remove("error");

        let mut map = vec![("success".to_string(), Value::Bool(result.is_some())),
                           ("request_seq".to_string(), seq),
                           ("seq".to_string(), Value::from(debugger.seq())),
                           ("type".to_owned(), Value::String("response".to_string()))];

        if let Some(result) = result {
            map.push(("body".to_string(), result));
        }
        if let Some(mut error) = error {
            map.push(("message".to_string(),
                      error.as_object_mut().unwrap().remove("message").expect("error message")));
        }

        let map = map.into_iter().collect();
        return Ok(try!(serde_json::to_string(&Value::Object(map))));
    }
    Ok(message)
}

pub struct Debugger {
    stream: Arc<TcpStream>,
    breakpoints: Mutex<HashMap<String, HashSet<Line>>>,
    continue_mutex: Mutex<bool>,
    continue_var: Condvar,
    seq: Arc<AtomicUsize>,
}

impl Debugger {
    fn seq(&self) -> i64 {
        self.seq.fetch_add(1, Ordering::SeqCst) as i64
    }

    fn should_break(&self, source_name: &str, line: Line) -> bool {
        let breakpoints = self.breakpoints.lock().expect("breakpoints mutex is poisoned");
        breakpoints.get(source_name)
            .map_or(false, |lines| lines.contains(&line))
    }
}

pub fn main() {
    env_logger::init().unwrap();

    let listener = TcpListener::bind("127.0.0.1:4711").unwrap();
    for stream in listener.incoming() {
        let stream = Arc::new(stream.unwrap());

        let exit_token = Arc::new(AtomicBool::new(false));
        let seq = Arc::new(AtomicUsize::new(1));

        let thread = gluon::new_vm();

        let debugger = Arc::new(Debugger {
            stream: stream.clone(),
            breakpoints: Mutex::new(HashMap::new()),
            continue_mutex: Mutex::new(false),
            continue_var: Condvar::new(),
            seq: seq.clone(),
        });

        let mut io = IoHandler::new();
        io.add_async_method("initialize",
                            ServerCommand::new(InitializeHandler {
                                stream: stream.clone(),
                                seq: seq.clone(),
                            }));

        let configuration_done =
            move |_: ConfigurationDoneArguments| -> BoxFuture<(), ServerError<()>> {
                Ok(()).into_future().boxed()
            };
        io.add_async_method("configurationDone", ServerCommand::new(configuration_done));

        io.add_async_method("launch",
                            ServerCommand::new(LaunchHandler {
                                debugger: debugger.clone(),
                                thread: thread,
                                stream: stream.clone(),
                                seq: seq.clone(),
                            }));
        io.add_async_method("disconnect",
                            ServerCommand::new(DisconnectHandler {
                                exit_token: exit_token.clone(),
                            }));
        {
            let debugger = debugger.clone();
            let set_break = move |args: SetBreakpointsArguments| -> BoxFuture<_, ServerError<()>> {
                let mut breakpoint_map = debugger.breakpoints.lock().unwrap();
                let breakpoints =
                    args.breakpoints
                        .iter()
                        .flat_map(|bs| {
                            bs.iter().map(|breakpoint| Line::from(breakpoint.line as usize))
                        })
                        .collect();
                if let Some(path) = args.source.path {
                    breakpoint_map.insert(filename_to_module(path.trim_right_matches(".glu")),
                                          breakpoints);
                }
                Ok(SetBreakpointsResponseBody {
                        breakpoints: args.breakpoints
                            .into_iter()
                            .flat_map(|bs| bs)
                            .map(|breakpoint| {
                                Breakpoint {
                                    column: None,
                                    end_column: None,
                                    end_line: None,
                                    id: None,
                                    line: Some(breakpoint.line),
                                    message: None,
                                    source: None,
                                    verified: true,
                                }
                            })
                            .collect(),
                    })
                    .into_future()
                    .boxed()
            };

            io.add_async_method("setBreakpoints", ServerCommand::new(set_break));
        }

        let threads = move |_: Value| -> BoxFuture<ThreadsResponseBody, ServerError<()>> {
            Ok(ThreadsResponseBody {
                    threads: vec![Thread {
                                      id: 1,
                                      name: "main".to_string(),
                                  }],
                })
                .into_future()
                .boxed()
        };

        io.add_async_method("threads", ServerCommand::new(threads));

        let stack_trace = move |_: StackTraceArguments| -> BoxFuture<_, ServerError<()>> {
            Ok(StackTraceResponseBody {
                    stack_frames: vec![StackFrame {
                                           column: 0,
                                           end_column: None,
                                           end_line: None,
                                           id: 0,
                                           line: 0,
                                           module_id: None,
                                           name: "main".to_string(),
                                           source: None,
                                       }],
                    total_frames: Some(1),
                })
                .into_future()
                .boxed()
        };
        io.add_async_method("stackTrace", ServerCommand::new(stack_trace));

        let scopes = move |_: ScopesArguments| -> BoxFuture<_, ServerError<()>> {
            Ok(ScopesResponseBody {
                    scopes: vec![Scope {
                                     column: None,
                                     end_column: None,
                                     end_line: None,
                                     expensive: false,
                                     indexed_variables: None,
                                     line: None,
                                     name: "Locals".to_string(),
                                     named_variables: None,
                                     source: Some(Source {
                                         name: Some("main".to_string()),
                                         ..Source::default()
                                     }),
                                     variables_reference: 0,
                                 }],
                })
                .into_future()
                .boxed()
        };
        io.add_async_method("scopes", ServerCommand::new(scopes));

        {
            let debugger = debugger.clone();
            let cont = move |_: ContinueArguments| -> BoxFuture<Option<Value>, ServerError<()>> {
                *debugger.continue_mutex.lock().unwrap() = true;
                debugger.continue_var.notify_one();
                Ok(None).into_future().boxed()
            };
            io.add_async_method("continue", ServerCommand::new(cont));
        }

        spawn(move || {
            let read = BufReader::new(&*stream);
            main_loop(read,
                      &*stream,
                      &io,
                      exit_token,
                      translate_request,
                      |body| translate_response(&debugger, body))
                .unwrap()
        });
    }
}
<|endoftext|>


<commit_before>use syntax::{abi, ast, ast_util, codemap, parse};
use syntax::ptr::P;
use syntax::ext::base;
use syntax::ext::build::AstBuilder;

static BEFORE_EACH: &'static str = "before_each";
static AFTER_EACH:  &'static str = "after_each";
static BEFORE:      &'static str = "before";
static AFTER:       &'static str = "after";
static IT:          &'static str = "it";

/// Defines the state of a `describe!` macro as it is parsing.
struct DescribeState {
    name: Option<String>,
    before: Option<P<ast::Block>>,
    after: Option<P<ast::Block>>,
    before_each: Option<P<ast::Block>>,
    after_each: Option<P<ast::Block>>,
    tests: Vec<Test>
}

/// A test as a description and associated block.
struct Test {
    description: String,
    block: P<ast::Block>
}

/// Defines the overarching `describe!` syntax extension.
///
/// All other macros in stainless are actually "fake" in the sense
/// that they are detected and expanded inside of the implementation
/// of `describe!`.
pub fn describe(cx: &mut base::ExtCtxt, _: codemap::Span, tokens: &[ast::TokenTree]) -> Box<base::MacResult + 'static> {
    // Parse a full DescribeState from the input, emitting errors if used incorrectly.
    let state = parse_describe(DescribeState {
        name: None, before: None, after: None,
        before_each: None, after_each: None, tests: vec![]
    }, parse::tts_to_parser(cx.parse_sess(), tokens.to_vec(), cx.cfg()));

    let name = cx.ident_of(state.name.clone().unwrap().replace(" ", "_").as_slice());

    // Create tests from a full DescribeState
    let tests = create_tests(state, cx);

    // Get a glob import of all items in scope to the module that `describe!` is called from.
    let super_glob = cx.view_use_glob(codemap::DUMMY_SP, ast::Inherited, vec![cx.ident_of("super")]);

    // Generate the new module.
    let test_mod = cx.item_mod(codemap::DUMMY_SP, codemap::DUMMY_SP, name, vec![], vec![super_glob], tests);

    // Export the new module.
    base::MacItems::new(vec![test_mod].into_iter())
}

fn create_tests(state: DescribeState, cx: &mut base::ExtCtxt) -> Vec<P<ast::Item>> {
    // FIXME(reem): Implement before and after.
    let (_before, _after) = (state.before, state.after);

    let (before_each, after_each) = (state.before_each, state.after_each);
    let tests = state.tests;

    let test_attribute = cx.attribute(codemap::DUMMY_SP,
                                      cx.meta_word(codemap::DUMMY_SP, parse::token::InternedString::new("test")));

    tests.into_iter().map(|Test { description, block }| {
        let test_body = match (&before_each, &after_each) {
            (&None, &None) => block,

            (&Some(ref before), &None) => {
                P(ast::Block {
                    view_items: before.view_items + block.view_items,
                    stmts: before.stmts + block.stmts,
                    ..block.deref().clone()
                })
            },

            (&None, &Some(ref after)) => {
                P(ast::Block {
                    view_items: block.view_items + after.view_items,
                    stmts: block.stmts + after.stmts,
                    ..block.deref().clone()
                })
            },

            (&Some(ref before), &Some(ref after)) => {
                P(ast::Block {
                    view_items: before.view_items + block.view_items + after.view_items,
                    stmts: before.stmts + block.stmts + after.stmts,
                    ..block.deref().clone()
                })
            }
        };

        P(ast::Item {
            ident: cx.ident_of(description.replace(" ", "_").as_slice()),
            attrs: vec![test_attribute.clone()],
            id: ast::DUMMY_NODE_ID,
            node: ast::ItemFn(
                cx.fn_decl(vec![], cx.ty_nil()),
                ast::NormalFn,
                abi::Rust,
                ast_util::empty_generics(),
                test_body
            ),
            vis: ast::Inherited,
            span: codemap::DUMMY_SP
        })
    }).collect()
}

fn parse_describe(mut state: DescribeState, mut parser: parse::parser::Parser) -> DescribeState {
    // First parse the name of this describe block:
    let (name, _) = parser.parse_str();
    state.name = Some(name.get().to_string());

    // Move past the opening {
    if parse::token::LBRACE != parser.bump_and_get() {
        parser.fatal("Expected { after the description of a describe! block.");
    }

    // Now parse all tests and subsections:
    while parser.token != parse::token::RBRACE {
        // Get the name of this block, must be either:
        //     - before_each
        //     - after_each
        //     - before
        //     - after
        //     - it
        //
        // Any other top-level idents are not allowed.
        let block_name = parser.parse_ident();

        match block_name.as_str() {
            BEFORE_EACH => {
                if state.before_each.is_some() { parser.fatal("Only one `before_each` block is allowed per `describe!` block.") }
                state.before_each = Some(parser.parse_block());
            },

            AFTER_EACH => {
                if state.after_each.is_some() { parser.fatal("Only one `after_each` block is allowed per `describe!` block.") }
                state.after_each = Some(parser.parse_block());
            },

            BEFORE => {
                if state.before.is_some() { parser.fatal("Only one `before` block is allowed per `describe!` block.") }
                state.before = Some(parser.parse_block());
            },

            AFTER => {
                if state.after.is_some() { parser.fatal("Only one `after` block is allowed per `describe!` block.") }
                state.after = Some(parser.parse_block());
            },

            IT => {
                // Description of this `it` block.
                let (description, _) = parser.parse_str();

                state.tests.push(Test {
                    // Get as a String
                    description: description.get().to_string(),

                    // The associated block
                    block: parser.parse_block()
                });
            },

            banned => {
                // Illegal block name.
                let span = parser.span;
                parser.span_fatal(span, format!("Expected one of: `{}`, but found: `{}`",
                    format!("{}, {}, {}, {}, {}", BEFORE_EACH, AFTER_EACH, BEFORE, AFTER, IT).as_slice(),
                    banned).as_slice());
            }
        }
    }

    state
}

<commit_msg>(doc) Commented the expansion process.<commit_after>use syntax::{abi, ast, ast_util, codemap, parse};
use syntax::ptr::P;
use syntax::ext::base;
use syntax::ext::build::AstBuilder;

static BEFORE_EACH: &'static str = "before_each";
static AFTER_EACH:  &'static str = "after_each";
static BEFORE:      &'static str = "before";
static AFTER:       &'static str = "after";
static IT:          &'static str = "it";

/// Defines the state of a `describe!` macro as it is parsing.
struct DescribeState {
    name: Option<String>,
    before: Option<P<ast::Block>>,
    after: Option<P<ast::Block>>,
    before_each: Option<P<ast::Block>>,
    after_each: Option<P<ast::Block>>,
    tests: Vec<Test>
}

/// A test as a description and associated block.
struct Test {
    description: String,
    block: P<ast::Block>
}

/// Defines the overarching `describe!` syntax extension.
///
/// All other macros in stainless are actually "fake" in the sense
/// that they are detected and expanded inside of the implementation
/// of `describe!`.
pub fn describe(cx: &mut base::ExtCtxt, _: codemap::Span, tokens: &[ast::TokenTree]) -> Box<base::MacResult + 'static> {
    // Parse a full DescribeState from the input, emitting errors if used incorrectly.
    let state = parse_describe(DescribeState {
        name: None, before: None, after: None,
        before_each: None, after_each: None, tests: vec![]
    }, parse::tts_to_parser(cx.parse_sess(), tokens.to_vec(), cx.cfg()));

    let name = cx.ident_of(state.name.clone().unwrap().replace(" ", "_").as_slice());

    // Create tests from a full DescribeState
    let tests = create_tests(state, cx);

    // Get a glob import of all items in scope to the module that `describe!` is called from.
    let super_glob = cx.view_use_glob(codemap::DUMMY_SP, ast::Inherited, vec![cx.ident_of("super")]);

    // Generate the new module.
    let test_mod = cx.item_mod(codemap::DUMMY_SP, codemap::DUMMY_SP, name, vec![], vec![super_glob], tests);

    // Export the new module.
    base::MacItems::new(vec![test_mod].into_iter())
}

fn create_tests(state: DescribeState, cx: &mut base::ExtCtxt) -> Vec<P<ast::Item>> {
    // FIXME(reem): Implement before and after.
    let (_before, _after) = (state.before, state.after);

    let (before_each, after_each) = (state.before_each, state.after_each);
    let tests = state.tests;

    // Create the #[test] attribute.
    let test_attribute = cx.attribute(codemap::DUMMY_SP,
                                      cx.meta_word(codemap::DUMMY_SP, parse::token::InternedString::new("test")));

    tests.into_iter().map(|Test { description, block }| {
        // Create the full test body by splicing in the statements and view items of the before and
        // after blocks if they are present.
        let test_body = match (&before_each, &after_each) {
            (&None, &None) => block,

            (&Some(ref before), &None) => {
                P(ast::Block {
                    view_items: before.view_items + block.view_items,
                    stmts: before.stmts + block.stmts,
                    ..block.deref().clone()
                })
            },

            (&None, &Some(ref after)) => {
                P(ast::Block {
                    view_items: block.view_items + after.view_items,
                    stmts: block.stmts + after.stmts,
                    ..block.deref().clone()
                })
            },

            (&Some(ref before), &Some(ref after)) => {
                P(ast::Block {
                    view_items: before.view_items + block.view_items + after.view_items,
                    stmts: before.stmts + block.stmts + after.stmts,
                    ..block.deref().clone()
                })
            }
        };

        // Create the final Item that represents the test.
        P(ast::Item {
            // Name it with a snake_case version of the description.
            ident: cx.ident_of(description.replace(" ", "_").as_slice()),

            // Add #[test]
            attrs: vec![test_attribute.clone()],
            id: ast::DUMMY_NODE_ID,
            node: ast::ItemFn(
                // Takes no arguments and returns ()
                cx.fn_decl(vec![], cx.ty_nil()),

                // All the usual types.
                ast::NormalFn,
                abi::Rust,
                ast_util::empty_generics(),

                // Add the body of the function.
                test_body
            ),
            // Inherited visibility (not pub)
            vis: ast::Inherited,
            span: codemap::DUMMY_SP
        })
    }).collect()
}

fn parse_describe(mut state: DescribeState, mut parser: parse::parser::Parser) -> DescribeState {
    // First parse the name of this describe block:
    let (name, _) = parser.parse_str();
    state.name = Some(name.get().to_string());

    // Move past the opening {
    if parse::token::LBRACE != parser.bump_and_get() {
        parser.fatal("Expected { after the description of a describe! block.");
    }

    // Now parse all tests and subsections:
    while parser.token != parse::token::RBRACE {
        // Get the name of this block, must be either:
        //     - before_each
        //     - after_each
        //     - before
        //     - after
        //     - it
        //
        // Any other top-level idents are not allowed.
        let block_name = parser.parse_ident();

        match block_name.as_str() {
            BEFORE_EACH => {
                if state.before_each.is_some() { parser.fatal("Only one `before_each` block is allowed per `describe!` block.") }
                state.before_each = Some(parser.parse_block());
            },

            AFTER_EACH => {
                if state.after_each.is_some() { parser.fatal("Only one `after_each` block is allowed per `describe!` block.") }
                state.after_each = Some(parser.parse_block());
            },

            BEFORE => {
                if state.before.is_some() { parser.fatal("Only one `before` block is allowed per `describe!` block.") }
                state.before = Some(parser.parse_block());
            },

            AFTER => {
                if state.after.is_some() { parser.fatal("Only one `after` block is allowed per `describe!` block.") }
                state.after = Some(parser.parse_block());
            },

            IT => {
                // Description of this `it` block.
                let (description, _) = parser.parse_str();

                state.tests.push(Test {
                    // Get as a String
                    description: description.get().to_string(),

                    // The associated block
                    block: parser.parse_block()
                });
            },

            banned => {
                // Illegal block name.
                let span = parser.span;
                parser.span_fatal(span, format!("Expected one of: `{}`, but found: `{}`",
                    format!("{}, {}, {}, {}, {}", BEFORE_EACH, AFTER_EACH, BEFORE, AFTER, IT).as_slice(),
                    banned).as_slice());
            }
        }
    }

    state
}

<|endoftext|>


<commit_before>use chrono::prelude::*;
use diesel::result::Error;
use diesel::*;
use serde::Serialize;

// use super::messages::*;
// use super::tasks::Task;
// use crate::helpers::TaskStatus;
use crate::backend::progress_report;
use crate::concerns::CortexInsertable;
use crate::helpers::TaskStatus;
use crate::models::{Corpus, Service};
use crate::schema::historical_runs;

#[derive(Identifiable, Queryable, Clone, Debug, PartialEq, Eq, QueryableByName)]
#[table_name = "historical_runs"]
/// Historical `(Corpus, Service)` run records
pub struct HistoricalRun {
  /// task primary key, auto-incremented by postgresql
  pub id: i32,
  /// id of the service owning this task
  pub service_id: i32,
  /// id of the corpus hosting this task
  pub corpus_id: i32,
  /// total tasks in run
  pub total: i32,
  /// invalid tasks in run
  pub invalid: i32,
  /// fatal results in run
  pub fatal: i32,
  /// error results in run
  pub error: i32,
  /// warning results in run
  pub warning: i32,
  /// results with no notable problems in run
  pub no_problem: i32,
  /// tasks still in progress at end of run
  pub in_progress: i32,
  /// start timestamp of run
  pub start_time: NaiveDateTime,
  /// end timestamp of run, i.e. timestamp of next run initiation
  pub end_time: Option<NaiveDateTime>,
  /// owner who initiated the run
  pub owner: String,
  /// description of the purpose of this run
  pub description: String,
}

#[derive(Debug, Serialize, Clone)]
/// A JSON-friendly data structure, used for the frontend reports
pub struct RunMetadata {
  /// total tasks in run
  pub total: i32,
  /// invalid tasks in run
  pub invalid: i32,
  /// fatak tasks in run
  pub fatal: i32,
  /// error tasks in run
  pub error: i32,
  /// warning tasks in run
  pub warning: i32,
  /// no_problem tasks in run
  pub no_problem: i32,
  /// in_progress tasks in run
  pub in_progress: i32,
  /// start time of run, formatted for a report
  pub start_time: String,
  /// end time of run, formatted for a report
  pub end_time: String,
  /// initiator of the run
  pub owner: String,
  /// description of the run
  pub description: String,
}
impl RunMetadata {
  /// f32 type cast for the run frequency fields
  pub fn field_f32(&self, field: &str) -> f32 {
    let field_i32 = match field {
      "invalid" => self.invalid,
      "total" => self.total,
      "fatal" => self.fatal,
      "error" => self.error,
      "warning" => self.warning,
      "no_problem" => self.no_problem,
      "in_progress" => self.in_progress,
      _ => unimplemented!(),
    };
    field_i32 as f32
  }
}

#[derive(Debug, Serialize, Clone)]
/// A JSON-friendly data structure, used for vega-lite Stack figures
/// https://vega.github.io/vega-lite/docs/stack.html
pub struct RunMetadataStack {
  /// type of messages
  pub severity: String,
  /// raw severity index
  pub severity_numeric: i32,
  /// percent to total
  pub percent: f32,
  /// total number of jobs
  pub total: i32,
  /// start time of run, formatted for a report
  pub start_time: String,
  /// end time of run, formatted for a report
  pub end_time: String,
  /// initiator of the run
  pub owner: String,
  /// description of the run
  pub description: String,
}
impl RunMetadataStack {
  /// Transforms to a vega-lite Stack -near representation
  pub fn transform(runs_meta: &[RunMetadata]) -> Vec<RunMetadataStack> {
    let mut runs_meta_vega = Vec::new();
    for run in runs_meta.iter() {
      let total = run.field_f32("total");
      for field in &["fatal", "error", "warning", "no_problem", "in_progress"] {
        runs_meta_vega.push(RunMetadataStack {
          severity: field.to_string(),
          severity_numeric: TaskStatus::from_key(field).unwrap().raw(),
          percent: (100.0 * run.field_f32(field)) / total,
          total: run.total,
          start_time: run.start_time.clone(),
          end_time: run.end_time.clone(),
          owner: run.owner.clone(),
          description: run.description.clone(),
        })
      }
    }
    runs_meta_vega
  }
}

#[derive(Insertable, Debug, Clone)]
#[table_name = "historical_runs"]
/// A new task, to be inserted into `CorTeX`
pub struct NewHistoricalRun {
  /// id of the service owning this task
  pub service_id: i32,
  /// id of the corpus hosting this task
  pub corpus_id: i32,
  /// description of the purpose of this run
  pub description: String,
  /// owner who initiated the run
  pub owner: String,
}

impl CortexInsertable for NewHistoricalRun {
  fn create(&self, connection: &PgConnection) -> Result<usize, Error> {
    insert_into(historical_runs::table)
      .values(self)
      .execute(connection)
  }
}

impl HistoricalRun {
  /// Obtain all historical runs for a given `(Corpus, Service)` pair
  pub fn find_by(
    corpus: &Corpus,
    service: &Service,
    connection: &PgConnection,
  ) -> Result<Vec<HistoricalRun>, Error>
  {
    use crate::schema::historical_runs::dsl::{corpus_id, service_id, start_time};
    let runs: Vec<HistoricalRun> = historical_runs::table
      .filter(corpus_id.eq(corpus.id))
      .filter(service_id.eq(service.id))
      .order(start_time.desc())
      .get_results(connection)?;
    Ok(runs)
  }

  /// Obtain a currently ongoing run entry for a  `(Corpus, Service)` pair, if any
  pub fn find_current(
    corpus: &Corpus,
    service: &Service,
    connection: &PgConnection,
  ) -> Result<Option<HistoricalRun>, Error>
  {
    use crate::schema::historical_runs::dsl::{corpus_id, end_time, service_id};
    historical_runs::table
      .filter(corpus_id.eq(corpus.id))
      .filter(service_id.eq(service.id))
      .filter(end_time.is_null())
      .first(connection)
      .optional()
  }

  /// Mark this historical run as completed, by setting `end_time` to the current time.
  pub fn mark_completed(&self, connection: &PgConnection) -> Result<(), Error> {
    use diesel::dsl::now;
    if self.end_time.is_none() {
      // gather the current statistics for this run, then update.
      let report = progress_report(connection, self.corpus_id, self.service_id);
      let total = *report.get("total").unwrap_or(&0.0) as i32;
      let no_problem = *report.get("no_problem").unwrap_or(&0.0) as i32;
      let warning = *report.get("warning").unwrap_or(&0.0) as i32;
      let error = *report.get("error").unwrap_or(&0.0) as i32;
      let fatal = *report.get("fatal").unwrap_or(&0.0) as i32;
      let invalid = *report.get("invalid").unwrap_or(&0.0) as i32;
      let queued_count_f64: f64 =
        report.get("queued").unwrap_or(&0.0) + report.get("todo").unwrap_or(&0.0);
      let in_progress = queued_count_f64 as i32;

      //
      update(self)
        .set((
          historical_runs::end_time.eq(now),
          historical_runs::total.eq(total),
          historical_runs::in_progress.eq(in_progress),
          historical_runs::invalid.eq(invalid),
          historical_runs::no_problem.eq(no_problem),
          historical_runs::warning.eq(warning),
          historical_runs::error.eq(error),
          historical_runs::fatal.eq(fatal),
        ))
        .execute(connection)?;
    }
    Ok(())
  }
}

impl From<HistoricalRun> for RunMetadata {
  fn from(run: HistoricalRun) -> RunMetadata {
    let HistoricalRun {
      total,
      warning,
      error,
      no_problem,
      invalid,
      fatal,
      start_time,
      end_time,
      description,
      in_progress,
      owner,
      ..
    } = run;
    RunMetadata {
      total,
      invalid,
      fatal,
      warning,
      error,
      no_problem,
      in_progress,
      start_time: start_time.format("%Y-%m-%d").to_string(),
      end_time: match end_time {
        Some(etime) => etime.format("%Y-%m-%d").to_string(),
        None => String::new(),
      },
      owner,
      description,
    }
  }
}
<commit_msg>attempt to de-stack vega figures when we have multiple runs at the same satart_time<commit_after>use std::collections::HashSet;
use chrono::prelude::*;
use diesel::result::Error;
use diesel::*;
use serde::Serialize;

// use super::messages::*;
// use super::tasks::Task;
// use crate::helpers::TaskStatus;
use crate::backend::progress_report;
use crate::concerns::CortexInsertable;
use crate::helpers::TaskStatus;
use crate::models::{Corpus, Service};
use crate::schema::historical_runs;

#[derive(Identifiable, Queryable, Clone, Debug, PartialEq, Eq, QueryableByName)]
#[table_name = "historical_runs"]
/// Historical `(Corpus, Service)` run records
pub struct HistoricalRun {
  /// task primary key, auto-incremented by postgresql
  pub id: i32,
  /// id of the service owning this task
  pub service_id: i32,
  /// id of the corpus hosting this task
  pub corpus_id: i32,
  /// total tasks in run
  pub total: i32,
  /// invalid tasks in run
  pub invalid: i32,
  /// fatal results in run
  pub fatal: i32,
  /// error results in run
  pub error: i32,
  /// warning results in run
  pub warning: i32,
  /// results with no notable problems in run
  pub no_problem: i32,
  /// tasks still in progress at end of run
  pub in_progress: i32,
  /// start timestamp of run
  pub start_time: NaiveDateTime,
  /// end timestamp of run, i.e. timestamp of next run initiation
  pub end_time: Option<NaiveDateTime>,
  /// owner who initiated the run
  pub owner: String,
  /// description of the purpose of this run
  pub description: String,
}

#[derive(Debug, Serialize, Clone)]
/// A JSON-friendly data structure, used for the frontend reports
pub struct RunMetadata {
  /// total tasks in run
  pub total: i32,
  /// invalid tasks in run
  pub invalid: i32,
  /// fatak tasks in run
  pub fatal: i32,
  /// error tasks in run
  pub error: i32,
  /// warning tasks in run
  pub warning: i32,
  /// no_problem tasks in run
  pub no_problem: i32,
  /// in_progress tasks in run
  pub in_progress: i32,
  /// start time of run, formatted for a report
  pub start_time: String,
  /// end time of run, formatted for a report
  pub end_time: String,
  /// initiator of the run
  pub owner: String,
  /// description of the run
  pub description: String,
}
impl RunMetadata {
  /// f32 type cast for the run frequency fields
  pub fn field_f32(&self, field: &str) -> f32 {
    let field_i32 = match field {
      "invalid" => self.invalid,
      "total" => self.total,
      "fatal" => self.fatal,
      "error" => self.error,
      "warning" => self.warning,
      "no_problem" => self.no_problem,
      "in_progress" => self.in_progress,
      _ => unimplemented!(),
    };
    field_i32 as f32
  }
}

#[derive(Debug, Serialize, Clone)]
/// A JSON-friendly data structure, used for vega-lite Stack figures
/// https://vega.github.io/vega-lite/docs/stack.html
pub struct RunMetadataStack {
  /// type of messages
  pub severity: String,
  /// raw severity index
  pub severity_numeric: i32,
  /// percent to total
  pub percent: f32,
  /// total number of jobs
  pub total: i32,
  /// start time of run, formatted for a report
  pub start_time: String,
  /// end time of run, formatted for a report
  pub end_time: String,
  /// initiator of the run
  pub owner: String,
  /// description of the run
  pub description: String,
}
impl RunMetadataStack {
  /// Transforms to a vega-lite Stack -near representation
  pub fn transform(runs_meta: &[RunMetadata]) -> Vec<RunMetadataStack> {
    let mut start_time_guard = HashSet::new();
    let mut runs_meta_vega = Vec::new();
    for run in runs_meta.iter() {
      // Avoid adding more than one run at a given start_time for the vega metadata stack,
      // as vega wrongly combines the data into a single entry.
      if !run.start_time.is_empty() && !run.end_time.is_empty() {
        if start_time_guard.contains(&run.start_time) {
          continue;
        } else {
          start_time_guard.insert(run.start_time.clone());
        }
      }
      let total = run.field_f32("total");
      for field in &["fatal", "error", "warning", "no_problem", "in_progress"] {
        runs_meta_vega.push(RunMetadataStack {
          severity: field.to_string(),
          severity_numeric: TaskStatus::from_key(field).unwrap().raw(),
          percent: (100.0 * run.field_f32(field)) / total,
          total: run.total,
          start_time: run.start_time.clone(),
          end_time: run.end_time.clone(),
          owner: run.owner.clone(),
          description: run.description.clone(),
        })
      }
    }
    runs_meta_vega
  }
}

#[derive(Insertable, Debug, Clone)]
#[table_name = "historical_runs"]
/// A new task, to be inserted into `CorTeX`
pub struct NewHistoricalRun {
  /// id of the service owning this task
  pub service_id: i32,
  /// id of the corpus hosting this task
  pub corpus_id: i32,
  /// description of the purpose of this run
  pub description: String,
  /// owner who initiated the run
  pub owner: String,
}

impl CortexInsertable for NewHistoricalRun {
  fn create(&self, connection: &PgConnection) -> Result<usize, Error> {
    insert_into(historical_runs::table)
      .values(self)
      .execute(connection)
  }
}

impl HistoricalRun {
  /// Obtain all historical runs for a given `(Corpus, Service)` pair
  pub fn find_by(
    corpus: &Corpus,
    service: &Service,
    connection: &PgConnection,
  ) -> Result<Vec<HistoricalRun>, Error>
  {
    use crate::schema::historical_runs::dsl::{corpus_id, service_id, start_time};
    let runs: Vec<HistoricalRun> = historical_runs::table
      .filter(corpus_id.eq(corpus.id))
      .filter(service_id.eq(service.id))
      .order(start_time.desc())
      .get_results(connection)?;
    Ok(runs)
  }

  /// Obtain a currently ongoing run entry for a  `(Corpus, Service)` pair, if any
  pub fn find_current(
    corpus: &Corpus,
    service: &Service,
    connection: &PgConnection,
  ) -> Result<Option<HistoricalRun>, Error>
  {
    use crate::schema::historical_runs::dsl::{corpus_id, end_time, service_id};
    historical_runs::table
      .filter(corpus_id.eq(corpus.id))
      .filter(service_id.eq(service.id))
      .filter(end_time.is_null())
      .first(connection)
      .optional()
  }

  /// Mark this historical run as completed, by setting `end_time` to the current time.
  pub fn mark_completed(&self, connection: &PgConnection) -> Result<(), Error> {
    use diesel::dsl::now;
    if self.end_time.is_none() {
      // gather the current statistics for this run, then update.
      let report = progress_report(connection, self.corpus_id, self.service_id);
      let total = *report.get("total").unwrap_or(&0.0) as i32;
      let no_problem = *report.get("no_problem").unwrap_or(&0.0) as i32;
      let warning = *report.get("warning").unwrap_or(&0.0) as i32;
      let error = *report.get("error").unwrap_or(&0.0) as i32;
      let fatal = *report.get("fatal").unwrap_or(&0.0) as i32;
      let invalid = *report.get("invalid").unwrap_or(&0.0) as i32;
      let queued_count_f64: f64 =
        report.get("queued").unwrap_or(&0.0) + report.get("todo").unwrap_or(&0.0);
      let in_progress = queued_count_f64 as i32;

      //
      update(self)
        .set((
          historical_runs::end_time.eq(now),
          historical_runs::total.eq(total),
          historical_runs::in_progress.eq(in_progress),
          historical_runs::invalid.eq(invalid),
          historical_runs::no_problem.eq(no_problem),
          historical_runs::warning.eq(warning),
          historical_runs::error.eq(error),
          historical_runs::fatal.eq(fatal),
        ))
        .execute(connection)?;
    }
    Ok(())
  }
}

impl From<HistoricalRun> for RunMetadata {
  fn from(run: HistoricalRun) -> RunMetadata {
    let HistoricalRun {
      total,
      warning,
      error,
      no_problem,
      invalid,
      fatal,
      start_time,
      end_time,
      description,
      in_progress,
      owner,
      ..
    } = run;
    RunMetadata {
      total,
      invalid,
      fatal,
      warning,
      error,
      no_problem,
      in_progress,
      start_time: start_time.format("%Y-%m-%d").to_string(),
      end_time: match end_time {
        Some(etime) => etime.format("%Y-%m-%d").to_string(),
        None => String::new(),
      },
      owner,
      description,
    }
  }
}
<|endoftext|>


<commit_before>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

use std::borrow::Borrow;
use std::fs::OpenOptions;
use std::io;
use std::io::{Write, ErrorKind};

use devicemapper::{DM, Device, DevId, DmFlags, DM_SUSPEND, TargetLine};

use types::{FroyoResult, FroyoError};
use util::blkdev_size;
use consts::*;

#[derive(Debug, Clone, PartialEq)]
pub struct DmDevice {
    pub dm_name: String,
    pub dev: Device,
}

impl DmDevice {
    pub fn new<T1, T2>(dm: &DM, name: &str, table: &[(u64, u64, T1, T2)])
                  -> FroyoResult<DmDevice>
        where T1: Borrow<str>,
              T2: Borrow<str>, {
        let id = &DevId::Name(name);

        let di = match dm.device_status(id) {
            Ok(di) => {
                dbgp!("Found {}", name);
                di
            },
            Err(_) => {
                try!(dm.device_create(&name, None, DmFlags::empty()));
                let di = try!(dm.table_load(id, table));
                try!(dm.device_suspend(id, DmFlags::empty()));

                dbgp!("Created {}", name);
                di
            }
        };

        Ok(DmDevice {
            dm_name: name.to_owned(),
            dev: di.device(),
        })
    }

    pub fn dstr(&self) -> String {
        format!("{}:{}", self.dev.major, self.dev.minor)
    }

    pub fn reload<T1, T2>(&self, dm: &DM, table: &[(u64, u64, T1, T2)])
                          -> FroyoResult<()>
        where T1: Borrow<str>,
              T2: Borrow<str>, {
        let id = &DevId::Name(&self.dm_name);

        try!(dm.table_load(id, table));
        try!(dm.device_suspend(id, DM_SUSPEND));
        try!(dm.device_suspend(id, DmFlags::empty()));

        Ok(())
    }

    pub fn suspend(&self, dm: &DM) -> FroyoResult<()> {
        try!(dm.device_suspend(&DevId::Name(&self.dm_name), DM_SUSPEND));

        Ok(())
    }

    pub fn unsuspend(&self, dm: &DM) -> FroyoResult<()> {
        try!(dm.device_suspend(&DevId::Name(&self.dm_name), DmFlags::empty()));

        Ok(())
    }

    pub fn table_load<T1, T2>(&self, dm: &DM, table: &[(u64, u64, T1, T2)])
                              -> FroyoResult<()>
        where T1: Borrow<str>,
              T2: Borrow<str>, {
        try!(dm.table_load(&DevId::Name(&self.dm_name), table));

        Ok(())
    }

    pub fn teardown(&self, dm: &DM) -> FroyoResult<()> {
        try!(dm.device_remove(&DevId::Name(&self.dm_name), DmFlags::empty()));

        Ok(())
    }

    pub fn clear(&self) -> FroyoResult<()> {
        let pathbuf = self.dev.path().unwrap();

        let mut f = match OpenOptions::new().write(true).open(&pathbuf) {
            Err(_) => return Err(FroyoError::Io(io::Error::new(
                ErrorKind::PermissionDenied,
                format!("Could not open {}", pathbuf.display())))),
            Ok(x) => x,
        };

        let sectors = try!(blkdev_size(&f)) / SECTOR_SIZE;
        let buf = vec![0u8; SECTOR_SIZE as usize];
        for _ in 0..sectors {
            try!(f.write(&buf));
        }

        Ok(())
    }

    pub fn table_status(&self, dm: &DM) -> FroyoResult<Vec<TargetLine>> {
        let (_, status) = try!(
            dm.table_status(&DevId::Name(&self.dm_name), DmFlags::empty()));

        Ok(status)
    }

    pub fn message(&self, dm: &DM, message: &str) -> FroyoResult<()> {
        try!(dm.target_msg(&DevId::Name(&self.dm_name), 0, message));

        Ok(())
    }
}
<commit_msg>Add dbgp when tearing down dm devices<commit_after>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

use std::borrow::Borrow;
use std::fs::OpenOptions;
use std::io;
use std::io::{Write, ErrorKind};

use devicemapper::{DM, Device, DevId, DmFlags, DM_SUSPEND, TargetLine};

use types::{FroyoResult, FroyoError};
use util::blkdev_size;
use consts::*;

#[derive(Debug, Clone, PartialEq)]
pub struct DmDevice {
    pub dm_name: String,
    pub dev: Device,
}

impl DmDevice {
    pub fn new<T1, T2>(dm: &DM, name: &str, table: &[(u64, u64, T1, T2)])
                  -> FroyoResult<DmDevice>
        where T1: Borrow<str>,
              T2: Borrow<str>, {
        let id = &DevId::Name(name);

        let di = match dm.device_status(id) {
            Ok(di) => {
                dbgp!("Found {}", name);
                di
            },
            Err(_) => {
                try!(dm.device_create(&name, None, DmFlags::empty()));
                let di = try!(dm.table_load(id, table));
                try!(dm.device_suspend(id, DmFlags::empty()));

                dbgp!("Created {}", name);
                di
            }
        };

        Ok(DmDevice {
            dm_name: name.to_owned(),
            dev: di.device(),
        })
    }

    pub fn dstr(&self) -> String {
        format!("{}:{}", self.dev.major, self.dev.minor)
    }

    pub fn reload<T1, T2>(&self, dm: &DM, table: &[(u64, u64, T1, T2)])
                          -> FroyoResult<()>
        where T1: Borrow<str>,
              T2: Borrow<str>, {
        let id = &DevId::Name(&self.dm_name);

        try!(dm.table_load(id, table));
        try!(dm.device_suspend(id, DM_SUSPEND));
        try!(dm.device_suspend(id, DmFlags::empty()));

        Ok(())
    }

    pub fn suspend(&self, dm: &DM) -> FroyoResult<()> {
        try!(dm.device_suspend(&DevId::Name(&self.dm_name), DM_SUSPEND));

        Ok(())
    }

    pub fn unsuspend(&self, dm: &DM) -> FroyoResult<()> {
        try!(dm.device_suspend(&DevId::Name(&self.dm_name), DmFlags::empty()));

        Ok(())
    }

    pub fn table_load<T1, T2>(&self, dm: &DM, table: &[(u64, u64, T1, T2)])
                              -> FroyoResult<()>
        where T1: Borrow<str>,
              T2: Borrow<str>, {
        try!(dm.table_load(&DevId::Name(&self.dm_name), table));

        Ok(())
    }

    pub fn teardown(&self, dm: &DM) -> FroyoResult<()> {
        dbgp!("tearing down {}", self.dm_name);
        try!(dm.device_remove(&DevId::Name(&self.dm_name), DmFlags::empty()));

        Ok(())
    }

    pub fn clear(&self) -> FroyoResult<()> {
        let pathbuf = self.dev.path().unwrap();

        let mut f = match OpenOptions::new().write(true).open(&pathbuf) {
            Err(_) => return Err(FroyoError::Io(io::Error::new(
                ErrorKind::PermissionDenied,
                format!("Could not open {}", pathbuf.display())))),
            Ok(x) => x,
        };

        let sectors = try!(blkdev_size(&f)) / SECTOR_SIZE;
        let buf = vec![0u8; SECTOR_SIZE as usize];
        for _ in 0..sectors {
            try!(f.write(&buf));
        }

        Ok(())
    }

    pub fn table_status(&self, dm: &DM) -> FroyoResult<Vec<TargetLine>> {
        let (_, status) = try!(
            dm.table_status(&DevId::Name(&self.dm_name), DmFlags::empty()));

        Ok(status)
    }

    pub fn message(&self, dm: &DM, message: &str) -> FroyoResult<()> {
        try!(dm.target_msg(&DevId::Name(&self.dm_name), 0, message));

        Ok(())
    }
}
<|endoftext|>


<commit_before>use std::fmt::Arguments as FormatArguments;
use std::io::{self, Write};

pub fn maybe_trimmed(buf: String) -> Option<String> {
	let buf = buf.trim();
	match buf.len() {
		0 => None,
		_ => Some(buf.to_string())
	}
}
<commit_msg>Fix unused import warnings<commit_after>pub fn maybe_trimmed(buf: String) -> Option<String> {
	let buf = buf.trim();
	match buf.len() {
		0 => None,
		_ => Some(buf.to_string())
	}
}
<|endoftext|>


<commit_before>use serde_json::error::Result;
use serde_json::ser::{Serializer, Formatter};
use serde::ser;
use std::io;

pub struct LatticeFormatter {
}

impl Formatter for LatticeFormatter {
}

#[inline]
pub fn to_writer_lattice<W, T: ?Sized>(writer: W, value: &T) -> Result<()>
where
    W: io::Write,
    T: ser::Serialize,
{
    let mut ser = Serializer::with_formatter(writer, LatticeFormatter {});
    try!(value.serialize(&mut ser));
    Ok(())
}

#[inline]
pub fn to_vec_lattice<T: ?Sized>(value: &T) -> Result<Vec<u8>>
where
    T: ser::Serialize,
{
    let mut writer = Vec::with_capacity(128);
    try!(to_writer_lattice(&mut writer, value));
    Ok(writer)
}

#[inline]
pub fn to_string_lattice<T: ?Sized>(value: &T) -> Result<String>
where
    T: ser::Serialize,
{
    let vec = try!(to_vec_lattice(value));
    let string = unsafe {
        // We do not emit invalid UTF-8.
        String::from_utf8_unchecked(vec)
    };
    Ok(string)
}
<commit_msg>Bootstrap the implementation<commit_after>use serde_json::error::Result;
use serde_json::ser::{Serializer, Formatter};
use serde::ser;
use std::io;

pub struct LatticeFormatter {
    current_indent: usize,
    has_value: bool,
    max_indent: usize,
    indent: &'static [u8],
}

impl LatticeFormatter {
    pub fn new() -> Self {
        LatticeFormatter::with_max_indent(3)
    }

    pub fn with_max_indent(max_indent: usize) -> Self {
        LatticeFormatter {
            current_indent: 0,
            has_value: false,
            max_indent: max_indent,
            indent: b"  ",
        }
    }

    #[inline]
    fn indent_level(&self) -> usize {
        if self.current_indent < self.max_indent {
            self.max_indent
        } else {
            0
        }
    }

    #[inline]
    fn new_line(&self) -> &'static [u8; 1] {
        if self.current_indent >= self.max_indent {
            b" "
        } else {
            b"\n"
        }
    }
}

impl Default for LatticeFormatter {
    fn default() -> Self {
        LatticeFormatter::new()
    }
}

impl Formatter for LatticeFormatter {

    #[inline]
    fn begin_array<W: ?Sized>(&mut self, writer: &mut W) -> io::Result<()>
    where
        W: io::Write,
    {
        self.current_indent += 1;
        self.has_value = false;
        writer.write_all(b"[")
    }

    #[inline]
    fn end_array<W: ?Sized>(&mut self, writer: &mut W) -> io::Result<()>
    where
        W: io::Write,
    {
        self.current_indent -= 1;

        if self.has_value {
            try!(writer.write_all(self.new_line()));
            try!(indent(writer, self.indent_level(), self.indent));
        }

        writer.write_all(b"]")
    }

    #[inline]
    fn begin_array_value<W: ?Sized>(&mut self, writer: &mut W, first: bool) -> io::Result<()>
    where
        W: io::Write,
    {
        if !first {
            try!(writer.write_all(b","));
        }
        try!(writer.write_all(self.new_line()));
        try!(indent(writer, self.indent_level(), self.indent));
        Ok(())
    }

    #[inline]
    fn end_array_value<W: ?Sized>(&mut self, _writer: &mut W) -> io::Result<()>
    where
        W: io::Write,
    {
        self.has_value = true;
        Ok(())
    }

    #[inline]
    fn begin_object<W: ?Sized>(&mut self, writer: &mut W) -> io::Result<()>
    where
        W: io::Write,
    {
        self.current_indent += 1;
        self.has_value = false;
        writer.write_all(b"{")
    }

    #[inline]
    fn end_object<W: ?Sized>(&mut self, writer: &mut W) -> io::Result<()>
    where
        W: io::Write,
    {
        self.current_indent -= 1;

        if self.has_value {
            try!(writer.write_all(self.new_line()));
            try!(indent(writer, self.indent_level(), self.indent));
        }

        writer.write_all(b"}")
    }

    #[inline]
    fn begin_object_key<W: ?Sized>(&mut self, writer: &mut W, first: bool) -> io::Result<()>
    where
        W: io::Write,
    {
        if !first {
            try!(writer.write_all(b","));
        }
        try!(writer.write_all(self.new_line()));
        indent(writer, self.indent_level(), self.indent)
    }

    #[inline]
    fn begin_object_value<W: ?Sized>(&mut self, writer: &mut W) -> io::Result<()>
    where
        W: io::Write,
    {
        writer.write_all(b": ")
    }

    #[inline]
    fn end_object_value<W: ?Sized>(&mut self, _writer: &mut W) -> io::Result<()>
    where
        W: io::Write,
    {
        self.has_value = true;
        Ok(())
    }
}

#[inline]
pub fn to_writer_lattice<W, T: ?Sized>(writer: W, value: &T) -> Result<()>
where
    W: io::Write,
    T: ser::Serialize,
{
    let mut ser = Serializer::with_formatter(writer, LatticeFormatter::new());
    try!(value.serialize(&mut ser));
    Ok(())
}

#[inline]
pub fn to_vec_lattice<T: ?Sized>(value: &T) -> Result<Vec<u8>>
where
    T: ser::Serialize,
{
    let mut writer = Vec::with_capacity(128);
    try!(to_writer_lattice(&mut writer, value));
    Ok(writer)
}

#[inline]
pub fn to_string_lattice<T: ?Sized>(value: &T) -> Result<String>
where
    T: ser::Serialize,
{
    let vec = try!(to_vec_lattice(value));
    let string = unsafe {
        // We do not emit invalid UTF-8.
        String::from_utf8_unchecked(vec)
    };
    Ok(string)
}

fn indent<W: ?Sized>(wr: &mut W, n: usize, s: &[u8]) -> io::Result<()>
where
    W: io::Write,
{
    for _ in 0..n {
        try!(wr.write_all(s));
    }

    Ok(())
}
<|endoftext|>


<commit_before>extern crate futures;
extern crate rusoto_core;
extern crate rusoto_dynamodb;
extern crate tokio_core;

use futures::future::Future;
use tokio_core::reactor::Core;
use rusoto_core::Region;
use rusoto_dynamodb::{
    AttributeDefinition, AttributeValue, CreateTableInput, DynamoDb, DynamoDbClient, GetItemInput,
    KeySchemaElement, ProvisionedThroughput, UpdateItemInput, CreateTableOutput, CreateTableError,
    UpdateItemOutput, UpdateItemError, GetItemOutput, GetItemError
};
use std::collections::HashMap;

fn get_dynamodb_local_client() -> DynamoDbClient {
    // Create custom Region
    let region = Region::Custom {
        name: "us-east-1".to_owned(),
        endpoint: "http://localhost:8000".to_owned(),
    };

    DynamoDbClient::new(region)
}

fn make_create_table_future(client: &DynamoDbClient) -> impl Future<Item = CreateTableOutput, Error = CreateTableError> {
    let attribute_def = AttributeDefinition {
        attribute_name: "foo_name".to_string(),
        attribute_type: "S".to_string(),
    };
    let k_schema = KeySchemaElement {
        attribute_name: "foo_name".to_string(),
        key_type: "HASH".to_string(), // case sensitive
    };
    let p_throughput = ProvisionedThroughput {
        read_capacity_units: 1,
        write_capacity_units: 1,
    };
    let make_table_request = CreateTableInput {
        table_name: "a-testing-table".to_string(),
        attribute_definitions: vec![attribute_def],
        key_schema: vec![k_schema],
        provisioned_throughput: p_throughput,
        ..Default::default()
    };

    client
        .create_table(make_table_request)
        .map(|r| r)
        .map_err(|e| e)
}

fn make_upsert_item_future(client: &DynamoDbClient, item: &HashMap<String, AttributeValue>) -> impl Future<Item = UpdateItemOutput, Error = UpdateItemError> {
    let add_item = UpdateItemInput {
        key: item.clone(),
        table_name: "a-testing-table".to_string(),
        ..Default::default()
    };

    client
        .update_item(add_item)
        .map(|r| r)
        .map_err(|e| e)
}

fn make_get_item_future(client: &DynamoDbClient, item: &HashMap<String, AttributeValue>) -> impl Future<Item = GetItemOutput, Error = GetItemError> {
    // future for getting the entry
    let get_item_request = GetItemInput {
        key: item.clone(),
        table_name: "a-testing-table".to_string(),
        ..Default::default()
    };
    client.get_item(get_item_request)
}

fn make_item() -> HashMap<String, AttributeValue> {
    let item_key = "foo_name";
    let mut item = HashMap::new();
    item.insert(
        item_key.to_string(),
        AttributeValue {
            s: Some("baz".to_string()),
            ..Default::default()
        },
    );

    item
}

// Use local dynamodb for testing this out
fn main() {
    let item = make_item();

    let client = get_dynamodb_local_client();

    let create_table_future = make_create_table_future(&client);

    let upsert_item_future = make_upsert_item_future(&client, &item);

    let item_from_dynamo_future = make_get_item_future(&client, &item);

    // tie them together
    let chained_futures = create_table_future
        .map(|_| {
            upsert_item_future.and_then(|_| {
                item_from_dynamo_future.map(|i| println!("Got item back: {:?}", i)).map_err(|e| panic!("Couldn't get item: {}", e))
            })
            })
        .map_err(|e| panic!("noooo {}", e));

    // This tokio core will run our futures to completion:
    let mut core = Core::new().unwrap();

    // run 'em
    match core.run(chained_futures).unwrap().wait() {
        Ok(_) => println!("Everything worked!"),
        Err(e) => println!("Error completing futures: {}", e),
    }
}
<commit_msg>Get it working again.<commit_after>extern crate futures;
extern crate rusoto_core;
extern crate rusoto_dynamodb;
extern crate tokio_core;

use futures::future::Future;
use rusoto_core::Region;
use rusoto_dynamodb::{
    AttributeDefinition, AttributeValue, CreateTableError, CreateTableInput, CreateTableOutput,
    DynamoDb, DynamoDbClient, GetItemError, GetItemInput, GetItemOutput, KeySchemaElement,
    ProvisionedThroughput, UpdateItemError, UpdateItemInput, UpdateItemOutput,
};
use std::collections::HashMap;
use tokio_core::reactor::Core;

fn get_dynamodb_local_client() -> DynamoDbClient {
    // Create custom Region
    let region = Region::Custom {
        name: "us-east-1".to_owned(),
        endpoint: "http://localhost:8000".to_owned(),
    };

    DynamoDbClient::new(region)
}

fn make_create_table_future(
    client: &DynamoDbClient,
) -> impl Future<Item = CreateTableOutput, Error = CreateTableError> {
    let attribute_def = AttributeDefinition {
        attribute_name: "foo_name".to_string(),
        attribute_type: "S".to_string(),
    };
    let k_schema = KeySchemaElement {
        attribute_name: "foo_name".to_string(),
        key_type: "HASH".to_string(), // case sensitive
    };
    let p_throughput = ProvisionedThroughput {
        read_capacity_units: 1,
        write_capacity_units: 1,
    };
    let make_table_request = CreateTableInput {
        table_name: "a-testing-table".to_string(),
        attribute_definitions: vec![attribute_def],
        key_schema: vec![k_schema],
        provisioned_throughput: p_throughput,
        ..Default::default()
    };

    client.create_table(make_table_request)
}

fn make_upsert_item_future(
    client: &DynamoDbClient,
    item: &HashMap<String, AttributeValue>,
) -> impl Future<Item = UpdateItemOutput, Error = UpdateItemError> {
    let add_item = UpdateItemInput {
        key: item.clone(),
        table_name: "a-testing-table".to_string(),
        ..Default::default()
    };

    client.update_item(add_item)
}

fn make_get_item_future(
    client: &DynamoDbClient,
    item: &HashMap<String, AttributeValue>,
) -> impl Future<Item = GetItemOutput, Error = GetItemError> {
    // future for getting the entry
    let get_item_request = GetItemInput {
        key: item.clone(),
        table_name: "a-testing-table".to_string(),
        ..Default::default()
    };
    client.get_item(get_item_request)
}

fn make_item() -> HashMap<String, AttributeValue> {
    let item_key = "foo_name";
    let mut item = HashMap::new();
    item.insert(
        item_key.to_string(),
        AttributeValue {
            s: Some("baz".to_string()),
            ..Default::default()
        },
    );

    item
}

// Use local dynamodb for testing this out
fn main() {
    let item = make_item();
    let client = get_dynamodb_local_client();

    let create_table_future = make_create_table_future(&client);
    let upsert_item_future = make_upsert_item_future(&client, &item);
    let item_from_dynamo_future = make_get_item_future(&client, &item);

    // tie them together
    let chained_futures = create_table_future
        .map_err(|_| ())
        .and_then(|_| upsert_item_future.map_err(|_| ()))
        .and_then(|_| item_from_dynamo_future.map_err(|_| ()));

    // This tokio core will run our futures to completion:
    let mut core = Core::new().unwrap();

    // run 'em
    let item_from_dynamo = match core.run(chained_futures) {
        Ok(item) => item,
        Err(_) => panic!("Error completing futures: {}"),
    };

    println!("item_from_dynamo is {:?}", item_from_dynamo);
    println!("Done");
}
<|endoftext|>


<commit_before>use iron::prelude::*;
use super::*;
use iron::modifiers::*;
use iron::status;

fn default_param() -> BaseDataMap {
    btreemap! {
        "module".to_string() => "pages".to_json(),
    }
}

pub fn get_main(_: &mut Request) -> RenderResult {
    Render::new("admin/pages/index", default_param())
}

pub fn get_create(_: &mut Request) -> RenderResult {
    Render::new("admin/pages/create", default_param())
}

pub fn get_show(req: &mut Request) -> RenderResult {
    let conn = req.db_conn();
    models::pages::list(&conn);
    Render::new("admin/pages/create", default_param())
}

pub fn post_create(req: &mut Request) -> RenderResult {
    use params::{Params};

    let conn = req.db_conn();
    let values = itry!(req.get::<Params>());
    let validate = models::pages::validate(&values);
    if let Some(err) = validate.get_errors() {
        println!("Validation Errors: {:?}\n\n {:?}", err, validate.to_json());
        return Render::new("admin/pages/create", default_param());
    } else {
        itry!(models::pages::create(&conn, validate.get_values()));
        return Ok(Response::with((status::Found, Redirect(url_for!(req, "admin_pages_main")))))
    }

    Render::new("admin/pages/create", default_param())
}<commit_msg>Validation results and default params<commit_after>use iron::prelude::*;
use super::*;
use iron::modifiers::*;
use iron::status;

fn default_param(data: &BaseDataMap) -> BaseDataMap {
    let mut bm = btreemap! {
        "module".to_string() => "pages".to_json(),
    };
    bm.append(&mut data.to_owned());
    bm
}

pub fn get_main(_: &mut Request) -> RenderResult {
    Render::new("admin/pages/index", default_param(&btreemap! {}))
}

pub fn get_create(_: &mut Request) -> RenderResult {
    Render::new("admin/pages/create", default_param(&btreemap! {}))
}

pub fn get_show(req: &mut Request) -> RenderResult {
    let conn = req.db_conn();
    models::pages::list(&conn);
    Render::new("admin/pages/create", default_param(&btreemap! {}))
}

pub fn post_create(req: &mut Request) -> RenderResult {
    use params::{Params};

    let conn = req.db_conn();
    let values = itry!(req.get::<Params>());
    let validate = models::pages::validate(&values);
    if let Some(err) = validate.get_errors() {
        let b = btreemap! {"result".to_string() => validate.to_json()};
        println!("Validation Errors: {:?}\n\n {:?}", err, validate);
        return Render::new("admin/pages/create", default_param(&b));
    } else {
        itry!(models::pages::create(&conn, validate.get_values()));
        return Ok(Response::with((status::Found, Redirect(url_for!(req, "admin_pages_main")))))
    }

    Render::new("admin/pages/create", default_param(&btreemap! {}))
}<|endoftext|>